From 628ab41c3374ab3da3674b76867d9eaa638ebb61 Mon Sep 17 00:00:00 2001 From: lcaggio Date: Fri, 7 May 2021 09:07:36 +0200 Subject: [PATCH 1/6] Add Support for Ingress Egress policy --- modules/vpc-sc/README.md | 31 +++++- modules/vpc-sc/main.tf | 182 +++++++++++++++++++++++++++++++++++- modules/vpc-sc/variables.tf | 22 +++++ 3 files changed, 232 insertions(+), 3 deletions(-) diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index 0191b651..ef78844c 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -28,10 +28,35 @@ module "vpc-sc" { } } access_level_perimeters = { - my_trusted_proxy = { + enforced = { my_trusted_proxy = ["perimeter"] } } + egress_policies = { + egress_1 = { + egress_from = { + identity_type = "ANY_IDENTITY" + } + egress_to = { + resources = ["*"] + operations = [ + { + service_name = "storage.googleapis.com" + method_selectors = { method = "google.storage.objects.create" } + }, + { + service_name = "bigquery.googleapis.com" + method_selectors = { method = "BigQueryStorage.ReadRows" } + } + ] + } + } + } + egress_policies_perimeters = { + enforced = { + egress_1 = ["perimeter"] + } + } perimeters = { perimeter = { type = "PERIMETER_TYPE_REGULAR" @@ -106,6 +131,10 @@ module "vpc-sc" { | organization_id | Organization id in organizations/nnnnnn format. | string | ✓ | | | *access_level_perimeters* | Enforced mode -> Access Level -> Perimeters mapping. Enforced mode can be 'enforced' or 'dry_run' | map(map(list(string))) | | {} | | *access_levels* | Map of Access Levels to be created. For each Access Level you can specify 'ip_subnetworks, required_access_levels, members, negate or regions'. | map(object({...})) | | {} | +| *egress_policies* | List of EgressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#ingress_policies) | | | null | +| *egress_policies_perimeters* | Enforced mode -> Egress Policy -> Perimeters mapping. Enforced mode can be 'enforced' or 'dry_run' | map(map(list(string))) | | {} | +| *ingress_policies* | List of IngressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#ingress_policies) | | | null | +| *ingress_policies_perimeters* | Enforced mode -> Ingress Policy -> Perimeters mapping. Enforced mode can be 'enforced' or 'dry_run' | map(map(list(string))) | | {} | | *perimeter_projects* | Perimeter -> Enforced Mode -> Projects Number mapping. Enforced mode can be 'enforced' or 'dry_run'. | map(map(list(number))) | | {} | | *perimeters* | Set of Perimeters. | map(object({...})) | | {} | diff --git a/modules/vpc-sc/main.tf b/modules/vpc-sc/main.tf index 489643c4..32a40648 100644 --- a/modules/vpc-sc/main.tf +++ b/modules/vpc-sc/main.tf @@ -27,8 +27,12 @@ locals { key => value if value.type == "PERIMETER_TYPE_BRIDGE" } - perimeter_access_levels_enforced = try(transpose(var.access_level_perimeters.enforced), null) - perimeter_access_levels_dry_run = try(transpose(var.access_level_perimeters.dry_run), null) + perimeter_access_levels_enforced = try(transpose(var.access_level_perimeters.enforced), null) + perimeter_access_levels_dry_run = try(transpose(var.access_level_perimeters.dry_run), null) + perimeter_ingress_policies_enforced = try(transpose(var.ingress_policies_perimeters.enforced), null) + perimeter_ingress_policies_dry_run = try(transpose(var.ingress_policies_perimeters.dry_run), null) + perimeter_egress_policies_enforced = try(transpose(var.egress_policies_perimeters.enforced), null) + perimeter_egress_policies_dry_run = try(transpose(var.egress_policies_perimeters.dry_run), null) } resource "google_access_context_manager_access_policy" "default" { @@ -89,6 +93,93 @@ resource "google_access_context_manager_service_perimeter" "standard" { allowed_services = each.value.enforced_config.vpc_accessible_services } } + + dynamic "egress_policies" { + for_each = try(local.perimeter_egress_policies_enforced[each.key] != null ? local.perimeter_egress_policies_enforced[each.key] : [], []) + + content { + dynamic "egress_from" { + for_each = try(var.egress_policies[egress_policies.value].egress_from != null ? [""] : [], []) + + content { + identity_type = try(var.egress_policies[egress_policies.value].egress_from.identity_type, null) + identities = try(var.egress_policies[egress_policies.value].egress_from.identities, null) + } + } + dynamic "egress_to" { + for_each = try(var.egress_policies[egress_policies.value].egress_to != null ? [""] : [], []) + + content { + resources = try(var.egress_policies[egress_policies.value].egress_to.resources, null) + + dynamic "operations" { + for_each = try(var.egress_policies[egress_policies.value].egress_to.operations, []) + + content { + service_name = try(operations.value.service_name, null) + + dynamic "method_selectors" { + for_each = try([operations.value.method_selectors], []) + + content { + method = try(method_selectors.value.method, null) + permission = try(method_selectors.value.permission, null) + } + } + } + } + } + } + } + } + + dynamic "ingress_policies" { + for_each = try(local.perimeter_ingress_policies_enforced[each.key] != null ? local.perimeter_ingress_policies_enforced[each.key] : [], []) + + content { + dynamic "ingress_from" { + for_each = try(var.ingress_policies[ingress_policies.value].ingress_from != null ? [""] : [], []) + + content { + identity_type = try(var.ingress_policies[ingress_policies.value].ingress_from.identity_type, null) + identities = try(var.ingress_policies[ingress_policies.value].ingress_from.identities, null) + + dynamic "sources" { + for_each = toset(try([var.ingress_policies[ingress_policies.value].ingress_from.sources], [])) + + content { + access_level = try(sources.value.access_level, null) + resource = try(sources.value.resource, null) + } + } + } + } + dynamic "ingress_to" { + for_each = try(var.ingress_policies[ingress_policies.value].ingress_to != null ? [""] : [], []) + + content { + resources = try(var.ingress_policies[ingress_policies.value].ingress_to.resources, null) + + dynamic "operations" { + for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations, []) + + content { + service_name = try(operations.value.service_name, null) + + dynamic "method_selectors" { + for_each = try([operations.value.method_selectors], []) + + content { + method = try(method_selectors.value.method, null) + permission = try(method_selectors.value.permission, null) + } + } + } + } + } + } + } + } } } @@ -115,6 +206,93 @@ resource "google_access_context_manager_service_perimeter" "standard" { allowed_services = try(each.value.dry_run_config.vpc_accessible_services, null) } } + + dynamic "egress_policies" { + for_each = try(local.perimeter_egress_policies_dry_run[each.key] != null ? local.perimeter_egress_policies_dry_run[each.key] : [], []) + + content { + dynamic "egress_from" { + for_each = try(var.egress_policies[egress_policies.value].egress_from != null ? [""] : [], []) + + content { + identity_type = try(var.egress_policies[egress_policies.value].egress_from.identity_type, null) + identities = try(var.egress_policies[egress_policies.value].egress_from.identities, null) + } + } + dynamic "egress_to" { + for_each = try(var.egress_policies[egress_policies.value].egress_to != null ? [""] : [], []) + + content { + resources = try(var.egress_policies[egress_policies.value].egress_to.resources, null) + + dynamic "operations" { + for_each = try(var.egress_policies[egress_policies.value].egress_to.operations, []) + + content { + service_name = try(operations.value.service_name, null) + + dynamic "method_selectors" { + for_each = try([operations.value.method_selectors], []) + + content { + method = try(method_selectors.value.method, null) + permission = try(method_selectors.value.permission, null) + } + } + } + } + } + } + } + } + + dynamic "ingress_policies" { + for_each = try(local.perimeter_ingress_policies_dry_run[each.key] != null ? local.perimeter_ingress_policies_dry_run[each.key] : [], []) + + content { + dynamic "ingress_from" { + for_each = try(var.ingress_policies[ingress_policies.value].ingress_from != null ? [""] : [], []) + + content { + identity_type = try(var.ingress_policies[ingress_policies.value].ingress_from.identity_type, null) + identities = try(var.ingress_policies[ingress_policies.value].ingress_from.identities, null) + + dynamic "sources" { + for_each = toset(try([var.ingress_policies[ingress_policies.value].ingress_from.sources], [])) + + content { + access_level = try(sources.value.access_level, null) + resource = try(sources.value.resource, null) + } + } + } + } + dynamic "ingress_to" { + for_each = try(var.ingress_policies[ingress_policies.value].ingress_to != null ? [""] : [], []) + + content { + resources = try(var.ingress_policies[ingress_policies.value].ingress_to.resources, null) + + dynamic "operations" { + for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations, []) + + content { + service_name = try(operations.value.service_name, null) + + dynamic "method_selectors" { + for_each = try([operations.value.method_selectors], []) + + content { + method = try(method_selectors.value.method, null) + permission = try(method_selectors.value.permission, null) + } + } + } + } + } + } + } + } } } diff --git a/modules/vpc-sc/variables.tf b/modules/vpc-sc/variables.tf index f90c3026..38fa13a3 100644 --- a/modules/vpc-sc/variables.tf +++ b/modules/vpc-sc/variables.tf @@ -40,6 +40,28 @@ variable "access_policy_title" { type = string } +variable "egress_policies" { + description = "List of EgressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#ingress_policies)" + default = null +} + +variable "egress_policies_perimeters" { + description = "Enforced mode -> Egress Policy -> Perimeters mapping. Enforced mode can be 'enforced' or 'dry_run'" + type = map(map(list(string))) + default = {} +} + +variable "ingress_policies" { + description = "List of IngressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#ingress_policies)" + default = null +} + +variable "ingress_policies_perimeters" { + description = "Enforced mode -> Ingress Policy -> Perimeters mapping. Enforced mode can be 'enforced' or 'dry_run'" + type = map(map(list(string))) + default = {} +} + variable "organization_id" { description = "Organization id in organizations/nnnnnn format." type = string From f306f01fbce1faca4ad3ae532881d23d2d3be56d Mon Sep 17 00:00:00 2001 From: lcaggio Date: Sun, 16 May 2021 08:31:55 +0200 Subject: [PATCH 2/6] Fix and change variable --- modules/vpc-sc/README.md | 42 ++++++++++++++++++++++++++++------------ modules/vpc-sc/main.tf | 24 +++++++++++------------ 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index ef78844c..4c73ae58 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -32,23 +32,41 @@ module "vpc-sc" { my_trusted_proxy = ["perimeter"] } } + ingress_policies = { + ingress_1 = { + ingress_from = { + identity_type = "ANY_IDENTITY" + } + ingress_to = { + resources = ["*"] + operations = [ + { + "storage.googleapis.com" = [{ method = "google.storage.objects.create" }] + "bigquery.googleapis.com" = [{ method = "BigQueryStorage.ReadRows" }] + } + ] + } + } + } + ingress_policies_perimeters = { + enforced = { + ingress_1 = ["default"] + } + } + egress_policies = { egress_1 = { egress_from = { - identity_type = "ANY_IDENTITY" + identity_type = "ANY_USER_ACCOUNT" } egress_to = { - resources = ["*"] - operations = [ - { - service_name = "storage.googleapis.com" - method_selectors = { method = "google.storage.objects.create" } - }, - { - service_name = "bigquery.googleapis.com" - method_selectors = { method = "BigQueryStorage.ReadRows" } - } - ] + resources = ["*"] + operations = [ + { + "storage.googleapis.com" = [{ method = "google.storage.objects.create" }], + "bigquery.googleapis.com" = [{ method = "BigQueryStorage.ReadRows" },{ method = "TableService.ListTables" }, { permission = "bigquery.jobs.get" }] + } + ] } } } diff --git a/modules/vpc-sc/main.tf b/modules/vpc-sc/main.tf index 32a40648..085b151b 100644 --- a/modules/vpc-sc/main.tf +++ b/modules/vpc-sc/main.tf @@ -113,13 +113,13 @@ resource "google_access_context_manager_service_perimeter" "standard" { resources = try(var.egress_policies[egress_policies.value].egress_to.resources, null) dynamic "operations" { - for_each = try(var.egress_policies[egress_policies.value].egress_to.operations, []) + for_each = try(var.egress_policies[egress_policies.value].egress_to.operations[0], []) content { - service_name = try(operations.value.service_name, null) + service_name = try(operations.key, null) dynamic "method_selectors" { - for_each = try([operations.value.method_selectors], []) + for_each = try(operations.value, []) content { method = try(method_selectors.value.method, null) @@ -161,13 +161,13 @@ resource "google_access_context_manager_service_perimeter" "standard" { resources = try(var.ingress_policies[ingress_policies.value].ingress_to.resources, null) dynamic "operations" { - for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations, []) + for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations[0], []) content { - service_name = try(operations.value.service_name, null) + service_name = try(operations.key, null) dynamic "method_selectors" { - for_each = try([operations.value.method_selectors], []) + for_each = try(operations.value, []) content { method = try(method_selectors.value.method, null) @@ -226,13 +226,13 @@ resource "google_access_context_manager_service_perimeter" "standard" { resources = try(var.egress_policies[egress_policies.value].egress_to.resources, null) dynamic "operations" { - for_each = try(var.egress_policies[egress_policies.value].egress_to.operations, []) + for_each = try(var.egress_policies[egress_policies.value].egress_to.operations[0], []) content { - service_name = try(operations.value.service_name, null) + service_name = try(operations.key, null) dynamic "method_selectors" { - for_each = try([operations.value.method_selectors], []) + for_each = try(operations.value, []) content { method = try(method_selectors.value.method, null) @@ -274,13 +274,13 @@ resource "google_access_context_manager_service_perimeter" "standard" { resources = try(var.ingress_policies[ingress_policies.value].ingress_to.resources, null) dynamic "operations" { - for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations, []) + for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations[0], []) content { - service_name = try(operations.value.service_name, null) + service_name = try(operations.key, null) dynamic "method_selectors" { - for_each = try([operations.value.method_selectors], []) + for_each = try(operations.value, []) content { method = try(method_selectors.value.method, null) From 4ecd13225a6945b2caef4b42441ad8aba8ab2aea Mon Sep 17 00:00:00 2001 From: lcaggio Date: Mon, 17 May 2021 18:38:46 +0200 Subject: [PATCH 3/6] Fix variable --- modules/vpc-sc/README.md | 20 ++++++++------------ modules/vpc-sc/main.tf | 8 ++++---- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index 4c73ae58..075fd2cd 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -39,12 +39,10 @@ module "vpc-sc" { } ingress_to = { resources = ["*"] - operations = [ - { - "storage.googleapis.com" = [{ method = "google.storage.objects.create" }] - "bigquery.googleapis.com" = [{ method = "BigQueryStorage.ReadRows" }] - } - ] + operations = { + "storage.googleapis.com" = [{ method = "google.storage.objects.create" }] + "bigquery.googleapis.com" = [{ method = "BigQueryStorage.ReadRows" }] + } } } } @@ -61,12 +59,10 @@ module "vpc-sc" { } egress_to = { resources = ["*"] - operations = [ - { - "storage.googleapis.com" = [{ method = "google.storage.objects.create" }], - "bigquery.googleapis.com" = [{ method = "BigQueryStorage.ReadRows" },{ method = "TableService.ListTables" }, { permission = "bigquery.jobs.get" }] - } - ] + operations = { + "storage.googleapis.com" = [{ method = "google.storage.objects.create" }], + "bigquery.googleapis.com" = [{ method = "BigQueryStorage.ReadRows" },{ method = "TableService.ListTables" }, { permission = "bigquery.jobs.get" }] + } } } } diff --git a/modules/vpc-sc/main.tf b/modules/vpc-sc/main.tf index 085b151b..876dd9ba 100644 --- a/modules/vpc-sc/main.tf +++ b/modules/vpc-sc/main.tf @@ -113,7 +113,7 @@ resource "google_access_context_manager_service_perimeter" "standard" { resources = try(var.egress_policies[egress_policies.value].egress_to.resources, null) dynamic "operations" { - for_each = try(var.egress_policies[egress_policies.value].egress_to.operations[0], []) + for_each = try(var.egress_policies[egress_policies.value].egress_to.operations, []) content { service_name = try(operations.key, null) @@ -161,7 +161,7 @@ resource "google_access_context_manager_service_perimeter" "standard" { resources = try(var.ingress_policies[ingress_policies.value].ingress_to.resources, null) dynamic "operations" { - for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations[0], []) + for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations, []) content { service_name = try(operations.key, null) @@ -226,7 +226,7 @@ resource "google_access_context_manager_service_perimeter" "standard" { resources = try(var.egress_policies[egress_policies.value].egress_to.resources, null) dynamic "operations" { - for_each = try(var.egress_policies[egress_policies.value].egress_to.operations[0], []) + for_each = try(var.egress_policies[egress_policies.value].egress_to.operations, []) content { service_name = try(operations.key, null) @@ -274,7 +274,7 @@ resource "google_access_context_manager_service_perimeter" "standard" { resources = try(var.ingress_policies[ingress_policies.value].ingress_to.resources, null) dynamic "operations" { - for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations[0], []) + for_each = try(var.ingress_policies[ingress_policies.value].ingress_to.operations, []) content { service_name = try(operations.key, null) From 722b3f59f878935606bd284ebb15ff7f6607c34b Mon Sep 17 00:00:00 2001 From: lcaggio Date: Mon, 17 May 2021 18:41:37 +0200 Subject: [PATCH 4/6] Fix link --- modules/vpc-sc/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vpc-sc/variables.tf b/modules/vpc-sc/variables.tf index 38fa13a3..490f4951 100644 --- a/modules/vpc-sc/variables.tf +++ b/modules/vpc-sc/variables.tf @@ -41,7 +41,7 @@ variable "access_policy_title" { } variable "egress_policies" { - description = "List of EgressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#ingress_policies)" + description = "List of EgressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#egress_policies)" default = null } From a7d58a73cf1945b7876ceae4add6acdc36dbe240 Mon Sep 17 00:00:00 2001 From: lcaggio Date: Mon, 17 May 2021 20:41:59 +0200 Subject: [PATCH 5/6] Fix README --- modules/vpc-sc/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index 075fd2cd..2c64bb1c 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -145,7 +145,7 @@ module "vpc-sc" { | organization_id | Organization id in organizations/nnnnnn format. | string | ✓ | | | *access_level_perimeters* | Enforced mode -> Access Level -> Perimeters mapping. Enforced mode can be 'enforced' or 'dry_run' | map(map(list(string))) | | {} | | *access_levels* | Map of Access Levels to be created. For each Access Level you can specify 'ip_subnetworks, required_access_levels, members, negate or regions'. | map(object({...})) | | {} | -| *egress_policies* | List of EgressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#ingress_policies) | | | null | +| *egress_policies* | List of EgressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#egress_policies) | | | null | | *egress_policies_perimeters* | Enforced mode -> Egress Policy -> Perimeters mapping. Enforced mode can be 'enforced' or 'dry_run' | map(map(list(string))) | | {} | | *ingress_policies* | List of IngressPolicies in the form described in the [documentation](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/access_context_manager_service_perimeter#ingress_policies) | | | null | | *ingress_policies_perimeters* | Enforced mode -> Ingress Policy -> Perimeters mapping. Enforced mode can be 'enforced' or 'dry_run' | map(map(list(string))) | | {} | From 558e31a5bde83761b5b6b746f07be13619b1ad31 Mon Sep 17 00:00:00 2001 From: lcaggio Date: Tue, 18 May 2021 09:50:16 +0200 Subject: [PATCH 6/6] Update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 344a5847..b12ebe69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] - added support for `CORS` to the `gcs` module +- added support for VPC-SC Ingress Egress policies ## [4.7.0] - 2021-04-21