【问题标题】:Managing granular network acl's with terraform使用 terraform 管理粒度网络 acl
【发布时间】:2018-05-03 10:41:00
【问题描述】:

我正在使用 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 解决这类问题?

【问题讨论】:

  • 我强烈建议阅读“Terraform up and running”一书,作者是来自战壕的人。
  • @marco.m,谢谢你的建议,我已经读过这本书了,很好,但它没有回答我的问题:)

标签: amazon-web-services terraform hcl


【解决方案1】:

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

【讨论】:

  • 我考虑过使用 python + jinja 进行模板化,但在完全理解 terraform 之前我不想承诺它。我想我会随着一些奇怪的模块进行一些重复,并且会实现一些可以接受的东西。如果效果好,我会发布解决方案。
【解决方案2】:

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规则:

【讨论】:

    猜你喜欢
    • 2019-01-20
    • 1970-01-01
    • 2010-10-03
    • 2014-03-22
    • 1970-01-01
    • 1970-01-01
    • 2019-01-19
    • 1970-01-01
    • 2023-03-16
    相关资源
    最近更新 更多