I'm doing a proof-of-concept work with terraform to move our infrastructure code to it. It's my second day and I feel like I'm doing something extremely wrong or missing some points while trying to setup network ACL's because the code became very complex quickly and didn't even solve all the repetition.
I've tried to create a network-acl-rule module which I can re-use throughout the environments. Currently it looks like this;
# 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)}"
}
I use this with the following variables and module declaration, to make it easier for you to understand.
# 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"],
# :::
}
}
and below is how I call the module
# 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
}
I'm okay to have a bloated module implementation because that will be write once and never look back again for something like network acl. This implementation is nice for grouping rules per some cidr blocks. But it has the drawback that I need to repeat calling the module multiple times for every different cidr block I need the rule which will yield a lot of duplication.
In the end, what I'd like to achieve is, having a module which I can say http_inbound for this cidr blocks, ssh inbound for this cidr blocks and ephemeral outbound for all vpc kind of flexibility.
I could fight for bloating the module code a little bit more, but it felt to me It's not a correct way of doing the ACL's. Maybe smarter variable definitions with more duplication there rather than the duplication when calling the module. How people solve this kind of problems with terraform?