Add support for SCIM to workforce identity (#3951)
* Add support for SCIM to workforce identity * Update schemas and tests
This commit is contained in:
@@ -971,6 +971,7 @@ module "org" {
|
||||
}
|
||||
}
|
||||
oidc-full = {
|
||||
scim_usage = "ENABLED_FOR_GROUPS"
|
||||
attribute_mapping = {
|
||||
"google.subject" = "assertion.sub"
|
||||
}
|
||||
@@ -993,12 +994,20 @@ module "org" {
|
||||
attributes_type = "AZURE_AD_GROUPS_MAIL"
|
||||
}
|
||||
}
|
||||
scim_tenant = {
|
||||
id = "my-scim-tenant"
|
||||
display_name = "My SCIM Tenant"
|
||||
claim_mapping = {
|
||||
"google.subject" = "user.externalId"
|
||||
"google.group" = "group.externalId"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
# tftest modules=1 resources=4 inventory=wfif.yaml
|
||||
# tftest inventory=wfif.yaml
|
||||
```
|
||||
|
||||
<!-- TFDOC OPTS files:1 -->
|
||||
@@ -1009,7 +1018,7 @@ module "org" {
|
||||
|---|---|---|
|
||||
| [assets.tf](./assets.tf) | None | <code>google_cloud_asset_organization_feed</code> |
|
||||
| [iam.tf](./iam.tf) | IAM bindings. | <code>google_organization_iam_binding</code> · <code>google_organization_iam_custom_role</code> · <code>google_organization_iam_member</code> |
|
||||
| [identity-providers.tf](./identity-providers.tf) | Workforce Identity Federation provider definitions. | <code>google_iam_workforce_pool</code> · <code>google_iam_workforce_pool_provider</code> |
|
||||
| [identity-providers.tf](./identity-providers.tf) | Workforce Identity Federation provider definitions. | <code>google_iam_workforce_pool</code> · <code>google_iam_workforce_pool_provider</code> · <code>google_iam_workforce_pool_provider_scim_tenant</code> |
|
||||
| [logging.tf](./logging.tf) | Log sinks and data access logs. | <code>google_bigquery_dataset_iam_member</code> · <code>google_logging_organization_exclusion</code> · <code>google_logging_organization_settings</code> · <code>google_logging_organization_sink</code> · <code>google_organization_iam_audit_config</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_compute_firewall_policy_association</code> · <code>google_essential_contacts_contact</code> |
|
||||
| [org-policy-custom-constraints.tf](./org-policy-custom-constraints.tf) | None | <code>google_org_policy_custom_constraint</code> |
|
||||
@@ -1080,11 +1089,12 @@ module "org" {
|
||||
| [organization_policies_ids](outputs.tf#L113) | Map of ORGANIZATION_POLICIES => ID in the organization. | |
|
||||
| [scc_custom_sha_modules_ids](outputs.tf#L118) | Map of SCC CUSTOM SHA MODULES => ID in the organization. | |
|
||||
| [scc_mute_configs](outputs.tf#L123) | SCC mute configurations. | |
|
||||
| [service_agents](outputs.tf#L128) | Identities of all organization-level service agents. | |
|
||||
| [sink_writer_identities](outputs.tf#L136) | Writer identities created for each sink. | |
|
||||
| [tag_keys](outputs.tf#L144) | Tag key resources. | |
|
||||
| [tag_values](outputs.tf#L153) | Tag value resources. | |
|
||||
| [workforce_identity_pool_ids](outputs.tf#L161) | Workforce identity pool ids. | |
|
||||
| [workforce_identity_provider_names](outputs.tf#L168) | Workforce Identity provider names. | |
|
||||
| [workforce_identity_providers](outputs.tf#L175) | Workforce Identity provider attributes. | |
|
||||
| [scim_tenants](outputs.tf#L128) | Workforce Identity provider SCIM tenants. | |
|
||||
| [service_agents](outputs.tf#L142) | Identities of all organization-level service agents. | |
|
||||
| [sink_writer_identities](outputs.tf#L150) | Writer identities created for each sink. | |
|
||||
| [tag_keys](outputs.tf#L158) | Tag key resources. | |
|
||||
| [tag_values](outputs.tf#L167) | Tag value resources. | |
|
||||
| [workforce_identity_pool_ids](outputs.tf#L175) | Workforce identity pool ids. | |
|
||||
| [workforce_identity_provider_names](outputs.tf#L182) | Workforce Identity provider names. | |
|
||||
| [workforce_identity_providers](outputs.tf#L189) | Workforce Identity provider attributes. | |
|
||||
<!-- END TFDOC -->
|
||||
|
||||
@@ -44,6 +44,14 @@ locals {
|
||||
})
|
||||
}
|
||||
]...)
|
||||
|
||||
wfif_scim_tenants = {
|
||||
for k, v in local.wfif_providers : k => merge(v.scim_tenant, {
|
||||
provider_id = v.provider_id
|
||||
pool = v.pool
|
||||
})
|
||||
if try(v.scim_tenant, null) != null
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_iam_workforce_pool" "default" {
|
||||
@@ -70,12 +78,14 @@ resource "google_iam_workforce_pool" "default" {
|
||||
}
|
||||
|
||||
resource "google_iam_workforce_pool_provider" "default" {
|
||||
for_each = local.wfif_providers
|
||||
provider_id = each.value.provider_id
|
||||
attribute_condition = each.value.attribute_condition
|
||||
description = each.value.description
|
||||
disabled = each.value.disabled
|
||||
display_name = each.value.display_name
|
||||
for_each = local.wfif_providers
|
||||
provider_id = each.value.provider_id
|
||||
attribute_condition = each.value.attribute_condition
|
||||
description = each.value.description
|
||||
disabled = each.value.disabled
|
||||
detailed_audit_logging = each.value.detailed_audit_logging
|
||||
display_name = each.value.display_name
|
||||
scim_usage = each.value.scim_usage
|
||||
attribute_mapping = merge(
|
||||
try(local.wfif_attribute_mappings[each.value.attribute_mapping_template], {}),
|
||||
each.value.attribute_mapping
|
||||
@@ -193,3 +203,15 @@ resource "google_iam_workforce_pool_provider" "default" {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "google_iam_workforce_pool_provider_scim_tenant" "default" {
|
||||
for_each = local.wfif_scim_tenants
|
||||
location = each.value.location
|
||||
workforce_pool_id = google_iam_workforce_pool.default[each.value.pool].workforce_pool_id
|
||||
provider_id = google_iam_workforce_pool_provider.default[each.key].provider_id
|
||||
scim_tenant_id = each.value.id
|
||||
display_name = each.value.display_name
|
||||
description = each.value.description
|
||||
claim_mapping = each.value.claim_mapping
|
||||
hard_delete = each.value.hard_delete
|
||||
}
|
||||
|
||||
@@ -125,6 +125,20 @@ output "scc_mute_configs" {
|
||||
value = google_scc_v2_organization_mute_config.scc_mute_configs
|
||||
}
|
||||
|
||||
output "scim_tenants" {
|
||||
description = "Workforce Identity provider SCIM tenants."
|
||||
value = {
|
||||
for k, v in google_iam_workforce_pool_provider_scim_tenant.default : k => {
|
||||
id = v.id
|
||||
pool = v.workforce_pool_id
|
||||
provider = v.provider_id
|
||||
state = v.state
|
||||
base_uri = v.base_uri
|
||||
service_agent = v.service_agent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output "service_agents" {
|
||||
description = "Identities of all organization-level service agents."
|
||||
value = local.service_agents
|
||||
|
||||
@@ -34,6 +34,8 @@ variable "workforce_identity_pools" {
|
||||
attribute_mapping = optional(map(string), {})
|
||||
attribute_mapping_template = optional(string)
|
||||
disabled = optional(bool, false)
|
||||
detailed_audit_logging = optional(bool, false)
|
||||
scim_usage = optional(string)
|
||||
identity_provider = object({
|
||||
oidc = optional(object({
|
||||
issuer_uri = string
|
||||
@@ -67,70 +69,101 @@ variable "workforce_identity_pools" {
|
||||
query_filter = optional(string)
|
||||
}))
|
||||
}), {})
|
||||
scim_tenant = optional(object({
|
||||
id = string
|
||||
claim_mapping = map(string)
|
||||
location = optional(string, "global")
|
||||
display_name = optional(string)
|
||||
description = optional(string)
|
||||
hard_delete = optional(bool)
|
||||
}))
|
||||
})), {})
|
||||
}))
|
||||
nullable = false
|
||||
default = {}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for v in try(var.workforce_identity_pools.providers, {}) : contains(
|
||||
["azuread", "okta"],
|
||||
coalesce(v.attribute_mapping_template, "azuread")
|
||||
)
|
||||
])
|
||||
condition = alltrue(flatten([
|
||||
for pool in values(var.workforce_identity_pools) : [
|
||||
for prov in values(pool.providers) : (
|
||||
prov.attribute_mapping_template == null || contains(
|
||||
["azuread", "okta"],
|
||||
prov.attribute_mapping_template
|
||||
)
|
||||
)
|
||||
]
|
||||
]))
|
||||
error_message = "Supported mapping templates are: azuread, okta."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for v in try(var.workforce_identity_pools.providers, {}) : (
|
||||
(try(v.identity_provider.oidc, null) == null ? 0 : 1) +
|
||||
(try(v.identity_provider.saml, null) == null ? 0 : 1)
|
||||
) == 1
|
||||
])
|
||||
condition = alltrue(flatten([
|
||||
for pool in values(var.workforce_identity_pools) : [
|
||||
for prov in values(pool.providers) : (
|
||||
(try(prov.identity_provider.oidc, null) == null ? 0 : 1) +
|
||||
(try(prov.identity_provider.saml, null) == null ? 0 : 1)
|
||||
) == 1
|
||||
]
|
||||
]))
|
||||
error_message = "Only one of identity_provider.oidc or identity_provider.saml can be defined."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for v in try(var.workforce_identity_pools.providers, {}) : contains(
|
||||
["CODE", "ID_TOKEN"],
|
||||
coalesce(try(
|
||||
v.identity_provider.oidc.web_sso_config.response_type, null
|
||||
), "CODE")
|
||||
)
|
||||
])
|
||||
error_message = "Invalid OIDC web SSO config response type."
|
||||
condition = alltrue(flatten([
|
||||
for pool in values(var.workforce_identity_pools) : [
|
||||
for prov in values(pool.providers) : (
|
||||
try(prov.identity_provider.oidc.web_sso_config.response_type, null) == null || contains(
|
||||
["CODE", "ID_TOKEN"],
|
||||
try(prov.identity_provider.oidc.web_sso_config.response_type, null)
|
||||
)
|
||||
)
|
||||
]
|
||||
]))
|
||||
error_message = "Supported OIDC web SSO config response types are: CODE, ID_TOKEN."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for v in try(var.workforce_identity_pools.providers, {}) : contains(
|
||||
["MERGE_USER_INFO_OVER_ID_TOKEN_CLAIMS", "ONLY_ID_TOKEN_CLAIMS"],
|
||||
coalesce(try(
|
||||
v.identity_provider.oidc.web_sso_config.assertion_claims_behavior, null
|
||||
), "MERGE_USER_INFO_OVER_ID_TOKEN_CLAIMS")
|
||||
)
|
||||
])
|
||||
error_message = "Invalid OIDC web SSO config assertion claims behavior."
|
||||
condition = alltrue(flatten([
|
||||
for pool in values(var.workforce_identity_pools) : [
|
||||
for prov in values(pool.providers) : (
|
||||
try(prov.identity_provider.oidc.web_sso_config.assertion_claims_behavior, null) == null || contains(
|
||||
["MERGE_USER_INFO_OVER_ID_TOKEN_CLAIMS", "ONLY_ID_TOKEN_CLAIMS"],
|
||||
try(prov.identity_provider.oidc.web_sso_config.assertion_claims_behavior, null)
|
||||
)
|
||||
)
|
||||
]
|
||||
]))
|
||||
error_message = "Supported OIDC web SSO config assertion claims behaviors are: MERGE_USER_INFO_OVER_ID_TOKEN_CLAIMS, ONLY_ID_TOKEN_CLAIMS."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for v in try(var.workforce_identity_pools.providers, {}) : contains(
|
||||
["AZURE_AD_GROUPS_MAIL", "AZURE_AD_GROUPS_ID"],
|
||||
coalesce(try(
|
||||
v.oauth2_client_config.extended_attributes.attributes_type, null
|
||||
), "AZURE_AD_GROUPS_MAIL")
|
||||
)
|
||||
])
|
||||
error_message = "Invalid AzureAD attribute type in OAuth 2.0 client extended attributes.."
|
||||
condition = alltrue(flatten([
|
||||
for pool in values(var.workforce_identity_pools) : [
|
||||
for prov in values(pool.providers) : (
|
||||
try(prov.oauth2_client_config.extended_attributes.attributes_type, null) == null || contains(
|
||||
["AZURE_AD_GROUPS_MAIL", "AZURE_AD_GROUPS_ID"],
|
||||
try(prov.oauth2_client_config.extended_attributes.attributes_type, null)
|
||||
)
|
||||
)
|
||||
]
|
||||
]))
|
||||
error_message = "Supported AzureAD attribute types in OAuth 2.0 client extended attributes are: AZURE_AD_GROUPS_MAIL, AZURE_AD_GROUPS_ID."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for v in try(var.workforce_identity_pools.providers, {}) : contains(
|
||||
["AZURE_AD_GROUPS_MAIL", "AZURE_AD_GROUPS_ID"],
|
||||
coalesce(try(
|
||||
v.oauth2_client_config.extra_attributes.attributes_type, null
|
||||
), "AZURE_AD_GROUPS_MAIL")
|
||||
)
|
||||
])
|
||||
error_message = "Invalid AzureAD attribute type in OAuth 2.0 client extra attributes.."
|
||||
condition = alltrue(flatten([
|
||||
for pool in values(var.workforce_identity_pools) : [
|
||||
for prov in values(pool.providers) : (
|
||||
try(prov.oauth2_client_config.extra_attributes.attributes_type, null) == null || contains(
|
||||
["AZURE_AD_GROUPS_MAIL", "AZURE_AD_GROUPS_ID"],
|
||||
try(prov.oauth2_client_config.extra_attributes.attributes_type, null)
|
||||
)
|
||||
)
|
||||
]
|
||||
]))
|
||||
error_message = "Supported AzureAD attribute types in OAuth 2.0 client extra attributes are: AZURE_AD_GROUPS_MAIL, AZURE_AD_GROUPS_ID."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue(flatten([
|
||||
for pool in values(var.workforce_identity_pools) : [
|
||||
for prov in values(pool.providers) :
|
||||
prov.scim_usage == null || prov.scim_usage == "ENABLED_FOR_GROUPS"
|
||||
]
|
||||
]))
|
||||
error_message = "Supported scim_usage values are: ENABLED_FOR_GROUPS."
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user