diff --git a/data-solutions/cmek-via-centralized-kms/main.tf b/data-solutions/cmek-via-centralized-kms/main.tf index bf19d03f..4f7e351a 100644 --- a/data-solutions/cmek-via-centralized-kms/main.tf +++ b/data-solutions/cmek-via-centralized-kms/main.tf @@ -60,11 +60,10 @@ module "vpc" { } module "vpc-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = module.project-service.project_id - network = module.vpc.name - admin_ranges_enabled = true - admin_ranges = [var.vpc_ip_cidr_range] + source = "../../modules/net-vpc-firewall" + project_id = module.project-service.project_id + network = module.vpc.name + admin_ranges = [var.vpc_ip_cidr_range] } ############################################################################### diff --git a/data-solutions/data-platform-foundations/02-resources/main.tf b/data-solutions/data-platform-foundations/02-resources/main.tf index 9e9b1f8d..d67930d4 100644 --- a/data-solutions/data-platform-foundations/02-resources/main.tf +++ b/data-solutions/data-platform-foundations/02-resources/main.tf @@ -167,14 +167,13 @@ module "vpc-transformation" { } module "firewall" { - source = "../../../modules/net-vpc-firewall" - project_id = var.project_ids.transformation - network = module.vpc-transformation.name - admin_ranges_enabled = false - admin_ranges = [""] - http_source_ranges = [] - https_source_ranges = [] - ssh_source_ranges = [] + source = "../../../modules/net-vpc-firewall" + project_id = var.project_ids.transformation + network = module.vpc-transformation.name + admin_ranges = [] + http_source_ranges = [] + https_source_ranges = [] + ssh_source_ranges = [] custom_rules = { iap-svc = { diff --git a/data-solutions/gcs-to-bq-with-dataflow/main.tf b/data-solutions/gcs-to-bq-with-dataflow/main.tf index c2e56084..f179f7d2 100644 --- a/data-solutions/gcs-to-bq-with-dataflow/main.tf +++ b/data-solutions/gcs-to-bq-with-dataflow/main.tf @@ -178,11 +178,10 @@ module "vpc" { } module "vpc-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = module.project-service.project_id - network = module.vpc.name - admin_ranges_enabled = true - admin_ranges = [var.vpc_ip_cidr_range] + source = "../../modules/net-vpc-firewall" + project_id = module.project-service.project_id + network = module.vpc.name + admin_ranges = [var.vpc_ip_cidr_range] } module "nat" { diff --git a/modules/net-vpc-firewall/README.md b/modules/net-vpc-firewall/README.md index d4909fec..83f8f7cd 100644 --- a/modules/net-vpc-firewall/README.md +++ b/modules/net-vpc-firewall/README.md @@ -19,7 +19,6 @@ module "firewall" { source = "./modules/net-vpc-firewall" project_id = "my-project" network = "my-network" - admin_ranges_enabled = true admin_ranges = ["10.0.0.0/8"] } # tftest:modules=1:resources=4 @@ -31,11 +30,10 @@ This is an example of how to define custom rules, with a sample rule allowing op ```hcl module "firewall" { - source = "./modules/net-vpc-firewall" - project_id = "my-project" - network = "my-network" - admin_ranges_enabled = true - admin_ranges = ["10.0.0.0/8"] + source = "./modules/net-vpc-firewall" + project_id = "my-project" + network = "my-network" + admin_ranges = ["10.0.0.0/8"] custom_rules = { ntp-svc = { description = "NTP service." @@ -53,6 +51,36 @@ module "firewall" { # tftest:modules=1:resources=5 ``` +### No predefined rules + +If you don't want any predefined rules set `admin_ranges`, `http_source_ranges`, `https_source_ranges` and `ssh_source_ranges` to an empty list. + +```hcl +module "firewall" { + source = "./modules/net-vpc-firewall" + project_id = "my-project" + network = "my-network" + admin_ranges = [] + http_source_ranges = [] + https_source_ranges = [] + ssh_source_ranges = [] + custom_rules = { + allow-https = { + description = "Allow HTTPS from internal networks." + direction = "INGRESS" + action = "allow" + sources = [] + ranges = ["rfc1918"] + targets = [] + use_service_accounts = false + rules = [{ protocol = "tcp", ports = [443] }] + extra_attributes = {} + } + } +} +# tftest:modules=1:resources=1 +``` + ## Variables @@ -61,10 +89,10 @@ module "firewall" { | network | Name of the network this set of firewall rules applies to. | string | ✓ | | | project_id | Project id of the project that holds the network. | string | ✓ | | | *admin_ranges* | IP CIDR ranges that have complete access to all subnets. | list(string) | | [] | -| *admin_ranges_enabled* | Enable admin ranges-based rules. | bool | | false | | *custom_rules* | List of custom rule definitions (refer to variables file for syntax). | map(object({...})) | | {} | | *http_source_ranges* | List of IP CIDR ranges for tag-based HTTP rule, defaults to the health checkers ranges. | list(string) | | ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"] | | *https_source_ranges* | List of IP CIDR ranges for tag-based HTTPS rule, defaults to the health checkers ranges. | list(string) | | ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"] | +| *named_ranges* | Names that can be used of valid values for the `ranges` field of `custom_rules` | map(list(string)) | | ... | | *ssh_source_ranges* | List of IP CIDR ranges for tag-based SSH rule, defaults to the IAP forwarders range. | list(string) | | ["35.235.240.0/20"] | ## Outputs @@ -76,4 +104,5 @@ module "firewall" { | custom_egress_deny_rules | Custom egress rules with allow blocks. | | | custom_ingress_allow_rules | Custom ingress rules with allow blocks. | | | custom_ingress_deny_rules | Custom ingress rules with deny blocks. | | +| rules | All google_compute_firewall resources created. | | diff --git a/modules/net-vpc-firewall/main.tf b/modules/net-vpc-firewall/main.tf index 2e2a1825..c196e470 100644 --- a/modules/net-vpc-firewall/main.tf +++ b/modules/net-vpc-firewall/main.tf @@ -15,11 +15,17 @@ */ locals { - rules-allow = { - for name, attrs in var.custom_rules : name => attrs if attrs.action == "allow" - } - rules-deny = { - for name, attrs in var.custom_rules : name => attrs if attrs.action == "deny" + custom_rules = { + for id, rule in var.custom_rules : + id => merge(rule, { + # make rules a map so we use it in a for_each + rules = { for index, ports in rule.rules : index => ports } + # lookup any named ranges references + ranges = flatten([ + for range in rule.ranges : + try(var.named_ranges[range], range) + ]) + }) } } @@ -28,7 +34,7 @@ locals { ############################################################################### resource "google_compute_firewall" "allow-admins" { - count = var.admin_ranges_enabled == true ? 1 : 0 + count = length(var.admin_ranges) > 0 ? 1 : 0 name = "${var.network}-ingress-admins" description = "Access from the admin subnet to all subnets" network = var.network @@ -87,44 +93,9 @@ resource "google_compute_firewall" "allow-tag-https" { # dynamic rules # ################################################################################ -resource "google_compute_firewall" "custom_allow" { +resource "google_compute_firewall" "custom-rules" { # provider = "google-beta" - for_each = local.rules-allow - name = each.key - description = each.value.description - direction = each.value.direction - network = var.network - project = var.project_id - source_ranges = each.value.direction == "INGRESS" ? each.value.ranges : null - destination_ranges = each.value.direction == "EGRESS" ? each.value.ranges : null - source_tags = each.value.use_service_accounts || each.value.direction == "EGRESS" ? null : each.value.sources - source_service_accounts = each.value.use_service_accounts && each.value.direction == "INGRESS" ? each.value.sources : null - target_tags = each.value.use_service_accounts ? null : each.value.targets - target_service_accounts = each.value.use_service_accounts ? each.value.targets : null - disabled = lookup(each.value.extra_attributes, "disabled", false) - priority = lookup(each.value.extra_attributes, "priority", 1000) - - dynamic "log_config" { - for_each = lookup(each.value.extra_attributes, "logging", null) != null ? [each.value.extra_attributes.logging] : [] - iterator = logging_config - content { - metadata = logging_config.value - } - } - - dynamic "allow" { - for_each = each.value.rules - iterator = rule - content { - protocol = rule.value.protocol - ports = rule.value.ports - } - } -} - -resource "google_compute_firewall" "custom_deny" { - # provider = "google-beta" - for_each = local.rules-deny + for_each = local.custom_rules name = each.key description = each.value.description direction = each.value.direction @@ -148,7 +119,18 @@ resource "google_compute_firewall" "custom_deny" { } dynamic "deny" { - for_each = each.value.rules + for_each = each.value.action == "deny" ? each.value.rules : {} + + iterator = rule + content { + protocol = rule.value.protocol + ports = rule.value.ports + } + } + + dynamic "allow" { + for_each = each.value.action == "allow" ? each.value.rules : {} + iterator = rule content { protocol = rule.value.protocol diff --git a/modules/net-vpc-firewall/outputs.tf b/modules/net-vpc-firewall/outputs.tf index 5a952f2a..5ddb56b1 100644 --- a/modules/net-vpc-firewall/outputs.tf +++ b/modules/net-vpc-firewall/outputs.tf @@ -18,39 +18,50 @@ output "admin_ranges" { description = "Admin ranges data." value = { - enabled = var.admin_ranges_enabled - ranges = var.admin_ranges_enabled ? join(",", var.admin_ranges) : "" + enabled = length(var.admin_ranges) > 0 + ranges = join(",", var.admin_ranges) } } output "custom_ingress_allow_rules" { description = "Custom ingress rules with allow blocks." value = [ - for rule in google_compute_firewall.custom_allow : - rule.name if rule.direction == "INGRESS" + for rule in google_compute_firewall.custom-rules : + rule.name if rule.direction == "INGRESS" && try(length(rule.allow), 0) > 0 ] } output "custom_ingress_deny_rules" { description = "Custom ingress rules with deny blocks." value = [ - for rule in google_compute_firewall.custom_deny : - rule.name if rule.direction == "INGRESS" + for rule in google_compute_firewall.custom-rules : + rule.name if rule.direction == "INGRESS" && try(length(rule.deny), 0) > 0 ] } output "custom_egress_allow_rules" { description = "Custom egress rules with allow blocks." value = [ - for rule in google_compute_firewall.custom_allow : - rule.name if rule.direction == "EGRESS" + for rule in google_compute_firewall.custom-rules : + rule.name if rule.direction == "EGRESS" && try(length(rule.allow), 0) > 0 ] } output "custom_egress_deny_rules" { description = "Custom egress rules with allow blocks." value = [ - for rule in google_compute_firewall.custom_deny : - rule.name if rule.direction == "EGRESS" + for rule in google_compute_firewall.custom-rules : + rule.name if rule.direction == "EGRESS" && try(length(rule.deny), 0) > 0 ] } + +output "rules" { + description = "All google_compute_firewall resources created." + value = merge( + google_compute_firewall.custom-rules, + try({ (google_compute_firewall.allow-admins.0.name) = google_compute_firewall.allow-admins.0 }, {}), + try({ (google_compute_firewall.allow-tag-ssh.0.name) = google_compute_firewall.allow-tag-ssh.0 }, {}), + try({ (google_compute_firewall.allow-tag-http.0.name) = google_compute_firewall.allow-tag-http.0 }, {}), + try({ (google_compute_firewall.allow-tag-https.0.name) = google_compute_firewall.allow-tag-https.0 }, {}) + ) +} diff --git a/modules/net-vpc-firewall/variables.tf b/modules/net-vpc-firewall/variables.tf index ff8a5b60..94755d2e 100644 --- a/modules/net-vpc-firewall/variables.tf +++ b/modules/net-vpc-firewall/variables.tf @@ -14,46 +14,12 @@ * limitations under the License. */ -variable "network" { - description = "Name of the network this set of firewall rules applies to." - type = string -} - -variable "project_id" { - description = "Project id of the project that holds the network." - type = string -} - -variable "admin_ranges_enabled" { - description = "Enable admin ranges-based rules." - type = bool - default = false -} - variable "admin_ranges" { description = "IP CIDR ranges that have complete access to all subnets." type = list(string) default = [] } -variable "ssh_source_ranges" { - description = "List of IP CIDR ranges for tag-based SSH rule, defaults to the IAP forwarders range." - type = list(string) - default = ["35.235.240.0/20"] -} - -variable "http_source_ranges" { - description = "List of IP CIDR ranges for tag-based HTTP rule, defaults to the health checkers ranges." - type = list(string) - default = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"] -} - -variable "https_source_ranges" { - description = "List of IP CIDR ranges for tag-based HTTPS rule, defaults to the health checkers ranges." - type = list(string) - default = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"] -} - variable "custom_rules" { description = "List of custom rule definitions (refer to variables file for syntax)." type = map(object({ @@ -72,3 +38,45 @@ variable "custom_rules" { })) default = {} } + +variable "http_source_ranges" { + description = "List of IP CIDR ranges for tag-based HTTP rule, defaults to the health checkers ranges." + type = list(string) + default = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"] +} + +variable "https_source_ranges" { + description = "List of IP CIDR ranges for tag-based HTTPS rule, defaults to the health checkers ranges." + type = list(string) + default = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"] +} + +variable "named_ranges" { + description = "Names that can be used of valid values for the `ranges` field of `custom_rules`" + type = map(list(string)) + default = { + any = ["0.0.0.0/0"] + dns-forwarders = ["35.199.192.0/19"] + health-checkers = ["35.191.0.0/16", "130.211.0.0/22", "209.85.152.0/22", "209.85.204.0/22"] + iap-forwarders = ["35.235.240.0/20"] + private-googleapis = ["199.36.153.8/30"] + restricted-googleapis = ["199.36.153.4/30"] + rfc1918 = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"] + } +} + +variable "network" { + description = "Name of the network this set of firewall rules applies to." + type = string +} + +variable "project_id" { + description = "Project id of the project that holds the network." + type = string +} + +variable "ssh_source_ranges" { + description = "List of IP CIDR ranges for tag-based SSH rule, defaults to the IAP forwarders range." + type = list(string) + default = ["35.235.240.0/20"] +} diff --git a/networking/hub-and-spoke-peering/main.tf b/networking/hub-and-spoke-peering/main.tf index a4800de4..6a6b3bfa 100644 --- a/networking/hub-and-spoke-peering/main.tf +++ b/networking/hub-and-spoke-peering/main.tf @@ -74,11 +74,10 @@ module "nat-hub" { } module "vpc-hub-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = var.project_id - network = module.vpc-hub.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) + source = "../../modules/net-vpc-firewall" + project_id = var.project_id + network = module.vpc-hub.name + admin_ranges = values(var.ip_ranges) } ################################################################################ @@ -100,11 +99,10 @@ module "vpc-spoke-1" { } module "vpc-spoke-1-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = module.project.project_id - network = module.vpc-spoke-1.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) + source = "../../modules/net-vpc-firewall" + project_id = module.project.project_id + network = module.vpc-spoke-1.name + admin_ranges = values(var.ip_ranges) } module "nat-spoke-1" { @@ -146,11 +144,10 @@ module "vpc-spoke-2" { } module "vpc-spoke-2-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = module.project.project_id - network = module.vpc-spoke-2.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) + source = "../../modules/net-vpc-firewall" + project_id = module.project.project_id + network = module.vpc-spoke-2.name + admin_ranges = values(var.ip_ranges) } module "nat-spoke-2" { diff --git a/networking/hub-and-spoke-vpn/main.tf b/networking/hub-and-spoke-vpn/main.tf index f3a1dec4..e1d61bc3 100644 --- a/networking/hub-and-spoke-vpn/main.tf +++ b/networking/hub-and-spoke-vpn/main.tf @@ -48,11 +48,10 @@ module "vpc-hub" { } module "vpc-hub-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = var.project_id - network = module.vpc-hub.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) + source = "../../modules/net-vpc-firewall" + project_id = var.project_id + network = module.vpc-hub.name + admin_ranges = values(var.ip_ranges) } module "vpn-hub-a" { @@ -140,11 +139,10 @@ module "vpc-spoke-1" { } module "vpc-spoke-1-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = var.project_id - network = module.vpc-spoke-1.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) + source = "../../modules/net-vpc-firewall" + project_id = var.project_id + network = module.vpc-spoke-1.name + admin_ranges = values(var.ip_ranges) } module "vpn-spoke-1" { @@ -204,11 +202,10 @@ module "vpc-spoke-2" { } module "vpc-spoke-2-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = var.project_id - network = module.vpc-spoke-2.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) + source = "../../modules/net-vpc-firewall" + project_id = var.project_id + network = module.vpc-spoke-2.name + admin_ranges = values(var.ip_ranges) } module "vpn-spoke-2" { diff --git a/networking/ilb-next-hop/vpc-left.tf b/networking/ilb-next-hop/vpc-left.tf index aedf3a4d..c5f8df22 100644 --- a/networking/ilb-next-hop/vpc-left.tf +++ b/networking/ilb-next-hop/vpc-left.tf @@ -38,12 +38,11 @@ module "vpc-left" { } module "firewall-left" { - source = "../../modules/net-vpc-firewall" - project_id = module.project.project_id - network = module.vpc-left.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) - ssh_source_ranges = ["35.235.240.0/20", "35.191.0.0/16", "130.211.0.0/22"] + source = "../../modules/net-vpc-firewall" + project_id = module.project.project_id + network = module.vpc-left.name + admin_ranges = values(var.ip_ranges) + ssh_source_ranges = ["35.235.240.0/20", "35.191.0.0/16", "130.211.0.0/22"] } module "nat-left" { diff --git a/networking/ilb-next-hop/vpc-right.tf b/networking/ilb-next-hop/vpc-right.tf index 661fd5d4..1bf590e9 100644 --- a/networking/ilb-next-hop/vpc-right.tf +++ b/networking/ilb-next-hop/vpc-right.tf @@ -52,12 +52,11 @@ module "vpc-right" { } module "firewall-right" { - source = "../../modules/net-vpc-firewall" - project_id = module.project.project_id - network = module.vpc-right.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) - ssh_source_ranges = ["35.235.240.0/20", "35.191.0.0/16", "130.211.0.0/22"] + source = "../../modules/net-vpc-firewall" + project_id = module.project.project_id + network = module.vpc-right.name + admin_ranges = values(var.ip_ranges) + ssh_source_ranges = ["35.235.240.0/20", "35.191.0.0/16", "130.211.0.0/22"] } module "nat-right" { diff --git a/networking/onprem-google-access-dns/main.tf b/networking/onprem-google-access-dns/main.tf index 9f39265d..caf66563 100644 --- a/networking/onprem-google-access-dns/main.tf +++ b/networking/onprem-google-access-dns/main.tf @@ -71,12 +71,11 @@ module "vpc" { } module "vpc-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = var.project_id - network = module.vpc.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) - ssh_source_ranges = var.ssh_source_ranges + source = "../../modules/net-vpc-firewall" + project_id = var.project_id + network = module.vpc.name + admin_ranges = values(var.ip_ranges) + ssh_source_ranges = var.ssh_source_ranges } module "vpn1" { diff --git a/networking/shared-vpc-gke/main.tf b/networking/shared-vpc-gke/main.tf index da404f04..fa11ebf4 100644 --- a/networking/shared-vpc-gke/main.tf +++ b/networking/shared-vpc-gke/main.tf @@ -130,11 +130,10 @@ module "vpc-shared" { } module "vpc-shared-firewall" { - source = "../../modules/net-vpc-firewall" - project_id = module.project-host.project_id - network = module.vpc-shared.name - admin_ranges_enabled = true - admin_ranges = values(var.ip_ranges) + source = "../../modules/net-vpc-firewall" + project_id = module.project-host.project_id + network = module.vpc-shared.name + admin_ranges = values(var.ip_ranges) } module "nat" {