Update hierarchical firewall resource

This replaces all the `google_compute_organization_security_*`
resources with the newer `google_compute_firewall_*` resources.
This commit is contained in:
Julio Castillo 2021-12-31 11:36:14 +00:00
parent 640a5fe39c
commit f78902aee8
14 changed files with 87 additions and 124 deletions

View File

@ -192,22 +192,20 @@ module "folder1" {
firewall_policies = {
iap-policy = {
allow-iap-ssh = {
description = "Always allow ssh from IAP"
direction = "INGRESS"
action = "allow"
priority = 100
ranges = ["35.235.240.0/20"]
ports = {
tcp = ["22"]
}
description = "Always allow ssh from IAP"
direction = "INGRESS"
action = "allow"
priority = 100
ranges = ["35.235.240.0/20"]
ports = { tcp = ["22"] }
target_service_accounts = null
target_resources = null
logging = false
}
}
}
firewall_policy_attachments = {
iap-policy = module.folder1.firewall_policy_id["iap-policy"]
firewall_policy_association = {
iap-policy = "iap-policy"
}
}
@ -215,7 +213,7 @@ module "folder2" {
source = "./modules/folder"
parent = var.organization_id
name = "hf2"
firewall_policy_attachments = {
firewall_policy_association = {
iap-policy = module.folder1.firewall_policy_id["iap-policy"]
}
}
@ -232,7 +230,7 @@ module "folder2" {
|---|---|:---:|:---:|:---:|
| contacts | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| firewall_policies | Hierarchical firewall policies created in this folder. | <code title="map&#40;map&#40;object&#40;&#123;&#10; action &#61; string&#10; description &#61; string&#10; direction &#61; string&#10; logging &#61; bool&#10; ports &#61; map&#40;list&#40;string&#41;&#41;&#10; priority &#61; number&#10; ranges &#61; list&#40;string&#41;&#10; target_resources &#61; list&#40;string&#41;&#10; target_service_accounts &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;&#41;">map&#40;map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| firewall_policy_attachments | List of hierarchical firewall policy IDs to attached to this folder. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| firewall_policy_association | The hierarchical firewall policy to associate to this folder. Must be either a key in the `firewall_policies` map or the id of a policy defined somewhere else. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| firewall_policy_factory | Configuration for the firewall policy factory. | <code title="object&#40;&#123;&#10; cidr_file &#61; string&#10; policy_name &#61; string&#10; rules_file &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| folder_create | Create folder. When set to false, uses id to reference an existing folder. | <code>bool</code> | | <code>true</code> |
| group_iam | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |

View File

@ -52,17 +52,15 @@ locals {
}
}
resource "google_compute_organization_security_policy" "policy" {
provider = google-beta
for_each = local.firewall_policies
display_name = each.key
parent = local.folder.id
resource "google_compute_firewall_policy" "policy" {
for_each = local.firewall_policies
short_name = each.key
parent = local.folder.id
}
resource "google_compute_organization_security_policy_rule" "rule" {
provider = google-beta
resource "google_compute_firewall_policy_rule" "rule" {
for_each = local.firewall_rules
policy_id = google_compute_organization_security_policy.policy[each.value.policy].id
firewall_policy = google_compute_firewall_policy.policy[each.value.policy].id
action = each.value.action
direction = each.value.direction
priority = try(each.value.priority, null)
@ -70,33 +68,26 @@ resource "google_compute_organization_security_policy_rule" "rule" {
target_service_accounts = try(each.value.target_service_accounts, null)
enable_logging = try(each.value.logging, null)
# preview = each.value.preview
description = each.value.description
match {
description = each.value.description
config {
src_ip_ranges = each.value.direction == "INGRESS" ? each.value.ranges : null
dest_ip_ranges = each.value.direction == "EGRESS" ? each.value.ranges : null
dynamic "layer4_config" {
for_each = each.value.ports
iterator = port
content {
ip_protocol = port.key
ports = port.value
}
src_ip_ranges = each.value.direction == "INGRESS" ? each.value.ranges : null
dest_ip_ranges = each.value.direction == "EGRESS" ? each.value.ranges : null
dynamic "layer4_configs" {
for_each = each.value.ports
iterator = port
content {
ip_protocol = port.key
ports = port.value
}
}
}
# TODO: remove once provider issues is fixed
# https://github.com/hashicorp/terraform-provider-google/issues/7790
lifecycle {
ignore_changes = [match.0.description]
}
}
resource "google_compute_organization_security_policy_association" "attachment" {
provider = google-beta
for_each = var.firewall_policy_attachments
name = "${local.folder.id}-${each.key}"
attachment_id = local.folder.id
policy_id = each.value
resource "google_compute_firewall_policy_association" "association" {
for_each = var.firewall_policy_association
name = replace(local.folder.id, "/", "-")
attachment_target = local.folder.id
firewall_policy = try(google_compute_firewall_policy.policy[each.value].id, each.value)
}

View File

@ -15,18 +15,12 @@
*/
output "firewall_policies" {
description = "Map of firewall policy resources created in this folder."
value = {
for name, _ in var.firewall_policies :
name => google_compute_organization_security_policy.policy[name]
}
value = { for k, v in google_compute_firewall_policy.policy : k => v }
}
output "firewall_policy_id" {
description = "Map of firewall policy ids created in this folder."
value = {
for name, _ in local.firewall_policies :
name => google_compute_organization_security_policy.policy[name].id
}
value = { for k, v in google_compute_firewall_policy.policy : k => v.id }
}
output "folder" {

View File

@ -36,8 +36,8 @@ variable "firewall_policies" {
default = {}
}
variable "firewall_policy_attachments" {
description = "List of hierarchical firewall policy IDs to attached to this folder."
variable "firewall_policy_association" {
description = "The hierarchical firewall policy to associate to this folder. Must be either a key in the `firewall_policies` map or the id of a policy defined somewhere else."
type = map(string)
default = {}
}

View File

@ -52,7 +52,7 @@ Hirerarchical firewall policies can be managed in two ways:
- via the `firewall_policies` variable, to directly define policies and rules in Terraform
- via the `firewall_policy_factory` variable, to leverage external YaML files via a simple "factory" embedded in the module ([see here](../../factories) for more context on factories)
Once you have policies (either created via the module or externally), you can attach them using the `firewall_policy_attachments` variable.
Once you have policies (either created via the module or externally), you can associate them using the `firewall_policy_association` variable.
### Directly defined firewall policies
@ -77,8 +77,8 @@ module "org" {
}
}
}
firewall_policy_attachments = {
iap_policy = module.org.firewall_policy_id["iap-policy"]
firewall_policy_association = {
iap_policy = "iap-policy"
}
}
# tftest:modules=1:resources=3
@ -250,7 +250,7 @@ module "org" {
| contacts | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| custom_roles | Map of role name => list of permissions to create in this project. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| firewall_policies | Hierarchical firewall policy rules created in the organization. | <code title="map&#40;map&#40;object&#40;&#123;&#10; action &#61; string&#10; description &#61; string&#10; direction &#61; string&#10; logging &#61; bool&#10; ports &#61; map&#40;list&#40;string&#41;&#41;&#10; priority &#61; number&#10; ranges &#61; list&#40;string&#41;&#10; target_resources &#61; list&#40;string&#41;&#10; target_service_accounts &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;&#41;">map&#40;map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| firewall_policy_attachments | List of hierarchical firewall policy IDs attached to the organization. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| firewall_policy_association | The hierarchical firewall policy to associate to this folder. Must be either a key in the `firewall_policies` map or the id of a policy defined somewhere else. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| firewall_policy_factory | Configuration for the firewall policy factory. | <code title="object&#40;&#123;&#10; cidr_file &#61; string&#10; policy_name &#61; string&#10; rules_file &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| group_iam | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| iam | IAM bindings, in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
@ -270,11 +270,9 @@ module "org" {
|---|---|:---:|
| custom_role_id | Map of custom role IDs created in the organization. | |
| custom_roles | Map of custom roles resources created in the organization. | |
| firewall_policies | Map of firewall policy resources created in the organization. | |
| firewall_policy_id | Map of firewall policy ids created in the organization. | |
| firewall_policies | Map of firewall policy resources created in this folder. | |
| firewall_policy_id | Map of firewall policy ids created in this folder. | |
| organization_id | Organization id dependent on module resources. | |
| sink_writer_identities | Writer identities created for each sink. | |
<!-- END TFDOC -->

View File

@ -52,11 +52,10 @@ locals {
}
}
resource "google_compute_organization_security_policy" "policy" {
provider = google-beta
for_each = local.firewall_policies
display_name = each.key
parent = var.organization_id
resource "google_compute_firewall_policy" "policy" {
for_each = local.firewall_policies
short_name = each.key
parent = var.organization_id
depends_on = [
google_organization_iam_audit_config.config,
google_organization_iam_binding.authoritative,
@ -66,10 +65,9 @@ resource "google_compute_organization_security_policy" "policy" {
]
}
resource "google_compute_organization_security_policy_rule" "rule" {
provider = google-beta
resource "google_compute_firewall_policy_rule" "rule" {
for_each = local.firewall_rules
policy_id = google_compute_organization_security_policy.policy[each.value.policy].id
firewall_policy = google_compute_firewall_policy.policy[each.value.policy].id
action = each.value.action
direction = each.value.direction
priority = try(each.value.priority, null)
@ -77,33 +75,25 @@ resource "google_compute_organization_security_policy_rule" "rule" {
target_service_accounts = try(each.value.target_service_accounts, null)
enable_logging = try(each.value.logging, null)
# preview = each.value.preview
description = each.value.description
match {
description = each.value.description
config {
src_ip_ranges = each.value.direction == "INGRESS" ? each.value.ranges : null
dest_ip_ranges = each.value.direction == "EGRESS" ? each.value.ranges : null
dynamic "layer4_config" {
for_each = each.value.ports
iterator = port
content {
ip_protocol = port.key
ports = port.value
}
src_ip_ranges = each.value.direction == "INGRESS" ? each.value.ranges : null
dest_ip_ranges = each.value.direction == "EGRESS" ? each.value.ranges : null
dynamic "layer4_configs" {
for_each = each.value.ports
iterator = port
content {
ip_protocol = port.key
ports = port.value
}
}
}
# TODO: remove once provider issues is fixed
# https://github.com/hashicorp/terraform-provider-google/issues/7790
lifecycle {
ignore_changes = [match.0.description]
}
}
resource "google_compute_organization_security_policy_association" "attachment" {
provider = google-beta
for_each = var.firewall_policy_attachments
name = "${var.organization_id}-${each.key}"
attachment_id = var.organization_id
policy_id = each.value
resource "google_compute_firewall_policy_association" "association" {
for_each = var.firewall_policy_association
name = replace(var.organization_id, "/", "-")
attachment_target = var.organization_id
firewall_policy = try(google_compute_firewall_policy.policy[each.value].id, each.value)
}

View File

@ -34,19 +34,13 @@ output "custom_roles" {
}
output "firewall_policies" {
description = "Map of firewall policy resources created in the organization."
value = {
for name, _ in var.firewall_policies :
name => google_compute_organization_security_policy.policy[name]
}
description = "Map of firewall policy resources created in this folder."
value = { for k, v in google_compute_firewall_policy.policy : k => v }
}
output "firewall_policy_id" {
description = "Map of firewall policy ids created in the organization."
value = {
for name, _ in local.firewall_policies :
name => google_compute_organization_security_policy.policy[name].id
}
description = "Map of firewall policy ids created in this folder."
value = { for k, v in google_compute_firewall_policy.policy : k => v.id }
}
output "organization_id" {

View File

@ -43,8 +43,8 @@ variable "firewall_policies" {
default = {}
}
variable "firewall_policy_attachments" {
description = "List of hierarchical firewall policy IDs attached to the organization."
variable "firewall_policy_association" {
description = "The hierarchical firewall policy to associate to this folder. Must be either a key in the `firewall_policies` map or the id of a policy defined somewhere else."
type = map(string)
default = {}
}

View File

@ -22,7 +22,7 @@ module "test" {
policy_boolean = var.policy_boolean
policy_list = var.policy_list
firewall_policies = var.firewall_policies
firewall_policy_attachments = var.firewall_policy_attachments
firewall_policy_association = var.firewall_policy_association
logging_sinks = var.logging_sinks
logging_exclusions = var.logging_exclusions
}

View File

@ -49,7 +49,7 @@ variable "firewall_policies" {
default = {}
}
variable "firewall_policy_attachments" {
variable "firewall_policy_association" {
type = map(string)
default = {}
}

View File

@ -54,17 +54,17 @@ def test_firweall_policy(plan_runner):
}
}
"""
attachment = '{ iap_policy = "policy1" }'
association = '{policy1="policy1"}'
_, resources = plan_runner(FIXTURES_DIR, firewall_policies=policy,
firewall_policy_attachments=attachment)
firewall_policy_association=association)
assert len(resources) == 5
policies = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy']
if r['type'] == 'google_compute_firewall_policy']
assert len(policies) == 1
rules = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy_rule']
if r['type'] == 'google_compute_firewall_policy_rule']
assert len(rules) == 2
rule_values = []
@ -74,22 +74,20 @@ def test_firweall_policy(plan_runner):
action = rule['values']['action']
direction = rule['values']['direction']
priority = rule['values']['priority']
config = rule['values']['match']
assert len(config) == 1
config = config[0]['config']
rule_values.append((name, index, action, direction, priority, config))
match = rule['values']['match']
rule_values.append((name, index, action, direction, priority, match))
assert sorted(rule_values) == sorted([
('rule', 'policy1-allow-ingress', 'allow', 'INGRESS', 100,[
{
'dest_ip_ranges': None,
'layer4_config': [{'ip_protocol': 'tcp', 'ports': ['22']}],
'layer4_configs': [{'ip_protocol': 'tcp', 'ports': ['22']}],
'src_ip_ranges': ['10.0.0.0/8']
}]),
('rule', 'policy1-deny-egress', 'deny', 'EGRESS', 200, [
{
'dest_ip_ranges': ['192.168.0.0/24'],
'layer4_config': [{'ip_protocol': 'tcp', 'ports': ['443']}],
'layer4_configs': [{'ip_protocol': 'tcp', 'ports': ['443']}],
'src_ip_ranges': None
}])
])

View File

@ -26,7 +26,7 @@ module "test" {
policy_boolean = var.policy_boolean
policy_list = var.policy_list
firewall_policies = var.firewall_policies
firewall_policy_attachments = var.firewall_policy_attachments
firewall_policy_association = var.firewall_policy_association
firewall_policy_factory = var.firewall_policy_factory
logging_sinks = var.logging_sinks
logging_exclusions = var.logging_exclusions

View File

@ -74,7 +74,7 @@ variable "firewall_policies" {
default = {}
}
variable "firewall_policy_attachments" {
variable "firewall_policy_association" {
type = map(string)
default = {}
}

View File

@ -80,9 +80,9 @@ def test_custom(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, firewall_policies=_POLICIES)
assert len(resources) == 5
policies = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy']
if r['type'] == 'google_compute_firewall_policy']
rules = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy_rule']
if r['type'] == 'google_compute_firewall_policy_rule']
assert set(r['index'] for r in policies) == set([
'policy1', 'policy2'
])
@ -96,9 +96,9 @@ def test_factory(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, firewall_policy_factory=_FACTORY)
assert len(resources) == 3
policies = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy']
if r['type'] == 'google_compute_firewall_policy']
rules = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy_rule']
if r['type'] == 'google_compute_firewall_policy_rule']
assert set(r['index'] for r in policies) == set([
'factory-1'
])
@ -113,7 +113,7 @@ def test_factory_name(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, firewall_policy_factory=factory)
assert len(resources) == 3
policies = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy']
if r['type'] == 'google_compute_firewall_policy']
assert set(r['index'] for r in policies) == set([
'factory'
])
@ -125,9 +125,9 @@ def test_combined(plan_runner):
firewall_policy_factory=_FACTORY)
assert len(resources) == 8
policies = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy']
if r['type'] == 'google_compute_firewall_policy']
rules = [r for r in resources
if r['type'] == 'google_compute_organization_security_policy_rule']
if r['type'] == 'google_compute_firewall_policy_rule']
assert set(r['index'] for r in policies) == set([
'factory-1', 'policy1', 'policy2'
])