2

我正在使用 terraform 进行概念验证工作,以将我们的基础架构代码移至其中。这是我的第二天,我觉得我在尝试设置网络 ACL 时做错了什么或遗漏了一些要点,因为代码很快变得非常复杂,甚至没有解决所有重复问题。

我尝试创建一个可以在整个环境中重复使用的 network-acl-rule 模块。目前它看起来像这样;

# modules/acl/main.tf
resource "aws_network_acl_rule" "acl-rule-example" {
  network_acl_id = "${var.network_acl_id}"
  count = "${length(var.cidrs) * length(var.rules)}"

  rule_number    = "${var.rule_number + count.index}"
  from_port      = "${element(var.all_acl_rules[var.rules[floor(count.index / length(var.cidrs))]], 0)}"
  to_port        = "${element(var.all_acl_rules[var.rules[floor(count.index / length(var.cidrs))]], 1)}"
  egress         = "${element(var.all_acl_rules[var.rules[floor(count.index / length(var.cidrs))]], 2)}"
  protocol       = "${element(var.all_acl_rules[var.rules[floor(count.index / length(var.cidrs))]], 3)}"
  rule_action    = "${element(var.all_acl_rules[var.rules[floor(count.index / length(var.cidrs))]], 4)}"
  cidr_block     = "${element(var.cidrs, count.index)}"
}

我将它与以下变量和模块声明一起使用,以使您更容易理解。

# variables.tf
variable "all_acl_rules" {
  type = "map"

  # [from_port, to_port, egress, protocol, action, description]
  default = {
    # ephemeral outbound
    ephemeral_outbound = [1024, 65535, true, "tcp", "allow", "ephemeral-outbound"]

    # basic inbounds
    http_inbound  = [80, 80, false, "tcp", "allow", "http-inbound"]
    https_inbound = [443, 443, false, "tcp", "allow", "https-inbound"]
    ssh_inbound   = [22, 22, false, "tcp", "allow", "https-inbound"]

    # :::
  }
}

variable "cidr_blocks" {
  type = "map"
  default = {
    "all"     = ["0.0.0.0/0"],
    "vpc"     = ["10.0.0.0/8"],
    "clients" = ["x.x.x.x/32", "x.x.x.x/32", "x.x.x.x/30"],

    # :::
  }
}

下面是我如何调用模块

# main.tf
module "clients-acl-rule" {
 source = "modules/acl"

 network_acl_id = "${aws_network_acl.public-acl.id}"

 all_acl_rules = "${var.acl_rules}"
 cidrs = "${var.cidr_blocks["clients"]}"
 rules = ["http_inbound", "https_inbound", "ephemeral_outbound"]
 rule_number = 20
}

我可以有一个臃肿的模块实现,因为这将被编写一次,并且永远不会再回头看网络 acl 之类的东西。此实现非常适合按某些 cidr 块对规则进行分组。但它的缺点是我需要为每个不同的 cidr 块重复调用模块多次,我需要会产生大量重复的规则。

最后,我想要实现的是,拥有一个模块,我可以说这个 cidr 块的 http_inbound、这个 cidr 块的 ssh 入站和所有 vpc 类型的灵活性的临时出站。

我可以争取更多地膨胀模块代码,但我觉得这不是做 ACL 的正确方法。也许更聪明的变量定义有更多的重复而不是调用模块时的重复。人们如何用 terraform 解决这类问题?

4

2 回答 2

1

在实现countin modules 的支持之前,您没有太多选择。过去,我使用其他脚本工具(bash/python)在运行时生成 .tf 文件来解决这个 DRY 问题。

于 2017-11-21T14:55:00.323 回答
0

Terraform 0.12 支持动态嵌套块

例如,您像这样使用它:

resource "aws_network_acl" "public_tier" {
  vpc_id = aws_vpc.my_vpc.id
  subnet_ids = [for s in aws_subnet.public : s.id]

  tags = {
    Name = "my-nacl"
  }

  dynamic "egress" {
    for_each = [for rule_obj in local.nacl_rules : {
      port       = rule_obj.port
      rule_no    = rule_obj.rule_num
      cidr_block = rule_obj.cidr
    }]
    content {
      protocol   = "tcp"
      rule_no    = egress.value["rule_no"]
      action     = "allow"
      cidr_block = egress.value["cidr_block"]
      from_port  = egress.value["port"]
      to_port    = egress.value["port"]
    }
  }

  dynamic "ingress" {
    for_each = [for rule_obj in local.nacl_rules : {
      port       = rule_obj.port
      rule_no    = rule_obj.rule_num
      cidr_block = rule_obj.cidr
    }]
    content {
      protocol   = "tcp"
      rule_no    = ingress.value["rule_no"]
      action     = "allow"
      cidr_block = ingress.value["cidr_block"]
      from_port  = ingress.value["port"]
      to_port    = ingress.value["port"]
    }
  }

}


locals {
  nacl_rules = [
    { port : 22,   rule_num : 100, cidr : "0.0.0.0/0" },
    { port : 80,   rule_num : 110, cidr : "0.0.0.0/0" },
    { port : 443,  rule_num : 120, cidr : "0.0.0.0/0" }
  ]
}

请注意,您可能需要添加以下egress块:

  egress{
     protocol   = "tcp"
      rule_no    = 300
      action     = "allow"
      cidr_block = "0.0.0.0/0"
      from_port  = 1024
      to_port    = 65535
  }

如此处所述:

要启用与实例上运行的服务的连接,关联的网络 ACL 必须允许服务正在侦听的端口上的入站流量以及来自临时端口的出站流量。当客户端连接到服务器时,临时端口范围 (1024-65535) 中的随机端口将成为客户端的源端口。


我们可以在控制台中自动添加(*)DENY ALL规则:

在此处输入图像描述

在此处输入图像描述

于 2020-09-16T12:09:03.830 回答