Merge branch 'master' into net-dash-psa

This commit is contained in:
Julio Castillo 2022-11-09 11:55:47 +01:00 committed by GitHub
commit 68c3bd7af9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 294 additions and 37 deletions

View File

@ -52,6 +52,7 @@ All notable changes to this project will be documented in this file.
### DOCUMENTATION
- [[#961](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/961)] Remove extra file from root ([ludoo](https://github.com/ludoo)) <!-- 2022-11-09 07:53:11+00:00 -->
- [[#943](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/943)] Update bootstrap README.md with unique project id requirements ([KPRepos](https://github.com/KPRepos)) <!-- 2022-11-03 22:22:22+00:00 -->
- [[#937](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/937)] Fix typos in blueprints README.md ([kumar-dhanagopal](https://github.com/kumar-dhanagopal)) <!-- 2022-11-02 07:39:26+00:00 -->
- [[#921](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/921)] Align documentation, move glb blueprint ([ludoo](https://github.com/ludoo)) <!-- 2022-10-26 12:31:04+00:00 -->
@ -62,6 +63,7 @@ All notable changes to this project will be documented in this file.
### FAST
- [[#956](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/956)] FAST: bootstrap and extra stage CI/CD improvements and fixes ([ludoo](https://github.com/ludoo)) <!-- 2022-11-08 08:38:16+00:00 -->
- [[#949](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/949)] **incompatible change:** Refactor VPC firewall module for Terraform 1.3 ([ludoo](https://github.com/ludoo)) <!-- 2022-11-04 12:56:08+00:00 -->
- [[#943](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/943)] Update bootstrap README.md with unique project id requirements ([KPRepos](https://github.com/KPRepos)) <!-- 2022-11-03 22:22:22+00:00 -->
- [[#948](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/948)] Use display_name instead of description for FAST service accounts ([juliocc](https://github.com/juliocc)) <!-- 2022-11-03 16:22:18+00:00 -->
@ -90,6 +92,8 @@ All notable changes to this project will be documented in this file.
### MODULES
- [[#958](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/958)] Add support for org policy custom constraints ([averbuks](https://github.com/averbuks)) <!-- 2022-11-09 09:07:46+00:00 -->
- [[#960](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/960)] Fix README typo in firewall module ([valeriobponza](https://github.com/valeriobponza)) <!-- 2022-11-08 23:25:34+00:00 -->
- [[#953](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/953)] Added IAM Additive and converted some outputs to static ([muresan](https://github.com/muresan)) <!-- 2022-11-07 13:20:17+00:00 -->
- [[#951](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/951)] cloud-functions v2 - fix reference to bucket_name ([wiktorn](https://github.com/wiktorn)) <!-- 2022-11-06 07:32:39+00:00 -->
- [[#949](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/949)] **incompatible change:** Refactor VPC firewall module for Terraform 1.3 ([ludoo](https://github.com/ludoo)) <!-- 2022-11-04 12:56:08+00:00 -->

View File

@ -138,10 +138,10 @@ module "firewall" {
project_id = "my-project"
network = "my-network"
factories_config = {
rules_folder = "config/firewall"
cidr_tpl_file = "config/cidr_template.yaml"
}
data_folder = "config/firewall"
cidr_template_file = "config/cidr_template.yaml"
}
# tftest skip
```

View File

@ -6,6 +6,7 @@ This module allows managing several organization properties:
- custom IAM roles
- audit logging configuration for services
- organization policies
- organization policy custom constraints
To manage organization policies, the `orgpolicy.googleapis.com` service should be enabled in the quota project.
@ -22,7 +23,21 @@ module "org" {
"roles/resourcemanager.projectCreator" = ["group:cloud-admins@example.org"]
}
org_policy_custom_constraints = {
"custom.gkeEnableAutoUpgrade" = {
resource_types = ["container.googleapis.com/NodePool"]
method_types = ["CREATE"]
condition = "resource.management.autoUpgrade == true"
action_type = "ALLOW"
display_name = "Enable node auto-upgrade"
description = "All node pools must have node auto-upgrade enabled."
}
}
org_policies = {
"custom.gkeEnableAutoUpgrade" = {
enforce = true
}
"compute.disableGuestAttributesAccess" = {
enforce = true
}
@ -61,7 +76,7 @@ module "org" {
}
}
}
# tftest modules=1 resources=10
# tftest modules=1 resources=12
```
## IAM
@ -74,15 +89,100 @@ There are several mutually exclusive ways of managing IAM in this module
If you set audit policies via the `iam_audit_config_authoritative` variable, be sure to also configure IAM bindings via `iam_bindings_authoritative`, as audit policies use the underlying `google_organization_iam_policy` resource, which is also authoritative for any role.
Some care must also be takend with the `groups_iam` variable (and in some situations with the additive variables) to ensure that variable keys are static values, so that Terraform is able to compute the dependency graph.
Some care must also be taken with the `groups_iam` variable (and in some situations with the additive variables) to ensure that variable keys are static values, so that Terraform is able to compute the dependency graph.
### Organization policy factory
See the [organization policy factory in the project module](../project#organization-policy-factory).
### Org policy custom constraints
Refer to the [Creating and managing custom constraints](https://cloud.google.com/resource-manager/docs/organization-policy/creating-managing-custom-constraints) documentation for details on usage.
To manage organization policy custom constraints, the `orgpolicy.googleapis.com` service should be enabled in the quota project.
```hcl
module "org" {
source = "./fabric/modules/organization"
organization_id = var.organization_id
org_policy_custom_constraints = {
"custom.gkeEnableAutoUpgrade" = {
resource_types = ["container.googleapis.com/NodePool"]
method_types = ["CREATE"]
condition = "resource.management.autoUpgrade == true"
action_type = "ALLOW"
display_name = "Enable node auto-upgrade"
description = "All node pools must have node auto-upgrade enabled."
}
}
# not necessarily to enforce on the org level, policy may be applied on folder/project levels
org_policies = {
"custom.gkeEnableAutoUpgrade" = {
enforce = true
}
}
}
# tftest modules=1 resources=2
```
### Org policy custom constraints factory
Org policy custom constraints can be loaded from a directory containing YAML files where each file defines one or more custom constraints. The structure of the YAML files is exactly the same as the `org_policy_custom_constraints` variable.
The example below deploys a few org policy custom constraints split between two YAML files.
```hcl
module "org" {
source = "./fabric/modules/organization"
organization_id = var.organization_id
org_policy_custom_constraints_data_path = "/my/path"
}
# tftest skip
```
```yaml
# /my/path/gke.yaml
custom.gkeEnableLogging:
resource_types:
- container.googleapis.com/Cluster
method_types:
- CREATE
- UPDATE
condition: resource.loggingService == "none"
action_type: DENY
display_name: Do not disable Cloud Logging
custom.gkeEnableAutoUpgrade:
resource_types:
- container.googleapis.com/NodePool
method_types:
- CREATE
condition: resource.management.autoUpgrade == true
action_type: ALLOW
display_name: Enable node auto-upgrade
description: All node pools must have node auto-upgrade enabled.
```
```yaml
# /my/path/dataproc.yaml
custom.dataprocNoMoreThan10Workers
resource_types:
- dataproc.googleapis.com/Cluster
method_types:
- CREATE
- UPDATE
condition: resource.config.workerConfig.numInstances + resource.config.secondaryWorkerConfig.numInstances > 10
action_type: DENY
display_name: Total number of worker instances cannot be larger than 10
description: Cluster cannot have more than 10 workers, including primary and secondary workers.
```
## Hierarchical firewall policies
Hirerarchical firewall policies can be managed in two ways:
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)
@ -314,6 +414,7 @@ module "org" {
| [iam.tf](./iam.tf) | IAM bindings, roles and audit logging resources. | <code>google_organization_iam_audit_config</code> · <code>google_organization_iam_binding</code> · <code>google_organization_iam_custom_role</code> · <code>google_organization_iam_member</code> · <code>google_organization_iam_policy</code> |
| [logging.tf](./logging.tf) | Log sinks and supporting resources. | <code>google_bigquery_dataset_iam_member</code> · <code>google_logging_organization_exclusion</code> · <code>google_logging_organization_sink</code> · <code>google_project_iam_member</code> · <code>google_pubsub_topic_iam_member</code> · <code>google_storage_bucket_iam_member</code> |
| [main.tf](./main.tf) | Module-level locals and resources. | <code>google_essential_contacts_contact</code> |
| [org-policy-custom-constraints.tf](./org-policy-custom-constraints.tf) | None | <code>google_org_policy_custom_constraint</code> |
| [organization-policies.tf](./organization-policies.tf) | Organization-level organization policies. | <code>google_org_policy_policy</code> |
| [outputs.tf](./outputs.tf) | Module outputs. | |
| [tags.tf](./tags.tf) | None | <code>google_tags_tag_binding</code> · <code>google_tags_tag_key</code> · <code>google_tags_tag_key_iam_binding</code> · <code>google_tags_tag_value</code> · <code>google_tags_tag_value_iam_binding</code> |
@ -324,7 +425,7 @@ module "org" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [organization_id](variables.tf#L191) | Organization id in organizations/nnnnnn format. | <code>string</code> | ✓ | |
| [organization_id](variables.tf#L217) | Organization id in organizations/nnnnnn format. | <code>string</code> | ✓ | |
| [contacts](variables.tf#L17) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [custom_roles](variables.tf#L24) | Map of role name => list of permissions to create in this project. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [firewall_policies](variables.tf#L31) | Hierarchical firewall policy rules created in the organization. | <code title="map&#40;map&#40;object&#40;&#123;&#10; action &#61; string&#10; description &#61; string&#10; direction &#61; string&#10; logging &#61; bool&#10; ports &#61; map&#40;list&#40;string&#41;&#41;&#10; priority &#61; number&#10; ranges &#61; list&#40;string&#41;&#10; target_resources &#61; list&#40;string&#41;&#10; target_service_accounts &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;&#41;">map&#40;map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
@ -340,9 +441,11 @@ module "org" {
| [logging_exclusions](variables.tf#L122) | Logging exclusions for this organization in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L129) | Logging sinks to create for this organization. | <code title="map&#40;object&#40;&#123;&#10; destination &#61; string&#10; type &#61; string&#10; filter &#61; string&#10; include_children &#61; bool&#10; bq_partitioned_table &#61; bool&#10; exclusions &#61; map&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies](variables.tf#L151) | Organization policies applied to this organization keyed by policy name. | <code title="map&#40;object&#40;&#123;&#10; inherit_from_parent &#61; optional&#40;bool&#41; &#35; for list policies only.&#10; reset &#61; optional&#40;bool&#41;&#10; allow &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; deny &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; enforce &#61; optional&#40;bool, true&#41; &#35; for boolean policies only.&#10; rules &#61; optional&#40;list&#40;object&#40;&#123;&#10; allow &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; deny &#61; optional&#40;object&#40;&#123;&#10; all &#61; optional&#40;bool&#41;&#10; values &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; enforce &#61; optional&#40;bool, true&#41; &#35; for boolean policies only.&#10; condition &#61; object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; expression &#61; optional&#40;string&#41;&#10; location &#61; optional&#40;string&#41;&#10; title &#61; optional&#40;string&#41;&#10; &#125;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies_data_path](variables.tf#L200) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
| [tag_bindings](variables.tf#L206) | Tag bindings for this organization, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L212) | Tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map&#40;object&#40;&#123;&#10; description &#61; string&#10; iam &#61; map&#40;list&#40;string&#41;&#41;&#10; values &#61; map&#40;object&#40;&#123;&#10; description &#61; string&#10; iam &#61; map&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>null</code> |
| [org_policies_data_path](variables.tf#L191) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
| [org_policy_custom_constraints](variables.tf#L197) | Organization policiy custom constraints keyed by constraint name. | <code title="map&#40;object&#40;&#123;&#10; display_name &#61; optional&#40;string&#41;&#10; description &#61; optional&#40;string&#41;&#10; action_type &#61; string&#10; condition &#61; string&#10; method_types &#61; list&#40;string&#41;&#10; resource_types &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policy_custom_constraints_data_path](variables.tf#L211) | Path containing org policy custom constraints in YAML format. | <code>string</code> | | <code>null</code> |
| [tag_bindings](variables.tf#L227) | Tag bindings for this organization, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L233) | Tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map&#40;object&#40;&#123;&#10; description &#61; string&#10; iam &#61; map&#40;list&#40;string&#41;&#41;&#10; values &#61; map&#40;object&#40;&#123;&#10; description &#61; string&#10; iam &#61; map&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>null</code> |
## Outputs

View File

@ -0,0 +1,62 @@
/**
* 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.
*/
locals {
_custom_constraints_factory_data_raw = (
var.org_policy_custom_constraints_data_path == null
? tomap({})
: tomap(merge([
for f in fileset(var.org_policy_custom_constraints_data_path, "*.yaml") :
yamldecode(file("${var.org_policy_custom_constraints_data_path}/${f}"))
]...))
)
_custom_constraints_factory_data = {
for k, v in local._custom_constraints_factory_data_raw :
k => {
display_name = try(v.display_name, null)
description = try(v.description, null)
action_type = v.action_type
condition = v.condition
method_types = v.method_types
resource_types = v.resource_types
}
}
_custom_constraints = merge(local._custom_constraints_factory_data, var.org_policy_custom_constraints)
custom_constraints = {
for k, v in local._custom_constraints :
k => merge(v, {
name = k
parent = var.organization_id
})
}
}
resource "google_org_policy_custom_constraint" "constraint" {
provider = google-beta
for_each = local.custom_constraints
name = each.value.name
parent = each.value.parent
display_name = each.value.display_name
description = each.value.description
action_type = each.value.action_type
condition = each.value.condition
method_types = each.value.method_types
resource_types = each.value.resource_types
}

View File

@ -150,5 +150,6 @@ resource "google_org_policy_policy" "default" {
google_organization_iam_custom_role.roles,
google_organization_iam_member.additive,
google_organization_iam_policy.authoritative,
google_org_policy_custom_constraint.constraint,
]
}

View File

@ -188,6 +188,32 @@ variable "org_policies" {
nullable = false
}
variable "org_policies_data_path" {
description = "Path containing org policies in YAML format."
type = string
default = null
}
variable "org_policy_custom_constraints" {
description = "Organization policiy custom constraints keyed by constraint name."
type = map(object({
display_name = optional(string)
description = optional(string)
action_type = string
condition = string
method_types = list(string)
resource_types = list(string)
}))
default = {}
nullable = false
}
variable "org_policy_custom_constraints_data_path" {
description = "Path containing org policy custom constraints in YAML format."
type = string
default = null
}
variable "organization_id" {
description = "Organization id in organizations/nnnnnn format."
type = string
@ -197,11 +223,6 @@ variable "organization_id" {
}
}
variable "org_policies_data_path" {
description = "Path containing org policies in YAML format."
type = string
default = null
}
variable "tag_bindings" {
description = "Tag bindings for this organization, in key => tag value id format."

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

View File

@ -15,21 +15,23 @@
*/
module "test" {
source = "../../../../modules/organization"
organization_id = "organizations/1234567890"
custom_roles = var.custom_roles
firewall_policies = var.firewall_policies
firewall_policy_association = var.firewall_policy_association
firewall_policy_factory = var.firewall_policy_factory
group_iam = var.group_iam
iam = var.iam
iam_additive = var.iam_additive
iam_additive_members = var.iam_additive_members
iam_audit_config = var.iam_audit_config
logging_sinks = var.logging_sinks
logging_exclusions = var.logging_exclusions
org_policies = var.org_policies
org_policies_data_path = var.org_policies_data_path
tag_bindings = var.tag_bindings
tags = var.tags
source = "../../../../modules/organization"
organization_id = "organizations/1234567890"
custom_roles = var.custom_roles
firewall_policies = var.firewall_policies
firewall_policy_association = var.firewall_policy_association
firewall_policy_factory = var.firewall_policy_factory
group_iam = var.group_iam
iam = var.iam
iam_additive = var.iam_additive
iam_additive_members = var.iam_additive_members
iam_audit_config = var.iam_audit_config
logging_sinks = var.logging_sinks
logging_exclusions = var.logging_exclusions
org_policies = var.org_policies
org_policies_data_path = var.org_policies_data_path
org_policy_custom_constraints = var.org_policy_custom_constraints
org_policy_custom_constraints_data_path = var.org_policy_custom_constraints_data_path
tag_bindings = var.tag_bindings
tags = var.tags
}

View File

@ -0,0 +1,18 @@
org_policy_custom_constraints = {
"custom.gkeEnableAutoUpgrade" = {
resource_types = ["container.googleapis.com/NodePool"]
method_types = ["CREATE"]
condition = "resource.management.autoUpgrade == true"
action_type = "ALLOW"
display_name = "Enable node auto-upgrade"
description = "All node pools must have node auto-upgrade enabled."
},
"custom.dataprocNoMoreThan10Workers" = {
resource_types = ["dataproc.googleapis.com/Cluster"]
method_types = ["CREATE", "UPDATE"]
condition = "resource.config.workerConfig.numInstances + resource.config.secondaryWorkerConfig.numInstances > 10"
action_type = "DENY"
display_name = "Total number of worker instances cannot be larger than 10"
description = "Cluster cannot have more than 10 workers, including primary and secondary workers."
}
}

View File

@ -79,6 +79,16 @@ variable "org_policies_data_path" {
default = null
}
variable "org_policy_custom_constraints" {
type = any
default = {}
}
variable "org_policy_custom_constraints_data_path" {
type = any
default = null
}
variable "tag_bindings" {
type = any
default = null

View File

@ -14,7 +14,7 @@
import pathlib
from .validate_policies import validate_policy_boolean, validate_policy_list
from .validate_policies import validate_policy_boolean, validate_policy_list, validate_policy_custom_constraints
def test_policy_boolean(plan_runner):
@ -31,6 +31,13 @@ def test_policy_list(plan_runner):
validate_policy_list(resources)
def test_policy_custom_constraints(plan_runner):
"Test org policy custom constraints."
tfvars = 'test.orgpolicy-custom-constraints.tfvars'
_, resources = plan_runner(tf_var_file=tfvars)
validate_policy_custom_constraints(resources)
def test_factory_policy_boolean(plan_runner, tfvars_to_yaml, tmp_path):
dest = tmp_path / 'policies.yaml'
tfvars_to_yaml('test.orgpolicies-boolean.tfvars', dest, 'org_policies')
@ -43,3 +50,10 @@ def test_factory_policy_list(plan_runner, tfvars_to_yaml, tmp_path):
tfvars_to_yaml('test.orgpolicies-list.tfvars', dest, 'org_policies')
_, resources = plan_runner(org_policies_data_path=f'"{tmp_path}"')
validate_policy_list(resources)
def test_factory_policy_custom_constraints(plan_runner, tfvars_to_yaml, tmp_path):
dest = tmp_path / 'constraints.yaml'
tfvars_to_yaml('test.orgpolicy-custom-constraints.tfvars', dest, 'org_policy_custom_constraints')
_, resources = plan_runner(org_policy_custom_constraints_data_path=f'"{tmp_path}"')
validate_policy_custom_constraints(resources)

View File

@ -72,11 +72,10 @@ def test_policy_implementation():
'- name = "${local.folder.name}/policies/${k}"\n',
'- parent = local.folder.name\n',
'+ name = "${var.organization_id}/policies/${k}"\n',
'+ parent = var.organization_id\n',
' \n',
'+ parent = var.organization_id\n', ' \n',
' is_boolean_policy = v.allow == null && v.deny == null\n',
' has_values = (\n',
'@@ -143,4 +143,12 @@\n',
'@@ -143,4 +143,13 @@\n',
' }\n',
' }\n',
' }\n',
@ -87,6 +86,7 @@ def test_policy_implementation():
'+ google_organization_iam_custom_role.roles,\n',
'+ google_organization_iam_member.additive,\n',
'+ google_organization_iam_policy.authoritative,\n',
'+ google_org_policy_custom_constraint.constraint,\n',
'+ ]\n',
' }\n',
' }\n'
]

View File

@ -138,3 +138,25 @@ def validate_policy_list(resources):
'enforce': None,
'values': []
}
def validate_policy_custom_constraints(resources):
assert len(resources) == 2
assert all(
r['values']['parent'] == 'organizations/1234567890' for r in resources)
constraints = {
r['index']: r['values']
for r in resources
if r['type'] == 'google_org_policy_custom_constraint'
}
assert len(constraints) == 2
c1 = constraints['custom.gkeEnableAutoUpgrade']
assert c1['resource_types'][0] == 'container.googleapis.com/NodePool'
assert c1['method_types'] == ['CREATE']
assert c1['condition'] == 'resource.management.autoUpgrade == true'
assert c1['action_type'] == 'ALLOW'
c2 = constraints['custom.dataprocNoMoreThan10Workers']
assert c2['resource_types'][0] == 'dataproc.googleapis.com/Cluster'
assert c2['method_types'] == ['CREATE', 'UPDATE']
assert c2['condition'] == 'resource.config.workerConfig.numInstances + resource.config.secondaryWorkerConfig.numInstances > 10'
assert c2['action_type'] == 'DENY'