如何通过Terratest的init和plan验证Terraform安全组规则端口
用Terratest精准验证Terraform安全组规则(仅Init/Plan)
不用部署资源,直接解析Terraform Plan的结构化输出,就能精准校验安全组的入站、出站端口,比模糊的字符串匹配靠谱得多。
实现步骤
1. 生成并解析Terraform Plan的JSON输出
通过Terratest执行terraform init和terraform plan,并将计划输出转为JSON格式,直接提取结构化的安全组规则数据,避免靠字符串匹配猜测内容。
2. 提取安全组规则的端口信息
从JSON输出中定位到目标安全组的ingress和egress字段,解析其中的端口范围字段(比如AWS安全组用from_port和to_port,不同云厂商字段可能有差异)。
3. 编写精准断言
用Terratest集成的assert包直接校验端口值是否符合预期,比如检查入站是否仅开放指定端口、出站端口范围是否合规。
代码示例
package test import ( "encoding/json" "testing" "github.com/gruntwork-io/terratest/modules/terraform" "github.com/stretchr/testify/assert" ) // 仅定义Plan中需要用到的结构体字段,可按需扩展 type TerraformPlan struct { ResourceChanges []struct { Address string `json:"address"` Change struct { After map[string]interface{} `json:"after"` } `json:"change"` } `json:"resource_changes"` } func TestSecurityGroupRules(t *testing.T) { t.Parallel() // 配置Terraform模块路径 terraformOpts := &terraform.Options{ TerraformDir: "../path/to/your/terraform/module", } // 执行init和plan,生成plan文件 planFilePath := terraform.InitAndPlanWithOpts(t, terraformOpts, terraform.WithPlanOut("plan.out")) // 将plan文件转为JSON格式输出 planJSON := terraform.ShowPlanJSON(t, terraformOpts, planFilePath) // 解析JSON到结构体 var plan TerraformPlan err := json.Unmarshal([]byte(planJSON), &plan) assert.NoError(t, err) // 定位目标安全组 targetSGAddress := "aws_security_group.your_sg_name" var targetSG map[string]interface{} for _, rc := range plan.ResourceChanges { if rc.Address == targetSGAddress { targetSG = rc.Change.After break } } assert.NotNil(t, targetSG, "目标安全组未在Plan中找到") // 校验入站规则端口 ingressRules := targetSG["ingress"].([]interface{}) expectedIngressPorts := []int{22, 443} for _, rule := range ingressRules { ruleMap := rule.(map[string]interface{}) fromPort := int(ruleMap["from_port"].(float64)) toPort := int(ruleMap["to_port"].(float64)) // 验证端口在预期列表内,且为单一端口(from=to) assert.Contains(t, expectedIngressPorts, fromPort) assert.Equal(t, fromPort, toPort) } // 校验出站规则(示例:允许所有端口) egressRules := targetSG["egress"].([]interface{}) for _, rule := range egressRules { ruleMap := rule.(map[string]interface{}) fromPort := int(ruleMap["from_port"].(float64)) toPort := int(ruleMap["to_port"].(float64)) assert.Equal(t, 0, fromPort) assert.Equal(t, 0, toPort) // AWS安全组中0代表所有端口 } }
关键说明
- 结构体
TerraformPlan可根据实际Plan的JSON结构扩展字段,比如需要校验源IP、协议等规则时,只需补充对应字段即可。 - 不同云厂商的安全组字段可能不同:比如Azure用
destination_port_ranges,需要对应调整解析逻辑。 - 用
terraform.ShowPlanJSON直接获取结构化输出,比自行执行shell命令解析更稳定可靠。
内容的提问来源于stack exchange,提问作者Bunny
相关产品推荐
相关产品推荐

