如何创建支持多场景配置的可复用AWS安全组Terraform模块
可复用Terraform AWS安全组模块解决方案
核心思路
将单一的端口变量重构为结构化的规则数组,每个规则独立定义端口范围、协议、来源类型(CIDR/安全组ID),通过dynamic块遍历生成对应Ingress规则,同时支持灵活的Egress规则配置,完全覆盖混合使用CIDR和安全组引用的场景。
模块实现代码
variables.tf
定义结构化规则变量,添加验证逻辑避免无效配置:
variable "name" { description = "安全组名称" type = string } variable "description" { description = "安全组描述" type = string default = "Managed by Terraform" } variable "vpc_id" { description = "安全组所属VPC ID" type = string } # 结构化Ingress规则:支持CIDR、IPv6 CIDR或安全组来源 variable "ingress_rules" { description = "Ingress规则列表,每个规则需指定端口、协议及至少一种来源" type = list(object({ description = string from_port = number to_port = number protocol = string cidr_blocks = list(string) source_security_group_ids = list(string) ipv6_cidr_blocks = list(string) })) default = [] # 验证规则:确保每个规则至少有一个合法来源 validation { condition = alltrue([for r in var.ingress_rules : length(r.cidr_blocks) > 0 || length(r.source_security_group_ids) > 0 || length(r.ipv6_cidr_blocks) > 0]) error_message = "每个Ingress规则必须指定CIDR、IPv6 CIDR或安全组来源中的至少一种。" } } # 可选默认Egress规则:开放全部出站流量 variable "egress_rules" { description = "Egress规则列表" type = list(object({ description = string from_port = number to_port = number protocol = string cidr_blocks = list(string) ipv6_cidr_blocks = list(string) })) default = [ { description = "Allow all outbound traffic" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } ] }
main.tf
通过dynamic块遍历规则数组,生成安全组配置:
resource "aws_security_group" "this" { name = var.name description = var.description vpc_id = var.vpc_id # 动态生成Ingress规则 dynamic "ingress" { for_each = var.ingress_rules content { description = ingress.value.description from_port = ingress.value.from_port to_port = ingress.value.to_port protocol = ingress.value.protocol cidr_blocks = ingress.value.cidr_blocks source_security_group_ids = ingress.value.source_security_group_ids ipv6_cidr_blocks = ingress.value.ipv6_cidr_blocks } } # 动态生成Egress规则 dynamic "egress" { for_each = var.egress_rules content { description = egress.value.description from_port = egress.value.from_port to_port = egress.value.to_port protocol = egress.value.protocol cidr_blocks = egress.value.cidr_blocks ipv6_cidr_blocks = egress.value.ipv6_cidr_blocks } } tags = { Name = var.name } }
outputs.tf
输出安全组ID/ARN,供其他资源或模块引用:
output "security_group_id" { description = "安全组ID" value = aws_security_group.this.id } output "security_group_arn" { description = "安全组ARN" value = aws_security_group.this.arn }
模块使用示例(匹配需求场景)
调用模块创建你需要的四个安全组:
# 1. Web EC2安全组:开放80、443端口至公网 module "web_ec2_sg" { source = "./path/to/your/sg-module" # 替换为你的模块实际路径 name = "web-ec2-sg" description = "Web EC2安全组:允许公网访问80/443" vpc_id = var.vpc_id ingress_rules = [ { description = "Allow HTTP from public" from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] source_security_group_ids = [] ipv6_cidr_blocks = ["::/0"] }, { description = "Allow HTTPS from public" from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] source_security_group_ids = [] ipv6_cidr_blocks = ["::/0"] } ] } # 2. App EC2安全组:开放8000端口至公网 module "app_ec2_sg" { source = "./path/to/your/sg-module" name = "app-ec2-sg" description = "App EC2安全组:允许公网访问8000" vpc_id = var.vpc_id ingress_rules = [ { description = "Allow App traffic from public" from_port = 8000 to_port = 8000 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] source_security_group_ids = [] ipv6_cidr_blocks = ["::/0"] } ] } # 3. RDS安全组:开放5432端口给Web/App EC2安全组 module "rds_sg" { source = "./path/to/your/sg-module" name = "rds-sg" description = "RDS安全组:仅允许Web/App EC2访问5432" vpc_id = var.vpc_id ingress_rules = [ { description = "Allow PostgreSQL from Web/App EC2" from_port = 5432 to_port = 5432 protocol = "tcp" cidr_blocks = [] source_security_group_ids = [module.web_ec2_sg.security_group_id, module.app_ec2_sg.security_group_id] ipv6_cidr_blocks = [] } ] } # 4. Redis安全组:开放6379端口给Web/App EC2安全组 module "redis_sg" { source = "./path/to/your/sg-module" name = "redis-sg" description = "Redis安全组:仅允许Web/App EC2访问6379" vpc_id = var.vpc_id ingress_rules = [ { description = "Allow Redis from Web/App EC2" from_port = 6379 to_port = 6379 protocol = "tcp" cidr_blocks = [] source_security_group_ids = [module.web_ec2_sg.security_group_id, module.app_ec2_sg.security_group_id] ipv6_cidr_blocks = [] } ] }
关键说明
- 灵活性:每个Ingress规则可独立选择来源类型,同时支持CIDR公网访问和安全组内部访问。
- 可复用性:模块可重复调用创建任意数量的安全组,无需修改核心代码。
- 依赖自动处理:Terraform会自动识别安全组之间的依赖关系(如RDS安全组依赖Web/App安全组ID),无需手动配置
depends_on。 - 错误预防:变量验证逻辑避免出现无来源的无效规则。
内容的提问来源于stack exchange,提问作者Nijo
相关产品推荐
相关产品推荐

