diff --git a/blueprints/data-solutions/data-playground/main.tf b/blueprints/data-solutions/data-playground/main.tf index 548bee37..a3cfd54e 100644 --- a/blueprints/data-solutions/data-playground/main.tf +++ b/blueprints/data-solutions/data-playground/main.tf @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -83,8 +83,8 @@ module "project" { } org_policies = { - # "constraints/compute.requireOsLogin" = { - # enforce = false + # "compute.requireOsLogin" = { + # rules = [{ enforce = false }] # } # Example of applying a project wide policy, mainly useful for Composer 1 } diff --git a/blueprints/data-solutions/shielded-folder/data/org-policies/compute.yaml b/blueprints/data-solutions/shielded-folder/data/org-policies/compute.yaml index 0d27ac42..a3f96b1b 100644 --- a/blueprints/data-solutions/shielded-folder/data/org-policies/compute.yaml +++ b/blueprints/data-solutions/shielded-folder/data/org-policies/compute.yaml @@ -3,71 +3,90 @@ # sample subset of useful organization policies, edit to suit requirements compute.disableGuestAttributesAccess: - enforce: true + rules: + - enforce: true compute.requireOsLogin: - enforce: true + rules: + - enforce: true compute.restrictLoadBalancerCreationForTypes: - allow: - values: - - in:INTERNAL + rules: + - allow: + values: + - in:INTERNAL compute.skipDefaultNetworkCreation: - enforce: true + rules: + - enforce: true compute.vmExternalIpAccess: - deny: - all: true + rules: + - deny: + all: true # compute.disableInternetNetworkEndpointGroup: -# enforce: true +# rules: +# - enforce: true # compute.disableNestedVirtualization: -# enforce: true +# rules: +# - enforce: true # compute.disableSerialPortAccess: -# enforce: true +# rules: +# - enforce: true # compute.restrictCloudNATUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictDedicatedInterconnectUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictPartnerInterconnectUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictProtocolForwardingCreationForTypes: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictSharedVpcHostProjects: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictSharedVpcSubnetworks: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictVpcPeering: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictVpnPeerIPs: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictXpnProjectLienRemoval: -# enforce: true +# rules: +# - enforce: true # compute.setNewProjectDefaultToZonalDNSOnly: -# enforce: true +# rules: +# - enforce: true # compute.vmCanIpForward: -# deny: -# all: true +# rules: +# - deny: +# all: true diff --git a/blueprints/data-solutions/shielded-folder/data/org-policies/iam.yaml b/blueprints/data-solutions/shielded-folder/data/org-policies/iam.yaml index 4d83f827..58e0032c 100644 --- a/blueprints/data-solutions/shielded-folder/data/org-policies/iam.yaml +++ b/blueprints/data-solutions/shielded-folder/data/org-policies/iam.yaml @@ -3,10 +3,13 @@ # sample subset of useful organization policies, edit to suit requirements iam.automaticIamGrantsForDefaultServiceAccounts: - enforce: true + rules: + - enforce: true iam.disableServiceAccountKeyCreation: - enforce: true + rules: + - enforce: true iam.disableServiceAccountKeyUpload: - enforce: true + rules: + - enforce: true diff --git a/blueprints/data-solutions/shielded-folder/data/org-policies/serverless.yaml b/blueprints/data-solutions/shielded-folder/data/org-policies/serverless.yaml index de62e6c7..3efb23cd 100644 --- a/blueprints/data-solutions/shielded-folder/data/org-policies/serverless.yaml +++ b/blueprints/data-solutions/shielded-folder/data/org-policies/serverless.yaml @@ -3,24 +3,29 @@ # sample subset of useful organization policies, edit to suit requirements run.allowedIngress: - allow: - values: - - is:internal + rules: + - allow: + values: + - is:internal # run.allowedVPCEgress: -# allow: -# values: +# rules: +# - allow: +# values: # - is:private-ranges-only # cloudfunctions.allowedIngressSettings: -# allow: -# values: -# - is:ALLOW_INTERNAL_ONLY +# rules: +# - allow: +# values: +# - is:ALLOW_INTERNAL_ONLY # cloudfunctions.allowedVpcConnectorEgressSettings: -# allow: -# values: -# - is:PRIVATE_RANGES_ONLY +# rules: +# - allow: +# values: +# - is:PRIVATE_RANGES_ONLY # cloudfunctions.requireVPCConnector: -# enforce: true +# rules: +# - enforce: true diff --git a/blueprints/data-solutions/shielded-folder/data/org-policies/sql.yaml b/blueprints/data-solutions/shielded-folder/data/org-policies/sql.yaml index 88b84d9d..0eee8045 100644 --- a/blueprints/data-solutions/shielded-folder/data/org-policies/sql.yaml +++ b/blueprints/data-solutions/shielded-folder/data/org-policies/sql.yaml @@ -3,7 +3,9 @@ # sample subset of useful organization policies, edit to suit requirements sql.restrictAuthorizedNetworks: - enforce: true + rules: + - enforce: true sql.restrictPublicIp: - enforce: true + rules: + - enforce: true diff --git a/blueprints/data-solutions/shielded-folder/data/org-policies/storage.yaml b/blueprints/data-solutions/shielded-folder/data/org-policies/storage.yaml index 6c0a673f..448357b8 100644 --- a/blueprints/data-solutions/shielded-folder/data/org-policies/storage.yaml +++ b/blueprints/data-solutions/shielded-folder/data/org-policies/storage.yaml @@ -3,4 +3,5 @@ # sample subset of useful organization policies, edit to suit requirements storage.uniformBucketLevelAccess: - enforce: true + rules: + - enforce: true diff --git a/blueprints/data-solutions/vertex-mlops/main.tf b/blueprints/data-solutions/vertex-mlops/main.tf index 5f7fbc0c..27129298 100644 --- a/blueprints/data-solutions/vertex-mlops/main.tf +++ b/blueprints/data-solutions/vertex-mlops/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -112,7 +112,7 @@ module "gcs-bucket" { encryption_key = try(local.service_encryption_keys.storage, null) } -# Default bucket for Cloud Build to prevent error: "'us' violates constraint ‘constraints/gcp.resourceLocations’" +# Default bucket for Cloud Build to prevent error: "'us' violates constraint ‘gcp.resourceLocations’" # https://stackoverflow.com/questions/53206667/cloud-build-fails-with-resource-location-constraint module "gcs-bucket-cloudbuild" { source = "../../../modules/gcs" @@ -230,8 +230,8 @@ module "project" { org_policies = { # Example of applying a project wide policy - # "constraints/compute.requireOsLogin" = { - # enforce = false + # "compute.requireOsLogin" = { + # rules = [{ enforce = false }] # } } diff --git a/blueprints/factories/project-factory/README.md b/blueprints/factories/project-factory/README.md index 2b8c3874..68e2e1d0 100644 --- a/blueprints/factories/project-factory/README.md +++ b/blueprints/factories/project-factory/README.md @@ -156,15 +156,18 @@ labels: # [opt] Org policy overrides defined at project level org_policies: - constraints/compute.disableGuestAttributesAccess: - enforce: true - constraints/compute.trustedImageProjects: - allow: - values: + compute.disableGuestAttributesAccess: + rules: + - enforce: true + compute.trustedImageProjects: + rules: + - allow: + values: - projects/fast-dev-iac-core-0 - constraints/compute.vmExternalIpAccess: - deny: - all: true + compute.vmExternalIpAccess: + rules: + - deny: + all: true # [opt] Service account to create for the project and their roles on the project # in name => [roles] format @@ -223,8 +226,8 @@ vpc: | name | description | type | required | default | |---|---|:---:|:---:|:---:| | [billing_account_id](variables.tf#L17) | Billing account id. | string | ✓ | | -| [prefix](variables.tf#L157) | Prefix used for resource names. | string | ✓ | | -| [project_id](variables.tf#L166) | Project id. | string | ✓ | | +| [prefix](variables.tf#L144) | Prefix used for resource names. | string | ✓ | | +| [project_id](variables.tf#L153) | Project id. | string | ✓ | | | [billing_alert](variables.tf#L22) | Billing alert configuration. | object({…}) | | null | | [defaults](variables.tf#L35) | Project factory default values. | object({…}) | | null | | [descriptive_name](variables.tf#L57) | Name of the project name. Used for project name instead of `name` variable. | string | | null | @@ -237,15 +240,15 @@ vpc: | [iam_additive](variables.tf#L99) | Custom additive IAM settings in role => [principal] format. | map(list(string)) | | {} | | [kms_service_agents](variables.tf#L105) | KMS IAM configuration in as service => [key]. | map(list(string)) | | {} | | [labels](variables.tf#L111) | Labels to be assigned at project level. | map(string) | | {} | -| [org_policies](variables.tf#L117) | Org-policy overrides at project level. | map(object({…})) | | {} | -| [service_accounts](variables.tf#L171) | Service accounts to be created, and roles assigned them on the project. | map(list(string)) | | {} | -| [service_accounts_additive](variables.tf#L177) | Service accounts to be created, and roles assigned them on the project additively. | map(list(string)) | | {} | -| [service_accounts_iam](variables.tf#L183) | IAM bindings on service account resources. Format is KEY => {ROLE => [MEMBERS]}. | map(map(list(string))) | | {} | -| [service_accounts_iam_additive](variables.tf#L190) | IAM additive bindings on service account resources. Format is KEY => {ROLE => [MEMBERS]}. | map(map(list(string))) | | {} | -| [service_identities_iam](variables.tf#L197) | Custom IAM settings for service identities in service => [role] format. | map(list(string)) | | {} | -| [service_identities_iam_additive](variables.tf#L204) | Custom additive IAM settings for service identities in service => [role] format. | map(list(string)) | | {} | -| [services](variables.tf#L211) | Services to be enabled for the project. | list(string) | | [] | -| [vpc](variables.tf#L218) | VPC configuration for the project. | object({…}) | | null | +| [org_policies](variables.tf#L117) | Org-policy overrides at project level. | map(object({…})) | | {} | +| [service_accounts](variables.tf#L158) | Service accounts to be created, and roles assigned them on the project. | map(list(string)) | | {} | +| [service_accounts_additive](variables.tf#L164) | Service accounts to be created, and roles assigned them on the project additively. | map(list(string)) | | {} | +| [service_accounts_iam](variables.tf#L170) | IAM bindings on service account resources. Format is KEY => {ROLE => [MEMBERS]}. | map(map(list(string))) | | {} | +| [service_accounts_iam_additive](variables.tf#L177) | IAM additive bindings on service account resources. Format is KEY => {ROLE => [MEMBERS]}. | map(map(list(string))) | | {} | +| [service_identities_iam](variables.tf#L184) | Custom IAM settings for service identities in service => [role] format. | map(list(string)) | | {} | +| [service_identities_iam_additive](variables.tf#L191) | Custom additive IAM settings for service identities in service => [role] format. | map(list(string)) | | {} | +| [services](variables.tf#L198) | Services to be enabled for the project. | list(string) | | [] | +| [vpc](variables.tf#L205) | VPC configuration for the project. | object({…}) | | null | ## Outputs diff --git a/blueprints/factories/project-factory/sample-data/projects/project.yaml b/blueprints/factories/project-factory/sample-data/projects/project.yaml index 03449913..cd7b1837 100644 --- a/blueprints/factories/project-factory/sample-data/projects/project.yaml +++ b/blueprints/factories/project-factory/sample-data/projects/project.yaml @@ -48,15 +48,18 @@ labels: # [opt] Org policy overrides defined at project level org_policies: - constraints/compute.disableGuestAttributesAccess: - enforce: true - constraints/compute.trustedImageProjects: - allow: - values: + compute.disableGuestAttributesAccess: + rules: + - enforce: true + compute.trustedImageProjects: + rules: + - allow: + values: - projects/fast-dev-iac-core-0 - constraints/compute.vmExternalIpAccess: - deny: - all: true + compute.vmExternalIpAccess: + rules: + - deny: + all: true # [opt] Prefix - overrides default if set prefix: test1 diff --git a/blueprints/factories/project-factory/variables.tf b/blueprints/factories/project-factory/variables.tf index 3aa3fa36..a2089bcf 100644 --- a/blueprints/factories/project-factory/variables.tf +++ b/blueprints/factories/project-factory/variables.tf @@ -119,19 +119,6 @@ variable "org_policies" { type = map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) - - # default (unconditional) values - allow = optional(object({ - all = optional(bool) - values = optional(list(string)) - })) - deny = optional(object({ - all = optional(bool) - values = optional(list(string)) - })) - enforce = optional(bool, true) # for boolean policies only. - - # conditional values rules = optional(list(object({ allow = optional(object({ all = optional(bool) @@ -141,13 +128,13 @@ variable "org_policies" { all = optional(bool) values = optional(list(string)) })) - enforce = optional(bool, true) # for boolean policies only. - condition = object({ + enforce = optional(bool) # for boolean policies only. + condition = optional(object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) - }) + }), {}) })), []) })) default = {} diff --git a/blueprints/gke/multitenant-fleet/main.tf b/blueprints/gke/multitenant-fleet/main.tf index 588d6c5b..4079db99 100644 --- a/blueprints/gke/multitenant-fleet/main.tf +++ b/blueprints/gke/multitenant-fleet/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,10 +64,10 @@ module "gke-project-0" { } # specify project-level org policies here if you need them # policy_boolean = { - # "constraints/compute.disableGuestAttributesAccess" = true + # "compute.disableGuestAttributesAccess" = true # } # policy_list = { - # "constraints/compute.trustedImageProjects" = { + # "compute.trustedImageProjects" = { # inherit_from_parent = null # suggested_value = null # status = true diff --git a/blueprints/networking/filtering-proxy/main.tf b/blueprints/networking/filtering-proxy/main.tf index 06efa814..b36f0140 100644 --- a/blueprints/networking/filtering-proxy/main.tf +++ b/blueprints/networking/filtering-proxy/main.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -227,8 +227,8 @@ module "folder-apps" { name = "apps" org_policies = { # prevent VMs with public IPs in the apps folder - "constraints/compute.vmExternalIpAccess" = { - deny = { all = true } + "compute.vmExternalIpAccess" = { + rules = [{ deny = { all = true } }] } } } diff --git a/fast/stages-multitenant/1-resman-tenant/branch-sandbox.tf b/fast/stages-multitenant/1-resman-tenant/branch-sandbox.tf index 6f3d526c..39ab03ed 100644 --- a/fast/stages-multitenant/1-resman-tenant/branch-sandbox.tf +++ b/fast/stages-multitenant/1-resman-tenant/branch-sandbox.tf @@ -28,8 +28,8 @@ module "branch-sandbox-folder" { "roles/resourcemanager.projectCreator" = [local.automation_sas_iam.sandbox] } org_policies = { - "constraints/sql.restrictPublicIp" = { enforce = false } - "constraints/compute.vmExternalIpAccess" = { allow = { all = true } } + "sql.restrictPublicIp" = { rules = [{ enforce = false }] } + "compute.vmExternalIpAccess" = { rules = [{ allow = { all = true } }] } } tag_bindings = { context = var.tags.values["${var.tags.names.context}/sandbox"] diff --git a/fast/stages-multitenant/1-resman-tenant/data/org-policies/compute.yaml b/fast/stages-multitenant/1-resman-tenant/data/org-policies/compute.yaml index 0d27ac42..a3f96b1b 100644 --- a/fast/stages-multitenant/1-resman-tenant/data/org-policies/compute.yaml +++ b/fast/stages-multitenant/1-resman-tenant/data/org-policies/compute.yaml @@ -3,71 +3,90 @@ # sample subset of useful organization policies, edit to suit requirements compute.disableGuestAttributesAccess: - enforce: true + rules: + - enforce: true compute.requireOsLogin: - enforce: true + rules: + - enforce: true compute.restrictLoadBalancerCreationForTypes: - allow: - values: - - in:INTERNAL + rules: + - allow: + values: + - in:INTERNAL compute.skipDefaultNetworkCreation: - enforce: true + rules: + - enforce: true compute.vmExternalIpAccess: - deny: - all: true + rules: + - deny: + all: true # compute.disableInternetNetworkEndpointGroup: -# enforce: true +# rules: +# - enforce: true # compute.disableNestedVirtualization: -# enforce: true +# rules: +# - enforce: true # compute.disableSerialPortAccess: -# enforce: true +# rules: +# - enforce: true # compute.restrictCloudNATUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictDedicatedInterconnectUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictPartnerInterconnectUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictProtocolForwardingCreationForTypes: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictSharedVpcHostProjects: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictSharedVpcSubnetworks: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictVpcPeering: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictVpnPeerIPs: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictXpnProjectLienRemoval: -# enforce: true +# rules: +# - enforce: true # compute.setNewProjectDefaultToZonalDNSOnly: -# enforce: true +# rules: +# - enforce: true # compute.vmCanIpForward: -# deny: -# all: true +# rules: +# - deny: +# all: true diff --git a/fast/stages-multitenant/1-resman-tenant/data/org-policies/iam.yaml b/fast/stages-multitenant/1-resman-tenant/data/org-policies/iam.yaml index 4d83f827..58e0032c 100644 --- a/fast/stages-multitenant/1-resman-tenant/data/org-policies/iam.yaml +++ b/fast/stages-multitenant/1-resman-tenant/data/org-policies/iam.yaml @@ -3,10 +3,13 @@ # sample subset of useful organization policies, edit to suit requirements iam.automaticIamGrantsForDefaultServiceAccounts: - enforce: true + rules: + - enforce: true iam.disableServiceAccountKeyCreation: - enforce: true + rules: + - enforce: true iam.disableServiceAccountKeyUpload: - enforce: true + rules: + - enforce: true diff --git a/fast/stages-multitenant/1-resman-tenant/data/org-policies/serverless.yaml b/fast/stages-multitenant/1-resman-tenant/data/org-policies/serverless.yaml index de62e6c7..3efb23cd 100644 --- a/fast/stages-multitenant/1-resman-tenant/data/org-policies/serverless.yaml +++ b/fast/stages-multitenant/1-resman-tenant/data/org-policies/serverless.yaml @@ -3,24 +3,29 @@ # sample subset of useful organization policies, edit to suit requirements run.allowedIngress: - allow: - values: - - is:internal + rules: + - allow: + values: + - is:internal # run.allowedVPCEgress: -# allow: -# values: +# rules: +# - allow: +# values: # - is:private-ranges-only # cloudfunctions.allowedIngressSettings: -# allow: -# values: -# - is:ALLOW_INTERNAL_ONLY +# rules: +# - allow: +# values: +# - is:ALLOW_INTERNAL_ONLY # cloudfunctions.allowedVpcConnectorEgressSettings: -# allow: -# values: -# - is:PRIVATE_RANGES_ONLY +# rules: +# - allow: +# values: +# - is:PRIVATE_RANGES_ONLY # cloudfunctions.requireVPCConnector: -# enforce: true +# rules: +# - enforce: true diff --git a/fast/stages-multitenant/1-resman-tenant/data/org-policies/sql.yaml b/fast/stages-multitenant/1-resman-tenant/data/org-policies/sql.yaml index 88b84d9d..0eee8045 100644 --- a/fast/stages-multitenant/1-resman-tenant/data/org-policies/sql.yaml +++ b/fast/stages-multitenant/1-resman-tenant/data/org-policies/sql.yaml @@ -3,7 +3,9 @@ # sample subset of useful organization policies, edit to suit requirements sql.restrictAuthorizedNetworks: - enforce: true + rules: + - enforce: true sql.restrictPublicIp: - enforce: true + rules: + - enforce: true diff --git a/fast/stages-multitenant/1-resman-tenant/data/org-policies/storage.yaml b/fast/stages-multitenant/1-resman-tenant/data/org-policies/storage.yaml index 6c0a673f..448357b8 100644 --- a/fast/stages-multitenant/1-resman-tenant/data/org-policies/storage.yaml +++ b/fast/stages-multitenant/1-resman-tenant/data/org-policies/storage.yaml @@ -3,4 +3,5 @@ # sample subset of useful organization policies, edit to suit requirements storage.uniformBucketLevelAccess: - enforce: true + rules: + - enforce: true diff --git a/fast/stages/0-bootstrap/README.md b/fast/stages/0-bootstrap/README.md index e1bb2948..88bdceb3 100644 --- a/fast/stages/0-bootstrap/README.md +++ b/fast/stages/0-bootstrap/README.md @@ -452,7 +452,10 @@ The remaining configuration is manual, as it regards the repositories themselves - edit the modules source to match your modules repository - a simple way is using the "Replace in files" function of your editor - search for `source\s*= "../../../modules/([^"]+)"` - - replace with `source = "git@github.com:my-org/fast-modules.git//$1?ref=v1.0"` + - replace with: + - modules stored on GitHub: `source = "git@github.com:my-org/fast-modules.git//$1?ref=v1.0"` + - modules stored on Gitlab: `source = "git::ssh://git@gitlab.com/my-org/fast-modules.git//$1?ref=v1.0"` + - modules stored on Source Repositories: `source = git::https://source.developers.google.com/p/my-project/r/my-repository//$1?ref=v1.0"`. You may need to run `git config --global credential.'https://source.developers.google.com'.helper gcloud.sh` first as documented [here](https://cloud.google.com/source-repositories/docs/adding-repositories-as-remotes#add_the_repository_as_a_remote) - copy the generated workflow file for the stage from the GCS output files bucket or from the local clone if enabled - for GitHub, place it in a `.github/workflows` folder in the repository root - for Gitlab, rename it to `.gitlab-ci.yml` and place it in the repository root diff --git a/fast/stages/1-resman/branch-sandbox.tf b/fast/stages/1-resman/branch-sandbox.tf index 8b54e749..72221bc0 100644 --- a/fast/stages/1-resman/branch-sandbox.tf +++ b/fast/stages/1-resman/branch-sandbox.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,8 +33,8 @@ module "branch-sandbox-folder" { "roles/resourcemanager.projectCreator" = [module.branch-sandbox-sa.0.iam_email] } org_policies = { - "constraints/sql.restrictPublicIp" = { enforce = false } - "constraints/compute.vmExternalIpAccess" = { allow = { all = true } } + "sql.restrictPublicIp" = { rules = [{ enforce = false }] } + "compute.vmExternalIpAccess" = { rules = [{ allow = { all = true } }] } } tag_bindings = { context = try( diff --git a/fast/stages/1-resman/data/org-policies/compute.yaml b/fast/stages/1-resman/data/org-policies/compute.yaml index 0d27ac42..a3f96b1b 100644 --- a/fast/stages/1-resman/data/org-policies/compute.yaml +++ b/fast/stages/1-resman/data/org-policies/compute.yaml @@ -3,71 +3,90 @@ # sample subset of useful organization policies, edit to suit requirements compute.disableGuestAttributesAccess: - enforce: true + rules: + - enforce: true compute.requireOsLogin: - enforce: true + rules: + - enforce: true compute.restrictLoadBalancerCreationForTypes: - allow: - values: - - in:INTERNAL + rules: + - allow: + values: + - in:INTERNAL compute.skipDefaultNetworkCreation: - enforce: true + rules: + - enforce: true compute.vmExternalIpAccess: - deny: - all: true + rules: + - deny: + all: true # compute.disableInternetNetworkEndpointGroup: -# enforce: true +# rules: +# - enforce: true # compute.disableNestedVirtualization: -# enforce: true +# rules: +# - enforce: true # compute.disableSerialPortAccess: -# enforce: true +# rules: +# - enforce: true # compute.restrictCloudNATUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictDedicatedInterconnectUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictPartnerInterconnectUsage: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictProtocolForwardingCreationForTypes: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictSharedVpcHostProjects: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictSharedVpcSubnetworks: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictVpcPeering: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictVpnPeerIPs: -# deny: -# all: true +# rules: +# - deny: +# all: true # compute.restrictXpnProjectLienRemoval: -# enforce: true +# rules: +# - enforce: true # compute.setNewProjectDefaultToZonalDNSOnly: -# enforce: true +# rules: +# - enforce: true # compute.vmCanIpForward: -# deny: -# all: true +# rules: +# - deny: +# all: true diff --git a/fast/stages/1-resman/data/org-policies/iam.yaml b/fast/stages/1-resman/data/org-policies/iam.yaml index 4d83f827..58e0032c 100644 --- a/fast/stages/1-resman/data/org-policies/iam.yaml +++ b/fast/stages/1-resman/data/org-policies/iam.yaml @@ -3,10 +3,13 @@ # sample subset of useful organization policies, edit to suit requirements iam.automaticIamGrantsForDefaultServiceAccounts: - enforce: true + rules: + - enforce: true iam.disableServiceAccountKeyCreation: - enforce: true + rules: + - enforce: true iam.disableServiceAccountKeyUpload: - enforce: true + rules: + - enforce: true diff --git a/fast/stages/1-resman/data/org-policies/serverless.yaml b/fast/stages/1-resman/data/org-policies/serverless.yaml index de62e6c7..3efb23cd 100644 --- a/fast/stages/1-resman/data/org-policies/serverless.yaml +++ b/fast/stages/1-resman/data/org-policies/serverless.yaml @@ -3,24 +3,29 @@ # sample subset of useful organization policies, edit to suit requirements run.allowedIngress: - allow: - values: - - is:internal + rules: + - allow: + values: + - is:internal # run.allowedVPCEgress: -# allow: -# values: +# rules: +# - allow: +# values: # - is:private-ranges-only # cloudfunctions.allowedIngressSettings: -# allow: -# values: -# - is:ALLOW_INTERNAL_ONLY +# rules: +# - allow: +# values: +# - is:ALLOW_INTERNAL_ONLY # cloudfunctions.allowedVpcConnectorEgressSettings: -# allow: -# values: -# - is:PRIVATE_RANGES_ONLY +# rules: +# - allow: +# values: +# - is:PRIVATE_RANGES_ONLY # cloudfunctions.requireVPCConnector: -# enforce: true +# rules: +# - enforce: true diff --git a/fast/stages/1-resman/data/org-policies/sql.yaml b/fast/stages/1-resman/data/org-policies/sql.yaml index 88b84d9d..0eee8045 100644 --- a/fast/stages/1-resman/data/org-policies/sql.yaml +++ b/fast/stages/1-resman/data/org-policies/sql.yaml @@ -3,7 +3,9 @@ # sample subset of useful organization policies, edit to suit requirements sql.restrictAuthorizedNetworks: - enforce: true + rules: + - enforce: true sql.restrictPublicIp: - enforce: true + rules: + - enforce: true diff --git a/fast/stages/1-resman/data/org-policies/storage.yaml b/fast/stages/1-resman/data/org-policies/storage.yaml index 6c0a673f..448357b8 100644 --- a/fast/stages/1-resman/data/org-policies/storage.yaml +++ b/fast/stages/1-resman/data/org-policies/storage.yaml @@ -3,4 +3,5 @@ # sample subset of useful organization policies, edit to suit requirements storage.uniformBucketLevelAccess: - enforce: true + rules: + - enforce: true diff --git a/fast/stages/1-resman/organization.tf b/fast/stages/1-resman/organization.tf index 3d7db46d..a3bc2f0d 100644 --- a/fast/stages/1-resman/organization.tf +++ b/fast/stages/1-resman/organization.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -68,7 +68,11 @@ module "organization" { # sample subset of useful organization policies, edit to suit requirements org_policies = { - "iam.allowedPolicyMemberDomains" = { allow = { values = local.all_drs_domains } } + "iam.allowedPolicyMemberDomains" = { + rules = [ + { allow = { values = local.all_drs_domains } } + ] + } #"gcp.resourceLocations" = { # allow = { values = local.allowed_regions } diff --git a/fast/stages/3-project-factory/dev/data/projects/project.yaml.sample b/fast/stages/3-project-factory/dev/data/projects/project.yaml.sample index 88ba0bf5..5311019d 100644 --- a/fast/stages/3-project-factory/dev/data/projects/project.yaml.sample +++ b/fast/stages/3-project-factory/dev/data/projects/project.yaml.sample @@ -48,15 +48,18 @@ labels: # [opt] Org policy overrides defined at project level org_policies: - constraints/compute.disableGuestAttributesAccess: - enforce: true - constraints/compute.trustedImageProjects: - allow: - values: + compute.disableGuestAttributesAccess: + rules: + - enforce: true + compute.trustedImageProjects: + rules: + - allow: + values: - projects/fast-dev-iac-core-0 - constraints/compute.vmExternalIpAccess: - deny: - all: true + compute.vmExternalIpAccess: + rules: + - deny: + all: true # [opt] Service account to create for the project and their roles on the project # in name => [roles] format diff --git a/modules/folder/README.md b/modules/folder/README.md index e1ad6809..8addd48e 100644 --- a/modules/folder/README.md +++ b/modules/folder/README.md @@ -42,40 +42,46 @@ module "folder" { name = "Folder name" org_policies = { "compute.disableGuestAttributesAccess" = { - enforce = true + rules = [{ enforce = true }] } - "constraints/compute.skipDefaultNetworkCreation" = { - enforce = true + "compute.skipDefaultNetworkCreation" = { + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyCreation" = { - enforce = true + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyUpload" = { - enforce = false rules = [ { condition = { - expression = "resource.matchTagId(\"tagKeys/1234\", \"tagValues/1234\")" + expression = "resource.matchTagId('tagKeys/1234', 'tagValues/1234')" title = "condition" description = "test condition" location = "somewhere" } enforce = true + }, + { + enforce = false } ] } - "constraints/iam.allowedPolicyMemberDomains" = { - allow = { - values = ["C0xxxxxxx", "C0yyyyyyy"] - } + "iam.allowedPolicyMemberDomains" = { + rules = [{ + allow = { + values = ["C0xxxxxxx", "C0yyyyyyy"] + } + }] } - "constraints/compute.trustedImageProjects" = { - allow = { - values = ["projects/my-project"] - } + "compute.trustedImageProjects" = { + rules = [{ + allow = { + values = ["projects/my-project"] + } + }] } - "constraints/compute.vmExternalIpAccess" = { - deny = { all = true } + "compute.vmExternalIpAccess" = { + rules = [{ deny = { all = true } }] } } } @@ -340,10 +346,10 @@ module "folder" { | [logging_exclusions](variables.tf#L98) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string) | | {} | | [logging_sinks](variables.tf#L105) | Logging sinks to create for the organization. | map(object({…})) | | {} | | [name](variables.tf#L135) | Folder name. | string | | null | -| [org_policies](variables.tf#L141) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} | -| [org_policies_data_path](variables.tf#L181) | Path containing org policies in YAML format. | string | | null | -| [parent](variables.tf#L187) | Parent in folders/folder_id or organizations/org_id format. | string | | null | -| [tag_bindings](variables.tf#L197) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | +| [org_policies](variables.tf#L141) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} | +| [org_policies_data_path](variables.tf#L168) | Path containing org policies in YAML format. | string | | null | +| [parent](variables.tf#L174) | Parent in folders/folder_id or organizations/org_id format. | string | | null | +| [tag_bindings](variables.tf#L184) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null | ## Outputs diff --git a/modules/folder/organization-policies.tf b/modules/folder/organization-policies.tf index 47532f21..2bf79c4a 100644 --- a/modules/folder/organization-policies.tf +++ b/modules/folder/organization-policies.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,16 +28,6 @@ locals { k => { inherit_from_parent = try(v.inherit_from_parent, null) reset = try(v.reset, null) - allow = can(v.allow) ? { - all = try(v.allow.all, null) - values = try(v.allow.values, null) - } : null - deny = can(v.deny) ? { - all = try(v.deny.all, null) - values = try(v.deny.values, null) - } : null - enforce = try(v.enforce, true) - rules = [ for r in try(v.rules, []) : { allow = can(r.allow) ? { @@ -48,7 +38,7 @@ locals { all = try(r.deny.all, null) values = try(r.deny.values, null) } : null - enforce = try(r.enforce, true) + enforce = try(r.enforce, null) condition = { description = try(r.condition.description, null) expression = try(r.condition.expression, null) @@ -67,8 +57,9 @@ locals { k => merge(v, { name = "${local.folder.name}/policies/${k}" parent = local.folder.name - - is_boolean_policy = v.allow == null && v.deny == null + is_boolean_policy = ( + alltrue([for r in v.rules : r.allow == null && r.deny == null]) + ) has_values = ( length(coalesce(try(v.allow.values, []), [])) > 0 || length(coalesce(try(v.deny.values, []), [])) > 0 @@ -90,11 +81,9 @@ resource "google_org_policy_policy" "default" { for_each = local.org_policies name = each.value.name parent = each.value.parent - spec { inherit_from_parent = each.value.inherit_from_parent reset = each.value.reset - dynamic "rules" { for_each = each.value.rules iterator = rule @@ -106,11 +95,14 @@ resource "google_org_policy_policy" "default" { ? upper(tostring(rule.value.enforce)) : null ) - condition { - description = rule.value.condition.description - expression = rule.value.condition.expression - location = rule.value.condition.location - title = rule.value.condition.title + dynamic "condition" { + for_each = rule.value.condition.expression != null ? [1] : [] + content { + description = rule.value.condition.description + expression = rule.value.condition.expression + location = rule.value.condition.location + title = rule.value.condition.title + } } dynamic "values" { for_each = rule.value.has_values ? [1] : [] @@ -121,22 +113,5 @@ resource "google_org_policy_policy" "default" { } } } - - rules { - allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null - deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null - enforce = ( - each.value.is_boolean_policy && each.value.enforce != null - ? upper(tostring(each.value.enforce)) - : null - ) - dynamic "values" { - for_each = each.value.has_values ? [1] : [] - content { - allowed_values = try(each.value.allow.values, null) - denied_values = try(each.value.deny.values, null) - } - } - } } } diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf index a93ea1aa..e0abc612 100644 --- a/modules/folder/variables.tf +++ b/modules/folder/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -143,19 +143,6 @@ variable "org_policies" { type = map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) - - # default (unconditional) values - allow = optional(object({ - all = optional(bool) - values = optional(list(string)) - })) - deny = optional(object({ - all = optional(bool) - values = optional(list(string)) - })) - enforce = optional(bool, true) # for boolean policies only. - - # conditional values rules = optional(list(object({ allow = optional(object({ all = optional(bool) @@ -165,13 +152,13 @@ variable "org_policies" { all = optional(bool) values = optional(list(string)) })) - enforce = optional(bool, true) # for boolean policies only. - condition = object({ + enforce = optional(bool) # for boolean policies only. + condition = optional(object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) - }) + }), {}) })), []) })) default = {} diff --git a/modules/net-vpc/README.md b/modules/net-vpc/README.md index dbd85502..bd5675d2 100644 --- a/modules/net-vpc/README.md +++ b/modules/net-vpc/README.md @@ -314,7 +314,7 @@ module "vpc" { name = "my-network" data_folder = "config/subnets" } -# tftest modules=1 resources=3 files=subnet-simple,subnet-detailed inventory=factory.yaml +# tftest modules=1 resources=4 files=subnet-simple,subnet-detailed inventory=factory.yaml ``` ```yaml diff --git a/modules/net-vpc/subnets.tf b/modules/net-vpc/subnets.tf index ae094ecf..7c03bfca 100644 --- a/modules/net-vpc/subnets.tf +++ b/modules/net-vpc/subnets.tf @@ -31,6 +31,9 @@ locals { flow_logs_config = try(v.flow_logs, null) ipv6 = try(v.ipv6, null) secondary_ip_ranges = try(v.secondary_ip_ranges, null) + iam_groups = try(v.iam_groups, []) + iam_users = try(v.iam_users, []) + iam_service_accounts = try(v.iam_service_accounts, []) } } _factory_subnets_iam = [ diff --git a/modules/organization/README.md b/modules/organization/README.md index b6caa3cd..39b5ff29 100644 --- a/modules/organization/README.md +++ b/modules/organization/README.md @@ -25,50 +25,77 @@ module "org" { iam_additive_members = { "user:compute@example.org" = ["roles/compute.admin", "roles/container.viewer"] } - + tags = { + allowexternal = { + description = "Allow external identities." + values = { + true = {}, false = {} + } + } + } org_policies = { "custom.gkeEnableAutoUpgrade" = { - enforce = true + rules = [{ enforce = true }] } "compute.disableGuestAttributesAccess" = { - enforce = true + rules = [{ enforce = true }] } - "constraints/compute.skipDefaultNetworkCreation" = { - enforce = true + "compute.skipDefaultNetworkCreation" = { + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyCreation" = { - enforce = true + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyUpload" = { - enforce = false rules = [ { condition = { - expression = "resource.matchTagId(\"tagKeys/1234\", \"tagValues/1234\")" + expression = "resource.matchTagId('tagKeys/1234', 'tagValues/1234')" title = "condition" description = "test condition" location = "somewhere" } enforce = true + }, + { + enforce = false } ] } - "constraints/iam.allowedPolicyMemberDomains" = { - allow = { - values = ["C0xxxxxxx", "C0yyyyyyy"] - } + "iam.allowedPolicyMemberDomains" = { + rules = [ + { + allow = { all = true } + condition = { + expression = "resource.matchTag('1234567890/allowexternal', 'true')" + title = "Allow external identities" + description = "Allow external identities when resource has the `allowexternal` tag set to true." + } + }, + { + allow = { values = ["C0xxxxxxx", "C0yyyyyyy"] } + condition = { + expression = "!resource.matchTag('1234567890/allowexternal', 'true')" + title = "" + description = "For any resource without allowexternal=true, only allow identities from restricted domains." + } + } + ] } - "constraints/compute.trustedImageProjects" = { - allow = { - values = ["projects/my-project"] - } + + "compute.trustedImageProjects" = { + rules = [{ + allow = { + values = ["projects/my-project"] + } + }] } - "constraints/compute.vmExternalIpAccess" = { - deny = { all = true } + "compute.vmExternalIpAccess" = { + rules = [{ deny = { all = true } }] } } } -# tftest modules=1 resources=13 inventory=basic.yaml +# tftest modules=1 resources=16 inventory=basic.yaml ``` ## IAM @@ -111,7 +138,7 @@ module "org" { # not necessarily to enforce on the org level, policy may be applied on folder/project levels org_policies = { "custom.gkeEnableAutoUpgrade" = { - enforce = true + rules = [{ enforce = true }] } } } @@ -131,7 +158,7 @@ module "org" { org_policy_custom_constraints_data_path = "configs/custom-constraints" org_policies = { "custom.gkeEnableAutoUpgrade" = { - enforce = true + rules = [{ enforce = true }] } } } @@ -447,7 +474,7 @@ module "org" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [organization_id](variables.tf#L246) | Organization id in organizations/nnnnnn format. | string | ✓ | | +| [organization_id](variables.tf#L234) | Organization id in organizations/nnnnnn format. | string | ✓ | | | [contacts](variables.tf#L17) | 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. | map(list(string)) | | {} | | [custom_roles](variables.tf#L24) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} | | [firewall_policies](variables.tf#L31) | Hierarchical firewall policy rules created in the organization. | map(map(object({…}))) | | {} | @@ -463,12 +490,12 @@ module "org" { | [logging_exclusions](variables.tf#L122) | Logging exclusions for this organization in the form {NAME -> FILTER}. | map(string) | | {} | | [logging_sinks](variables.tf#L129) | Logging sinks to create for the organization. | map(object({…})) | | {} | | [network_tags](variables.tf#L159) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | -| [org_policies](variables.tf#L181) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} | -| [org_policies_data_path](variables.tf#L220) | Path containing org policies in YAML format. | string | | null | -| [org_policy_custom_constraints](variables.tf#L226) | Organization policiy custom constraints keyed by constraint name. | map(object({…})) | | {} | -| [org_policy_custom_constraints_data_path](variables.tf#L240) | Path containing org policy custom constraints in YAML format. | string | | null | -| [tag_bindings](variables.tf#L255) | Tag bindings for this organization, in key => tag value id format. | map(string) | | null | -| [tags](variables.tf#L261) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | +| [org_policies](variables.tf#L181) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} | +| [org_policies_data_path](variables.tf#L208) | Path containing org policies in YAML format. | string | | null | +| [org_policy_custom_constraints](variables.tf#L214) | Organization policiy custom constraints keyed by constraint name. | map(object({…})) | | {} | +| [org_policy_custom_constraints_data_path](variables.tf#L228) | Path containing org policy custom constraints in YAML format. | string | | null | +| [tag_bindings](variables.tf#L243) | Tag bindings for this organization, in key => tag value id format. | map(string) | | null | +| [tags](variables.tf#L249) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} | ## Outputs diff --git a/modules/organization/organization-policies.tf b/modules/organization/organization-policies.tf index 1a99ef9a..b43c5955 100644 --- a/modules/organization/organization-policies.tf +++ b/modules/organization/organization-policies.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,16 +28,6 @@ locals { k => { inherit_from_parent = try(v.inherit_from_parent, null) reset = try(v.reset, null) - allow = can(v.allow) ? { - all = try(v.allow.all, null) - values = try(v.allow.values, null) - } : null - deny = can(v.deny) ? { - all = try(v.deny.all, null) - values = try(v.deny.values, null) - } : null - enforce = try(v.enforce, true) - rules = [ for r in try(v.rules, []) : { allow = can(r.allow) ? { @@ -48,7 +38,7 @@ locals { all = try(r.deny.all, null) values = try(r.deny.values, null) } : null - enforce = try(r.enforce, true) + enforce = try(r.enforce, null) condition = { description = try(r.condition.description, null) expression = try(r.condition.expression, null) @@ -67,8 +57,9 @@ locals { k => merge(v, { name = "${var.organization_id}/policies/${k}" parent = var.organization_id - - is_boolean_policy = v.allow == null && v.deny == null + is_boolean_policy = ( + alltrue([for r in v.rules : r.allow == null && r.deny == null]) + ) has_values = ( length(coalesce(try(v.allow.values, []), [])) > 0 || length(coalesce(try(v.deny.values, []), [])) > 0 @@ -90,11 +81,9 @@ resource "google_org_policy_policy" "default" { for_each = local.org_policies name = each.value.name parent = each.value.parent - spec { inherit_from_parent = each.value.inherit_from_parent reset = each.value.reset - dynamic "rules" { for_each = each.value.rules iterator = rule @@ -106,11 +95,14 @@ resource "google_org_policy_policy" "default" { ? upper(tostring(rule.value.enforce)) : null ) - condition { - description = rule.value.condition.description - expression = rule.value.condition.expression - location = rule.value.condition.location - title = rule.value.condition.title + dynamic "condition" { + for_each = rule.value.condition.expression != null ? [1] : [] + content { + description = rule.value.condition.description + expression = rule.value.condition.expression + location = rule.value.condition.location + title = rule.value.condition.title + } } dynamic "values" { for_each = rule.value.has_values ? [1] : [] @@ -121,25 +113,7 @@ resource "google_org_policy_policy" "default" { } } } - - rules { - allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null - deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null - enforce = ( - each.value.is_boolean_policy && each.value.enforce != null - ? upper(tostring(each.value.enforce)) - : null - ) - dynamic "values" { - for_each = each.value.has_values ? [1] : [] - content { - allowed_values = try(each.value.allow.values, null) - denied_values = try(each.value.deny.values, null) - } - } - } } - depends_on = [ google_organization_iam_audit_config.config, google_organization_iam_binding.authoritative, diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf index ced5cad3..619056a0 100644 --- a/modules/organization/variables.tf +++ b/modules/organization/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -183,18 +183,6 @@ variable "org_policies" { type = map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) - - # default (unconditional) values - allow = optional(object({ - all = optional(bool) - values = optional(list(string)) - })) - deny = optional(object({ - all = optional(bool) - values = optional(list(string)) - })) - enforce = optional(bool, true) # for boolean policies only. - # conditional values rules = optional(list(object({ allow = optional(object({ all = optional(bool) @@ -204,13 +192,13 @@ variable "org_policies" { all = optional(bool) values = optional(list(string)) })) - enforce = optional(bool, true) # for boolean policies only. - condition = object({ + enforce = optional(bool) # for boolean policies only. + condition = optional(object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) - }) + }), {}) })), []) })) default = {} diff --git a/modules/project/README.md b/modules/project/README.md index e7a645fe..730fe190 100644 --- a/modules/project/README.md +++ b/modules/project/README.md @@ -213,7 +213,6 @@ module "service-project" { source = "./fabric/modules/project" name = "my-service-project" shared_vpc_service_config = { - attach = true host_project = module.host-project.project_id service_identity_iam = { "roles/compute.networkUser" = [ @@ -244,40 +243,46 @@ module "project" { prefix = "foo" org_policies = { "compute.disableGuestAttributesAccess" = { - enforce = true + rules = [{ enforce = true }] } - "constraints/compute.skipDefaultNetworkCreation" = { - enforce = true + "compute.skipDefaultNetworkCreation" = { + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyCreation" = { - enforce = true + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyUpload" = { - enforce = false rules = [ { condition = { - expression = "resource.matchTagId(\"tagKeys/1234\", \"tagValues/1234\")" + expression = "resource.matchTagId('tagKeys/1234', 'tagValues/1234')" title = "condition" description = "test condition" location = "somewhere" } enforce = true + }, + { + enforce = false } ] } - "constraints/iam.allowedPolicyMemberDomains" = { - allow = { - values = ["C0xxxxxxx", "C0yyyyyyy"] - } + "iam.allowedPolicyMemberDomains" = { + rules = [{ + allow = { + values = ["C0xxxxxxx", "C0yyyyyyy"] + } + }] } - "constraints/compute.trustedImageProjects" = { - allow = { - values = ["projects/my-project"] - } + "compute.trustedImageProjects" = { + rules = [{ + allow = { + values = ["projects/my-project"] + } + }] } - "constraints/compute.vmExternalIpAccess" = { - deny = { all = true } + "compute.vmExternalIpAccess" = { + rules = [{ deny = { all = true } }] } } } @@ -307,36 +312,42 @@ module "project" { ```yaml # tftest-file id=boolean path=configs/org-policies/boolean.yaml compute.disableGuestAttributesAccess: - enforce: true -constraints/compute.skipDefaultNetworkCreation: - enforce: true + rules: + - enforce: true +compute.skipDefaultNetworkCreation: + rules: + - enforce: true iam.disableServiceAccountKeyCreation: - enforce: true + rules: + - enforce: true iam.disableServiceAccountKeyUpload: - enforce: false rules: - condition: description: test condition - expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") + expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234') location: somewhere title: condition enforce: true + - enforce: false ``` ```yaml # tftest-file id=list path=configs/org-policies/list.yaml -constraints/compute.trustedImageProjects: - allow: - values: - - projects/my-project -constraints/compute.vmExternalIpAccess: - deny: - all: true -constraints/iam.allowedPolicyMemberDomains: - allow: - values: - - C0xxxxxxx - - C0yyyyyyy +compute.trustedImageProjects: + rules: + - allow: + values: + - projects/my-project +compute.vmExternalIpAccess: + rules: + - deny: + all: true +iam.allowedPolicyMemberDomains: + rules: + - allow: + values: + - C0xxxxxxx + - C0yyyyyyy ``` @@ -523,23 +534,23 @@ output "compute_robot" { | [logging_exclusions](variables.tf#L95) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string) | | {} | | [logging_sinks](variables.tf#L102) | Logging sinks to create for this project. | map(object({…})) | | {} | | [metric_scopes](variables.tf#L133) | List of projects that will act as metric scopes for this project. | list(string) | | [] | -| [org_policies](variables.tf#L145) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} | -| [org_policies_data_path](variables.tf#L185) | Path containing org policies in YAML format. | string | | null | -| [oslogin](variables.tf#L191) | Enable OS Login. | bool | | false | -| [oslogin_admins](variables.tf#L197) | List of IAM-style identities that will be granted roles necessary for OS Login administrators. | list(string) | | [] | -| [oslogin_users](variables.tf#L205) | List of IAM-style identities that will be granted roles necessary for OS Login users. | list(string) | | [] | -| [parent](variables.tf#L212) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null | -| [prefix](variables.tf#L222) | Optional prefix used to generate project id and name. | string | | null | -| [project_create](variables.tf#L232) | Create project. When set to false, uses a data source to reference existing project. | bool | | true | -| [service_config](variables.tf#L238) | Configure service API activation. | object({…}) | | {…} | -| [service_encryption_key_ids](variables.tf#L250) | Cloud KMS encryption key in {SERVICE => [KEY_URL]} format. | map(list(string)) | | {} | -| [service_perimeter_bridges](variables.tf#L257) | Name of VPC-SC Bridge perimeters to add project into. See comment in the variables file for format. | list(string) | | null | -| [service_perimeter_standard](variables.tf#L264) | Name of VPC-SC Standard perimeter to add project into. See comment in the variables file for format. | string | | null | -| [services](variables.tf#L270) | Service APIs to enable. | list(string) | | [] | -| [shared_vpc_host_config](variables.tf#L276) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null | -| [shared_vpc_service_config](variables.tf#L285) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | null | -| [skip_delete](variables.tf#L295) | Allows the underlying resources to be destroyed without destroying the project itself. | bool | | false | -| [tag_bindings](variables.tf#L301) | Tag bindings for this project, in key => tag value id format. | map(string) | | null | +| [org_policies](variables.tf#L145) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} | +| [org_policies_data_path](variables.tf#L172) | Path containing org policies in YAML format. | string | | null | +| [oslogin](variables.tf#L178) | Enable OS Login. | bool | | false | +| [oslogin_admins](variables.tf#L184) | List of IAM-style identities that will be granted roles necessary for OS Login administrators. | list(string) | | [] | +| [oslogin_users](variables.tf#L192) | List of IAM-style identities that will be granted roles necessary for OS Login users. | list(string) | | [] | +| [parent](variables.tf#L199) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null | +| [prefix](variables.tf#L209) | Optional prefix used to generate project id and name. | string | | null | +| [project_create](variables.tf#L219) | Create project. When set to false, uses a data source to reference existing project. | bool | | true | +| [service_config](variables.tf#L225) | Configure service API activation. | object({…}) | | {…} | +| [service_encryption_key_ids](variables.tf#L237) | Cloud KMS encryption key in {SERVICE => [KEY_URL]} format. | map(list(string)) | | {} | +| [service_perimeter_bridges](variables.tf#L244) | Name of VPC-SC Bridge perimeters to add project into. See comment in the variables file for format. | list(string) | | null | +| [service_perimeter_standard](variables.tf#L251) | Name of VPC-SC Standard perimeter to add project into. See comment in the variables file for format. | string | | null | +| [services](variables.tf#L257) | Service APIs to enable. | list(string) | | [] | +| [shared_vpc_host_config](variables.tf#L263) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null | +| [shared_vpc_service_config](variables.tf#L272) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | null | +| [skip_delete](variables.tf#L282) | Allows the underlying resources to be destroyed without destroying the project itself. | bool | | false | +| [tag_bindings](variables.tf#L288) | Tag bindings for this project, in key => tag value id format. | map(string) | | null | ## Outputs diff --git a/modules/project/organization-policies.tf b/modules/project/organization-policies.tf index 4ff5bb99..37e6f253 100644 --- a/modules/project/organization-policies.tf +++ b/modules/project/organization-policies.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,16 +28,6 @@ locals { k => { inherit_from_parent = try(v.inherit_from_parent, null) reset = try(v.reset, null) - allow = can(v.allow) ? { - all = try(v.allow.all, null) - values = try(v.allow.values, null) - } : null - deny = can(v.deny) ? { - all = try(v.deny.all, null) - values = try(v.deny.values, null) - } : null - enforce = try(v.enforce, true) - rules = [ for r in try(v.rules, []) : { allow = can(r.allow) ? { @@ -48,7 +38,7 @@ locals { all = try(r.deny.all, null) values = try(r.deny.values, null) } : null - enforce = try(r.enforce, true) + enforce = try(r.enforce, null) condition = { description = try(r.condition.description, null) expression = try(r.condition.expression, null) @@ -67,8 +57,9 @@ locals { k => merge(v, { name = "projects/${local.project.project_id}/policies/${k}" parent = "projects/${local.project.project_id}" - - is_boolean_policy = v.allow == null && v.deny == null + is_boolean_policy = ( + alltrue([for r in v.rules : r.allow == null && r.deny == null]) + ) has_values = ( length(coalesce(try(v.allow.values, []), [])) > 0 || length(coalesce(try(v.deny.values, []), [])) > 0 @@ -90,11 +81,9 @@ resource "google_org_policy_policy" "default" { for_each = local.org_policies name = each.value.name parent = each.value.parent - spec { inherit_from_parent = each.value.inherit_from_parent reset = each.value.reset - dynamic "rules" { for_each = each.value.rules iterator = rule @@ -106,11 +95,14 @@ resource "google_org_policy_policy" "default" { ? upper(tostring(rule.value.enforce)) : null ) - condition { - description = rule.value.condition.description - expression = rule.value.condition.expression - location = rule.value.condition.location - title = rule.value.condition.title + dynamic "condition" { + for_each = rule.value.condition.expression != null ? [1] : [] + content { + description = rule.value.condition.description + expression = rule.value.condition.expression + location = rule.value.condition.location + title = rule.value.condition.title + } } dynamic "values" { for_each = rule.value.has_values ? [1] : [] @@ -121,22 +113,5 @@ resource "google_org_policy_policy" "default" { } } } - - rules { - allow_all = try(each.value.allow.all, null) == true ? "TRUE" : null - deny_all = try(each.value.deny.all, null) == true ? "TRUE" : null - enforce = ( - each.value.is_boolean_policy && each.value.enforce != null - ? upper(tostring(each.value.enforce)) - : null - ) - dynamic "values" { - for_each = each.value.has_values ? [1] : [] - content { - allowed_values = try(each.value.allow.values, null) - denied_values = try(each.value.deny.values, null) - } - } - } } } diff --git a/modules/project/variables.tf b/modules/project/variables.tf index 3769a1fb..ede3a8c6 100644 --- a/modules/project/variables.tf +++ b/modules/project/variables.tf @@ -1,5 +1,5 @@ /** - * Copyright 2022 Google LLC + * Copyright 2023 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -147,19 +147,6 @@ variable "org_policies" { type = map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) - - # default (unconditional) values - allow = optional(object({ - all = optional(bool) - values = optional(list(string)) - })) - deny = optional(object({ - all = optional(bool) - values = optional(list(string)) - })) - enforce = optional(bool, true) # for boolean policies only. - - # conditional values rules = optional(list(object({ allow = optional(object({ all = optional(bool) @@ -169,13 +156,13 @@ variable "org_policies" { all = optional(bool) values = optional(list(string)) })) - enforce = optional(bool, true) # for boolean policies only. - condition = object({ + enforce = optional(bool) # for boolean policies only. + condition = optional(object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) - }) + }), {}) })), []) })) default = {} diff --git a/modules/vpc-sc/README.md b/modules/vpc-sc/README.md index 8e412bcf..7ad0cba5 100644 --- a/modules/vpc-sc/README.md +++ b/modules/vpc-sc/README.md @@ -147,8 +147,8 @@ module "test" { from = { identities = [ "serviceAccount:test-tf@myproject.iam.gserviceaccount.com", - ], - source_access_levels = ["*"] + ] + access_levels = ["*"] } to = { operations = [{ service_name = "*" }] diff --git a/tests/blueprints/factories/project_factory/fixture/projects/project.yaml b/tests/blueprints/factories/project_factory/fixture/projects/project.yaml index a1581984..b8d6e663 100644 --- a/tests/blueprints/factories/project_factory/fixture/projects/project.yaml +++ b/tests/blueprints/factories/project_factory/fixture/projects/project.yaml @@ -48,15 +48,14 @@ labels: # [opt] Org policy overrides defined at project level org_policies: - policy_boolean: - constraints/compute.disableGuestAttributesAccess: true - policy_list: - constraints/compute.trustedImageProjects: - inherit_from_parent: null - status: true - suggested_value: null - values: - - projects/fast-prod-iac-core-0 + compute.disableGuestAttributesAccess: + rules: + - enforce: true + compute.trustedImageProjects: + rules: + - allow: + values: + - projects/fast-prod-iac-core-0 # [opt] Prefix - overrides default if set prefix: test1 diff --git a/tests/fast/stages/s3_project_factory/data/projects/project.yaml b/tests/fast/stages/s3_project_factory/data/projects/project.yaml index d988d9d5..90354a2a 100644 --- a/tests/fast/stages/s3_project_factory/data/projects/project.yaml +++ b/tests/fast/stages/s3_project_factory/data/projects/project.yaml @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -60,15 +60,14 @@ labels: # [opt] Org policy overrides defined at project level org_policies: - policy_boolean: - constraints/compute.disableGuestAttributesAccess: true - policy_list: - constraints/compute.trustedImageProjects: - inherit_from_parent: null - status: true - suggested_value: null - values: - - projects/fast-prod-iac-core-0 + compute.disableGuestAttributesAccess: + rules: + - enforce: true + compute.trustedImageProjects: + rules: + - allow: + values: + - projects/fast-prod-iac-core-0 # [opt] Service account to create for the project and their roles on the project # in name => [roles] format diff --git a/tests/modules/folder/examples/org-policies.yaml b/tests/modules/folder/examples/org-policies.yaml index f8bf4187..c7bee123 100644 --- a/tests/modules/folder/examples/org-policies.yaml +++ b/tests/modules/folder/examples/org-policies.yaml @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ values: deny_all: null enforce: 'TRUE' values: [] - module.folder.google_org_policy_policy.default["constraints/compute.skipDefaultNetworkCreation"]: + module.folder.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]: spec: - inherit_from_parent: null reset: null @@ -36,7 +36,7 @@ values: deny_all: null enforce: 'TRUE' values: [] - module.folder.google_org_policy_policy.default["constraints/compute.trustedImageProjects"]: + module.folder.google_org_policy_policy.default["compute.trustedImageProjects"]: spec: - inherit_from_parent: null reset: null @@ -49,7 +49,7 @@ values: - allowed_values: - projects/my-project denied_values: null - module.folder.google_org_policy_policy.default["constraints/compute.vmExternalIpAccess"]: + module.folder.google_org_policy_policy.default["compute.vmExternalIpAccess"]: spec: - inherit_from_parent: null reset: null @@ -59,7 +59,7 @@ values: deny_all: 'TRUE' enforce: null values: [] - module.folder.google_org_policy_policy.default["constraints/iam.allowedPolicyMemberDomains"]: + module.folder.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]: spec: - inherit_from_parent: null reset: null @@ -91,7 +91,7 @@ values: - allow_all: null condition: - description: test condition - expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") + expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234') location: somewhere title: condition deny_all: null diff --git a/tests/modules/folder/org_policies_boolean.tfvars b/tests/modules/folder/org_policies_boolean.tfvars index eceafe6d..cf5047a2 100644 --- a/tests/modules/folder/org_policies_boolean.tfvars +++ b/tests/modules/folder/org_policies_boolean.tfvars @@ -1,9 +1,8 @@ org_policies = { "iam.disableServiceAccountKeyCreation" = { - enforce = true + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyUpload" = { - enforce = false rules = [ { condition = { @@ -13,6 +12,9 @@ org_policies = { location = "xxx" } enforce = true + }, + { + enforce = false } ] } diff --git a/tests/modules/folder/org_policies_list.tfvars b/tests/modules/folder/org_policies_list.tfvars index 73807173..2c83de47 100644 --- a/tests/modules/folder/org_policies_list.tfvars +++ b/tests/modules/folder/org_policies_list.tfvars @@ -1,14 +1,15 @@ org_policies = { "compute.vmExternalIpAccess" = { - deny = { all = true } + rules = [{ deny = { all = true } }] } "iam.allowedPolicyMemberDomains" = { - allow = { - values = ["C0xxxxxxx", "C0yyyyyyy"] - } + rules = [{ + allow = { + values = ["C0xxxxxxx", "C0yyyyyyy"] + } + }] } "compute.restrictLoadBalancerCreationForTypes" = { - deny = { values = ["in:EXTERNAL"] } rules = [ { condition = { @@ -31,6 +32,9 @@ org_policies = { allow = { all = true } + }, + { + deny = { values = ["in:EXTERNAL"] } } ] } diff --git a/tests/modules/net_vpc/examples/factory.yaml b/tests/modules/net_vpc/examples/factory.yaml index 48671c29..0724b597 100644 --- a/tests/modules/net_vpc/examples/factory.yaml +++ b/tests/modules/net_vpc/examples/factory.yaml @@ -44,7 +44,18 @@ values: region: europe-west4 role: null secondary_ip_range: [] + module.vpc.google_compute_subnetwork_iam_binding.binding["europe-west1/subnet-detailed.roles/compute.networkUser"]: + condition: [] + members: + - group:lorem@example.com + - serviceAccount:fbz@prj.iam.gserviceaccount.com + - user:foobar@example.com + project: my-project + region: europe-west1 + role: roles/compute.networkUser + subnetwork: subnet-detailed counts: google_compute_network: 1 google_compute_subnetwork: 2 + google_compute_subnetwork_iam_binding: 1 diff --git a/tests/modules/organization/examples/basic.yaml b/tests/modules/organization/examples/basic.yaml index f7b63a1d..9960a712 100644 --- a/tests/modules/organization/examples/basic.yaml +++ b/tests/modules/organization/examples/basic.yaml @@ -25,8 +25,8 @@ values: deny_all: null enforce: 'TRUE' values: [] - module.org.google_org_policy_policy.default["constraints/compute.skipDefaultNetworkCreation"]: - name: organizations/1234567890/policies/constraints/compute.skipDefaultNetworkCreation + module.org.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]: + name: organizations/1234567890/policies/compute.skipDefaultNetworkCreation parent: organizations/1234567890 spec: - inherit_from_parent: null @@ -37,8 +37,8 @@ values: deny_all: null enforce: 'TRUE' values: [] - module.org.google_org_policy_policy.default["constraints/compute.trustedImageProjects"]: - name: organizations/1234567890/policies/constraints/compute.trustedImageProjects + module.org.google_org_policy_policy.default["compute.trustedImageProjects"]: + name: organizations/1234567890/policies/compute.trustedImageProjects parent: organizations/1234567890 spec: - inherit_from_parent: null @@ -52,8 +52,8 @@ values: - allowed_values: - projects/my-project denied_values: null - module.org.google_org_policy_policy.default["constraints/compute.vmExternalIpAccess"]: - name: organizations/1234567890/policies/constraints/compute.vmExternalIpAccess + module.org.google_org_policy_policy.default["compute.vmExternalIpAccess"]: + name: organizations/1234567890/policies/compute.vmExternalIpAccess parent: organizations/1234567890 spec: - inherit_from_parent: null @@ -64,15 +64,30 @@ values: deny_all: 'TRUE' enforce: null values: [] - module.org.google_org_policy_policy.default["constraints/iam.allowedPolicyMemberDomains"]: - name: organizations/1234567890/policies/constraints/iam.allowedPolicyMemberDomains + module.org.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]: + name: organizations/1234567890/policies/iam.allowedPolicyMemberDomains parent: organizations/1234567890 spec: - inherit_from_parent: null reset: null rules: + - allow_all: 'TRUE' + condition: + - description: Allow external identities when resource has the `allowexternal` + tag set to true. + expression: resource.matchTag('1234567890/allowexternal', 'true') + location: null + title: Allow external identities + deny_all: null + enforce: null + values: [] - allow_all: null - condition: [] + condition: + - description: For any resource without allowexternal=true, only allow identities + from restricted domains. + expression: '!resource.matchTag(''1234567890/allowexternal'', ''true'')' + location: null + title: '' deny_all: null enforce: null values: @@ -102,7 +117,7 @@ values: - allow_all: null condition: - description: test condition - expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") + expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234') location: somewhere title: condition deny_all: null @@ -141,6 +156,20 @@ values: member: user:compute@example.org org_id: '1234567890' role: roles/container.viewer + module.org.google_tags_tag_key.default["allowexternal"]: + description: Allow external identities. + parent: organizations/1234567890 + purpose: null + purpose_data: null + short_name: allowexternal + module.org.google_tags_tag_value.default["allowexternal/false"]: + short_name: 'false' + module.org.google_tags_tag_value.default["allowexternal/true"]: + short_name: 'true' + counts: google_org_policy_policy: 8 google_organization_iam_binding: 3 + google_organization_iam_member: 2 + google_tags_tag_key: 1 + google_tags_tag_value: 2 diff --git a/tests/modules/organization/org_policies_boolean.tfvars b/tests/modules/organization/org_policies_boolean.tfvars index eceafe6d..cf5047a2 100644 --- a/tests/modules/organization/org_policies_boolean.tfvars +++ b/tests/modules/organization/org_policies_boolean.tfvars @@ -1,9 +1,8 @@ org_policies = { "iam.disableServiceAccountKeyCreation" = { - enforce = true + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyUpload" = { - enforce = false rules = [ { condition = { @@ -13,6 +12,9 @@ org_policies = { location = "xxx" } enforce = true + }, + { + enforce = false } ] } diff --git a/tests/modules/organization/org_policies_list.tfvars b/tests/modules/organization/org_policies_list.tfvars index f9de8dba..d03f8530 100644 --- a/tests/modules/organization/org_policies_list.tfvars +++ b/tests/modules/organization/org_policies_list.tfvars @@ -1,15 +1,17 @@ org_policies = { "compute.vmExternalIpAccess" = { - deny = { all = true } + rules = [{ deny = { all = true } }] } "iam.allowedPolicyMemberDomains" = { inherit_from_parent = true - allow = { - values = ["C0xxxxxxx", "C0yyyyyyy"] - } + rules = [{ + allow = { + values = ["C0xxxxxxx", "C0yyyyyyy"] + } + }] + } "compute.restrictLoadBalancerCreationForTypes" = { - deny = { values = ["in:EXTERNAL"] } rules = [ { condition = { @@ -32,6 +34,9 @@ org_policies = { allow = { all = true } + }, + { + deny = { values = ["in:EXTERNAL"] } } ] } diff --git a/tests/modules/organization/test_plan_org_policies_modules.py b/tests/modules/organization/test_plan_org_policies_modules.py index 1d19ee1e..30881d99 100644 --- a/tests/modules/organization/test_plan_org_policies_modules.py +++ b/tests/modules/organization/test_plan_org_policies_modules.py @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -26,61 +26,35 @@ def test_policy_implementation(): path = modules_path / module / 'organization-policies.tf' lines[module] = path.open().readlines() - diff1 = difflib.unified_diff(lines['project'], lines['folder']) + diff1 = difflib.unified_diff(lines['project'], lines['folder'], 'project', + 'folder', n=0) assert list(diff1) == [ - '--- \n', - '+++ \n', - '@@ -14,7 +14,7 @@\n', - ' * limitations under the License.\n', - ' */\n', - ' \n', + '--- project\n', + '+++ folder\n', + '@@ -17 +17 @@\n', '-# tfdoc:file:description Project-level organization policies.\n', '+# tfdoc:file:description Folder-level organization policies.\n', - ' \n', - ' locals {\n', - ' _factory_data_raw = merge([\n', - '@@ -65,8 +65,8 @@\n', - ' org_policies = {\n', - ' for k, v in local._org_policies :\n', - ' k => merge(v, {\n', + '@@ -58,2 +58,2 @@\n', '- name = "projects/${local.project.project_id}/policies/${k}"\n', '- parent = "projects/${local.project.project_id}"\n', '+ name = "${local.folder.name}/policies/${k}"\n', '+ parent = local.folder.name\n', - ' \n', - ' is_boolean_policy = v.allow == null && v.deny == null\n', - ' has_values = (\n', ] - diff2 = difflib.unified_diff(lines['folder'], lines['organization']) + diff2 = difflib.unified_diff(lines['folder'], lines['organization'], 'folder', + 'organization', n=0) assert list(diff2) == [ - '--- \n', - '+++ \n', - '@@ -14,7 +14,7 @@\n', - ' * limitations under the License.\n', - ' */\n', - ' \n', + '--- folder\n', + '+++ organization\n', + '@@ -17 +17 @@\n', '-# tfdoc:file:description Folder-level organization policies.\n', '+# tfdoc:file:description Organization-level organization policies.\n', - ' \n', - ' locals {\n', - ' _factory_data_raw = merge([\n', - '@@ -65,8 +65,8 @@\n', - ' org_policies = {\n', - ' for k, v in local._org_policies :\n', - ' k => merge(v, {\n', + '@@ -58,2 +58,2 @@\n', '- name = "${local.folder.name}/policies/${k}"\n', '- parent = local.folder.name\n', '+ name = "${var.organization_id}/policies/${k}"\n', '+ parent = var.organization_id\n', - ' \n', - ' is_boolean_policy = v.allow == null && v.deny == null\n', - ' has_values = (\n', - '@@ -139,4 +139,13 @@\n', - ' }\n', - ' }\n', - ' }\n', - '+\n', + '@@ -116,0 +117,8 @@\n', '+ depends_on = [\n', '+ google_organization_iam_audit_config.config,\n', '+ google_organization_iam_binding.authoritative,\n', @@ -89,5 +63,4 @@ def test_policy_implementation(): '+ google_organization_iam_policy.authoritative,\n', '+ google_org_policy_custom_constraint.constraint,\n', '+ ]\n', - ' }\n', ] diff --git a/tests/modules/project/examples/org-policies.yaml b/tests/modules/project/examples/org-policies.yaml index 8841dede..d4dddc75 100644 --- a/tests/modules/project/examples/org-policies.yaml +++ b/tests/modules/project/examples/org-policies.yaml @@ -1,4 +1,4 @@ -# Copyright 2022 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -25,8 +25,8 @@ values: deny_all: null enforce: 'TRUE' values: [] - module.project.google_org_policy_policy.default["constraints/compute.skipDefaultNetworkCreation"]: - name: projects/foo-project-example/policies/constraints/compute.skipDefaultNetworkCreation + module.project.google_org_policy_policy.default["compute.skipDefaultNetworkCreation"]: + name: projects/foo-project-example/policies/compute.skipDefaultNetworkCreation parent: projects/foo-project-example spec: - inherit_from_parent: null @@ -37,8 +37,8 @@ values: deny_all: null enforce: 'TRUE' values: [] - module.project.google_org_policy_policy.default["constraints/compute.trustedImageProjects"]: - name: projects/foo-project-example/policies/constraints/compute.trustedImageProjects + module.project.google_org_policy_policy.default["compute.trustedImageProjects"]: + name: projects/foo-project-example/policies/compute.trustedImageProjects parent: projects/foo-project-example spec: - inherit_from_parent: null @@ -52,8 +52,8 @@ values: - allowed_values: - projects/my-project denied_values: null - module.project.google_org_policy_policy.default["constraints/compute.vmExternalIpAccess"]: - name: projects/foo-project-example/policies/constraints/compute.vmExternalIpAccess + module.project.google_org_policy_policy.default["compute.vmExternalIpAccess"]: + name: projects/foo-project-example/policies/compute.vmExternalIpAccess parent: projects/foo-project-example spec: - inherit_from_parent: null @@ -64,8 +64,8 @@ values: deny_all: 'TRUE' enforce: null values: [] - module.project.google_org_policy_policy.default["constraints/iam.allowedPolicyMemberDomains"]: - name: projects/foo-project-example/policies/constraints/iam.allowedPolicyMemberDomains + module.project.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]: + name: projects/foo-project-example/policies/iam.allowedPolicyMemberDomains parent: projects/foo-project-example spec: - inherit_from_parent: null @@ -102,7 +102,7 @@ values: - allow_all: null condition: - description: test condition - expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") + expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234') location: somewhere title: condition deny_all: null diff --git a/tests/modules/project/org_policies_boolean.tfvars b/tests/modules/project/org_policies_boolean.tfvars index eceafe6d..cf5047a2 100644 --- a/tests/modules/project/org_policies_boolean.tfvars +++ b/tests/modules/project/org_policies_boolean.tfvars @@ -1,9 +1,8 @@ org_policies = { "iam.disableServiceAccountKeyCreation" = { - enforce = true + rules = [{ enforce = true }] } "iam.disableServiceAccountKeyUpload" = { - enforce = false rules = [ { condition = { @@ -13,6 +12,9 @@ org_policies = { location = "xxx" } enforce = true + }, + { + enforce = false } ] } diff --git a/tests/modules/project/org_policies_list.tfvars b/tests/modules/project/org_policies_list.tfvars index f9de8dba..4889547d 100644 --- a/tests/modules/project/org_policies_list.tfvars +++ b/tests/modules/project/org_policies_list.tfvars @@ -1,15 +1,16 @@ org_policies = { "compute.vmExternalIpAccess" = { - deny = { all = true } + rules = [{ deny = { all = true } }] } "iam.allowedPolicyMemberDomains" = { inherit_from_parent = true - allow = { - values = ["C0xxxxxxx", "C0yyyyyyy"] - } + rules = [{ + allow = { + values = ["C0xxxxxxx", "C0yyyyyyy"] + } + }] } "compute.restrictLoadBalancerCreationForTypes" = { - deny = { values = ["in:EXTERNAL"] } rules = [ { condition = { @@ -32,6 +33,9 @@ org_policies = { allow = { all = true } + }, + { + deny = { values = ["in:EXTERNAL"] } } ] }