From 065b1471a87e2aa3ad989e0c5f5bb72488b9f996 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 3 Jan 2023 16:37:32 +0100 Subject: [PATCH 1/5] Reorder org policy rules --- modules/folder/organization-policies.tf | 34 +++++++++---------- modules/organization/organization-policies.tf | 34 +++++++++---------- modules/project/organization-policies.tf | 34 +++++++++---------- .../organization/org_policies_boolean.yaml | 10 +++--- .../organization/org_policies_list.yaml | 16 ++++----- .../project/examples/org-policies.yaml | 10 +++--- .../modules/project/org_policies_boolean.yaml | 10 +++--- tests/modules/project/org_policies_list.yaml | 16 ++++----- 8 files changed, 82 insertions(+), 82 deletions(-) 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/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 From c8bfe892a692c3c7e50e7c7cb73c9a5cf7b6ffd6 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 3 Jan 2023 16:37:50 +0100 Subject: [PATCH 2/5] Update folder tests --- modules/folder/README.md | 172 +++++++++++------- tests/examples/test_plan.py | 5 + tests/modules/folder/common.tfvars | 2 + tests/modules/folder/examples/hfw.yaml | 67 +++++++ tests/modules/folder/examples/iam.yaml | 59 ++++++ tests/modules/folder/examples/logging.yaml | 75 ++++++++ .../modules/folder/examples/org-policies.yaml | 108 +++++++++++ tests/modules/folder/examples/tags.yaml | 41 +++++ tests/modules/folder/fixture/main.tf | 31 ---- .../folder/fixture/test.logging-sinks.tfvars | 29 --- tests/modules/folder/fixture/variables.tf | 65 ------- ...ean.tfvars => org_policies_boolean.tfvars} | 0 ...s-list.tfvars => org_policies_list.tfvars} | 0 tests/modules/folder/test_plan.py | 72 -------- .../folder/test_plan_firewall_policy.py | 85 --------- tests/modules/folder/test_plan_logging.py | 119 ------------ .../modules/folder/test_plan_org_policies.py | 39 ++-- tests/modules/folder/validate_policies.py | 158 ---------------- 18 files changed, 472 insertions(+), 655 deletions(-) create mode 100644 tests/modules/folder/common.tfvars create mode 100644 tests/modules/folder/examples/hfw.yaml create mode 100644 tests/modules/folder/examples/iam.yaml create mode 100644 tests/modules/folder/examples/logging.yaml create mode 100644 tests/modules/folder/examples/org-policies.yaml create mode 100644 tests/modules/folder/examples/tags.yaml delete mode 100644 tests/modules/folder/fixture/main.tf delete mode 100644 tests/modules/folder/fixture/test.logging-sinks.tfvars delete mode 100644 tests/modules/folder/fixture/variables.tf rename tests/modules/folder/{fixture/test.orgpolicies-boolean.tfvars => org_policies_boolean.tfvars} (100%) rename tests/modules/folder/{fixture/test.orgpolicies-list.tfvars => org_policies_list.tfvars} (100%) delete mode 100644 tests/modules/folder/test_plan.py delete mode 100644 tests/modules/folder/test_plan_firewall_policy.py delete mode 100644 tests/modules/folder/test_plan_logging.py delete mode 100644 tests/modules/folder/validate_policies.py 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/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': [] - } From 1114c6a8a4f1f0b77ad2f7cbcbb5469feab0dec7 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 3 Jan 2023 16:45:39 +0100 Subject: [PATCH 3/5] Fix org module tests --- tests/modules/organization/examples/basic.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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: From 2e35bff903ed3f2dabf674ea74a199c01c113b04 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Tue, 3 Jan 2023 16:51:15 +0100 Subject: [PATCH 4/5] Fix tests for latest provider version --- tests/modules/logging_bucket/test_plan.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) 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] From 25e0cba10a56eaea14f8b73e3087085258523776 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taneli=20Lepp=C3=A4?= Date: Tue, 3 Jan 2023 16:38:46 +0100 Subject: [PATCH 5/5] Added device_name field to compute-vm attached_disks parameter (for stateful disks). --- modules/compute-vm/README.md | 54 ++++++++++++++++----------------- modules/compute-vm/main.tf | 8 ++--- modules/compute-vm/variables.tf | 1 + 3 files changed, 32 insertions(+), 31 deletions(-) diff --git a/modules/compute-vm/README.md b/modules/compute-vm/README.md index ee25ac10..2f715555 100644 --- a/modules/compute-vm/README.md +++ b/modules/compute-vm/README.md @@ -278,34 +278,34 @@ module "instance-group" { | name | description | type | required | default | |---|---|:---:|:---:|:---:| -| [name](variables.tf#L180) | Instance name. | string | ✓ | | -| [network_interfaces](variables.tf#L185) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({…})) | ✓ | | -| [project_id](variables.tf#L222) | Project id. | string | ✓ | | -| [zone](variables.tf#L281) | Compute zone. | string | ✓ | | +| [name](variables.tf#L181) | Instance name. | string | ✓ | | +| [network_interfaces](variables.tf#L186) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({…})) | ✓ | | +| [project_id](variables.tf#L223) | Project id. | string | ✓ | | +| [zone](variables.tf#L282) | Compute zone. | string | ✓ | | | [attached_disk_defaults](variables.tf#L17) | Defaults for attached disks options. | object({…}) | | {…} | -| [attached_disks](variables.tf#L38) | Additional disks, if options is null defaults will be used in its place. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null. | list(object({…})) | | [] | -| [boot_disk](variables.tf#L81) | Boot disk properties. | object({…}) | | {…} | -| [can_ip_forward](variables.tf#L97) | Enable IP forwarding. | bool | | false | -| [confidential_compute](variables.tf#L103) | Enable Confidential Compute for these instances. | bool | | false | -| [create_template](variables.tf#L109) | Create instance template instead of instances. | bool | | false | -| [description](variables.tf#L114) | Description of a Compute Instance. | string | | "Managed by the compute-vm Terraform module." | -| [enable_display](variables.tf#L120) | Enable virtual display on the instances. | bool | | false | -| [encryption](variables.tf#L126) | Encryption options. Only one of kms_key_self_link and disk_encryption_key_raw may be set. If needed, you can specify to encrypt or not the boot disk. | object({…}) | | null | -| [group](variables.tf#L136) | Define this variable to create an instance group for instances. Disabled for template use. | object({…}) | | null | -| [hostname](variables.tf#L144) | Instance FQDN name. | string | | null | -| [iam](variables.tf#L150) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | -| [instance_type](variables.tf#L156) | Instance type. | string | | "f1-micro" | -| [labels](variables.tf#L162) | Instance labels. | map(string) | | {} | -| [metadata](variables.tf#L168) | Instance metadata. | map(string) | | {} | -| [min_cpu_platform](variables.tf#L174) | Minimum CPU platform. | string | | null | -| [options](variables.tf#L200) | Instance options. | object({…}) | | {…} | -| [scratch_disks](variables.tf#L227) | Scratch disks configuration. | object({…}) | | {…} | -| [service_account](variables.tf#L239) | Service account email. Unused if service account is auto-created. | string | | null | -| [service_account_create](variables.tf#L245) | Auto-create service account. | bool | | false | -| [service_account_scopes](variables.tf#L253) | Scopes applied to service account. | list(string) | | [] | -| [shielded_config](variables.tf#L259) | Shielded VM configuration of the instances. | object({…}) | | null | -| [tag_bindings](variables.tf#L269) | Tag bindings for this instance, in key => tag value id format. | map(string) | | null | -| [tags](variables.tf#L275) | Instance network tags for firewall rule targets. | list(string) | | [] | +| [attached_disks](variables.tf#L38) | Additional disks, if options is null defaults will be used in its place. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null. | list(object({…})) | | [] | +| [boot_disk](variables.tf#L82) | Boot disk properties. | object({…}) | | {…} | +| [can_ip_forward](variables.tf#L98) | Enable IP forwarding. | bool | | false | +| [confidential_compute](variables.tf#L104) | Enable Confidential Compute for these instances. | bool | | false | +| [create_template](variables.tf#L110) | Create instance template instead of instances. | bool | | false | +| [description](variables.tf#L115) | Description of a Compute Instance. | string | | "Managed by the compute-vm Terraform module." | +| [enable_display](variables.tf#L121) | Enable virtual display on the instances. | bool | | false | +| [encryption](variables.tf#L127) | Encryption options. Only one of kms_key_self_link and disk_encryption_key_raw may be set. If needed, you can specify to encrypt or not the boot disk. | object({…}) | | null | +| [group](variables.tf#L137) | Define this variable to create an instance group for instances. Disabled for template use. | object({…}) | | null | +| [hostname](variables.tf#L145) | Instance FQDN name. | string | | null | +| [iam](variables.tf#L151) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} | +| [instance_type](variables.tf#L157) | Instance type. | string | | "f1-micro" | +| [labels](variables.tf#L163) | Instance labels. | map(string) | | {} | +| [metadata](variables.tf#L169) | Instance metadata. | map(string) | | {} | +| [min_cpu_platform](variables.tf#L175) | Minimum CPU platform. | string | | null | +| [options](variables.tf#L201) | Instance options. | object({…}) | | {…} | +| [scratch_disks](variables.tf#L228) | Scratch disks configuration. | object({…}) | | {…} | +| [service_account](variables.tf#L240) | Service account email. Unused if service account is auto-created. | string | | null | +| [service_account_create](variables.tf#L246) | Auto-create service account. | bool | | false | +| [service_account_scopes](variables.tf#L254) | Scopes applied to service account. | list(string) | | [] | +| [shielded_config](variables.tf#L260) | Shielded VM configuration of the instances. | object({…}) | | null | +| [tag_bindings](variables.tf#L270) | Tag bindings for this instance, in key => tag value id format. | map(string) | | null | +| [tags](variables.tf#L276) | Instance network tags for firewall rule targets. | list(string) | | [] | ## Outputs diff --git a/modules/compute-vm/main.tf b/modules/compute-vm/main.tf index 32051555..31e37067 100644 --- a/modules/compute-vm/main.tf +++ b/modules/compute-vm/main.tf @@ -17,7 +17,7 @@ locals { attached_disks = { for disk in var.attached_disks : - disk.name => merge(disk, { + (disk.name != null ? disk.name : disk.device_name) => merge(disk, { options = disk.options == null ? var.attached_disk_defaults : disk.options }) } @@ -138,7 +138,7 @@ resource "google_compute_instance" "default" { for_each = local.attached_disks_zonal iterator = config content { - device_name = config.value.name + device_name = config.value.device_name != null ? config.value.device_name : config.value.name mode = config.value.options.mode source = ( config.value.source_type == "attach" @@ -152,7 +152,7 @@ resource "google_compute_instance" "default" { for_each = local.attached_disks_regional iterator = config content { - device_name = config.value.name + device_name = config.value.device_name != null ? config.value.device_name : config.value.name mode = config.value.options.mode source = ( config.value.source_type == "attach" @@ -285,7 +285,7 @@ resource "google_compute_instance_template" "default" { iterator = config content { auto_delete = config.value.options.auto_delete - device_name = config.value.name + device_name = config.value.device_name != null ? config.value.device_name : config.value.name # Cannot use `source` with any of the fields in # [disk_size_gb disk_name disk_type source_image labels] disk_type = ( diff --git a/modules/compute-vm/variables.tf b/modules/compute-vm/variables.tf index 4287999f..dc565177 100644 --- a/modules/compute-vm/variables.tf +++ b/modules/compute-vm/variables.tf @@ -39,6 +39,7 @@ variable "attached_disks" { description = "Additional disks, if options is null defaults will be used in its place. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null." type = list(object({ name = string + device_name = optional(string) size = string source = optional(string) source_type = optional(string)