Merge branch 'master' into stateful-disks-deletion-rule-fix

This commit is contained in:
Taneli Leppä 2023-01-04 08:39:43 +01:00 committed by GitHub
commit fbf42197a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 597 additions and 784 deletions

View File

@ -278,34 +278,34 @@ module "instance-group" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [name](variables.tf#L180) | Instance name. | <code>string</code> | ✓ | |
| [network_interfaces](variables.tf#L185) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | <code title="list&#40;object&#40;&#123;&#10; nat &#61; optional&#40;bool, false&#41;&#10; network &#61; string&#10; subnetwork &#61; string&#10; addresses &#61; optional&#40;object&#40;&#123;&#10; internal &#61; string&#10; external &#61; string&#10; &#125;&#41;, null&#41;&#10; alias_ips &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; nic_type &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | ✓ | |
| [project_id](variables.tf#L222) | Project id. | <code>string</code> | ✓ | |
| [zone](variables.tf#L281) | Compute zone. | <code>string</code> | ✓ | |
| [name](variables.tf#L181) | Instance name. | <code>string</code> | ✓ | |
| [network_interfaces](variables.tf#L186) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | <code title="list&#40;object&#40;&#123;&#10; nat &#61; optional&#40;bool, false&#41;&#10; network &#61; string&#10; subnetwork &#61; string&#10; addresses &#61; optional&#40;object&#40;&#123;&#10; internal &#61; string&#10; external &#61; string&#10; &#125;&#41;, null&#41;&#10; alias_ips &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; nic_type &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | ✓ | |
| [project_id](variables.tf#L223) | Project id. | <code>string</code> | ✓ | |
| [zone](variables.tf#L282) | Compute zone. | <code>string</code> | ✓ | |
| [attached_disk_defaults](variables.tf#L17) | Defaults for attached disks options. | <code title="object&#40;&#123;&#10; auto_delete &#61; optional&#40;bool, false&#41;&#10; mode &#61; string&#10; replica_zone &#61; string&#10; type &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; auto_delete &#61; true&#10; mode &#61; &#34;READ_WRITE&#34;&#10; replica_zone &#61; null&#10; type &#61; &#34;pd-balanced&#34;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [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. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; size &#61; string&#10; source &#61; optional&#40;string&#41;&#10; source_type &#61; optional&#40;string&#41;&#10; options &#61; optional&#40;&#10; object&#40;&#123;&#10; auto_delete &#61; optional&#40;bool, false&#41;&#10; mode &#61; optional&#40;string, &#34;READ_WRITE&#34;&#41;&#10; replica_zone &#61; optional&#40;string&#41;&#10; type &#61; optional&#40;string, &#34;pd-balanced&#34;&#41;&#10; &#125;&#41;,&#10; &#123;&#10; auto_delete &#61; true&#10; mode &#61; &#34;READ_WRITE&#34;&#10; replica_zone &#61; null&#10; type &#61; &#34;pd-balanced&#34;&#10; &#125;&#10; &#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [boot_disk](variables.tf#L81) | Boot disk properties. | <code title="object&#40;&#123;&#10; auto_delete &#61; optional&#40;bool, true&#41;&#10; image &#61; optional&#40;string, &#34;projects&#47;debian-cloud&#47;global&#47;images&#47;family&#47;debian-11&#34;&#41;&#10; size &#61; optional&#40;number, 10&#41;&#10; type &#61; optional&#40;string, &#34;pd-balanced&#34;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; auto_delete &#61; true&#10; image &#61; &#34;projects&#47;debian-cloud&#47;global&#47;images&#47;family&#47;debian-11&#34;&#10; type &#61; &#34;pd-balanced&#34;&#10; size &#61; 10&#10;&#125;">&#123;&#8230;&#125;</code> |
| [can_ip_forward](variables.tf#L97) | Enable IP forwarding. | <code>bool</code> | | <code>false</code> |
| [confidential_compute](variables.tf#L103) | Enable Confidential Compute for these instances. | <code>bool</code> | | <code>false</code> |
| [create_template](variables.tf#L109) | Create instance template instead of instances. | <code>bool</code> | | <code>false</code> |
| [description](variables.tf#L114) | Description of a Compute Instance. | <code>string</code> | | <code>&#34;Managed by the compute-vm Terraform module.&#34;</code> |
| [enable_display](variables.tf#L120) | Enable virtual display on the instances. | <code>bool</code> | | <code>false</code> |
| [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. | <code title="object&#40;&#123;&#10; encrypt_boot &#61; optional&#40;bool, false&#41;&#10; disk_encryption_key_raw &#61; optional&#40;string&#41;&#10; kms_key_self_link &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [group](variables.tf#L136) | Define this variable to create an instance group for instances. Disabled for template use. | <code title="object&#40;&#123;&#10; named_ports &#61; map&#40;number&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [hostname](variables.tf#L144) | Instance FQDN name. | <code>string</code> | | <code>null</code> |
| [iam](variables.tf#L150) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [instance_type](variables.tf#L156) | Instance type. | <code>string</code> | | <code>&#34;f1-micro&#34;</code> |
| [labels](variables.tf#L162) | Instance labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [metadata](variables.tf#L168) | Instance metadata. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [min_cpu_platform](variables.tf#L174) | Minimum CPU platform. | <code>string</code> | | <code>null</code> |
| [options](variables.tf#L200) | Instance options. | <code title="object&#40;&#123;&#10; allow_stopping_for_update &#61; optional&#40;bool, true&#41;&#10; deletion_protection &#61; optional&#40;bool, false&#41;&#10; spot &#61; optional&#40;bool, false&#41;&#10; termination_action &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; allow_stopping_for_update &#61; true&#10; deletion_protection &#61; false&#10; spot &#61; false&#10; termination_action &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [scratch_disks](variables.tf#L227) | Scratch disks configuration. | <code title="object&#40;&#123;&#10; count &#61; number&#10; interface &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; count &#61; 0&#10; interface &#61; &#34;NVME&#34;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [service_account](variables.tf#L239) | Service account email. Unused if service account is auto-created. | <code>string</code> | | <code>null</code> |
| [service_account_create](variables.tf#L245) | Auto-create service account. | <code>bool</code> | | <code>false</code> |
| [service_account_scopes](variables.tf#L253) | Scopes applied to service account. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [shielded_config](variables.tf#L259) | Shielded VM configuration of the instances. | <code title="object&#40;&#123;&#10; enable_secure_boot &#61; bool&#10; enable_vtpm &#61; bool&#10; enable_integrity_monitoring &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [tag_bindings](variables.tf#L269) | Tag bindings for this instance, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L275) | Instance network tags for firewall rule targets. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [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. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; device_name &#61; optional&#40;string&#41;&#10; size &#61; string&#10; source &#61; optional&#40;string&#41;&#10; source_type &#61; optional&#40;string&#41;&#10; options &#61; optional&#40;&#10; object&#40;&#123;&#10; auto_delete &#61; optional&#40;bool, false&#41;&#10; mode &#61; optional&#40;string, &#34;READ_WRITE&#34;&#41;&#10; replica_zone &#61; optional&#40;string&#41;&#10; type &#61; optional&#40;string, &#34;pd-balanced&#34;&#41;&#10; &#125;&#41;,&#10; &#123;&#10; auto_delete &#61; true&#10; mode &#61; &#34;READ_WRITE&#34;&#10; replica_zone &#61; null&#10; type &#61; &#34;pd-balanced&#34;&#10; &#125;&#10; &#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [boot_disk](variables.tf#L82) | Boot disk properties. | <code title="object&#40;&#123;&#10; auto_delete &#61; optional&#40;bool, true&#41;&#10; image &#61; optional&#40;string, &#34;projects&#47;debian-cloud&#47;global&#47;images&#47;family&#47;debian-11&#34;&#41;&#10; size &#61; optional&#40;number, 10&#41;&#10; type &#61; optional&#40;string, &#34;pd-balanced&#34;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; auto_delete &#61; true&#10; image &#61; &#34;projects&#47;debian-cloud&#47;global&#47;images&#47;family&#47;debian-11&#34;&#10; type &#61; &#34;pd-balanced&#34;&#10; size &#61; 10&#10;&#125;">&#123;&#8230;&#125;</code> |
| [can_ip_forward](variables.tf#L98) | Enable IP forwarding. | <code>bool</code> | | <code>false</code> |
| [confidential_compute](variables.tf#L104) | Enable Confidential Compute for these instances. | <code>bool</code> | | <code>false</code> |
| [create_template](variables.tf#L110) | Create instance template instead of instances. | <code>bool</code> | | <code>false</code> |
| [description](variables.tf#L115) | Description of a Compute Instance. | <code>string</code> | | <code>&#34;Managed by the compute-vm Terraform module.&#34;</code> |
| [enable_display](variables.tf#L121) | Enable virtual display on the instances. | <code>bool</code> | | <code>false</code> |
| [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. | <code title="object&#40;&#123;&#10; encrypt_boot &#61; optional&#40;bool, false&#41;&#10; disk_encryption_key_raw &#61; optional&#40;string&#41;&#10; kms_key_self_link &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [group](variables.tf#L137) | Define this variable to create an instance group for instances. Disabled for template use. | <code title="object&#40;&#123;&#10; named_ports &#61; map&#40;number&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [hostname](variables.tf#L145) | Instance FQDN name. | <code>string</code> | | <code>null</code> |
| [iam](variables.tf#L151) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [instance_type](variables.tf#L157) | Instance type. | <code>string</code> | | <code>&#34;f1-micro&#34;</code> |
| [labels](variables.tf#L163) | Instance labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [metadata](variables.tf#L169) | Instance metadata. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [min_cpu_platform](variables.tf#L175) | Minimum CPU platform. | <code>string</code> | | <code>null</code> |
| [options](variables.tf#L201) | Instance options. | <code title="object&#40;&#123;&#10; allow_stopping_for_update &#61; optional&#40;bool, true&#41;&#10; deletion_protection &#61; optional&#40;bool, false&#41;&#10; spot &#61; optional&#40;bool, false&#41;&#10; termination_action &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; allow_stopping_for_update &#61; true&#10; deletion_protection &#61; false&#10; spot &#61; false&#10; termination_action &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [scratch_disks](variables.tf#L228) | Scratch disks configuration. | <code title="object&#40;&#123;&#10; count &#61; number&#10; interface &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; count &#61; 0&#10; interface &#61; &#34;NVME&#34;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [service_account](variables.tf#L240) | Service account email. Unused if service account is auto-created. | <code>string</code> | | <code>null</code> |
| [service_account_create](variables.tf#L246) | Auto-create service account. | <code>bool</code> | | <code>false</code> |
| [service_account_scopes](variables.tf#L254) | Scopes applied to service account. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [shielded_config](variables.tf#L260) | Shielded VM configuration of the instances. | <code title="object&#40;&#123;&#10; enable_secure_boot &#61; bool&#10; enable_vtpm &#61; bool&#10; enable_integrity_monitoring &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [tag_bindings](variables.tf#L270) | Tag bindings for this instance, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L276) | Instance network tags for firewall rule targets. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
## Outputs

View File

@ -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 = (

View File

@ -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)

View File

@ -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
```
<!-- TFDOC OPTS files:1 -->

View File

@ -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)
}
}
}
}
}

View File

@ -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 = [

View File

@ -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)
}
}
}
}
}

View File

@ -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'

View File

@ -0,0 +1,2 @@
parent = "organizations/12345678"
name = "folder-a"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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"
}
}
}

View File

@ -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
}

View File

@ -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')])

View File

@ -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
}])
])

View File

@ -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"),
]

View File

@ -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

View File

@ -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': []
}

View File

@ -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]

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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'

View File

@ -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:

View File

@ -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