diff --git a/CHANGELOG.md b/CHANGELOG.md index 020e618f..b637ffba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file. ### FAST +- [[#767](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/767)] Allow interpolating SAs in project factory subnet IAM bindings ([ludoo](https://github.com/ludoo)) - [[#766](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/766)] FAST: refactor teams branch ([ludoo](https://github.com/ludoo)) - [[#765](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/765)] FAST: move region trigrams to a variable in network stages ([ludoo](https://github.com/ludoo)) - [[#759](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/759)] FAST: fix missing value to format principalSet ([imp14a](https://github.com/imp14a)) @@ -50,6 +51,8 @@ All notable changes to this project will be documented in this file. ### MODULES +- [[#768](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/768)] Add egress / ingress policy example to VPC SC module ([ludoo](https://github.com/ludoo)) +- [[#767](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/767)] Allow interpolating SAs in project factory subnet IAM bindings ([ludoo](https://github.com/ludoo)) - [[#764](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/764)] Add dependency on shared vpc service project attachment to project module outputs ([apichick](https://github.com/apichick)) - [[#761](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/761)] Fix gke hub module features condition ([ludoo](https://github.com/ludoo)) - [[#760](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/760)] **incompatible change:** GKE hub module refactor ([ludoo](https://github.com/ludoo)) diff --git a/examples/factories/project-factory/README.md b/examples/factories/project-factory/README.md index cbce8a0f..4f94afab 100644 --- a/examples/factories/project-factory/README.md +++ b/examples/factories/project-factory/README.md @@ -214,7 +214,7 @@ vpc: # [opt] Subnets in the host project where principals will be granted networkUser # in region/subnet-name => [principals] subnets_iam: - europe-west1/prod-default-ew1: [] + europe-west1/prod-default-ew1: - user:foobar@example.com - serviceAccount:service-account1@my-project.iam.gserviceaccount.com ``` diff --git a/examples/factories/project-factory/main.tf b/examples/factories/project-factory/main.tf index f34fe4f5..996b79e3 100644 --- a/examples/factories/project-factory/main.tf +++ b/examples/factories/project-factory/main.tf @@ -15,7 +15,6 @@ */ locals { - # internal structures for group IAM bindings _group_iam = { for r in local._group_iam_bindings : r => [ for k, v in var.group_iam : @@ -23,8 +22,11 @@ locals { ] } _group_iam_bindings = distinct(flatten(values(var.group_iam))) - # internal structures for project service accounts IAM bindings - _project_id = var.prefix == null || var.prefix == "" ? var.project_id : "${var.prefix}-${var.project_id}" + _project_id = ( + var.prefix == null || var.prefix == "" + ? var.project_id + : "${var.prefix}-${var.project_id}" + ) _service_accounts_iam = { for r in local._service_accounts_iam_bindings : r => [ for k, v in var.service_accounts : @@ -35,7 +37,6 @@ locals { _service_accounts_iam_bindings = distinct(flatten( values(var.service_accounts) )) - # internal structures for project services _services = concat([ "billingbudgets.googleapis.com", "essentialcontacts.googleapis.com" @@ -44,7 +45,6 @@ locals { try(var.vpc.gke_setup, null) != null ? ["container.googleapis.com"] : [], var.vpc != null ? ["compute.googleapis.com"] : [], ) - # internal structures for service identity IAM bindings _service_identities_roles = distinct(flatten(values(var.service_identities_iam))) _service_identities_iam = { for role in local._service_identities_roles : role => [ @@ -53,7 +53,6 @@ locals { if contains(roles, role) ] } - # internal structure for Shared VPC service project IAM bindings _vpc_subnet_bindings = ( local.vpc.subnets_iam == null || local.vpc.host_project == null ? [] @@ -67,7 +66,6 @@ locals { ] ]) ) - # structures for billing id billing_account_id = coalesce( var.billing_account_id, try(var.defaults.billing_account_id, "") ) @@ -76,11 +74,9 @@ locals { ? try(var.defaults.billing_alert, null) : var.billing_alert ) - # structure for essential contacts essential_contacts = concat( try(var.defaults.essential_contacts, []), var.essential_contacts ) - # structure that combines all authoritative IAM bindings iam = { for role in distinct(concat( keys(var.iam), @@ -95,13 +91,10 @@ locals { try(local._service_identities_iam[role], []), ) } - # merge labels with defaults labels = merge( coalesce(var.labels, {}), coalesce(try(var.defaults.labels, {}), {}) ) - # deduplicate services services = distinct(concat(var.services, local._services)) - # structures for Shared VPC resources in host project vpc = coalesce(var.vpc, { host_project = null, gke_setup = null, subnets_iam = null }) @@ -192,5 +185,9 @@ resource "google_compute_subnetwork_iam_member" "default" { subnetwork = "projects/${local.vpc.host_project}/regions/${each.value.region}/subnetworks/${each.value.subnet}" region = each.value.region role = "roles/compute.networkUser" - member = each.value.member + member = ( + lookup(var.service_accounts, each.value.member, null) != null + ? module.service-accounts[each.value.member].iam_email + : each.value.member + ) } diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index 98381bae..190348af 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -128,8 +128,38 @@ module "test" { access_levels = [module.test.access_level_names["a1"], "a2"] resources = ["projects/11111", "projects/111111"] restricted_services = ["storage.googleapis.com"] - egress_policies = null - ingress_policies = null + # example: allow writing to external GCS bucket + egress_policies = [ + { + egress_from = { + identity_type = null + identities = [ + "serviceAccount:foo@myproject.iam.gserviceaccount.com" + ] + } + egress_to = { + operations = [{ + method_selectors = ["*"], service_name = "storage.googleapis.com" + }] + resources = ["projects/123456789"] + } + } + ] + # example: allow management from external automation SA + ingress_policies = [ + { + ingress_from = { + identities = [ + "serviceAccount:test-tf@myproject.iam.gserviceaccount.com", + ], + source_access_levels = ["*"], identity_type = null, source_resources = null + } + ingress_to = { + operations = [{ method_selectors = [], service_name = "*" }] + resources = ["*"] + } + } + ] vpc_accessible_services = { allowed_services = ["storage.googleapis.com"] enable_restriction = true @@ -144,7 +174,7 @@ module "test" { ## Notes -- To remove an access level, first remove the binding between perimeter and the access level in `status` and/or `spec` without removing the access level itself. Once you have run `terraform apply`, you'll then be able to remove the access level and run `terraform apply` again. +- To remove an access level, first remove the binding between perimeter and the access level in `status` and/or `spec` without removing the access level itself. Once you have run `terraform apply`, you'll then be able to remove the access level and run `terraform apply` again. ## TODO diff --git a/tests/examples/factories/project_factory/fixture/projects/project.yaml b/tests/examples/factories/project_factory/fixture/projects/project.yaml index 7ad16016..b9d0d85a 100644 --- a/tests/examples/factories/project_factory/fixture/projects/project.yaml +++ b/tests/examples/factories/project_factory/fixture/projects/project.yaml @@ -97,4 +97,5 @@ vpc: subnets_iam: europe-west1/prod-default-ew1: - user:foobar@example.com - - serviceAccount:service-account1 + - serviceAccount:service-account1@example.com + - my-service-account diff --git a/tests/examples/factories/project_factory/fixture/variables.tf b/tests/examples/factories/project_factory/fixture/variables.tf index 4d2fd9c1..d0d6759b 100644 --- a/tests/examples/factories/project_factory/fixture/variables.tf +++ b/tests/examples/factories/project_factory/fixture/variables.tf @@ -58,7 +58,6 @@ variable "shared_vpc_self_link" { } variable "vpc_host_project" { - # tfdoc:variable:source 02-networking description = "Host project for the shared VPC." type = string default = "host-project" diff --git a/tools/changelog.py b/tools/changelog.py index 117a19e5..3b071e92 100755 --- a/tools/changelog.py +++ b/tools/changelog.py @@ -80,10 +80,10 @@ def changelog_dumps(releases, overrides=None): else: buffer.append(f'## [{name}]\n') ref_buffer.append(f'[Unreleased]: {URL}/compare/v{prev_name}...HEAD') - if name in overrides: - buffer.append( - f'\n') - pulls = group_pulls(overrides[name].pulls) + override = overrides.get(name, overrides.get(f'v{name}')) + if override: + buffer.append(f'\n') + pulls = group_pulls(override.pulls) for k in sorted(pulls.keys(), key=lambda s: s or ''): if k is not None: buffer.append(f'### {k}\n') @@ -164,6 +164,8 @@ def get_releases(api, filter_names=None): @click.command +@click.option('--all-releases', is_flag=True, default=False, + help='All releases.') @click.option( '--release', required=False, default=['Unreleased'], multiple=True, help='Release to replace, specify multiple times for more than one version.' @@ -174,8 +176,10 @@ def get_releases(api, filter_names=None): help='Write modified changelog file.') @click.argument('changelog', required=False, default='CHANGELOG.md', type=click.Path(exists=True)) -def main(token, changelog='CHANGELOG.md', release=None, write=False): +def main(token, changelog='CHANGELOG.md', all_releases=False, release=None, + write=False): api = get_api(token) + release = [] if all_releases else release releases = [r for r in get_releases(api, release)] releases = {r.name: r for r in get_release_pulls(api, releases)} try: