使用terraform管理粒度网络acl

时间:2017-11-20 08:55:59

标签: amazon-web-services terraform hcl

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

我尝试创建一个网络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,ssh入站这个cidr块和短暂出站的所有vpc类型的灵活性。

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

2 个答案:

答案 0 :(得分:1)

support for count in modules is implemented之前,你没有很多选择。在过去,我使用其他脚本工具(bash / python)在运行时生成了.tf文件,以解决这个干燥问题。

答案 1 :(得分:0)

Terraform 0.12支持Dynamic Nested Blocks

例如,您可以这样使用它:

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
  }

here所述:

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


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

enter image description here

enter image description here