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