diff --git a/modules/folder/README.md b/modules/folder/README.md
index 02166d741..a1466e3d6 100644
--- a/modules/folder/README.md
+++ b/modules/folder/README.md
@@ -125,7 +125,7 @@ module "folder" {
"iam.allowedPolicyMemberDomains" = {
rules = [{
allow = {
- values = ["C0xxxxxxx", "C0yyyyyyy"]
+ values = ["C0xxxxxxx", "C0yyyyyyy", "C0zzzzzzz"]
}
}]
}
@@ -144,7 +144,7 @@ module "folder" {
{
enforce = true
parameters = jsonencode({
- allowedDomains = ["@example.com"]
+ allowedDomains = ["@example.com", "@secondary.example.com"]
})
}
]
@@ -169,6 +169,19 @@ module "folder" {
name = "Folder name"
factories_config = {
org_policies = "configs/org-policies/"
+ context = {
+ org_policies = {
+ tags = {
+ my_conditional_tag = "tagKeys/1234"
+ }
+ domains = {
+ secondary = "@secondary.example.com"
+ }
+ customer_ids = {
+ extra = "C0zzzzzzz"
+ }
+ }
+ }
}
}
# tftest modules=1 resources=9 files=boolean,list inventory=org-policies.yaml e2e
@@ -188,7 +201,7 @@ iam.disableServiceAccountKeyUpload:
rules:
- condition:
description: test condition
- expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234')
+ expression: resource.matchTagId('${tags.my_conditional_tag}', 'tagValues/1234')
location: somewhere
title: condition
enforce: true
@@ -197,7 +210,7 @@ essentialcontacts.managed.allowedContactDomains:
rules:
- enforce: true
parameters: |
- {"allowedDomains": ["@example.com"]}
+ {"allowedDomains": ["@example.com", "${domains.secondary}"]}
# tftest-file id=boolean path=configs/org-policies/boolean.yaml schema=org-policies.schema.json
```
@@ -218,6 +231,7 @@ iam.allowedPolicyMemberDomains:
values:
- C0xxxxxxx
- C0yyyyyyy
+ - ${customer_ids.extra}
# tftest-file id=list path=configs/org-policies/list.yaml schema=org-policies.schema.json
```
@@ -413,23 +427,23 @@ module "folder" {
| [assured_workload_config](variables.tf#L17) | Create AssuredWorkloads folder instead of regular folder when value is provided. Incompatible with folder_create=false. | object({…}) | | null |
| [contacts](variables.tf#L70) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} |
| [deletion_protection](variables.tf#L77) | Deletion protection setting for this folder. | bool | | false |
-| [factories_config](variables.tf#L83) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
-| [firewall_policy](variables.tf#L92) | Hierarchical firewall policy to associate to this folder. | object({…}) | | null |
-| [folder_create](variables.tf#L101) | Create folder. When set to false, uses id to reference an existing folder. | bool | | true |
+| [factories_config](variables.tf#L83) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
+| [firewall_policy](variables.tf#L95) | Hierarchical firewall policy to associate to this folder. | object({…}) | | null |
+| [folder_create](variables.tf#L104) | Create folder. When set to false, uses id to reference an existing folder. | bool | | true |
| [iam](variables-iam.tf#L17) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
| [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} |
| [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} |
| [iam_by_principals](variables-iam.tf#L61) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam` variable. | map(list(string)) | | {} |
| [iam_by_principals_additive](variables-iam.tf#L54) | Additive IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam_bindings_additive` variable. | map(list(string)) | | {} |
-| [id](variables.tf#L107) | Folder ID in case you use folder_create=false. | string | | null |
+| [id](variables.tf#L110) | Folder ID in case you use folder_create=false. | string | | null |
| [logging_data_access](variables-logging.tf#L17) | Control activation of data access logs. The special 'allServices' key denotes configuration for all services. | map(object({…})) | | {} |
| [logging_exclusions](variables-logging.tf#L28) | Logging exclusions for this folder in the form {NAME -> FILTER}. | map(string) | | {} |
| [logging_settings](variables-logging.tf#L35) | Default settings for logging resources. | object({…}) | | null |
| [logging_sinks](variables-logging.tf#L45) | Logging sinks to create for the folder. | map(object({…})) | | {} |
-| [name](variables.tf#L113) | Folder name. | string | | null |
-| [org_policies](variables.tf#L119) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} |
-| [parent](variables.tf#L147) | Parent in folders/folder_id or organizations/org_id format. | string | | null |
-| [tag_bindings](variables.tf#L157) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null |
+| [name](variables.tf#L116) | Folder name. | string | | null |
+| [org_policies](variables.tf#L122) | Organization policies applied to this folder keyed by policy name. | map(object({…})) | | {} |
+| [parent](variables.tf#L150) | Parent in folders/folder_id or organizations/org_id format. | string | | null |
+| [tag_bindings](variables.tf#L160) | Tag bindings for this folder, in key => tag value id format. | map(string) | | null |
## Outputs
diff --git a/modules/folder/organization-policies.tf b/modules/folder/organization-policies.tf
index 85cbe885c..45c4c8dbe 100644
--- a/modules/folder/organization-policies.tf
+++ b/modules/folder/organization-policies.tf
@@ -31,21 +31,49 @@ locals {
rules = [
for r in try(v.rules, []) : {
allow = can(r.allow) ? {
- all = try(r.allow.all, null)
- values = try(r.allow.values, null)
+ all = try(r.allow.all, null)
+ values = (
+ can(r.allow.values)
+ ? [for x in r.allow.values : templatestring(x, var.factories_config.context.org_policies)]
+ : null
+ )
} : null
deny = can(r.deny) ? {
- all = try(r.deny.all, null)
- values = try(r.deny.values, null)
+ all = try(r.deny.all, null)
+ values = (
+ can(r.deny.values)
+ ? [for x in r.deny.values : templatestring(x, var.factories_config.context.org_policies)]
+ : null
+ )
} : null
enforce = try(r.enforce, null)
condition = {
- description = try(r.condition.description, null)
- expression = try(r.condition.expression, null)
- location = try(r.condition.location, null)
- title = try(r.condition.title, null)
+ description = (
+ can(r.condition.description)
+ ? templatestring(r.condition.description, var.factories_config.context.org_policies)
+ : null
+ )
+ expression = (
+ can(r.condition.expression)
+ ? templatestring(r.condition.expression, var.factories_config.context.org_policies)
+ : null
+ )
+ location = (
+ can(r.condition.location)
+ ? templatestring(r.condition.location, var.factories_config.context.org_policies)
+ : null
+ )
+ title = (
+ can(r.condition.title)
+ ? templatestring(r.condition.title, var.factories_config.context.org_policies)
+ : null
+ )
}
- parameters = try(r.parameters, null)
+ parameters = (
+ can(r.parameters)
+ ? templatestring(r.parameters, var.factories_config.context.org_policies)
+ : null
+ )
}
]
}
diff --git a/modules/folder/variables.tf b/modules/folder/variables.tf
index d82d3f07f..7ff29ca55 100644
--- a/modules/folder/variables.tf
+++ b/modules/folder/variables.tf
@@ -84,6 +84,9 @@ variable "factories_config" {
description = "Paths to data files and folders that enable factory functionality."
type = object({
org_policies = optional(string)
+ context = optional(object({
+ org_policies = optional(map(map(string)), {})
+ }), {})
})
nullable = false
default = {}
diff --git a/modules/organization/README.md b/modules/organization/README.md
index bb1d8c5e8..525ae912a 100644
--- a/modules/organization/README.md
+++ b/modules/organization/README.md
@@ -535,11 +535,11 @@ module "org" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [organization_id](variables.tf#L93) | Organization id in organizations/nnnnnn format. | string | ✓ | |
+| [organization_id](variables.tf#L96) | Organization id in organizations/nnnnnn format. | string | ✓ | |
| [contacts](variables.tf#L17) | List of essential contacts for this resource. Must be in the form EMAIL -> [NOTIFICATION_TYPES]. Valid notification types are ALL, SUSPENSION, SECURITY, TECHNICAL, BILLING, LEGAL, PRODUCT_UPDATES. | map(list(string)) | | {} |
| [custom_roles](variables.tf#L24) | Map of role name => list of permissions to create in this project. | map(list(string)) | | {} |
-| [factories_config](variables.tf#L31) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
-| [firewall_policy](variables.tf#L42) | Hierarchical firewall policies to associate to the organization. | object({…}) | | null |
+| [factories_config](variables.tf#L31) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
+| [firewall_policy](variables.tf#L45) | Hierarchical firewall policies to associate to the organization. | object({…}) | | null |
| [iam](variables-iam.tf#L17) | IAM bindings, in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
| [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} |
| [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} |
@@ -550,8 +550,8 @@ module "org" {
| [logging_settings](variables-logging.tf#L35) | Default settings for logging resources. | object({…}) | | null |
| [logging_sinks](variables-logging.tf#L45) | Logging sinks to create for the organization. | map(object({…})) | | {} |
| [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} |
-| [org_policies](variables.tf#L51) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} |
-| [org_policy_custom_constraints](variables.tf#L79) | Organization policy custom constraints keyed by constraint name. | map(object({…})) | | {} |
+| [org_policies](variables.tf#L54) | Organization policies applied to this organization keyed by policy name. | map(object({…})) | | {} |
+| [org_policy_custom_constraints](variables.tf#L82) | Organization policy custom constraints keyed by constraint name. | map(object({…})) | | {} |
| [tag_bindings](variables-tags.tf#L81) | Tag bindings for this organization, in key => tag value id format. | map(string) | | {} |
| [tags](variables-tags.tf#L88) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} |
diff --git a/modules/organization/organization-policies.tf b/modules/organization/organization-policies.tf
index 9369bfa4f..ff65f0df1 100644
--- a/modules/organization/organization-policies.tf
+++ b/modules/organization/organization-policies.tf
@@ -31,21 +31,49 @@ locals {
rules = [
for r in try(v.rules, []) : {
allow = can(r.allow) ? {
- all = try(r.allow.all, null)
- values = try(r.allow.values, null)
+ all = try(r.allow.all, null)
+ values = (
+ can(r.allow.values)
+ ? [for x in r.allow.values : templatestring(x, var.factories_config.context.org_policies)]
+ : null
+ )
} : null
deny = can(r.deny) ? {
- all = try(r.deny.all, null)
- values = try(r.deny.values, null)
+ all = try(r.deny.all, null)
+ values = (
+ can(r.deny.values)
+ ? [for x in r.deny.values : templatestring(x, var.factories_config.context.org_policies)]
+ : null
+ )
} : null
enforce = try(r.enforce, null)
condition = {
- description = try(r.condition.description, null)
- expression = try(r.condition.expression, null)
- location = try(r.condition.location, null)
- title = try(r.condition.title, null)
+ description = (
+ can(r.condition.description)
+ ? templatestring(r.condition.description, var.factories_config.context.org_policies)
+ : null
+ )
+ expression = (
+ can(r.condition.expression)
+ ? templatestring(r.condition.expression, var.factories_config.context.org_policies)
+ : null
+ )
+ location = (
+ can(r.condition.location)
+ ? templatestring(r.condition.location, var.factories_config.context.org_policies)
+ : null
+ )
+ title = (
+ can(r.condition.title)
+ ? templatestring(r.condition.title, var.factories_config.context.org_policies)
+ : null
+ )
}
- parameters = try(r.parameters, null)
+ parameters = (
+ can(r.parameters)
+ ? templatestring(r.parameters, var.factories_config.context.org_policies)
+ : null
+ )
}
]
}
diff --git a/modules/organization/variables.tf b/modules/organization/variables.tf
index 698286e58..e9b67bb01 100644
--- a/modules/organization/variables.tf
+++ b/modules/organization/variables.tf
@@ -34,6 +34,9 @@ variable "factories_config" {
custom_roles = optional(string)
org_policies = optional(string)
org_policy_custom_constraints = optional(string)
+ context = optional(object({
+ org_policies = optional(map(map(string)), {})
+ }), {})
})
nullable = false
default = {}
diff --git a/modules/project/README.md b/modules/project/README.md
index 48764c624..59612fe91 100644
--- a/modules/project/README.md
+++ b/modules/project/README.md
@@ -503,7 +503,7 @@ module "project" {
"iam.allowedPolicyMemberDomains" = {
rules = [{
allow = {
- values = ["C0xxxxxxx", "C0yyyyyyy"]
+ values = ["C0xxxxxxx", "C0yyyyyyy", "C0zzzzzzz"]
}
}]
}
@@ -522,7 +522,7 @@ module "project" {
{
enforce = true
parameters = jsonencode({
- allowedDomains = ["@example.com"]
+ allowedDomains = ["@example.com", "@secondary.example.com"]
})
}
]
@@ -549,6 +549,19 @@ module "project" {
prefix = var.prefix
factories_config = {
org_policies = "configs/org-policies/"
+ context = {
+ org_policies = {
+ tags = {
+ my_conditional_tag = "tagKeys/1234"
+ }
+ domains = {
+ secondary = "@secondary.example.com"
+ }
+ customer_ids = {
+ extra = "C0zzzzzzz"
+ }
+ }
+ }
}
}
# tftest modules=1 resources=9 files=boolean,list inventory=org-policies.yaml e2e
@@ -568,7 +581,7 @@ iam.disableServiceAccountKeyUpload:
rules:
- condition:
description: test condition
- expression: resource.matchTagId('tagKeys/1234', 'tagValues/1234')
+ expression: resource.matchTagId('${tags.my_conditional_tag}', 'tagValues/1234')
location: somewhere
title: condition
enforce: true
@@ -577,7 +590,7 @@ essentialcontacts.managed.allowedContactDomains:
rules:
- enforce: true
parameters: |
- {"allowedDomains": ["@example.com"]}
+ {"allowedDomains": ["@example.com", "${domains.secondary}"]}
# tftest-file id=boolean path=configs/org-policies/boolean.yaml schema=org-policies.schema.json
```
@@ -597,6 +610,8 @@ iam.allowedPolicyMemberDomains:
values:
- C0xxxxxxx
- C0yyyyyyy
+ - ${customer_ids.extra}
+
# tftest-file id=list path=configs/org-policies/list.yaml schema=org-policies.schema.json
```
@@ -1594,7 +1609,7 @@ alerts:
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L109) | Project name and id suffix. | string | ✓ | |
+| [name](variables.tf#L110) | Project name and id suffix. | string | ✓ | |
| [alerts](variables-observability.tf#L17) | Monitoring alerts. | map(object({…})) | | {} |
| [auto_create_network](variables.tf#L17) | Whether to create the default network for the project. | bool | | false |
| [billing_account](variables.tf#L23) | Billing account id. | string | | null |
@@ -1604,14 +1619,14 @@ alerts:
| [default_service_account](variables.tf#L50) | Project default service account setting: can be one of `delete`, `deprivilege`, `disable`, or `keep`. | string | | "keep" |
| [deletion_policy](variables.tf#L64) | Deletion policy setting for this project. | string | | "DELETE" |
| [descriptive_name](variables.tf#L75) | Name of the project name. Used for project name instead of `name` variable. | string | | null |
-| [factories_config](variables.tf#L81) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
+| [factories_config](variables.tf#L81) | Paths to data files and folders that enable factory functionality. | object({…}) | | {} |
| [iam](variables-iam.tf#L17) | Authoritative IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
| [iam_bindings](variables-iam.tf#L24) | Authoritative IAM bindings in {KEY => {role = ROLE, members = [], condition = {}}}. Keys are arbitrary. | map(object({…})) | | {} |
| [iam_bindings_additive](variables-iam.tf#L39) | Individual additive IAM bindings. Keys are arbitrary. | map(object({…})) | | {} |
| [iam_by_principals](variables-iam.tf#L61) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam` variable. | map(list(string)) | | {} |
| [iam_by_principals_additive](variables-iam.tf#L54) | Additive IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid errors. Merged internally with the `iam_bindings_additive` variable. | map(list(string)) | | {} |
-| [labels](variables.tf#L96) | Resource labels. | map(string) | | {} |
-| [lien_reason](variables.tf#L103) | If non-empty, creates a project lien with this description. | string | | null |
+| [labels](variables.tf#L97) | Resource labels. | map(string) | | {} |
+| [lien_reason](variables.tf#L104) | If non-empty, creates a project lien with this description. | string | | null |
| [log_scopes](variables-observability.tf#L117) | Log scopes under this project. | map(object({…})) | | {} |
| [logging_data_access](variables-observability.tf#L127) | Control activation of data access logs. The special 'allServices' key denotes configuration for all services. | map(object({…})) | | {} |
| [logging_exclusions](variables-observability.tf#L138) | Logging exclusions for this project in the form {NAME -> FILTER}. | map(string) | | {} |
@@ -1620,22 +1635,22 @@ alerts:
| [metric_scopes](variables-observability.tf#L216) | List of projects that will act as metric scopes for this project. | list(string) | | [] |
| [network_tags](variables-tags.tf#L17) | Network tags by key name. If `id` is provided, key creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} |
| [notification_channels](variables-observability.tf#L223) | Monitoring notification channels. | map(object({…})) | | {} |
-| [org_policies](variables.tf#L114) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} |
-| [parent](variables.tf#L142) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null |
-| [prefix](variables.tf#L152) | Optional prefix used to generate project id and name. | string | | null |
-| [project_create](variables.tf#L162) | Create project. When set to false, uses a data source to reference existing project. | bool | | true |
+| [org_policies](variables.tf#L115) | Organization policies applied to this project keyed by policy name. | map(object({…})) | | {} |
+| [parent](variables.tf#L143) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | string | | null |
+| [prefix](variables.tf#L153) | Optional prefix used to generate project id and name. | string | | null |
+| [project_create](variables.tf#L163) | Create project. When set to false, uses a data source to reference existing project. | bool | | true |
| [quotas](variables-quotas.tf#L17) | Service quota configuration. | map(object({…})) | | {} |
-| [service_agents_config](variables.tf#L168) | Automatic service agent configuration options. | object({…}) | | {} |
-| [service_config](variables.tf#L179) | Configure service API activation. | object({…}) | | {…} |
-| [service_encryption_key_ids](variables.tf#L191) | Service Agents to be granted encryption/decryption permissions over Cloud KMS encryption keys. Format {SERVICE_AGENT => [KEY_ID]}. | map(list(string)) | | {} |
-| [services](variables.tf#L198) | Service APIs to enable. | list(string) | | [] |
-| [shared_vpc_host_config](variables.tf#L204) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null |
-| [shared_vpc_service_config](variables.tf#L213) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | {…} |
-| [skip_delete](variables.tf#L241) | Deprecated. Use deletion_policy. | bool | | null |
+| [service_agents_config](variables.tf#L169) | Automatic service agent configuration options. | object({…}) | | {} |
+| [service_config](variables.tf#L180) | Configure service API activation. | object({…}) | | {…} |
+| [service_encryption_key_ids](variables.tf#L192) | Service Agents to be granted encryption/decryption permissions over Cloud KMS encryption keys. Format {SERVICE_AGENT => [KEY_ID]}. | map(list(string)) | | {} |
+| [services](variables.tf#L199) | Service APIs to enable. | list(string) | | [] |
+| [shared_vpc_host_config](variables.tf#L205) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | object({…}) | | null |
+| [shared_vpc_service_config](variables.tf#L214) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | object({…}) | | {…} |
+| [skip_delete](variables.tf#L242) | Deprecated. Use deletion_policy. | bool | | null |
| [tag_bindings](variables-tags.tf#L81) | Tag bindings for this project, in key => tag value id format. | map(string) | | null |
| [tags](variables-tags.tf#L88) | Tags by key name. If `id` is provided, key or value creation is skipped. The `iam` attribute behaves like the similarly named one at module level. | map(object({…})) | | {} |
-| [universe](variables.tf#L253) | GCP universe where to deploy the project. The prefix will be prepended to the project id. | object({…}) | | null |
-| [vpc_sc](variables.tf#L262) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…}) | | null |
+| [universe](variables.tf#L254) | GCP universe where to deploy the project. The prefix will be prepended to the project id. | object({…}) | | null |
+| [vpc_sc](variables.tf#L263) | VPC-SC configuration for the project, use when `ignore_changes` for resources is set in the VPC-SC module. | object({…}) | | null |
## Outputs
diff --git a/modules/project/organization-policies.tf b/modules/project/organization-policies.tf
index a7270bd16..5861d019c 100644
--- a/modules/project/organization-policies.tf
+++ b/modules/project/organization-policies.tf
@@ -31,21 +31,49 @@ locals {
rules = [
for r in try(v.rules, []) : {
allow = can(r.allow) ? {
- all = try(r.allow.all, null)
- values = try(r.allow.values, null)
+ all = try(r.allow.all, null)
+ values = (
+ can(r.allow.values)
+ ? [for x in r.allow.values : templatestring(x, var.factories_config.context.org_policies)]
+ : null
+ )
} : null
deny = can(r.deny) ? {
- all = try(r.deny.all, null)
- values = try(r.deny.values, null)
+ all = try(r.deny.all, null)
+ values = (
+ can(r.deny.values)
+ ? [for x in r.deny.values : templatestring(x, var.factories_config.context.org_policies)]
+ : null
+ )
} : null
enforce = try(r.enforce, null)
condition = {
- description = try(r.condition.description, null)
- expression = try(r.condition.expression, null)
- location = try(r.condition.location, null)
- title = try(r.condition.title, null)
+ description = (
+ can(r.condition.description)
+ ? templatestring(r.condition.description, var.factories_config.context.org_policies)
+ : null
+ )
+ expression = (
+ can(r.condition.expression)
+ ? templatestring(r.condition.expression, var.factories_config.context.org_policies)
+ : null
+ )
+ location = (
+ can(r.condition.location)
+ ? templatestring(r.condition.location, var.factories_config.context.org_policies)
+ : null
+ )
+ title = (
+ can(r.condition.title)
+ ? templatestring(r.condition.title, var.factories_config.context.org_policies)
+ : null
+ )
}
- parameters = try(r.parameters, null)
+ parameters = (
+ can(r.parameters)
+ ? templatestring(r.parameters, var.factories_config.context.org_policies)
+ : null
+ )
}
]
}
diff --git a/modules/project/variables.tf b/modules/project/variables.tf
index c961bdeea..b0e27c928 100644
--- a/modules/project/variables.tf
+++ b/modules/project/variables.tf
@@ -87,6 +87,7 @@ variable "factories_config" {
quotas = optional(string)
context = optional(object({
notification_channels = optional(map(string), {})
+ org_policies = optional(map(map(string)), {})
}), {})
})
nullable = false
diff --git a/tests/modules/folder/examples/org-policies.yaml b/tests/modules/folder/examples/org-policies.yaml
index d5fdd69df..a7793abb0 100644
--- a/tests/modules/folder/examples/org-policies.yaml
+++ b/tests/modules/folder/examples/org-policies.yaml
@@ -84,7 +84,7 @@ values:
condition: []
deny_all: null
enforce: 'TRUE'
- parameters: '{"allowedDomains":["@example.com"]}'
+ parameters: '{"allowedDomains":["@example.com","@secondary.example.com"]}'
values: []
timeouts: null
module.folder.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]:
@@ -102,6 +102,7 @@ values:
- allowed_values:
- C0xxxxxxx
- C0yyyyyyy
+ - C0zzzzzzz
denied_values: null
timeouts: null
module.folder.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]:
diff --git a/tests/modules/organization/test_plan_org_policies_modules.py b/tests/modules/organization/test_plan_org_policies_modules.py
index f1223b18a..5315da34a 100644
--- a/tests/modules/organization/test_plan_org_policies_modules.py
+++ b/tests/modules/organization/test_plan_org_policies_modules.py
@@ -34,7 +34,7 @@ def test_policy_implementation():
'@@ -17 +17 @@\n',
'-# tfdoc:file:description Project-level organization policies.\n',
'+# tfdoc:file:description Folder-level organization policies.\n',
- '@@ -81,2 +81,2 @@\n',
+ '@@ -109,2 +109,2 @@\n',
'- name = "projects/${local.project.project_id}/policies/${each.value}"\n',
'- parent = "projects/${local.project.project_id}"\n',
'+ name = "${local.folder_id}/policies/${each.value}"\n',
@@ -49,12 +49,12 @@ def test_policy_implementation():
'@@ -17 +17 @@\n',
'-# tfdoc:file:description Folder-level organization policies.\n',
'+# tfdoc:file:description Organization-level organization policies.\n',
- '@@ -81,2 +81,2 @@\n',
+ '@@ -109,2 +109,2 @@\n',
'- name = "${local.folder_id}/policies/${each.value}"\n',
'- parent = local.folder_id\n',
'+ name = "${var.organization_id}/policies/${each.value}"\n',
'+ parent = var.organization_id\n',
- '@@ -159,0 +160,9 @@\n',
+ '@@ -187,0 +188,9 @@\n',
'+ depends_on = [\n',
'+ google_organization_iam_binding.authoritative,\n',
'+ google_organization_iam_binding.bindings,\n',
diff --git a/tests/modules/project/examples/org-policies.yaml b/tests/modules/project/examples/org-policies.yaml
index 0fff78dae..50e1db6d0 100644
--- a/tests/modules/project/examples/org-policies.yaml
+++ b/tests/modules/project/examples/org-policies.yaml
@@ -88,7 +88,7 @@ values:
condition: []
deny_all: null
enforce: 'TRUE'
- parameters: '{"allowedDomains":["@example.com"]}'
+ parameters: '{"allowedDomains":["@example.com","@secondary.example.com"]}'
values: []
timeouts: null
module.project.google_org_policy_policy.default["iam.allowedPolicyMemberDomains"]:
@@ -108,6 +108,7 @@ values:
- allowed_values:
- C0xxxxxxx
- C0yyyyyyy
+ - C0zzzzzzz
denied_values: null
timeouts: null
module.project.google_org_policy_policy.default["iam.disableServiceAccountKeyCreation"]: