Terraform如何设置变量判定通配符匹配指定环境安全组
问题根因
你现在的实现有两个核心错误,导致匹配结果不符合预期:
- 环境判断逻辑有漏洞:仅用
contains()做子串匹配,一旦实例名里出现带dev/test/prod片段的非环境字段(比如devops、testvm这类命名),就会出现环境误判;且你最初的代码只定义了is_dev标识,is_test/is_prod判断缺失,三元表达式链逻辑不完整。 - 匹配规则语法完全错误:你写的
dp-[dev|stage|prod]*-eks_worker_sg混淆了正则和glob的语法规则:- 方括号
[]在glob、正则语法里都是单个字符的匹配集合,不是多选分组。你写的[dev|stage|prod]实际含义是匹配d/e/v/|/s/t/a/g/p/r/o这11个单个字符中的任意一个,根本不是匹配dev/test/prod三个完整字符串,自然会漏过规则匹配到无关安全组。 - Terraform的AWS安全组数据源普通
name过滤字段仅支持*(匹配任意长度任意字符)、?(匹配单个任意字符)的glob语法,不支持正则的多选、分组逻辑,要做复杂前缀匹配必须用name_regex字段传标准正则。
- 方括号
正确实现方案
第一步:修正环境判断逻辑
不要用简单的contains()做模糊匹配,用带边界的正则判断环境,避免子串误判,同时直接生成对应环境的安全组前缀,从根源上缩小匹配范围:
locals { # 匹配带边界的环境关键字,避免fdp、devops这类带零散字符的命名误判 is_dev = length(regexall("(^|[^a-z])dev([^a-z]|$)", var.dp_instance)) > 0 is_test = length(regexall("(^|[^a-z])test([^a-z]|$)", var.dp_instance)) > 0 is_prod = length(regexall("(^|[^a-z])prod([^a-z]|$)", var.dp_instance)) > 0 # 直接生成当前环境对应的安全组前缀,不会跨环境匹配 sg_name_pattern = is_dev ? "dp-dev*-worker_sg" : ( is_test ? "dp-test*-worker_sg" : ( is_prod ? "dp-prod*-worker_sg" : "dp-dev*-worker_sg" ) ) }
第二步:安全组匹配逻辑调整
推荐方案(零误匹配)
直接把上面生成的local.sg_name_pattern传给安全组查询的name参数即可。比如当前是dev环境,传入的匹配规则就是dp-dev*-worker_sg,只会匹配dp-dev开头的安全组,dp-fdp1-*这类不符合前缀要求的资源会被直接过滤,完全不需要写复杂的多环境合并通配规则,从逻辑上杜绝跨环境、无关资源误匹配的问题。
# 安全组查询示例 data "aws_security_groups" "worker" { filter { name = "group-name" values = [local.sg_name_pattern] } }
备选方案(需同时匹配三个环境时使用)
如果业务逻辑确实需要在一个规则里同时覆盖三个环境的安全组,不要在glob规则里硬写正则语法,改用name_regex字段传标准正则,严格限制前缀匹配:
data "aws_security_groups" "worker" { # 正则含义:^匹配字符串开头,严格要求dp-后紧跟dev/test/prod完整串,结尾必须是worker_sg name_regex = "^dp-(dev|test|prod).*-worker_sg$" }
这个正则会强制校验安全组名称开头必须是dp-dev/dp-test/dp-prod,dp-fdp1-xxx这类名称因为开头不符合要求,会被直接过滤。
避坑提醒
- 普通glob匹配不支持
|多选、()分组这类正则语法,不要混用两种匹配规则。 - 优先用「按当前环境生成单值匹配规则」的逻辑,不要写覆盖多环境的大通配,既能减少误匹配,也能避免跨环境资源被错误引用。
- 判断环境关键字时一定要加匹配边界,不要直接用
contains()做模糊匹配,避免非环境字段带关键字片段导致判断错误。
内容的提问来源于stack exchange,提问作者powerstar2
相关产品推荐
相关产品推荐

