如何在 Terraform 中验证 IP 地址?

use*_*708 5 variables azure terraform azure-devops

我正在使用 Terraform 将代码部署到我的 Azure 基础设施中。

我有一个带有一些网络规则的 Azure 防火墙,其中有一堆自由文本 IP 地址作为源/目标。下面是一个例子;[请注意,为了本示例,真实的 IP 地址已被更改];

网络规则收集

  network_rule_collection {
    name     = "test_rules"
    priority = 400
    action   = "Allow"
    rule {
      name                  = "test-rule-1"
      protocols             = ["Any"]
      source_addresses      = ["123.0.2.10/32"]
      destination_ports     = ["1234"]
      destination_addresses = ["124.82.189.200/32","125,82.189.200/32","126..82.189.200/32"]
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

[注意,IP地址中有错误是为了演示]

但是,当我运行 Terraform Validate 时,它​​没有显示任何错误(即使上面输入了无效的 IP 地址)

因此,我需要一种方法来验证自由文本 IP 地址,作为 Terraform 验证/计划的一部分。目前,Terraform 接受这一点并将无效 IP 部署到基础设施中。

Mar*_*ins 6

由于您填充的参数被定义为采用 CIDR 块地址,原则上提供程序可以验证这些,但在这种特殊情况下它似乎没有自己的验证规则,因此它依赖于远程 API 的验证因此仅在应用步骤期间生效。

可能值得在提供商的 GitHub 存储库中打开一个问题来讨论在此处添加内置验证的可能性,但为了这个答案,我将假设这是不可能的,并讨论如何在自己的配置中定义验证规则。


由于这些值直接硬编码在资源配置中,因此无法进行自定义验证,因为块的内容resource(除了一些特殊参数(如countfor_each))完全由相应提供者负责。

但是,如果您打算编写一个共享 Terraform 模块,将这些 IP 地址作为输入变量,然后从资源配置中引用它们,则可以编写自定义验证规则来描述附加约束,这些约束必须为 true 才能获得特定值该变量被认为是有效的。

condition块中的参数需要validation一个布尔值,即true条件是否成立以及false条件是否不满足。然而,由于 Terraform 还具有许多内置函数,如果不满足其自己的验证规则,这些函数会被定义为失败并出现错误,因此 Terraform 还具有一个特殊函数,可以在特殊can上下文中计算表达式,其中将失败转换为结果false,任何成功都会转化为true结果,从而满足论证的期望condition

典型的策略是识别现有的 Terraform 函数,该函数具有与您要应用的相同的验证规则,并在内部调用该值can以使用其成功或失败作为验证条件。

特别是对于 CIDR 块地址,Terraform 有少量函数将这些地址作为输入并生成派生的 CIDR 块地址或 IP 地址。例如,cidrnetmask采用 IPv4 CIDR 块地址并以网络掩码表示法返回相同的地址。如果给定的字符串不是有效的 IPv4 CIDR 块,它将失败,因此它似乎是描述您要在此处检查的规则的良好候选者:

variable "source_address" {
  type = string

  validation {
    condition     = can(cidrnetmask(var.source_address))
    error_message = "Must be a valid IPv4 CIDR block address."
  }
}
Run Code Online (Sandbox Code Playgroud)

这里的示例有接受多个地址的额外要求,因此需要稍微复杂的验证规则来测试条件是否适用于给定集合的所有成员,这就是该函数的alltrue用途

variable "source_addresses" {
  type = set(string)

  validation {
    condition = alltrue([
      for a in var.source_addresses : can(cidrnetmask(a))
    ])
    error_message = "All elements must be valid IPv4 CIDR block addresses."
  }
}
Run Code Online (Sandbox Code Playgroud)

这里的表达式通过尝试集合中的每个元素来[ for ... ]生成布尔结果列表。然后解释该结果并仅当列表中的每个元素都是 时才返回单个值。can(cidrnetmask(a))aalltruetruetrue

为了应用这些规则,您需要通过这些输入变量传递可能无效的 IP 地址,而不是像resource示例中那样直接在块内提供它们。只有当您打算编写一个可重用模块(其中调用者将为每个实例提供不同的 IP 地址)时,这才真正有意义。如果您打算只拥有一组固定的 IP 地址,那么在最初指定它们时确保它们有效并相信它们在未来将保持有效(除非发生更改)会更简单。


CSh*_*cks 2

根据文档,验证将验证语法,而不是值。

验证运行检查以验证配置在语法上是否有效

一种选择是定义变量并使用正则表达式添加自定义验证规则。参考

variable "ip_address" {
    type          = string
    description   = "Example to validate IP address."
    validation {
        condition = can(regex("^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",var.ip_address))
        error_message = "Invalid IP address provided."
    }
}
Run Code Online (Sandbox Code Playgroud)