/** * Copyright 2024 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ locals { _factory_rules_folder = try(pathexpand(var.factories_config.rules_folder), null) # define list of rule files _factory_rule_files = local._factory_rules_folder == null ? [] : [ for f in try(fileset(local._factory_rules_folder, "**/*.yaml"), []) : "${local._factory_rules_folder}/${f}" ] # decode rule files and account for optional attributes _factory_rule_list = flatten([ for f in local._factory_rule_files : [ for direction, ruleset in yamldecode(file(f)) : [ for name, rule in ruleset : { name = name deny = try(rule.deny, false) rules = try(rule.rules, [{ protocol = "all", ports = null }]) description = try(rule.description, null) destination_ranges = try(rule.destination_ranges, null) direction = upper(direction) disabled = try(rule.disabled, null) enable_logging = try(rule.enable_logging, null) priority = try(rule.priority, 1000) source_ranges = try(rule.source_ranges, null) sources = try(rule.sources, null) targets = try(rule.targets, null) use_service_accounts = try(rule.use_service_accounts, false) } ] ] ]) _factory_rules = { for r in local._factory_rule_list : r.name => r if contains(["EGRESS", "INGRESS"], r.direction) } _named_ranges = merge( ( var.factories_config.cidr_tpl_file != null ? yamldecode(pathexpand(file(var.factories_config.cidr_tpl_file))) : {} ), var.named_ranges ) _rules = merge( local._factory_rules, local._rules_egress, local._rules_ingress ) _rules_egress = { for name, rule in merge(var.egress_rules) : name => merge(rule, { direction = "EGRESS" }) } _rules_ingress = { for name, rule in merge(var.ingress_rules) : name => merge(rule, { direction = "INGRESS" }) } # convert rules data to resource format and replace range template variables rules = { for name, rule in local._rules : name => merge(rule, { action = rule.deny == true ? "DENY" : "ALLOW" destination_ranges = ( try(rule.destination_ranges, null) == null ? null : flatten([ for range in rule.destination_ranges : try(local._named_ranges[range], range) ]) ) rules = { for k, v in rule.rules : k => v } source_ranges = ( try(rule.source_ranges, null) == null ? null : flatten([ for range in rule.source_ranges : try(local._named_ranges[range], range) ]) ) }) } } resource "google_compute_firewall" "custom-rules" { for_each = local.rules project = var.project_id network = var.network name = each.key description = each.value.description direction = each.value.direction source_ranges = ( each.value.direction == "INGRESS" ? ( each.value.source_ranges == null && each.value.sources == null ? ["0.0.0.0/0"] : each.value.source_ranges ) #for egress, we will include the source_ranges when provided. Previously, null was forced : each.value.source_ranges ) destination_ranges = ( each.value.direction == "EGRESS" ? ( each.value.destination_ranges == null ? ["0.0.0.0/0"] : each.value.destination_ranges ) #for ingress, we will include the destination_ranges when provided. Previously, null was forced : each.value.destination_ranges ) 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 = each.value.disabled == true priority = each.value.priority dynamic "log_config" { for_each = each.value.enable_logging == null ? [] : [""] content { metadata = ( try(each.value.enable_logging.include_metadata, null) == true ? "INCLUDE_ALL_METADATA" : "EXCLUDE_ALL_METADATA" ) } } dynamic "deny" { 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 ports = rule.value.ports } } }