diff --git a/modules/folder/README.md b/modules/folder/README.md index 6ed674f3..e1ad6809 100644 --- a/modules/folder/README.md +++ b/modules/folder/README.md @@ -2,9 +2,7 @@ This module allows the creation and management of folders, including support for IAM bindings, organization policies, and hierarchical firewall rules. -## Examples - -### IAM bindings +## Basic example with IAM bindings ```hcl module "folder" { @@ -14,17 +12,26 @@ module "folder" { group_iam = { "cloud-owners@example.org" = [ "roles/owner", + "roles/resourcemanager.folderAdmin", "roles/resourcemanager.projectCreator" ] } iam = { - "roles/owner" = ["user:one@example.com"] + "roles/owner" = ["user:one@example.org"] + } + iam_additive = { + "roles/compute.admin" = ["user:a1@example.org", "user:a2@example.org"] + "roles/compute.viewer" = ["user:a2@example.org"] + } + iam_additive_members = { + "user:am1@example.org" = ["roles/storage.admin"] + "user:am2@example.org" = ["roles/storage.objectViewer"] } } -# tftest modules=1 resources=3 +# tftest modules=1 resources=9 inventory=iam.yaml ``` -### Organization policies +## Organization policies To manage organization policies, the `orgpolicy.googleapis.com` service should be enabled in the quota project. @@ -72,70 +79,14 @@ module "folder" { } } } -# tftest modules=1 resources=8 +# tftest modules=1 resources=8 inventory=org-policies.yaml ``` ### Organization policy factory See the [organization policy factory in the project module](../project#organization-policy-factory). -### Firewall policy factory - -In the same way as for the [organization](../organization) module, the in-built factory allows you to define a single policy, using one file for rules, and an optional file for CIDR range substitution variables. Remember that non-absolute paths are relative to the root module (the folder where you run `terraform`). - -```hcl -module "folder" { - source = "./fabric/modules/folder" - parent = "organizations/1234567890" - name = "Folder name" - firewall_policy_factory = { - cidr_file = "configs/firewall-policies/cidrs.yaml" - policy_name = null - rules_file = "configs/firewall-policies/rules.yaml" - } - firewall_policy_association = { - factory-policy = module.folder.firewall_policy_id["factory"] - } -} -# tftest modules=1 resources=5 files=cidrs,rules -``` - -```yaml -# tftest-file id=cidrs path=configs/firewall-policies/cidrs.yaml -rfc1918: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 -``` - -```yaml -# tftest-file id=rules path=configs/firewall-policies/rules.yaml -allow-admins: - description: Access from the admin subnet to all subnets - direction: INGRESS - action: allow - priority: 1000 - ranges: - - $rfc1918 - ports: - all: [] - target_resources: null - enable_logging: false - -allow-ssh-from-iap: - description: Enable SSH from IAP - direction: INGRESS - action: allow - priority: 1002 - ranges: - - 35.235.240.0/20 - ports: - tcp: ["22"] - target_resources: null - enable_logging: false -``` - -### Logging Sinks +## Logging Sinks ```hcl module "gcs" { @@ -164,7 +115,6 @@ module "bucket" { id = "bucket" } - module "folder-sink" { source = "./fabric/modules/folder" parent = "folders/657104291943" @@ -198,10 +148,19 @@ module "folder-sink" { no-gce-instances = "resource.type=gce_instance" } } -# tftest modules=5 resources=14 +# tftest modules=5 resources=14 inventory=logging.yaml ``` -### Hierarchical firewall policies +## Hierarchical firewall policies + +Hierarchical firewall policies can be managed in two ways: + +- via the `firewall_policies` variable, to directly define policies and rules in Terraform +- via the `firewall_policy_factory` variable, to leverage external YaML files via a simple "factory" embedded in the module ([see here](../../blueprints/factories) for more context on factories) + +Once you have policies (either created via the module or externally), you can associate them using the `firewall_policy_association` variable. + +### Directly defined firewall policies ```hcl module "folder1" { @@ -211,6 +170,17 @@ module "folder1" { firewall_policies = { iap-policy = { + allow-admins = { + description = "Access from the admin subnet to all subnets" + direction = "INGRESS" + action = "allow" + priority = 1000 + ranges = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"] + ports = { all = [] } + target_service_accounts = null + target_resources = null + logging = false + } allow-iap-ssh = { description = "Always allow ssh from IAP" direction = "INGRESS" @@ -237,7 +207,71 @@ module "folder2" { iap-policy = module.folder1.firewall_policy_id["iap-policy"] } } -# tftest modules=2 resources=6 +# tftest modules=2 resources=7 inventory=hfw.yaml +``` +### Firewall policy factory + +The in-built factory allows you to define a single policy, using one file for rules, and an optional file for CIDR range substitution variables. Remember that non-absolute paths are relative to the root module (the folder where you run `terraform`). + +```hcl +module "folder1" { + source = "./fabric/modules/folder" + parent = var.organization_id + name = "policy-container" + firewall_policy_factory = { + cidr_file = "configs/firewall-policies/cidrs.yaml" + policy_name = "iap-policy" + rules_file = "configs/firewall-policies/rules.yaml" + } + firewall_policy_association = { + iap-policy = "iap-policy" + } +} + +module "folder2" { + source = "./fabric/modules/folder" + parent = var.organization_id + name = "hf2" + firewall_policy_association = { + iap-policy = module.folder1.firewall_policy_id["iap-policy"] + } +} +# tftest modules=2 resources=7 files=cidrs,rules inventory=hfw.yaml +``` + +```yaml +# tftest-file id=cidrs path=configs/firewall-policies/cidrs.yaml +rfc1918: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 +``` + +```yaml +# tftest-file id=rules path=configs/firewall-policies/rules.yaml +allow-admins: + description: Access from the admin subnet to all subnets + direction: INGRESS + action: allow + priority: 1000 + ranges: + - $rfc1918 + ports: + all: [] + target_resources: null + logging: false + +allow-iap-ssh: + description: "Always allow ssh from IAP" + direction: INGRESS + action: allow + priority: 100 + ranges: + - 35.235.240.0/20 + ports: + tcp: ["22"] + target_resources: null + logging: false ``` ## Tags @@ -269,7 +303,7 @@ module "folder" { foo = "tagValues/12345678" } } -# tftest modules=2 resources=6 +# tftest modules=2 resources=6 inventory=tags.yaml ``` diff --git a/modules/folder/organization-policies.tf b/modules/folder/organization-policies.tf index 999d1c58..47532f21 100644 --- a/modules/folder/organization-policies.tf +++ b/modules/folder/organization-policies.tf @@ -95,23 +95,6 @@ resource "google_org_policy_policy" "default" { inherit_from_parent = each.value.inherit_from_parent reset = each.value.reset - 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) - } - } - } - dynamic "rules" { for_each = each.value.rules iterator = rule @@ -138,5 +121,22 @@ 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/organization/organization-policies.tf b/modules/organization/organization-policies.tf index 62d46455..1a99ef9a 100644 --- a/modules/organization/organization-policies.tf +++ b/modules/organization/organization-policies.tf @@ -95,23 +95,6 @@ resource "google_org_policy_policy" "default" { inherit_from_parent = each.value.inherit_from_parent reset = each.value.reset - 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) - } - } - } - dynamic "rules" { for_each = each.value.rules iterator = rule @@ -138,6 +121,23 @@ 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 = [ diff --git a/modules/project/organization-policies.tf b/modules/project/organization-policies.tf index 7763aff4..4ff5bb99 100644 --- a/modules/project/organization-policies.tf +++ b/modules/project/organization-policies.tf @@ -95,23 +95,6 @@ resource "google_org_policy_policy" "default" { inherit_from_parent = each.value.inherit_from_parent reset = each.value.reset - 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) - } - } - } - dynamic "rules" { for_each = each.value.rules iterator = rule @@ -138,5 +121,22 @@ 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/tests/examples/test_plan.py b/tests/examples/test_plan.py index cbcc0b16..5f902cbe 100644 --- a/tests/examples/test_plan.py +++ b/tests/examples/test_plan.py @@ -49,6 +49,11 @@ def test_example(plan_validator, tmp_path, example): summary = plan_validator(module_path=tmp_path, inventory_paths=inventory, tf_var_files=[]) + import yaml + print(yaml.dump({"values": summary.values})) + print(yaml.dump({"counts": summary.counts})) + print(yaml.dump({"outputs": summary.outputs})) + counts = summary.counts num_modules, num_resources = counts['modules'], counts['resources'] assert expected_modules == num_modules, 'wrong number of modules' diff --git a/tests/modules/folder/common.tfvars b/tests/modules/folder/common.tfvars new file mode 100644 index 00000000..aebc74a0 --- /dev/null +++ b/tests/modules/folder/common.tfvars @@ -0,0 +1,2 @@ +parent = "organizations/12345678" +name = "folder-a" diff --git a/tests/modules/folder/examples/hfw.yaml b/tests/modules/folder/examples/hfw.yaml new file mode 100644 index 00000000..57abe480 --- /dev/null +++ b/tests/modules/folder/examples/hfw.yaml @@ -0,0 +1,67 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.folder1.google_compute_firewall_policy.policy["iap-policy"]: + description: null + short_name: iap-policy + module.folder1.google_compute_firewall_policy_association.association["iap-policy"]: {} + module.folder1.google_compute_firewall_policy_rule.rule["iap-policy-allow-admins"]: + action: allow + description: Access from the admin subnet to all subnets + direction: INGRESS + disabled: null + enable_logging: false + match: + - dest_ip_ranges: null + layer4_configs: + - ip_protocol: all + ports: [] + src_ip_ranges: + - 10.0.0.0/8 + - 172.16.0.0/12 + - 192.168.0.0/16 + priority: 1000 + target_resources: null + target_service_accounts: null + module.folder1.google_compute_firewall_policy_rule.rule["iap-policy-allow-iap-ssh"]: + action: allow + description: Always allow ssh from IAP + direction: INGRESS + disabled: null + enable_logging: false + match: + - dest_ip_ranges: null + layer4_configs: + - ip_protocol: tcp + ports: + - '22' + src_ip_ranges: + - 35.235.240.0/20 + priority: 100 + target_resources: null + target_service_accounts: null + module.folder1.google_folder.folder[0]: + display_name: policy-container + parent: organizations/1122334455 + module.folder2.google_compute_firewall_policy_association.association["iap-policy"]: {} + module.folder2.google_folder.folder[0]: + display_name: hf2 + parent: organizations/1122334455 + +counts: + google_compute_firewall_policy: 1 + google_compute_firewall_policy_association: 2 + google_compute_firewall_policy_rule: 2 + google_folder: 2 diff --git a/tests/modules/folder/examples/iam.yaml b/tests/modules/folder/examples/iam.yaml new file mode 100644 index 00000000..6f0fe2e5 --- /dev/null +++ b/tests/modules/folder/examples/iam.yaml @@ -0,0 +1,59 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.folder.google_folder.folder[0]: + display_name: Folder name + parent: organizations/1234567890 + module.folder.google_folder_iam_binding.authoritative["roles/owner"]: + condition: [] + members: + - group:cloud-owners@example.org + - user:one@example.org + role: roles/owner + module.folder.google_folder_iam_binding.authoritative["roles/resourcemanager.folderAdmin"]: + condition: [] + members: + - group:cloud-owners@example.org + role: roles/resourcemanager.folderAdmin + module.folder.google_folder_iam_binding.authoritative["roles/resourcemanager.projectCreator"]: + condition: [] + members: + - group:cloud-owners@example.org + role: roles/resourcemanager.projectCreator + module.folder.google_folder_iam_member.additive["roles/compute.admin-user:a1@example.org"]: + condition: [] + member: user:a1@example.org + role: roles/compute.admin + module.folder.google_folder_iam_member.additive["roles/compute.admin-user:a2@example.org"]: + condition: [] + member: user:a2@example.org + role: roles/compute.admin + module.folder.google_folder_iam_member.additive["roles/compute.viewer-user:a2@example.org"]: + condition: [] + member: user:a2@example.org + role: roles/compute.viewer + module.folder.google_folder_iam_member.additive["roles/storage.admin-user:am1@example.org"]: + condition: [] + member: user:am1@example.org + role: roles/storage.admin + module.folder.google_folder_iam_member.additive["roles/storage.objectViewer-user:am2@example.org"]: + condition: [] + member: user:am2@example.org + role: roles/storage.objectViewer + +counts: + google_folder: 1 + google_folder_iam_binding: 3 + google_folder_iam_member: 5 diff --git a/tests/modules/folder/examples/logging.yaml b/tests/modules/folder/examples/logging.yaml new file mode 100644 index 00000000..79b0e007 --- /dev/null +++ b/tests/modules/folder/examples/logging.yaml @@ -0,0 +1,75 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.folder-sink.google_bigquery_dataset_iam_member.bq-sinks-binding["info"]: + role: roles/bigquery.dataEditor + module.folder-sink.google_folder.folder[0]: + display_name: my-folder + parent: folders/657104291943 + module.folder-sink.google_logging_folder_exclusion.logging-exclusion["no-gce-instances"]: + description: no-gce-instances (Terraform-managed). + filter: resource.type=gce_instance + name: no-gce-instances + module.folder-sink.google_logging_folder_sink.sink["debug"]: + disabled: false + exclusions: + - description: null + disabled: false + filter: logName:compute + name: no-compute + filter: severity=DEBUG + include_children: true + name: debug + module.folder-sink.google_logging_folder_sink.sink["info"]: + disabled: false + exclusions: [] + filter: severity=INFO + include_children: true + name: info + module.folder-sink.google_logging_folder_sink.sink["notice"]: + disabled: false + exclusions: [] + filter: severity=NOTICE + include_children: true + name: notice + module.folder-sink.google_logging_folder_sink.sink["warnings"]: + description: warnings (Terraform-managed). + destination: storage.googleapis.com/gcs_sink + disabled: false + exclusions: [] + filter: severity=WARNING + include_children: true + name: warnings + module.folder-sink.google_project_iam_member.bucket-sinks-binding["debug"]: + condition: + - title: debug bucket writer + role: roles/logging.bucketWriter + module.folder-sink.google_pubsub_topic_iam_member.pubsub-sinks-binding["notice"]: + condition: [] + role: roles/pubsub.publisher + module.folder-sink.google_storage_bucket_iam_member.gcs-sinks-binding["warnings"]: + bucket: gcs_sink + condition: [] + role: roles/storage.objectCreator + +counts: + google_bigquery_dataset_iam_member: 1 + google_folder: 1 + google_logging_folder_exclusion: 1 + google_logging_folder_sink: 4 + google_logging_project_bucket_config: 1 + google_project_iam_member: 1 + google_pubsub_topic_iam_member: 1 + google_storage_bucket_iam_member: 1 diff --git a/tests/modules/folder/examples/org-policies.yaml b/tests/modules/folder/examples/org-policies.yaml new file mode 100644 index 00000000..f8bf4187 --- /dev/null +++ b/tests/modules/folder/examples/org-policies.yaml @@ -0,0 +1,108 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +values: + module.folder.google_folder.folder[0]: + display_name: Folder name + parent: organizations/1234567890 + module.folder.google_org_policy_policy.default["compute.disableGuestAttributesAccess"]: + spec: + - inherit_from_parent: null + reset: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: 'TRUE' + values: [] + module.folder.google_org_policy_policy.default["constraints/compute.skipDefaultNetworkCreation"]: + spec: + - inherit_from_parent: null + reset: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: 'TRUE' + values: [] + module.folder.google_org_policy_policy.default["constraints/compute.trustedImageProjects"]: + spec: + - inherit_from_parent: null + reset: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: null + values: + - allowed_values: + - projects/my-project + denied_values: null + module.folder.google_org_policy_policy.default["constraints/compute.vmExternalIpAccess"]: + spec: + - inherit_from_parent: null + reset: null + rules: + - allow_all: null + condition: [] + deny_all: 'TRUE' + enforce: null + values: [] + module.folder.google_org_policy_policy.default["constraints/iam.allowedPolicyMemberDomains"]: + spec: + - inherit_from_parent: null + reset: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: null + values: + - allowed_values: + - C0xxxxxxx + - C0yyyyyyy + denied_values: null + module.folder.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]: + spec: + - inherit_from_parent: null + reset: null + rules: + - allow_all: null + condition: [] + deny_all: null + enforce: 'TRUE' + values: [] + module.folder.google_org_policy_policy.default["iam.disableServiceAccountKeyUpload"]: + spec: + - inherit_from_parent: null + reset: null + rules: + - allow_all: null + condition: + - description: test condition + expression: resource.matchTagId("tagKeys/1234", "tagValues/1234") + location: somewhere + title: condition + deny_all: null + enforce: 'TRUE' + values: [] + - allow_all: null + condition: [] + deny_all: null + enforce: 'FALSE' + values: [] + +counts: + google_folder: 1 + google_org_policy_policy: 7 diff --git a/tests/modules/folder/examples/tags.yaml b/tests/modules/folder/examples/tags.yaml new file mode 100644 index 00000000..047fea06 --- /dev/null +++ b/tests/modules/folder/examples/tags.yaml @@ -0,0 +1,41 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +tests/examples/test_plan.py::test_example[modules/folder:Tags] values: + module.folder.google_folder.folder[0]: + display_name: Test + parent: organizations/1122334455 + module.folder.google_tags_tag_binding.binding["env-prod"]: {} + module.folder.google_tags_tag_binding.binding["foo"]: + tag_value: tagValues/12345678 + module.org.google_tags_tag_key.default["environment"]: + description: Environment specification. + parent: organizations/1122334455 + purpose: null + purpose_data: null + short_name: environment + timeouts: null + module.org.google_tags_tag_value.default["environment/dev"]: + description: Managed by the Terraform organization module. + short_name: dev + module.org.google_tags_tag_value.default["environment/prod"]: + description: Managed by the Terraform organization module. + short_name: prod + +counts: + google_folder: 1 + google_tags_tag_binding: 2 + google_tags_tag_key: 1 + google_tags_tag_value: 2 diff --git a/tests/modules/folder/fixture/main.tf b/tests/modules/folder/fixture/main.tf deleted file mode 100644 index a347f61b..00000000 --- a/tests/modules/folder/fixture/main.tf +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -module "test" { - source = "../../../../modules/folder" - parent = "organizations/12345678" - name = "folder-a" - group_iam = var.group_iam - iam = var.iam - iam_additive = var.iam_additive - iam_additive_members = var.iam_additive_members - firewall_policies = var.firewall_policies - firewall_policy_association = var.firewall_policy_association - logging_sinks = var.logging_sinks - logging_exclusions = var.logging_exclusions - org_policies = var.org_policies - org_policies_data_path = var.org_policies_data_path -} diff --git a/tests/modules/folder/fixture/test.logging-sinks.tfvars b/tests/modules/folder/fixture/test.logging-sinks.tfvars deleted file mode 100644 index 95a272e1..00000000 --- a/tests/modules/folder/fixture/test.logging-sinks.tfvars +++ /dev/null @@ -1,29 +0,0 @@ -logging_sinks = { - warning = { - destination = "mybucket" - type = "storage" - filter = "severity=WARNING" - } - info = { - destination = "projects/myproject/datasets/mydataset" - type = "bigquery" - filter = "severity=INFO" - disabled = true - } - notice = { - destination = "projects/myproject/topics/mytopic" - type = "pubsub" - filter = "severity=NOTICE" - include_children = false - } - debug = { - destination = "projects/myproject/locations/global/buckets/mybucket" - type = "logging" - filter = "severity=DEBUG" - include_children = false - exclusions = { - no-compute = "logName:compute" - no-container = "logName:container" - } - } -} diff --git a/tests/modules/folder/fixture/variables.tf b/tests/modules/folder/fixture/variables.tf deleted file mode 100644 index e2d7a293..00000000 --- a/tests/modules/folder/fixture/variables.tf +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Copyright 2022 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -variable "group_iam" { - type = any - default = {} -} - -variable "iam" { - type = any - default = {} -} - -variable "iam_additive" { - type = any - default = {} -} - -variable "iam_additive_members" { - type = any - default = {} -} - -variable "firewall_policies" { - type = any - default = {} -} - -variable "firewall_policy_association" { - type = any - default = {} -} - -variable "logging_sinks" { - type = any - default = {} -} - -variable "logging_exclusions" { - type = any - default = {} -} - -variable "org_policies" { - type = any - default = {} -} - -variable "org_policies_data_path" { - type = any - default = null -} diff --git a/tests/modules/folder/fixture/test.orgpolicies-boolean.tfvars b/tests/modules/folder/org_policies_boolean.tfvars similarity index 100% rename from tests/modules/folder/fixture/test.orgpolicies-boolean.tfvars rename to tests/modules/folder/org_policies_boolean.tfvars diff --git a/tests/modules/folder/fixture/test.orgpolicies-list.tfvars b/tests/modules/folder/org_policies_list.tfvars similarity index 100% rename from tests/modules/folder/fixture/test.orgpolicies-list.tfvars rename to tests/modules/folder/org_policies_list.tfvars diff --git a/tests/modules/folder/test_plan.py b/tests/modules/folder/test_plan.py deleted file mode 100644 index 0ce1ae4a..00000000 --- a/tests/modules/folder/test_plan.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -def test_folder(plan_runner): - "Test folder resources." - _, resources = plan_runner() - assert len(resources) == 1 - resource = resources[0] - assert resource['type'] == 'google_folder' - assert resource['values']['display_name'] == 'folder-a' - assert resource['values']['parent'] == 'organizations/12345678' - - -def test_iam(plan_runner): - "Test IAM." - group_iam = ( - '{' - '"owners@example.org" = ["roles/owner", "roles/resourcemanager.folderAdmin"],' - '"viewers@example.org" = ["roles/viewer"]' - '}') - iam = ('{' - '"roles/owner" = ["user:one@example.org", "user:two@example.org"],' - '"roles/browser" = ["domain:example.org"]' - '}') - _, resources = plan_runner(group_iam=group_iam, iam=iam) - roles = sorted([(r['values']['role'], sorted(r['values']['members'])) - for r in resources - if r['type'] == 'google_folder_iam_binding']) - assert roles == [ - ('roles/browser', ['domain:example.org']), - ('roles/owner', [ - 'group:owners@example.org', 'user:one@example.org', - 'user:two@example.org' - ]), - ('roles/resourcemanager.folderAdmin', ['group:owners@example.org']), - ('roles/viewer', ['group:viewers@example.org']), - ] - - -def test_iam_multiple_roles(plan_runner): - "Test folder resources with multiple iam roles." - iam = ('{ ' - '"roles/owner" = ["user:a@b.com"], ' - '"roles/viewer" = ["user:c@d.com"] ' - '} ') - _, resources = plan_runner(iam=iam) - assert len(resources) == 3 - - -def test_iam_additive_members(plan_runner): - "Test IAM additive members." - iam = ('{"user:one@example.org" = ["roles/owner"],' - '"user:two@example.org" = ["roles/owner", "roles/editor"]}') - _, resources = plan_runner(iam_additive_members=iam) - roles = set((r['values']['role'], r['values']['member']) - for r in resources - if r['type'] == 'google_folder_iam_member') - assert roles == set([('roles/owner', 'user:one@example.org'), - ('roles/owner', 'user:two@example.org'), - ('roles/editor', 'user:two@example.org')]) diff --git a/tests/modules/folder/test_plan_firewall_policy.py b/tests/modules/folder/test_plan_firewall_policy.py deleted file mode 100644 index 4364fbdf..00000000 --- a/tests/modules/folder/test_plan_firewall_policy.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -def test_firweall_policy(plan_runner): - "Test boolean folder policy." - policy = """ - { - policy1 = { - allow-ingress = { - description = "" - direction = "INGRESS" - action = "allow" - priority = 100 - ranges = ["10.0.0.0/8"] - ports = { - tcp = ["22"] - } - target_service_accounts = null - target_resources = null - logging = false - } - deny-egress = { - description = "" - direction = "EGRESS" - action = "deny" - priority = 200 - ranges = ["192.168.0.0/24"] - ports = { - tcp = ["443"] - } - target_service_accounts = null - target_resources = null - logging = false - } - } - } - """ - association = '{policy1="policy1"}' - _, resources = plan_runner(firewall_policies=policy, - firewall_policy_association=association) - assert len(resources) == 5 - - policies = [r for r in resources - if r['type'] == 'google_compute_firewall_policy'] - assert len(policies) == 1 - - rules = [r for r in resources - if r['type'] == 'google_compute_firewall_policy_rule'] - assert len(rules) == 2 - - rule_values = [] - for rule in rules: - name = rule['name'] - index = rule['index'] - action = rule['values']['action'] - direction = rule['values']['direction'] - priority = rule['values']['priority'] - match = rule['values']['match'] - rule_values.append((name, index, action, direction, priority, match)) - - assert sorted(rule_values) == sorted([ - ('rule', 'policy1-allow-ingress', 'allow', 'INGRESS', 100, [ - { - 'dest_ip_ranges': None, - 'layer4_configs': [{'ip_protocol': 'tcp', 'ports': ['22']}], - 'src_ip_ranges': ['10.0.0.0/8'] - }]), - ('rule', 'policy1-deny-egress', 'deny', 'EGRESS', 200, [ - { - 'dest_ip_ranges': ['192.168.0.0/24'], - 'layer4_configs': [{'ip_protocol': 'tcp', 'ports': ['443']}], - 'src_ip_ranges': None - }]) - ]) diff --git a/tests/modules/folder/test_plan_logging.py b/tests/modules/folder/test_plan_logging.py deleted file mode 100644 index 6b305d0b..00000000 --- a/tests/modules/folder/test_plan_logging.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from collections import Counter - - -def test_sinks(plan_runner): - "Test folder-level sinks." - tfvars = 'test.logging-sinks.tfvars' - _, resources = plan_runner(tf_var_file=tfvars) - assert len(resources) == 9 - - resource_types = Counter([r["type"] for r in resources]) - assert resource_types == { - "google_logging_folder_sink": 4, - "google_folder": 1, - "google_bigquery_dataset_iam_member": 1, - "google_project_iam_member": 1, - "google_pubsub_topic_iam_member": 1, - "google_storage_bucket_iam_member": 1, - } - - sinks = [r for r in resources if r["type"] == "google_logging_folder_sink"] - assert sorted([r["index"] for r in sinks]) == [ - "debug", - "info", - "notice", - "warning", - ] - values = [( - r["index"], - r["values"]["filter"], - r["values"]["destination"], - r["values"]["description"], - r["values"]["include_children"], - r["values"]["disabled"], - ) for r in sinks] - assert sorted(values) == [ - ("debug", "severity=DEBUG", - "logging.googleapis.com/projects/myproject/locations/global/buckets/mybucket", - "debug (Terraform-managed).", False, False), - ("info", "severity=INFO", - "bigquery.googleapis.com/projects/myproject/datasets/mydataset", - "info (Terraform-managed).", True, True), - ("notice", "severity=NOTICE", - "pubsub.googleapis.com/projects/myproject/topics/mytopic", - "notice (Terraform-managed).", False, False), - ("warning", "severity=WARNING", "storage.googleapis.com/mybucket", - "warning (Terraform-managed).", True, False), - ] - - bindings = [r for r in resources if "member" in r["type"]] - values = [(r["index"], r["type"], r["values"]["role"], - r["values"]["condition"]) for r in bindings] - assert sorted(values) == [ - ("debug", "google_project_iam_member", "roles/logging.bucketWriter", [{ - 'expression': - "resource.name.endsWith('projects/myproject/locations/global/buckets/mybucket')", - 'title': - 'debug bucket writer' - }]), - ("info", "google_bigquery_dataset_iam_member", - "roles/bigquery.dataEditor", []), - ("notice", "google_pubsub_topic_iam_member", "roles/pubsub.publisher", - []), - ("warning", "google_storage_bucket_iam_member", - "roles/storage.objectCreator", []), - ] - - exclusions = [(r["index"], r["values"]["exclusions"]) for r in sinks] - assert sorted(exclusions) == [ - ("debug", [{ - "description": None, - "disabled": False, - "filter": "logName:compute", - "name": "no-compute" - }, { - "description": None, - "disabled": False, - "filter": "logName:container", - "name": "no-container" - }]), - ("info", []), - ("notice", []), - ("warning", []), - ] - - -def test_exclusions(plan_runner): - "Test folder-level logging exclusions." - logging_exclusions = ("{" - 'exclusion1 = "resource.type=gce_instance", ' - 'exclusion2 = "severity=NOTICE", ' - "}") - _, resources = plan_runner(logging_exclusions=logging_exclusions) - assert len(resources) == 3 - exclusions = [ - r for r in resources if r["type"] == "google_logging_folder_exclusion" - ] - assert sorted([r["index"] for r in exclusions]) == [ - "exclusion1", - "exclusion2", - ] - values = [(r["index"], r["values"]["filter"]) for r in exclusions] - assert sorted(values) == [ - ("exclusion1", "resource.type=gce_instance"), - ("exclusion2", "severity=NOTICE"), - ] diff --git a/tests/modules/folder/test_plan_org_policies.py b/tests/modules/folder/test_plan_org_policies.py index 8463761e..16184537 100644 --- a/tests/modules/folder/test_plan_org_policies.py +++ b/tests/modules/folder/test_plan_org_policies.py @@ -12,33 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -from .validate_policies import validate_policy_boolean, validate_policy_list +import pytest + +_params = ['boolean', 'list'] -def test_policy_boolean(plan_runner): - "Test boolean org policy." - tfvars = 'test.orgpolicies-boolean.tfvars' - _, resources = plan_runner(tf_var_file=tfvars) - validate_policy_boolean(resources) - - -def test_policy_list(plan_runner): - "Test list org policy." - tfvars = 'test.orgpolicies-list.tfvars' - _, resources = plan_runner(tf_var_file=tfvars) - validate_policy_list(resources) - - -def test_factory_policy_boolean(plan_runner, tfvars_to_yaml, tmp_path): +@pytest.mark.parametrize('policy_type', _params) +def test_policy_factory(plan_summary, tfvars_to_yaml, tmp_path, policy_type): dest = tmp_path / 'policies.yaml' - tfvars_to_yaml('fixture/test.orgpolicies-boolean.tfvars', dest, - 'org_policies') - _, resources = plan_runner(org_policies_data_path=f'"{tmp_path}"') - validate_policy_boolean(resources) - - -def test_factory_policy_list(plan_runner, tfvars_to_yaml, tmp_path): - dest = tmp_path / 'policies.yaml' - tfvars_to_yaml('fixture/test.orgpolicies-list.tfvars', dest, 'org_policies') - _, resources = plan_runner(org_policies_data_path=f'"{tmp_path}"') - validate_policy_list(resources) + tfvars_to_yaml(f'org_policies_{policy_type}.tfvars', dest, 'org_policies') + tfvars_plan = plan_summary( + 'modules/folder', + tf_var_files=['common.tfvars', f'org_policies_{policy_type}.tfvars']) + yaml_plan = plan_summary('modules/folder', tf_var_files=['common.tfvars'], + org_policies_data_path=f'{tmp_path}') + assert tfvars_plan.values == yaml_plan.values diff --git a/tests/modules/folder/validate_policies.py b/tests/modules/folder/validate_policies.py deleted file mode 100644 index 385898b1..00000000 --- a/tests/modules/folder/validate_policies.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2022 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -def validate_policy_boolean(resources): - assert len(resources) == 3 - policies = [r for r in resources if r['type'] == 'google_org_policy_policy'] - assert len(policies) == 2 - - p1 = [ - r['values']['spec'][0] - for r in policies - if r['index'] == 'iam.disableServiceAccountKeyCreation' - ][0] - - assert p1['inherit_from_parent'] is None - assert p1['reset'] is None - assert p1['rules'] == [{ - 'allow_all': None, - 'condition': [], - 'deny_all': None, - 'enforce': 'TRUE', - 'values': [] - }] - - p2 = [ - r['values']['spec'][0] - for r in policies - if r['index'] == 'iam.disableServiceAccountKeyUpload' - ][0] - - assert p2['inherit_from_parent'] is None - assert p2['reset'] is None - assert len(p2['rules']) == 2 - assert p2['rules'][0] == { - 'allow_all': None, - 'condition': [], - 'deny_all': None, - 'enforce': 'FALSE', - 'values': [] - } - assert p2['rules'][1] == { - 'allow_all': None, - 'condition': [{ - 'description': 'test condition', - 'expression': 'resource.matchTagId(aa, bb)', - 'location': 'xxx', - 'title': 'condition' - }], - 'deny_all': None, - 'enforce': 'TRUE', - 'values': [] - } - - -def validate_policy_list(resources): - assert len(resources) == 4 - - policies = [r for r in resources if r['type'] == 'google_org_policy_policy'] - assert len(policies) == 3 - - p1 = [ - r['values']['spec'][0] - for r in policies - if r['index'] == 'compute.vmExternalIpAccess' - ][0] - assert p1['inherit_from_parent'] is None - assert p1['reset'] is None - assert p1['rules'] == [{ - 'allow_all': None, - 'condition': [], - 'deny_all': 'TRUE', - 'enforce': None, - 'values': [] - }] - - p2 = [ - r['values']['spec'][0] - for r in policies - if r['index'] == 'iam.allowedPolicyMemberDomains' - ][0] - assert p2['inherit_from_parent'] is None - assert p2['reset'] is None - assert p2['rules'] == [{ - 'allow_all': - None, - 'condition': [], - 'deny_all': - None, - 'enforce': - None, - 'values': [{ - 'allowed_values': [ - 'C0xxxxxxx', - 'C0yyyyyyy', - ], - 'denied_values': None - }] - }] - - p3 = [ - r['values']['spec'][0] - for r in policies - if r['index'] == 'compute.restrictLoadBalancerCreationForTypes' - ][0] - assert p3['inherit_from_parent'] is None - assert p3['reset'] is None - assert len(p3['rules']) == 3 - assert p3['rules'][0] == { - 'allow_all': None, - 'condition': [], - 'deny_all': None, - 'enforce': None, - 'values': [{ - 'allowed_values': None, - 'denied_values': ['in:EXTERNAL'] - }] - } - - assert p3['rules'][1] == { - 'allow_all': None, - 'condition': [{ - 'description': 'test condition', - 'expression': 'resource.matchTagId(aa, bb)', - 'location': 'xxx', - 'title': 'condition' - }], - 'deny_all': None, - 'enforce': None, - 'values': [{ - 'allowed_values': ['EXTERNAL_1'], - 'denied_values': None - }] - } - - assert p3['rules'][2] == { - 'allow_all': 'TRUE', - 'condition': [{ - 'description': 'test condition2', - 'expression': 'resource.matchTagId(cc, dd)', - 'location': 'xxx', - 'title': 'condition2' - }], - 'deny_all': None, - 'enforce': None, - 'values': [] - } diff --git a/tests/modules/logging_bucket/test_plan.py b/tests/modules/logging_bucket/test_plan.py index e3cf159f..8ec685ad 100644 --- a/tests/modules/logging_bucket/test_plan.py +++ b/tests/modules/logging_bucket/test_plan.py @@ -12,10 +12,10 @@ # See the License for the specific language governing permissions and # limitations under the License. + def test_project_logging_bucket(plan_runner): "Test project logging bucket." - _, resources = plan_runner(parent_type="project", - parent="myproject") + _, resources = plan_runner(parent_type="project", parent="myproject") assert len(resources) == 1 resource = resources[0] @@ -31,9 +31,7 @@ def test_project_logging_bucket(plan_runner): def test_folder_logging_bucket(plan_runner): "Test project logging bucket." - _, resources = plan_runner( - parent_type="folder", parent="folders/0123456789" - ) + _, resources = plan_runner(parent_type="folder", parent="folders/0123456789") assert len(resources) == 1 resource = resources[0] @@ -49,9 +47,8 @@ def test_folder_logging_bucket(plan_runner): def test_organization_logging_bucket(plan_runner): "Test project logging bucket." - _, resources = plan_runner( - parent_type="organization", parent="organizations/0123456789" - ) + _, resources = plan_runner(parent_type="organization", + parent="organizations/0123456789") assert len(resources) == 1 resource = resources[0] @@ -67,9 +64,7 @@ def test_organization_logging_bucket(plan_runner): def test_billing_account_logging_bucket(plan_runner): "Test project logging bucket." - _, resources = plan_runner( - parent_type="billing_account", parent="0123456789" - ) + _, resources = plan_runner(parent_type="billing_account", parent="0123456789") assert len(resources) == 1 resource = resources[0] diff --git a/tests/modules/organization/examples/basic.yaml b/tests/modules/organization/examples/basic.yaml index bcd12386..2ba70f40 100644 --- a/tests/modules/organization/examples/basic.yaml +++ b/tests/modules/organization/examples/basic.yaml @@ -99,11 +99,6 @@ values: - inherit_from_parent: null reset: null rules: - - allow_all: null - condition: [] - deny_all: null - enforce: 'FALSE' - values: [] - allow_all: null condition: - description: test condition @@ -113,6 +108,11 @@ values: deny_all: null enforce: 'TRUE' values: [] + - allow_all: null + condition: [] + deny_all: null + enforce: 'FALSE' + values: [] module.org.google_organization_iam_binding.authoritative["roles/owner"]: condition: [] members: diff --git a/tests/modules/organization/org_policies_boolean.yaml b/tests/modules/organization/org_policies_boolean.yaml index 310997a4..00f98b06 100644 --- a/tests/modules/organization/org_policies_boolean.yaml +++ b/tests/modules/organization/org_policies_boolean.yaml @@ -33,11 +33,6 @@ values: - inherit_from_parent: null reset: null rules: - - allow_all: null - condition: [] - deny_all: null - enforce: 'FALSE' - values: [] - allow_all: null condition: - description: test condition @@ -47,6 +42,11 @@ values: deny_all: null enforce: 'TRUE' values: [] + - allow_all: null + condition: [] + deny_all: null + enforce: 'FALSE' + values: [] timeouts: null counts: diff --git a/tests/modules/organization/org_policies_list.yaml b/tests/modules/organization/org_policies_list.yaml index 39c3a389..393eadde 100644 --- a/tests/modules/organization/org_policies_list.yaml +++ b/tests/modules/organization/org_policies_list.yaml @@ -20,14 +20,6 @@ values: - inherit_from_parent: null reset: null rules: - - allow_all: null - condition: [] - deny_all: null - enforce: null - values: - - allowed_values: null - denied_values: - - in:EXTERNAL - allow_all: null condition: - description: test condition @@ -49,6 +41,14 @@ values: deny_all: null enforce: null values: [] + - allow_all: null + condition: [] + deny_all: null + enforce: null + values: + - allowed_values: null + denied_values: + - in:EXTERNAL timeouts: null google_org_policy_policy.default["compute.vmExternalIpAccess"]: name: organizations/1234567890/policies/compute.vmExternalIpAccess diff --git a/tests/modules/project/examples/org-policies.yaml b/tests/modules/project/examples/org-policies.yaml index 38e0ba9b..8841dede 100644 --- a/tests/modules/project/examples/org-policies.yaml +++ b/tests/modules/project/examples/org-policies.yaml @@ -99,11 +99,6 @@ values: - inherit_from_parent: null reset: null rules: - - allow_all: null - condition: [] - deny_all: null - enforce: 'FALSE' - values: [] - allow_all: null condition: - description: test condition @@ -113,6 +108,11 @@ values: deny_all: null enforce: 'TRUE' values: [] + - allow_all: null + condition: [] + deny_all: null + enforce: 'FALSE' + values: [] module.project.google_project.project[0]: billing_account: 123456-123456-123456 folder_id: '1234567890' diff --git a/tests/modules/project/org_policies_boolean.yaml b/tests/modules/project/org_policies_boolean.yaml index 44cba34d..4f23958f 100644 --- a/tests/modules/project/org_policies_boolean.yaml +++ b/tests/modules/project/org_policies_boolean.yaml @@ -33,11 +33,6 @@ values: - inherit_from_parent: null reset: null rules: - - allow_all: null - condition: [] - deny_all: null - enforce: 'FALSE' - values: [] - allow_all: null condition: - description: test condition @@ -47,6 +42,11 @@ values: deny_all: null enforce: 'TRUE' values: [] + - allow_all: null + condition: [] + deny_all: null + enforce: 'FALSE' + values: [] timeouts: null counts: diff --git a/tests/modules/project/org_policies_list.yaml b/tests/modules/project/org_policies_list.yaml index ab556a10..2f1c64e0 100644 --- a/tests/modules/project/org_policies_list.yaml +++ b/tests/modules/project/org_policies_list.yaml @@ -20,14 +20,6 @@ values: - inherit_from_parent: null reset: null rules: - - allow_all: null - condition: [] - deny_all: null - enforce: null - values: - - allowed_values: null - denied_values: - - in:EXTERNAL - allow_all: null condition: - description: test condition @@ -49,6 +41,14 @@ values: deny_all: null enforce: null values: [] + - allow_all: null + condition: [] + deny_all: null + enforce: null + values: + - allowed_values: null + denied_values: + - in:EXTERNAL timeouts: null google_org_policy_policy.default["compute.vmExternalIpAccess"]: name: projects/my-project/policies/compute.vmExternalIpAccess