Terraform CIDR块变量验证

3

Terraform变量的CIDR验证,寻找正则表达式的替代方法

以下是在Terraform版本13.0中测试过的代码,是否有不使用正则表达式实现相同功能的替代方法?

CIDR块 - 开始172.28.0.0.0/16

    variable "vpc_cidr" {
      description = "Kubernetes cluster CIDR notation for vpc."
      validation {
        condition     = can(regex("^([0-9]{1,3}\\.){3}[0-9]{1,3}($|/(16))$", var.pod_cidr))
        error_message = "Vpc_cidr value must be greater than 172.0.0.0/16."
      }
    }

如何使用cidrsubnet函数验证CIDR块172.28.x.x/16?
如果IP范围不在172.28.x.x/16之内,则验证将失败。
参考链接:https://www.terraform.io/docs/language/functions/cidrsubnet.html

1
请问您能否编辑一下您的问题,解释一下什么是被认为有效和无效的?您目前的验证(稍作修改以修复错误)似乎匹配了许多无效的CIDR以及没有前缀的CIDR(通常会被视为/32)。 - ydaetskcoR
5个回答

3

我更喜欢来自https://dev.to/drewmullen/terraform-variable-validation-with-samples-1ank的解决方案。

variable "string_like_valid_ipv4_cidr" {
  type    = string
  default = "10.0.0.0/16"

  validation {
    condition     = can(cidrhost(var.string_like_valid_ipv4_cidr, 32))
    error_message = "Must be valid IPv4 CIDR."
  }
}

请注意,正如在那里评论的那样,该条件需要进行修改才能适用于/32地址。

2
我想不到在今天的Terraform中有什么直接的方法可以实现你想要的功能,但我认为我们可以将检查分成两个条件,这两个条件合起来会产生相同的效果:
  1. 子网中的零地址必须为172.28.0.0
  2. 该范围的网络掩码必须为255.255.0.0
我们可以使用两个表达式来测试这两个规则:
  1. cidrhost(var.vpc_cidr, 0) == "172.28.0.0"
  2. cidrnetmask(var.vpc_cidr) == "255.255.0.0"
如果给定的内容无效,则这些函数都可能失败,而且如果给定一个IPv6地址,cidrnetmask函数也会失败,因此我们可以为它们两个添加try保护程序,将该错误转换为false结果作为condition期望的结果:
  1. try(cidrhost(var.vpc_cidr, 0), null) == "172.28.0.0"
  2. try(cidrnetmask(var.vpc_cidr), null) == "255.255.0.0"
try函数将返回第一个不产生动态错误的表达式的结果,因此,在上面的示例中,对cidrhostcidrnetmask函数的无效输入将导致诸如null == "172.28.0.0"的表达式,这将始终为false,因此仍然不会满足条件。
最后,我们可以使用&&运算符将它们组合在一起,以获得完整的condition表达式:
  condition = (
    try(cidrhost(var.vpc_cidr, 0), null) == "172.28.0.0" &&
    try(cidrnetmask(var.vpc_cidr), null) == "255.255.0.0"
  )

1
再次以全新的眼光看着这个问题,我意识到我可能误解了问题,因为我上面写的表达实际上与var.vpc_cidr == "172.28.0.0/16"是一样的,除了它可能允许非规范形式,如172.028.000.000/16。然而,我看到它被接受了,所以也许这是一个足够好的起点作为答案;我只是想在这里添加这个注释,以防将来有其他人看到并想知道同样的事情。 - Martin Atkins

0
你有一个0到多个,它应该大于172.0.0.0/16。例如:
172.1.0.0/16

不是:

172.0.0.0.0/16

0
有点小技巧,但还是可以的:
variable "vpc_cidr" {
  validation {
    condition = cidrsubnet("${var.pod_cidr}/16", 0, 0) == "172.28.0.0/16"
  }
}

0
这段代码是基于MartinAntkins Answer的,它允许你确保CIDR不仅是一个正确格式的值,而且前缀对于该大小是有效的;例如,10.0.0.1/16是无效的,因为范围中的第一个IP将是10.0.0.0,而这在前缀之前。
variable "demoIpv4Cidr" {
  type    = string
  default = "10.0.0.1/16" # try "10.0.0.0/16" for a valid value 
                          # or "10.0.0.x/16" for an invalidly formatted cidr

  validation {
    condition     = (
      can(cidrhost(var.demoIpv4Cidr, 0)) &&
      try(cidrhost(var.demoIpv4Cidr, 0), null) == split("/", var.demoIpv4Cidr)[0]
    )
    # the above could be simplified to:
    # condition = cidrhost(var.demoIpv4Cidr, 0) == split("/", var.demoIpv4Cidr)[0]
    # ...though that would throw "Error in function call" instead of "Invalid 
    # value for variable" were an invalid cidr (10.0.0.x/16) were used.
  
    error_message = "InvalidCIDRNotation: The CIDR is not correctly formatted, or the address prefix is invalid for the CIDR's size"
    # InvalidCIDRNotation is an existing error code; so may be helpful if anyone googles it.
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接