Merge branch 'master' into elia-gcve

This commit is contained in:
Ludovico Magnocavallo 2023-08-20 08:18:53 +02:00 committed by GitHub
commit 3a8071d93c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
66 changed files with 575 additions and 391 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@
**/.test.lock **/.test.lock
.idea .idea
.vscode .vscode
.idx/dev.nix
backend.tf backend.tf
backend-config.hcl backend-config.hcl
credentials.json credentials.json

View File

@ -8,10 +8,12 @@ All notable changes to this project will be documented in this file.
### FAST ### FAST
- [[#1593](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1593)] Fix FAST CI/CD for Gitlab ([ludoo](https://github.com/ludoo)) <!-- 2023-08-15 10:59:31+00:00 -->
- [[#1583](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1583)] Fix module path for teams cicd ([ludoo](https://github.com/ludoo)) <!-- 2023-08-09 21:41:57+00:00 --> - [[#1583](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1583)] Fix module path for teams cicd ([ludoo](https://github.com/ludoo)) <!-- 2023-08-09 21:41:57+00:00 -->
### MODULES ### MODULES
- [[#1591](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1591)] feat: 🎸 (modules/cloudsql-instance):add project_id for ssl cert ([erabusi](https://github.com/erabusi)) <!-- 2023-08-14 10:40:25+00:00 -->
- [[#1589](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1589)] Add new `iam_members` variable to IAM additive module interfaces ([ludoo](https://github.com/ludoo)) <!-- 2023-08-14 09:54:50+00:00 --> - [[#1589](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1589)] Add new `iam_members` variable to IAM additive module interfaces ([ludoo](https://github.com/ludoo)) <!-- 2023-08-14 09:54:50+00:00 -->
- [[#1588](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1588)] feat: 🎸 (modules/cloudsql-instance): enable require_ssl cert support ([erabusi](https://github.com/erabusi)) <!-- 2023-08-14 09:37:04+00:00 --> - [[#1588](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1588)] feat: 🎸 (modules/cloudsql-instance): enable require_ssl cert support ([erabusi](https://github.com/erabusi)) <!-- 2023-08-14 09:37:04+00:00 -->
- [[#1587](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1587)] **incompatible change:** Fix factory rules key in net firewall policy module ([ludoo](https://github.com/ludoo)) <!-- 2023-08-14 05:52:37+00:00 --> - [[#1587](https://github.com/GoogleCloudPlatform/cloud-foundation-fabric/pull/1587)] **incompatible change:** Fix factory rules key in net firewall policy module ([ludoo](https://github.com/ludoo)) <!-- 2023-08-14 05:52:37+00:00 -->

View File

@ -24,7 +24,7 @@ If the network_config variable is not provided, one VPC will be created in each
## Deploy your environment ## Deploy your environment
We assume the identiy running the following steps has the following role: We assume the identity running the following steps has the following role:
- resourcemanager.projectCreator in case a new project will be created. - resourcemanager.projectCreator in case a new project will be created.
- owner on the project in case you use an existing project. - owner on the project in case you use an existing project.

View File

@ -36,7 +36,7 @@ Once the resources have been created, do the following to verify that everything
kubectl apply -f tenant-setup.yaml kubectl apply -f tenant-setup.yaml
By applying that manifest thw following is created: By applying that manifest the following is created:
* A namespace called "apis". This is the namespace where the application will be deployed. * A namespace called "apis". This is the namespace where the application will be deployed.
* A Role and a RoleBinding in previously created namespace so the service account that has been configured for the CD pipeline trigger in Cloud Build is able to deploy the kubernetes application to that namespace. * A Role and a RoleBinding in previously created namespace so the service account that has been configured for the CD pipeline trigger in Cloud Build is able to deploy the kubernetes application to that namespace.

View File

@ -1,4 +1,4 @@
# Copyright 2022 Google LLC # Copyright 2023 Google LLC
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,8 +13,6 @@
# limitations under the License. # limitations under the License.
default: default:
before_script:
- echo "$${CI_JOB_JWT_V2}" > token.txt
image: image:
name: hashicorp/terraform name: hashicorp/terraform
entrypoint: entrypoint:
@ -27,7 +25,9 @@ variables:
FAST_SERVICE_ACCOUNT: ${service_account} FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider} FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock SSH_AUTH_SOCK: /tmp/ssh_agent.sock
%{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file} TF_PROVIDERS_FILE: ${tf_providers_file}
%{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)} TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
stages: stages:
@ -40,13 +40,26 @@ cache:
key: gcp-auth key: gcp-auth
paths: paths:
- cicd-sa-credentials.json - cicd-sa-credentials.json
- .tf-setup - token.txt
%{~ if tf_providers_file != "" ~}
- ${tf_providers_file}
%{~ endif ~}
%{~ for f in tf_var_files ~}
- ${f}
%{~ endfor ~}
gcp-auth: gcp-auth:
id_tokens:
GITLAB_TOKEN:
aud:
%{~ for aud in audiences ~}
- ${aud}
%{~ endfor ~}
image: image:
name: google/cloud-sdk:slim name: google/cloud-sdk:slim
stage: gcp-auth stage: gcp-auth
script: script:
- echo "$${GITLAB_TOKEN}" > token.txt
- | - |
gcloud iam workload-identity-pools create-cred-config \ gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \ $${FAST_WIF_PROVIDER} \
@ -54,6 +67,7 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \ --service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \ --output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt --credential-source-file=token.txt
tf-files: tf-files:
dependencies: dependencies:
- gcp-auth - gcp-auth
@ -63,15 +77,18 @@ tf-files:
script: script:
# - gcloud components install -q alpha # - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS} - gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- mkdir -p .tf-setup %{~ if tf_providers_file != "" ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
gcloud alpha storage cp -r \ %{~ endif ~}
"gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/ %{~ for f in tf_var_files ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
gcloud alpha storage cp -r \ %{~ endfor ~}
"gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/ - ls -l
tf-plan: tf-plan:
dependencies:
- tf-files
stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
# - | # - |
@ -80,20 +97,15 @@ tf-plan:
# mkdir -p ~/.ssh # mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
stage: tf-plan
script: script:
- cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- |
for f in $${TF_VAR_FILES}; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform plan - terraform plan
dependencies:
- tf-files
tf-apply: tf-apply:
dependencies:
- tf-files
stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
# - | # - |
@ -102,18 +114,10 @@ tf-apply:
# mkdir -p ~/.ssh # mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
stage: tf-apply
script: script:
- cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- |
for f in $${TF_VAR_FILES}; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform apply -input=false -auto-approve - terraform apply -input=false -auto-approve
dependencies:
- tf-files
when: manual when: manual
only: only:
variables: variables:

View File

@ -175,7 +175,6 @@ This configuration is possible but unsupported and only exists for development p
<!-- TFDOC OPTS files:1 show_extra:1 --> <!-- TFDOC OPTS files:1 show_extra:1 -->
<!-- BEGIN TFDOC --> <!-- BEGIN TFDOC -->
## Files ## Files
| name | description | modules | resources | | name | description | modules | resources |
@ -197,35 +196,34 @@ This configuration is possible but unsupported and only exists for development p
| name | description | type | required | default | producer | | name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L20) | Automation resources created by the organization-level bootstrap stage. | <code title="object&#40;&#123;&#10; outputs_bucket &#61; string&#10; project_id &#61; string&#10; project_number &#61; string&#10; federated_identity_pool &#61; string&#10; federated_identity_providers &#61; map&#40;object&#40;&#123;&#10; issuer &#61; string&#10; issuer_uri &#61; string&#10; name &#61; string&#10; principal_tpl &#61; string&#10; principalset_tpl &#61; string&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> | | [automation](variables.tf#L20) | Automation resources created by the organization-level bootstrap stage. | <code title="object&#40;&#123;&#10; outputs_bucket &#61; string&#10; project_id &#61; string&#10; project_number &#61; string&#10; federated_identity_pool &#61; string&#10; federated_identity_providers &#61; map&#40;object&#40;&#123;&#10; audiences &#61; list&#40;string&#41;&#10; issuer &#61; string&#10; issuer_uri &#61; string&#10; name &#61; string&#10; principal_tpl &#61; string&#10; principalset_tpl &#61; string&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> |
| [billing_account](variables.tf#L38) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | <code title="object&#40;&#123;&#10; id &#61; string&#10; is_org_level &#61; optional&#40;bool, true&#41;&#10; no_iam &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | | | [billing_account](variables.tf#L39) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | <code title="object&#40;&#123;&#10; id &#61; string&#10; is_org_level &#61; optional&#40;bool, true&#41;&#10; no_iam &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | |
| [organization](variables.tf#L191) | Organization details. | <code title="object&#40;&#123;&#10; domain &#61; string&#10; id &#61; number&#10; customer_id &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> | | [organization](variables.tf#L192) | Organization details. | <code title="object&#40;&#123;&#10; domain &#61; string&#10; id &#61; number&#10; customer_id &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> |
| [prefix](variables.tf#L207) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> | | [prefix](variables.tf#L208) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
| [tag_keys](variables.tf#L230) | Organization tag keys. | <code title="object&#40;&#123;&#10; context &#61; string&#10; environment &#61; string&#10; tenant &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>1-resman</code> | | [tag_keys](variables.tf#L231) | Organization tag keys. | <code title="object&#40;&#123;&#10; context &#61; string&#10; environment &#61; string&#10; tenant &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>1-resman</code> |
| [tag_names](variables.tf#L241) | Customized names for resource management tags. | <code title="object&#40;&#123;&#10; context &#61; string&#10; environment &#61; string&#10; tenant &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>1-resman</code> | | [tag_names](variables.tf#L242) | Customized names for resource management tags. | <code title="object&#40;&#123;&#10; context &#61; string&#10; environment &#61; string&#10; tenant &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>1-resman</code> |
| [tag_values](variables.tf#L252) | Organization resource management tag values. | <code>map&#40;string&#41;</code> | ✓ | | <code>1-resman</code> | | [tag_values](variables.tf#L253) | Organization resource management tag values. | <code>map&#40;string&#41;</code> | ✓ | | <code>1-resman</code> |
| [tenant_config](variables.tf#L259) | Tenant configuration. Short name must be 4 characters or less. If `short_name_is_prefix` is true, short name must be 9 characters or less, and will be used as the prefix as is. | <code title="object&#40;&#123;&#10; descriptive_name &#61; string&#10; groups &#61; object&#40;&#123;&#10; gcp-admins &#61; string&#10; gcp-devops &#61; optional&#40;string&#41;&#10; gcp-network-admins &#61; optional&#40;string&#41;&#10; gcp-security-admins &#61; optional&#40;string&#41;&#10; &#125;&#41;&#10; short_name &#61; string&#10; short_name_is_prefix &#61; optional&#40;bool, false&#41;&#10; fast_features &#61; optional&#40;object&#40;&#123;&#10; data_platform &#61; optional&#40;bool&#41;&#10; gke &#61; optional&#40;bool&#41;&#10; project_factory &#61; optional&#40;bool&#41;&#10; sandbox &#61; optional&#40;bool&#41;&#10; teams &#61; optional&#40;bool&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; locations &#61; optional&#40;object&#40;&#123;&#10; bq &#61; optional&#40;string&#41;&#10; gcs &#61; optional&#40;string&#41;&#10; logging &#61; optional&#40;string&#41;&#10; pubsub &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | | | [tenant_config](variables.tf#L260) | Tenant configuration. Short name must be 4 characters or less. If `short_name_is_prefix` is true, short name must be 9 characters or less, and will be used as the prefix as is. | <code title="object&#40;&#123;&#10; descriptive_name &#61; string&#10; groups &#61; object&#40;&#123;&#10; gcp-admins &#61; string&#10; gcp-devops &#61; optional&#40;string&#41;&#10; gcp-network-admins &#61; optional&#40;string&#41;&#10; gcp-security-admins &#61; optional&#40;string&#41;&#10; &#125;&#41;&#10; short_name &#61; string&#10; short_name_is_prefix &#61; optional&#40;bool, false&#41;&#10; fast_features &#61; optional&#40;object&#40;&#123;&#10; data_platform &#61; optional&#40;bool&#41;&#10; gke &#61; optional&#40;bool&#41;&#10; project_factory &#61; optional&#40;bool&#41;&#10; sandbox &#61; optional&#40;bool&#41;&#10; teams &#61; optional&#40;bool&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; locations &#61; optional&#40;object&#40;&#123;&#10; bq &#61; optional&#40;string&#41;&#10; gcs &#61; optional&#40;string&#41;&#10; logging &#61; optional&#40;string&#41;&#10; pubsub &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | |
| [cicd_repositories](variables.tf#L48) | CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | <code title="object&#40;&#123;&#10; bootstrap &#61; optional&#40;object&#40;&#123;&#10; branch &#61; optional&#40;string&#41;&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#41;&#10; resman &#61; optional&#40;object&#40;&#123;&#10; branch &#61; optional&#40;string&#41;&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | | [cicd_repositories](variables.tf#L49) | CI/CD repository configuration. Identity providers reference keys in the `federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | <code title="object&#40;&#123;&#10; bootstrap &#61; optional&#40;object&#40;&#123;&#10; branch &#61; optional&#40;string&#41;&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#41;&#10; resman &#61; optional&#40;object&#40;&#123;&#10; branch &#61; optional&#40;string&#41;&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | |
| [custom_roles](variables.tf#L94) | Custom roles defined at the organization level, in key => id format. | <code title="object&#40;&#123;&#10; service_project_network_admin &#61; string&#10; tenant_network_admin &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | <code>0-bootstrap</code> | | [custom_roles](variables.tf#L95) | Custom roles defined at the organization level, in key => id format. | <code title="object&#40;&#123;&#10; service_project_network_admin &#61; string&#10; tenant_network_admin &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | <code>0-bootstrap</code> |
| [fast_features](variables.tf#L104) | Selective control for top-level FAST features. | <code title="object&#40;&#123;&#10; data_platform &#61; optional&#40;bool, true&#41;&#10; gke &#61; optional&#40;bool, true&#41;&#10; project_factory &#61; optional&#40;bool, true&#41;&#10; sandbox &#61; optional&#40;bool, true&#41;&#10; teams &#61; optional&#40;bool, true&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | <code>0-bootstrap</code> | | [fast_features](variables.tf#L105) | Selective control for top-level FAST features. | <code title="object&#40;&#123;&#10; data_platform &#61; optional&#40;bool, true&#41;&#10; gke &#61; optional&#40;bool, true&#41;&#10; project_factory &#61; optional&#40;bool, true&#41;&#10; sandbox &#61; optional&#40;bool, true&#41;&#10; teams &#61; optional&#40;bool, true&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | <code>0-bootstrap</code> |
| [federated_identity_providers](variables.tf#L118) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | <code title="map&#40;object&#40;&#123;&#10; attribute_condition &#61; string&#10; issuer &#61; string&#10; custom_settings &#61; object&#40;&#123;&#10; issuer_uri &#61; string&#10; allowed_audiences &#61; list&#40;string&#41;&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | | [federated_identity_providers](variables.tf#L119) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | <code title="map&#40;object&#40;&#123;&#10; attribute_condition &#61; optional&#40;string&#41;&#10; issuer &#61; string&#10; custom_settings &#61; optional&#40;object&#40;&#123;&#10; issuer_uri &#61; optional&#40;string&#41;&#10; audiences &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [group_iam](variables.tf#L132) | Tenant-level custom group IAM settings in group => [roles] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | | [group_iam](variables.tf#L133) | Tenant-level custom group IAM settings in group => [roles] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [iam](variables.tf#L138) | Tenant-level custom IAM settings in role => [principal] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | | [iam](variables.tf#L139) | Tenant-level custom IAM settings in role => [principal] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [iam_additive](variables.tf#L144) | Tenant-level custom IAM settings in role => [principal] format for non-authoritative bindings. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | | [iam_additive](variables.tf#L145) | Tenant-level custom IAM settings in role => [principal] format for non-authoritative bindings. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [locations](variables.tf#L150) | Optional locations for GCS, BigQuery, and logging buckets created here. These are the defaults set at the organization level, and can be overridden via the tenant config variable. | <code title="object&#40;&#123;&#10; bq &#61; string&#10; gcs &#61; string&#10; logging &#61; string&#10; pubsub &#61; list&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; bq &#61; &#34;EU&#34;&#10; gcs &#61; &#34;EU&#34;&#10; logging &#61; &#34;global&#34;&#10; pubsub &#61; &#91;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> | <code>0-bootstrap</code> | | [locations](variables.tf#L151) | Optional locations for GCS, BigQuery, and logging buckets created here. These are the defaults set at the organization level, and can be overridden via the tenant config variable. | <code title="object&#40;&#123;&#10; bq &#61; string&#10; gcs &#61; string&#10; logging &#61; string&#10; pubsub &#61; list&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; bq &#61; &#34;EU&#34;&#10; gcs &#61; &#34;EU&#34;&#10; logging &#61; &#34;global&#34;&#10; pubsub &#61; &#91;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> | <code>0-bootstrap</code> |
| [log_sinks](variables.tf#L170) | Tenant-level log sinks, in name => {type, filter} format. | <code title="map&#40;object&#40;&#123;&#10; filter &#61; string&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code title="&#123;&#10; audit-logs &#61; &#123;&#10; filter &#61; &#34;logName:&#92;&#34;&#47;logs&#47;cloudaudit.googleapis.com&#37;2Factivity&#92;&#34; OR logName:&#92;&#34;&#47;logs&#47;cloudaudit.googleapis.com&#37;2Fsystem_event&#92;&#34;&#34;&#10; type &#61; &#34;logging&#34;&#10; &#125;&#10;&#125;">&#123;&#8230;&#125;</code> | | | [log_sinks](variables.tf#L171) | Tenant-level log sinks, in name => {type, filter} format. | <code title="map&#40;object&#40;&#123;&#10; filter &#61; string&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code title="&#123;&#10; audit-logs &#61; &#123;&#10; filter &#61; &#34;logName:&#92;&#34;&#47;logs&#47;cloudaudit.googleapis.com&#37;2Factivity&#92;&#34; OR logName:&#92;&#34;&#47;logs&#47;cloudaudit.googleapis.com&#37;2Fsystem_event&#92;&#34;&#34;&#10; type &#61; &#34;logging&#34;&#10; &#125;&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [outputs_location](variables.tf#L201) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | <code>string</code> | | <code>null</code> | | | [outputs_location](variables.tf#L202) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | <code>string</code> | | <code>null</code> | |
| [project_parent_ids](variables.tf#L217) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the tenant folder as parent. | <code title="object&#40;&#123;&#10; automation &#61; string&#10; logging &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; automation &#61; null&#10; logging &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> | | | [project_parent_ids](variables.tf#L218) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the tenant folder as parent. | <code title="object&#40;&#123;&#10; automation &#61; string&#10; logging &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; automation &#61; null&#10; logging &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [test_principal](variables.tf#L300) | Used when testing to bypass the data source returning the current identity. | <code>string</code> | | <code>null</code> | | | [test_principal](variables.tf#L301) | Used when testing to bypass the data source returning the current identity. | <code>string</code> | | <code>null</code> | |
## Outputs ## Outputs
| name | description | sensitive | consumers | | name | description | sensitive | consumers |
|---|---|:---:|---| |---|---|:---:|---|
| [cicd_workflows](outputs.tf#L107) | CI/CD workflows for tenant bootstrap and resource management stages. | ✓ | | | [cicd_workflows](outputs.tf#L109) | CI/CD workflows for tenant bootstrap and resource management stages. | ✓ | |
| [federated_identity](outputs.tf#L113) | Workload Identity Federation pool and providers. | | | | [federated_identity](outputs.tf#L115) | Workload Identity Federation pool and providers. | | |
| [provider](outputs.tf#L123) | Terraform provider file for tenant resource management stage. | ✓ | <code>stage-01</code> | | [provider](outputs.tf#L125) | Terraform provider file for tenant resource management stage. | ✓ | <code>stage-01</code> |
| [tenant_resources](outputs.tf#L130) | Tenant-level resources. | | | | [tenant_resources](outputs.tf#L132) | Tenant-level resources. | | |
| [tfvars](outputs.tf#L141) | Terraform variable files for the following tenant stages. | ✓ | | | [tfvars](outputs.tf#L143) | Terraform variable files for the following tenant stages. | ✓ | |
<!-- END TFDOC --> <!-- END TFDOC -->

View File

@ -20,23 +20,27 @@ locals {
_file_prefix = "tenants/${var.tenant_config.short_name}" _file_prefix = "tenants/${var.tenant_config.short_name}"
# derive identity pool names from identity providers for easy reference # derive identity pool names from identity providers for easy reference
cicd_identity_pools = { cicd_identity_pools = {
for k, v in local.cicd_identity_providers : for k, v in local.cicd_providers :
k => split("/providers/", v.name)[0] k => split("/providers/", v.name)[0]
} }
# merge org-level and tenant-level identity providers # merge org-level and tenant-level identity providers
cicd_identity_providers = merge( cicd_providers = merge(
var.automation.federated_identity_providers, var.automation.federated_identity_providers,
{ {
for k, v in google_iam_workload_identity_pool_provider.default : for k, v in google_iam_workload_identity_pool_provider.default :
k => { k => {
audiences = concat(
v.oidc[0].allowed_audiences,
["https://iam.googleapis.com/${v.name}"]
)
issuer = local.identity_providers[k].issuer issuer = local.identity_providers[k].issuer
issuer_uri = local.identity_providers[k].issuer_uri issuer_uri = try(v.oidc[0].issuer_uri, null)
name = v.name name = v.name
principal_tpl = local.identity_providers[k].principal_tpl principal_tpl = local.identity_providers[k].principal_tpl
principalset_tpl = local.identity_providers[k].principalset_tpl principalset_tpl = local.identity_providers[k].principalset_tpl
} }
}) }
# filter CI/CD repositories to only keep valid ones )
cicd_repositories = { cicd_repositories = {
for k, v in coalesce(var.cicd_repositories, {}) : k => v for k, v in coalesce(var.cicd_repositories, {}) : k => v
if( if(
@ -46,7 +50,7 @@ locals {
try(v.type, null) == "sourcerepo" try(v.type, null) == "sourcerepo"
|| ||
contains( contains(
keys(local.cicd_identity_providers), keys(local.cicd_providers),
coalesce(try(v.identity_provider, null), ":") coalesce(try(v.identity_provider, null), ":")
) )
) )
@ -111,12 +115,12 @@ module "automation-tf-cicd-sa-bootstrap" {
"roles/iam.workloadIdentityUser" = [ "roles/iam.workloadIdentityUser" = [
each.value.branch == null each.value.branch == null
? format( ? format(
local.cicd_identity_providers[each.value.identity_provider].principalset_tpl, local.cicd_providers[each.value.identity_provider].principalset_tpl,
local.cicd_identity_pools[each.value.identity_provider], local.cicd_identity_pools[each.value.identity_provider],
each.value.name each.value.name
) )
: format( : format(
local.cicd_identity_providers[each.value.identity_provider].principal_tpl, local.cicd_providers[each.value.identity_provider].principal_tpl,
local.cicd_identity_pools[each.value.identity_provider], local.cicd_identity_pools[each.value.identity_provider],
each.value.name, each.value.name,
each.value.branch each.value.branch
@ -201,12 +205,12 @@ module "automation-tf-cicd-sa-resman" {
"roles/iam.workloadIdentityUser" = [ "roles/iam.workloadIdentityUser" = [
each.value.branch == null each.value.branch == null
? format( ? format(
local.cicd_identity_providers[each.value.identity_provider].principalset_tpl, local.cicd_providers[each.value.identity_provider].principalset_tpl,
local.cicd_identity_pools[each.value.identity_provider], local.cicd_identity_pools[each.value.identity_provider],
each.value.name each.value.name
) )
: format( : format(
local.cicd_identity_providers[each.value.identity_provider].principal_tpl, local.cicd_providers[each.value.identity_provider].principal_tpl,
local.cicd_identity_pools[each.value.identity_provider], local.cicd_identity_pools[each.value.identity_provider],
each.value.name, each.value.name,
each.value.branch each.value.branch

View File

@ -38,7 +38,7 @@ locals {
principal_tpl = "principal://iam.googleapis.com/%s/subject/repo:%s:ref:refs/heads/%s" principal_tpl = "principal://iam.googleapis.com/%s/subject/repo:%s:ref:refs/heads/%s"
principalset_tpl = "principalSet://iam.googleapis.com/%s/attribute.repository/%s" principalset_tpl = "principalSet://iam.googleapis.com/%s/attribute.repository/%s"
} }
# https://docs.gitlab.com/ee/ci/cloud_services/index.html#how-it-works # https://docs.gitlab.com/ee/ci/secrets/id_token_authentication.html#token-payload
gitlab = { gitlab = {
attribute_mapping = { attribute_mapping = {
"google.subject" = "assertion.sub" "google.subject" = "assertion.sub"
@ -56,7 +56,6 @@ locals {
"attribute.ref_protected" = "assertion.ref_protected" "attribute.ref_protected" = "assertion.ref_protected"
"attribute.ref_type" = "assertion.ref_type" "attribute.ref_type" = "assertion.ref_type"
} }
allowed_audiences = ["https://gitlab.com"]
issuer_uri = "https://gitlab.com" issuer_uri = "https://gitlab.com"
principal_tpl = "principalSet://iam.googleapis.com/%s/attribute.sub/project_path:%s:ref_type:branch:ref:%s" principal_tpl = "principalSet://iam.googleapis.com/%s/attribute.sub/project_path:%s:ref_type:branch:ref:%s"
principalset_tpl = "principalSet://iam.googleapis.com/%s/attribute.repository/%s" principalset_tpl = "principalSet://iam.googleapis.com/%s/attribute.repository/%s"
@ -82,13 +81,11 @@ resource "google_iam_workload_identity_pool_provider" "default" {
attribute_condition = each.value.attribute_condition attribute_condition = each.value.attribute_condition
attribute_mapping = each.value.attribute_mapping attribute_mapping = each.value.attribute_mapping
oidc { oidc {
allowed_audiences = ( # Setting an empty list configures allowed_audiences to the url of the provider
try(each.value.custom_settings.allowed_audiences, null) != null allowed_audiences = each.value.custom_settings.audiences
? each.value.custom_settings.allowed_audiences # If users don't provide an issuer_uri, we set the public one for the plaform choosed.
: try(each.value.allowed_audiences, null)
)
issuer_uri = ( issuer_uri = (
try(each.value.custom_settings.issuer_uri, null) != null each.value.custom_settings.issuer_uri != null
? each.value.custom_settings.issuer_uri ? each.value.custom_settings.issuer_uri
: try(each.value.issuer_uri, null) : try(each.value.issuer_uri, null)
) )

View File

@ -20,8 +20,9 @@ locals {
"${path.module}/templates/workflow-${v.type}.yaml", ( "${path.module}/templates/workflow-${v.type}.yaml", (
k == "bootstrap" k == "bootstrap"
? { ? {
audiences = local.cicd_providers[v["identity_provider"]].audiences
identity_provider = try( identity_provider = try(
local.cicd_identity_providers[v["identity_provider"]].name, "" local.cicd_providers[v["identity_provider"]].name, ""
) )
outputs_bucket = var.automation.outputs_bucket outputs_bucket = var.automation.outputs_bucket
service_account = try( service_account = try(
@ -36,8 +37,9 @@ locals {
] ]
} }
: { : {
audiences = local.cicd_providers[v["identity_provider"]].audiences
identity_provider = try( identity_provider = try(
local.cicd_identity_providers[v["identity_provider"]].name, "" local.cicd_providers[v["identity_provider"]].name, ""
) )
outputs_bucket = module.automation-tf-output-gcs.name outputs_bucket = module.automation-tf-output-gcs.name
service_account = try( service_account = try(
@ -70,7 +72,7 @@ locals {
try(google_iam_workload_identity_pool.default.0.name, null), try(google_iam_workload_identity_pool.default.0.name, null),
var.automation.federated_identity_pool, var.automation.federated_identity_pool,
]) ])
federated_identity_providers = local.cicd_identity_providers federated_identity_providers = local.cicd_providers
service_accounts = merge( service_accounts = merge(
{ resman = module.automation-tf-resman-sa.email }, { resman = module.automation-tf-resman-sa.email },
{ {
@ -116,7 +118,7 @@ output "federated_identity" {
pool = try( pool = try(
google_iam_workload_identity_pool.default.0.name, null google_iam_workload_identity_pool.default.0.name, null
) )
providers = local.cicd_identity_providers providers = local.cicd_providers
} }
} }

View File

@ -1,4 +1,4 @@
# Copyright 2022 Google LLC # Copyright 2023 Google LLC
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,8 +13,6 @@
# limitations under the License. # limitations under the License.
default: default:
before_script:
- echo "$${CI_JOB_JWT_V2}" > token.txt
image: image:
name: hashicorp/terraform name: hashicorp/terraform
entrypoint: entrypoint:
@ -42,13 +40,26 @@ cache:
key: gcp-auth key: gcp-auth
paths: paths:
- cicd-sa-credentials.json - cicd-sa-credentials.json
- .tf-setup - token.txt
%{~ if tf_providers_file != "" ~}
- ${tf_providers_file}
%{~ endif ~}
%{~ for f in tf_var_files ~}
- ${f}
%{~ endfor ~}
gcp-auth: gcp-auth:
id_tokens:
GITLAB_TOKEN:
aud:
%{~ for aud in audiences ~}
- ${aud}
%{~ endfor ~}
image: image:
name: google/cloud-sdk:slim name: google/cloud-sdk:slim
stage: gcp-auth stage: gcp-auth
script: script:
- echo "$${GITLAB_TOKEN}" > token.txt
- | - |
gcloud iam workload-identity-pools create-cred-config \ gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \ $${FAST_WIF_PROVIDER} \
@ -56,6 +67,7 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \ --service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \ --output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt --credential-source-file=token.txt
tf-files: tf-files:
dependencies: dependencies:
- gcp-auth - gcp-auth
@ -65,17 +77,18 @@ tf-files:
script: script:
# - gcloud components install -q alpha # - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS} - gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- mkdir -p .tf-setup
%{~ if tf_providers_file != "" ~} %{~ if tf_providers_file != "" ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
gcloud alpha storage cp -r \
"gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/
%{~ endif ~} %{~ endif ~}
- | %{~ for f in tf_var_files ~}
gcloud alpha storage cp -r \ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
"gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/ %{~ endfor ~}
- ls -l
tf-plan: tf-plan:
dependencies:
- tf-files
stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
# - | # - |
@ -84,20 +97,15 @@ tf-plan:
# mkdir -p ~/.ssh # mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
stage: tf-plan
script: script:
- cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- |
for f in $${TF_VAR_FILES}; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform plan - terraform plan
dependencies:
- tf-files
tf-apply: tf-apply:
dependencies:
- tf-files
stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
# - | # - |
@ -106,18 +114,10 @@ tf-apply:
# mkdir -p ~/.ssh # mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
stage: tf-apply
script: script:
- cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- |
for f in $${TF_VAR_FILES}; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform apply -input=false -auto-approve - terraform apply -input=false -auto-approve
dependencies:
- tf-files
when: manual when: manual
only: only:
variables: variables:

View File

@ -26,6 +26,7 @@ variable "automation" {
project_number = string project_number = string
federated_identity_pool = string federated_identity_pool = string
federated_identity_providers = map(object({ federated_identity_providers = map(object({
audiences = list(string)
issuer = string issuer = string
issuer_uri = string issuer_uri = string
name = string name = string
@ -118,12 +119,12 @@ variable "fast_features" {
variable "federated_identity_providers" { variable "federated_identity_providers" {
description = "Workload Identity Federation pools. The `cicd_repositories` variable references keys here." description = "Workload Identity Federation pools. The `cicd_repositories` variable references keys here."
type = map(object({ type = map(object({
attribute_condition = string attribute_condition = optional(string)
issuer = string issuer = string
custom_settings = object({ custom_settings = optional(object({
issuer_uri = string issuer_uri = optional(string)
allowed_audiences = list(string) audiences = optional(list(string), [])
}) }), {})
})) }))
default = {} default = {}
nullable = false nullable = false

View File

@ -126,7 +126,6 @@ Once the configuration is done just go through the usual `init/apply` cycle. On
<!-- TFDOC OPTS files:1 show_extra:1 --> <!-- TFDOC OPTS files:1 show_extra:1 -->
<!-- BEGIN TFDOC --> <!-- BEGIN TFDOC -->
## Files ## Files
| name | description | modules | resources | | name | description | modules | resources |
@ -154,21 +153,21 @@ Once the configuration is done just go through the usual `init/apply` cycle. On
| name | description | type | required | default | producer | | name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | <code title="object&#40;&#123;&#10; outputs_bucket &#61; string&#10; project_id &#61; string&#10; project_number &#61; string&#10; federated_identity_pools &#61; list&#40;string&#41;&#10; federated_identity_providers &#61; map&#40;object&#40;&#123;&#10; issuer &#61; string&#10; issuer_uri &#61; string&#10; name &#61; string&#10; principal_tpl &#61; string&#10; principalset_tpl &#61; string&#10; &#125;&#41;&#41;&#10; service_accounts &#61; object&#40;&#123;&#10; networking &#61; string&#10; resman &#61; string&#10; security &#61; string&#10; dp-dev &#61; optional&#40;string&#41;&#10; dp-prod &#61; optional&#40;string&#41;&#10; gke-dev &#61; optional&#40;string&#41;&#10; gke-prod &#61; optional&#40;string&#41;&#10; pf-dev &#61; optional&#40;string&#41;&#10; pf-prod &#61; optional&#40;string&#41;&#10; sandbox &#61; optional&#40;string&#41;&#10; teams &#61; optional&#40;string&#41;&#10; &#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> | | [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | <code title="object&#40;&#123;&#10; outputs_bucket &#61; string&#10; project_id &#61; string&#10; project_number &#61; string&#10; federated_identity_pools &#61; list&#40;string&#41;&#10; federated_identity_providers &#61; map&#40;object&#40;&#123;&#10; audiences &#61; list&#40;string&#41;&#10; issuer &#61; string&#10; issuer_uri &#61; string&#10; name &#61; string&#10; principal_tpl &#61; string&#10; principalset_tpl &#61; string&#10; &#125;&#41;&#41;&#10; service_accounts &#61; object&#40;&#123;&#10; networking &#61; string&#10; resman &#61; string&#10; security &#61; string&#10; dp-dev &#61; optional&#40;string&#41;&#10; dp-prod &#61; optional&#40;string&#41;&#10; gke-dev &#61; optional&#40;string&#41;&#10; gke-prod &#61; optional&#40;string&#41;&#10; pf-dev &#61; optional&#40;string&#41;&#10; pf-prod &#61; optional&#40;string&#41;&#10; sandbox &#61; optional&#40;string&#41;&#10; teams &#61; optional&#40;string&#41;&#10; &#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> |
| [billing_account](variables.tf#L51) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | <code title="object&#40;&#123;&#10; id &#61; string&#10; is_org_level &#61; optional&#40;bool, true&#41;&#10; no_iam &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> | | [billing_account](variables.tf#L52) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | <code title="object&#40;&#123;&#10; id &#61; string&#10; is_org_level &#61; optional&#40;bool, true&#41;&#10; no_iam &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> |
| [organization](variables.tf#L204) | Organization details. | <code title="object&#40;&#123;&#10; domain &#61; string&#10; id &#61; number&#10; customer_id &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> | | [organization](variables.tf#L205) | Organization details. | <code title="object&#40;&#123;&#10; domain &#61; string&#10; id &#61; number&#10; customer_id &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> |
| [prefix](variables.tf#L226) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> | | [prefix](variables.tf#L227) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
| [root_node](variables.tf#L237) | Root folder node for the tenant, in folders/nnnnnn format. | <code>string</code> | ✓ | | | | [root_node](variables.tf#L237) | Root folder node for the tenant, in folders/nnnnnn format. | <code>string</code> | ✓ | | |
| [short_name](variables.tf#L242) | Short name used to identify the tenant. | <code>string</code> | ✓ | | | | [short_name](variables.tf#L242) | Short name used to identify the tenant. | <code>string</code> | ✓ | | |
| [tags](variables.tf#L247) | Resource management tags. | <code title="object&#40;&#123;&#10; keys &#61; object&#40;&#123;&#10; context &#61; string&#10; environment &#61; string&#10; tenant &#61; string&#10; &#125;&#41;&#10; names &#61; object&#40;&#123;&#10; context &#61; string&#10; environment &#61; string&#10; tenant &#61; string&#10; &#125;&#41;&#10; values &#61; map&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | | | [tags](variables.tf#L247) | Resource management tags. | <code title="object&#40;&#123;&#10; keys &#61; object&#40;&#123;&#10; context &#61; string&#10; environment &#61; string&#10; tenant &#61; string&#10; &#125;&#41;&#10; names &#61; object&#40;&#123;&#10; context &#61; string&#10; environment &#61; string&#10; tenant &#61; string&#10; &#125;&#41;&#10; values &#61; map&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | |
| [cicd_repositories](variables.tf#L62) | CI/CD repository configuration. Identity providers reference keys in the `automation.federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | <code title="object&#40;&#123;&#10; data_platform_dev &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; data_platform_prod &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; gke_dev &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; gke_prod &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; networking &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; project_factory_dev &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; project_factory_prod &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; security &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | | [cicd_repositories](variables.tf#L63) | CI/CD repository configuration. Identity providers reference keys in the `automation.federated_identity_providers` variable. Set to null to disable, or set individual repositories to null if not needed. | <code title="object&#40;&#123;&#10; data_platform_dev &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; data_platform_prod &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; gke_dev &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; gke_prod &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; networking &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; project_factory_dev &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; project_factory_prod &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10; security &#61; object&#40;&#123;&#10; branch &#61; string&#10; identity_provider &#61; string&#10; name &#61; string&#10; type &#61; string&#10; &#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | |
| [custom_roles](variables.tf#L144) | Custom roles defined at the org level, in key => id format. | <code title="object&#40;&#123;&#10; service_project_network_admin &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | <code>0-bootstrap</code> | | [custom_roles](variables.tf#L145) | Custom roles defined at the org level, in key => id format. | <code title="object&#40;&#123;&#10; service_project_network_admin &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | <code>0-bootstrap</code> |
| [data_dir](variables.tf#L153) | Relative path for the folder storing configuration data. | <code>string</code> | | <code>&#34;data&#34;</code> | | | [data_dir](variables.tf#L154) | Relative path for the folder storing configuration data. | <code>string</code> | | <code>&#34;data&#34;</code> | |
| [fast_features](variables.tf#L159) | Selective control for top-level FAST features. | <code title="object&#40;&#123;&#10; data_platform &#61; optional&#40;bool, false&#41;&#10; gke &#61; optional&#40;bool, false&#41;&#10; project_factory &#61; optional&#40;bool, false&#41;&#10; sandbox &#61; optional&#40;bool, false&#41;&#10; teams &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | <code>0-0-bootstrap</code> | | [fast_features](variables.tf#L160) | Selective control for top-level FAST features. | <code title="object&#40;&#123;&#10; data_platform &#61; optional&#40;bool, false&#41;&#10; gke &#61; optional&#40;bool, false&#41;&#10; project_factory &#61; optional&#40;bool, false&#41;&#10; sandbox &#61; optional&#40;bool, false&#41;&#10; teams &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | <code>0-0-bootstrap</code> |
| [groups](variables.tf#L173) | Group names to grant organization-level permissions. | <code title="object&#40;&#123;&#10; gcp-devops &#61; optional&#40;string&#41;&#10; gcp-network-admins &#61; optional&#40;string&#41;&#10; gcp-security-admins &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | <code>0-bootstrap</code> | | [groups](variables.tf#L174) | Group names to grant organization-level permissions. | <code title="object&#40;&#123;&#10; gcp-devops &#61; optional&#40;string&#41;&#10; gcp-network-admins &#61; optional&#40;string&#41;&#10; gcp-security-admins &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | <code>0-bootstrap</code> |
| [locations](variables.tf#L186) | Optional locations for GCS, BigQuery, and logging buckets created here. | <code title="object&#40;&#123;&#10; bq &#61; string&#10; gcs &#61; string&#10; logging &#61; string&#10; pubsub &#61; list&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; bq &#61; &#34;EU&#34;&#10; gcs &#61; &#34;EU&#34;&#10; logging &#61; &#34;global&#34;&#10; pubsub &#61; &#91;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> | <code>0-bootstrap</code> | | [locations](variables.tf#L187) | Optional locations for GCS, BigQuery, and logging buckets created here. | <code title="object&#40;&#123;&#10; bq &#61; string&#10; gcs &#61; string&#10; logging &#61; string&#10; pubsub &#61; list&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; bq &#61; &#34;EU&#34;&#10; gcs &#61; &#34;EU&#34;&#10; logging &#61; &#34;global&#34;&#10; pubsub &#61; &#91;&#93;&#10;&#125;">&#123;&#8230;&#125;</code> | <code>0-bootstrap</code> |
| [organization_policy_data_path](variables.tf#L214) | Path for the data folder used by the organization policies factory. | <code>string</code> | | <code>null</code> | | | [organization_policy_data_path](variables.tf#L215) | Path for the data folder used by the organization policies factory. | <code>string</code> | | <code>null</code> | |
| [outputs_location](variables.tf#L220) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | <code>string</code> | | <code>null</code> | | | [outputs_location](variables.tf#L221) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | <code>string</code> | | <code>null</code> | |
| [team_folders](variables.tf#L265) | Team folders to be created. Format is described in a code comment. | <code title="map&#40;object&#40;&#123;&#10; descriptive_name &#61; string&#10; group_iam &#61; map&#40;list&#40;string&#41;&#41;&#10; impersonation_groups &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>null</code> | | | [team_folders](variables.tf#L265) | Team folders to be created. Format is described in a code comment. | <code title="map&#40;object&#40;&#123;&#10; descriptive_name &#61; string&#10; group_iam &#61; map&#40;list&#40;string&#41;&#41;&#10; impersonation_groups &#61; list&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>null</code> | |
| [test_skip_data_sources](variables.tf#L275) | Used when testing to bypass data sources. | <code>bool</code> | | <code>false</code> | | | [test_skip_data_sources](variables.tf#L275) | Used when testing to bypass data sources. | <code>bool</code> | | <code>false</code> | |
@ -176,15 +175,14 @@ Once the configuration is done just go through the usual `init/apply` cycle. On
| name | description | sensitive | consumers | | name | description | sensitive | consumers |
|---|---|:---:|---| |---|---|:---:|---|
| [cicd_repositories](outputs.tf#L189) | WIF configuration for CI/CD repositories. | | | | [cicd_repositories](outputs.tf#L192) | WIF configuration for CI/CD repositories. | | |
| [dataplatform](outputs.tf#L203) | Data for the Data Platform stage. | | | | [dataplatform](outputs.tf#L206) | Data for the Data Platform stage. | | |
| [gke_multitenant](outputs.tf#L219) | Data for the GKE multitenant stage. | | <code>03-gke-multitenant</code> | | [gke_multitenant](outputs.tf#L222) | Data for the GKE multitenant stage. | | <code>03-gke-multitenant</code> |
| [networking](outputs.tf#L240) | Data for the networking stage. | | | | [networking](outputs.tf#L243) | Data for the networking stage. | | |
| [project_factories](outputs.tf#L249) | Data for the project factories stage. | | | | [project_factories](outputs.tf#L252) | Data for the project factories stage. | | |
| [providers](outputs.tf#L264) | Terraform provider files for this stage and dependent stages. | ✓ | <code>02-networking</code> · <code>02-security</code> · <code>03-dataplatform</code> · <code>xx-sandbox</code> · <code>xx-teams</code> | | [providers](outputs.tf#L267) | Terraform provider files for this stage and dependent stages. | ✓ | <code>02-networking</code> · <code>02-security</code> · <code>03-dataplatform</code> · <code>xx-sandbox</code> · <code>xx-teams</code> |
| [sandbox](outputs.tf#L271) | Data for the sandbox stage. | | <code>xx-sandbox</code> | | [sandbox](outputs.tf#L274) | Data for the sandbox stage. | | <code>xx-sandbox</code> |
| [security](outputs.tf#L285) | Data for the networking stage. | | <code>02-security</code> | | [security](outputs.tf#L288) | Data for the networking stage. | | <code>02-security</code> |
| [teams](outputs.tf#L295) | Data for the teams stage. | | | | [teams](outputs.tf#L298) | Data for the teams stage. | | |
| [tfvars](outputs.tf#L307) | Terraform variable files for the following stages. | ✓ | | | [tfvars](outputs.tf#L310) | Terraform variable files for the following stages. | ✓ | |
<!-- END TFDOC --> <!-- END TFDOC -->

View File

@ -62,6 +62,9 @@ locals {
for k, v in local.cicd_repositories : k => templatefile( for k, v in local.cicd_repositories : k => templatefile(
"${path.module}/templates/workflow-${v.type}.yaml", "${path.module}/templates/workflow-${v.type}.yaml",
merge(local.cicd_workflow_attrs[k], { merge(local.cicd_workflow_attrs[k], {
audiences = try(
local.cicd_identity_providers[v.identity_provider].audiences, null
)
identity_provider = try( identity_provider = try(
local.cicd_identity_providers[v.identity_provider].name, null local.cicd_identity_providers[v.identity_provider].name, null
) )

View File

@ -1,4 +1,4 @@
# Copyright 2022 Google LLC # Copyright 2023 Google LLC
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -13,8 +13,6 @@
# limitations under the License. # limitations under the License.
default: default:
before_script:
- echo "$${CI_JOB_JWT_V2}" > token.txt
image: image:
name: hashicorp/terraform name: hashicorp/terraform
entrypoint: entrypoint:
@ -27,7 +25,9 @@ variables:
FAST_SERVICE_ACCOUNT: ${service_account} FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider} FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock SSH_AUTH_SOCK: /tmp/ssh_agent.sock
%{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file} TF_PROVIDERS_FILE: ${tf_providers_file}
%{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)} TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
stages: stages:
@ -40,13 +40,26 @@ cache:
key: gcp-auth key: gcp-auth
paths: paths:
- cicd-sa-credentials.json - cicd-sa-credentials.json
- .tf-setup - token.txt
%{~ if tf_providers_file != "" ~}
- ${tf_providers_file}
%{~ endif ~}
%{~ for f in tf_var_files ~}
- ${f}
%{~ endfor ~}
gcp-auth: gcp-auth:
id_tokens:
GITLAB_TOKEN:
aud:
%{~ for aud in audiences ~}
- ${aud}
%{~ endfor ~}
image: image:
name: google/cloud-sdk:slim name: google/cloud-sdk:slim
stage: gcp-auth stage: gcp-auth
script: script:
- echo "$${GITLAB_TOKEN}" > token.txt
- | - |
gcloud iam workload-identity-pools create-cred-config \ gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \ $${FAST_WIF_PROVIDER} \
@ -54,6 +67,7 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \ --service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \ --output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt --credential-source-file=token.txt
tf-files: tf-files:
dependencies: dependencies:
- gcp-auth - gcp-auth
@ -63,15 +77,18 @@ tf-files:
script: script:
# - gcloud components install -q alpha # - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS} - gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- mkdir -p .tf-setup %{~ if tf_providers_file != "" ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
gcloud alpha storage cp -r \ %{~ endif ~}
"gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/ %{~ for f in tf_var_files ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
gcloud alpha storage cp -r \ %{~ endfor ~}
"gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/ - ls -l
tf-plan: tf-plan:
dependencies:
- tf-files
stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
# - | # - |
@ -80,20 +97,15 @@ tf-plan:
# mkdir -p ~/.ssh # mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
stage: tf-plan
script: script:
- cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- |
for f in $${TF_VAR_FILES}; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform plan - terraform plan
dependencies:
- tf-files
tf-apply: tf-apply:
dependencies:
- tf-files
stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
# - | # - |
@ -102,18 +114,10 @@ tf-apply:
# mkdir -p ~/.ssh # mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
stage: tf-apply
script: script:
- cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- |
for f in $${TF_VAR_FILES}; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform apply -input=false -auto-approve - terraform apply -input=false -auto-approve
dependencies:
- tf-files
when: manual when: manual
only: only:
variables: variables:

View File

@ -26,6 +26,7 @@ variable "automation" {
project_number = string project_number = string
federated_identity_pools = list(string) federated_identity_pools = list(string)
federated_identity_providers = map(object({ federated_identity_providers = map(object({
audiences = list(string)
issuer = string issuer = string
issuer_uri = string issuer_uri = string
name = string name = string
@ -227,7 +228,6 @@ variable "prefix" {
# tfdoc:variable:source 0-bootstrap # tfdoc:variable:source 0-bootstrap
description = "Prefix used for resources that need unique names. Use 9 characters or less." description = "Prefix used for resources that need unique names. Use 9 characters or less."
type = string type = string
validation { validation {
condition = try(length(var.prefix), 0) < 13 condition = try(length(var.prefix), 0) < 13
error_message = "Use a maximum of 12 characters for prefix (which is a combination of org prefix and tenant short name)." error_message = "Use a maximum of 12 characters for prefix (which is a combination of org prefix and tenant short name)."

View File

@ -421,7 +421,7 @@ federated_identity_providers = {
attribute_condition = "attribute.namespace_path==\"my-gitlab-org\"" attribute_condition = "attribute.namespace_path==\"my-gitlab-org\""
issuer = "gitlab" issuer = "gitlab"
custom_settings = { custom_settings = {
allowed_audiences = ["https://gitlab.fast.example.com"] audiences = ["https://gitlab.fast.example.com"]
issuer_uri = "https://gitlab.fast.example.com" issuer_uri = "https://gitlab.fast.example.com"
} }
} }
@ -516,7 +516,7 @@ The remaining configuration is manual, as it regards the repositories themselves
| [custom_role_names](variables.tf#L79) | Names of custom roles defined at the org level. | <code title="object&#40;&#123;&#10; organization_iam_admin &#61; string&#10; service_project_network_admin &#61; string&#10; tenant_network_admin &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; organization_iam_admin &#61; &#34;organizationIamAdmin&#34;&#10; service_project_network_admin &#61; &#34;serviceProjectNetworkAdmin&#34;&#10; tenant_network_admin &#61; &#34;tenantNetworkAdmin&#34;&#10;&#125;">&#123;&#8230;&#125;</code> | | | [custom_role_names](variables.tf#L79) | Names of custom roles defined at the org level. | <code title="object&#40;&#123;&#10; organization_iam_admin &#61; string&#10; service_project_network_admin &#61; string&#10; tenant_network_admin &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; organization_iam_admin &#61; &#34;organizationIamAdmin&#34;&#10; service_project_network_admin &#61; &#34;serviceProjectNetworkAdmin&#34;&#10; tenant_network_admin &#61; &#34;tenantNetworkAdmin&#34;&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [custom_roles](variables.tf#L93) | Map of role names => list of permissions to additionally create at the organization level. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | | [custom_roles](variables.tf#L93) | Map of role names => list of permissions to additionally create at the organization level. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [fast_features](variables.tf#L100) | Selective control for top-level FAST features. | <code title="object&#40;&#123;&#10; data_platform &#61; optional&#40;bool, false&#41;&#10; gke &#61; optional&#40;bool, false&#41;&#10; project_factory &#61; optional&#40;bool, false&#41;&#10; sandbox &#61; optional&#40;bool, false&#41;&#10; teams &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | | | [fast_features](variables.tf#L100) | Selective control for top-level FAST features. | <code title="object&#40;&#123;&#10; data_platform &#61; optional&#40;bool, false&#41;&#10; gke &#61; optional&#40;bool, false&#41;&#10; project_factory &#61; optional&#40;bool, false&#41;&#10; sandbox &#61; optional&#40;bool, false&#41;&#10; teams &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | |
| [federated_identity_providers](variables.tf#L113) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | <code title="map&#40;object&#40;&#123;&#10; attribute_condition &#61; optional&#40;string&#41;&#10; issuer &#61; string&#10; custom_settings &#61; optional&#40;object&#40;&#123;&#10; issuer_uri &#61; optional&#40;string&#41;&#10; allowed_audiences &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | | [federated_identity_providers](variables.tf#L113) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | <code title="map&#40;object&#40;&#123;&#10; attribute_condition &#61; optional&#40;string&#41;&#10; issuer &#61; string&#10; custom_settings &#61; optional&#40;object&#40;&#123;&#10; issuer_uri &#61; optional&#40;string&#41;&#10; audiences &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [groups](variables.tf#L132) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code>map&#40;string&#41;</code> | | <code title="&#123;&#10; gcp-billing-admins &#61; &#34;gcp-billing-admins&#34;,&#10; gcp-devops &#61; &#34;gcp-devops&#34;,&#10; gcp-network-admins &#61; &#34;gcp-network-admins&#34;&#10; gcp-organization-admins &#61; &#34;gcp-organization-admins&#34;&#10; gcp-security-admins &#61; &#34;gcp-security-admins&#34;&#10; gcp-support &#61; &#34;gcp-devops&#34;&#10;&#125;">&#123;&#8230;&#125;</code> | | | [groups](variables.tf#L132) | Group names or emails to grant organization-level permissions. If just the name is provided, the default organization domain is assumed. | <code>map&#40;string&#41;</code> | | <code title="&#123;&#10; gcp-billing-admins &#61; &#34;gcp-billing-admins&#34;,&#10; gcp-devops &#61; &#34;gcp-devops&#34;,&#10; gcp-network-admins &#61; &#34;gcp-network-admins&#34;&#10; gcp-organization-admins &#61; &#34;gcp-organization-admins&#34;&#10; gcp-security-admins &#61; &#34;gcp-security-admins&#34;&#10; gcp-support &#61; &#34;gcp-devops&#34;&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [iam](variables.tf#L150) | Organization-level custom IAM settings in role => [principal] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | | [iam](variables.tf#L150) | Organization-level custom IAM settings in role => [principal] format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
| [iam_additive](variables.tf#L156) | Organization-level custom IAM settings in role => [principal] format for non-authoritative bindings. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | | [iam_additive](variables.tf#L156) | Organization-level custom IAM settings in role => [principal] format for non-authoritative bindings. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | |
@ -529,14 +529,14 @@ The remaining configuration is manual, as it regards the repositories themselves
| name | description | sensitive | consumers | | name | description | sensitive | consumers |
|---|---|:---:|---| |---|---|:---:|---|
| [automation](outputs.tf#L100) | Automation resources. | | | | [automation](outputs.tf#L102) | Automation resources. | | |
| [billing_dataset](outputs.tf#L105) | BigQuery dataset prepared for billing export. | | | | [billing_dataset](outputs.tf#L107) | BigQuery dataset prepared for billing export. | | |
| [cicd_repositories](outputs.tf#L110) | CI/CD repository configurations. | | | | [cicd_repositories](outputs.tf#L112) | CI/CD repository configurations. | | |
| [custom_roles](outputs.tf#L122) | Organization-level custom roles. | | | | [custom_roles](outputs.tf#L124) | Organization-level custom roles. | | |
| [federated_identity](outputs.tf#L127) | Workload Identity Federation pool and providers. | | | | [federated_identity](outputs.tf#L129) | Workload Identity Federation pool and providers. | | |
| [outputs_bucket](outputs.tf#L137) | GCS bucket where generated output files are stored. | | | | [outputs_bucket](outputs.tf#L139) | GCS bucket where generated output files are stored. | | |
| [project_ids](outputs.tf#L142) | Projects created by this stage. | | | | [project_ids](outputs.tf#L144) | Projects created by this stage. | | |
| [providers](outputs.tf#L152) | Terraform provider files for this stage and dependent stages. | ✓ | <code>stage-01</code> | | [providers](outputs.tf#L154) | Terraform provider files for this stage and dependent stages. | ✓ | <code>stage-01</code> |
| [service_accounts](outputs.tf#L159) | Automation service accounts created by this stage. | | | | [service_accounts](outputs.tf#L161) | Automation service accounts created by this stage. | | |
| [tfvars](outputs.tf#L168) | Terraform variable files for the following stages. | ✓ | | | [tfvars](outputs.tf#L170) | Terraform variable files for the following stages. | ✓ | |
<!-- END TFDOC --> <!-- END TFDOC -->

View File

@ -20,9 +20,9 @@ locals {
cicd_providers = { cicd_providers = {
for k, v in google_iam_workload_identity_pool_provider.default : for k, v in google_iam_workload_identity_pool_provider.default :
k => { k => {
audience = try( audiences = concat(
v.oidc[0].allowed_audiences[0], v.oidc[0].allowed_audiences,
"https://iam.googleapis.com/${v.name}" ["https://iam.googleapis.com/${v.name}"]
) )
issuer = local.identity_providers[k].issuer issuer = local.identity_providers[k].issuer
issuer_uri = try(v.oidc[0].issuer_uri, null) issuer_uri = try(v.oidc[0].issuer_uri, null)
@ -39,10 +39,15 @@ locals {
( (
try(v.type, null) == "sourcerepo" try(v.type, null) == "sourcerepo"
|| ||
contains(keys(local.identity_providers), coalesce(try(v.identity_provider, null), ":")) contains(
keys(local.identity_providers),
coalesce(try(v.identity_provider, null), ":")
)
) )
&& &&
fileexists(format("${path.module}/templates/workflow-%s.yaml", try(v.type, ""))) fileexists(
format("${path.module}/templates/workflow-%s.yaml", try(v.type, ""))
)
) )
} }
cicd_workflow_providers = { cicd_workflow_providers = {

View File

@ -82,7 +82,7 @@ resource "google_iam_workload_identity_pool_provider" "default" {
attribute_mapping = each.value.attribute_mapping attribute_mapping = each.value.attribute_mapping
oidc { oidc {
# Setting an empty list configures allowed_audiences to the url of the provider # Setting an empty list configures allowed_audiences to the url of the provider
allowed_audiences = each.value.custom_settings.allowed_audiences allowed_audiences = each.value.custom_settings.audiences
# If users don't provide an issuer_uri, we set the public one for the plaform choosed. # If users don't provide an issuer_uri, we set the public one for the plaform choosed.
issuer_uri = ( issuer_uri = (
each.value.custom_settings.issuer_uri != null each.value.custom_settings.issuer_uri != null

View File

@ -22,7 +22,9 @@ locals {
"${path.module}/templates/workflow-${v.type}.yaml", { "${path.module}/templates/workflow-${v.type}.yaml", {
# If users give a list of custom audiences we set by default the first element. # If users give a list of custom audiences we set by default the first element.
# If no audiences are given, we set https://iam.googleapis.com/{PROVIDER_NAME} # If no audiences are given, we set https://iam.googleapis.com/{PROVIDER_NAME}
audience = local.cicd_providers[v["identity_provider"]].audience audiences = try(
local.cicd_providers[v["identity_provider"]].audiences, ""
)
identity_provider = try( identity_provider = try(
local.cicd_providers[v["identity_provider"]].name, "" local.cicd_providers[v["identity_provider"]].name, ""
) )

View File

@ -20,13 +20,14 @@ default:
- "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
variables: variables:
AUDIENCE: ${audience}
GOOGLE_CREDENTIALS: cicd-sa-credentials.json GOOGLE_CREDENTIALS: cicd-sa-credentials.json
FAST_OUTPUTS_BUCKET: ${outputs_bucket} FAST_OUTPUTS_BUCKET: ${outputs_bucket}
FAST_SERVICE_ACCOUNT: ${service_account} FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider} FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock SSH_AUTH_SOCK: /tmp/ssh_agent.sock
%{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file} TF_PROVIDERS_FILE: ${tf_providers_file}
%{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)} TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
stages: stages:
@ -38,16 +39,27 @@ stages:
cache: cache:
key: gcp-auth key: gcp-auth
paths: paths:
- .tf-setup - cicd-sa-credentials.json
- token.txt
%{~ if tf_providers_file != "" ~}
- ${tf_providers_file}
%{~ endif ~}
%{~ for f in tf_var_files ~}
- ${f}
%{~ endfor ~}
gcp-auth: gcp-auth:
stage: gcp-auth
id_tokens: id_tokens:
GITLAB_TOKEN: GITLAB_TOKEN:
aud: "$${AUDIENCE}" aud:
%{~ for aud in audiences ~}
- ${aud}
%{~ endfor ~}
image: image:
name: google/cloud-sdk:slim name: google/cloud-sdk:slim
stage: gcp-auth
script: script:
- echo "$${GITLAB_TOKEN}" > token.txt
- | - |
gcloud iam workload-identity-pools create-cred-config \ gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \ $${FAST_WIF_PROVIDER} \
@ -55,30 +67,27 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \ --service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \ --output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt --credential-source-file=token.txt
- rm token.txt
artifacts:
untracked: true
tf-files: tf-files:
stage: tf-files dependencies:
- gcp-auth
image: image:
name: google/cloud-sdk:slim name: google/cloud-sdk:slim
stage: tf-files
script: script:
# - gcloud components install -q alpha # - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS} - gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- mkdir -p .tf-setup %{~ if tf_providers_file != "" ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
gcloud alpha storage cp -r \ %{~ endif ~}
"gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/ %{~ for f in tf_var_files ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
gcloud alpha storage cp -r \ %{~ endfor ~}
"gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/ - ls -l
artifacts:
untracked: true
dependencies:
- gcp-auth
tf-plan: tf-plan:
dependencies:
- tf-files
stage: tf-plan stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
@ -89,20 +98,13 @@ tf-plan:
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script: script:
- cp ".tf-setup/$${TF_PROVIDERS_FILE}" ./
- |
for f in "$${TF_VAR_FILES}"; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform plan - terraform plan
artifacts:
untracked: true
dependencies:
- tf-files
tf-apply: tf-apply:
dependencies:
- tf-files
stage: tf-apply stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
@ -113,18 +115,9 @@ tf-apply:
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script: script:
- cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- |
for f in $${TF_VAR_FILES}; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform apply -input=false -auto-approve - terraform apply -input=false -auto-approve
artifacts:
untracked: true
dependencies:
- tf-files
when: manual when: manual
only: only:
variables: variables:

View File

@ -117,7 +117,7 @@ variable "federated_identity_providers" {
issuer = string issuer = string
custom_settings = optional(object({ custom_settings = optional(object({
issuer_uri = optional(string) issuer_uri = optional(string)
allowed_audiences = optional(list(string), []) audiences = optional(list(string), [])
}), {}) }), {})
})) }))
default = {} default = {}

View File

@ -365,7 +365,7 @@ Due to its simplicity, this stage lends itself easily to customizations: adding
| name | description | type | required | default | producer | | name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|:---:|
| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | <code title="object&#40;&#123;&#10; outputs_bucket &#61; string&#10; project_id &#61; string&#10; project_number &#61; string&#10; federated_identity_pool &#61; string&#10; federated_identity_providers &#61; map&#40;object&#40;&#123;&#10; audience &#61; string&#10; issuer &#61; string&#10; issuer_uri &#61; string&#10; name &#61; string&#10; principal_tpl &#61; string&#10; principalset_tpl &#61; string&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> | | [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | <code title="object&#40;&#123;&#10; outputs_bucket &#61; string&#10; project_id &#61; string&#10; project_number &#61; string&#10; federated_identity_pool &#61; string&#10; federated_identity_providers &#61; map&#40;object&#40;&#123;&#10; audiences &#61; list&#40;string&#41;&#10; issuer &#61; string&#10; issuer_uri &#61; string&#10; name &#61; string&#10; principal_tpl &#61; string&#10; principalset_tpl &#61; string&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> |
| [billing_account](variables.tf#L39) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | <code title="object&#40;&#123;&#10; id &#61; string&#10; is_org_level &#61; optional&#40;bool, true&#41;&#10; no_iam &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> | | [billing_account](variables.tf#L39) | Billing account id. If billing account is not part of the same org set `is_org_level` to `false`. To disable handling of billing IAM roles set `no_iam` to `true`. | <code title="object&#40;&#123;&#10; id &#61; string&#10; is_org_level &#61; optional&#40;bool, true&#41;&#10; no_iam &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> |
| [organization](variables.tf#L192) | Organization details. | <code title="object&#40;&#123;&#10; domain &#61; string&#10; id &#61; number&#10; customer_id &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> | | [organization](variables.tf#L192) | Organization details. | <code title="object&#40;&#123;&#10; domain &#61; string&#10; id &#61; number&#10; customer_id &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | <code>0-bootstrap</code> |
| [prefix](variables.tf#L216) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> | | [prefix](variables.tf#L216) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |

View File

@ -62,8 +62,8 @@ locals {
for k, v in local.cicd_repositories : k => templatefile( for k, v in local.cicd_repositories : k => templatefile(
"${path.module}/templates/workflow-${v.type}.yaml", "${path.module}/templates/workflow-${v.type}.yaml",
merge(local.cicd_workflow_attrs[k], { merge(local.cicd_workflow_attrs[k], {
audience = try( audiences = try(
local.identity_providers[v.identity_provider].audience, null local.identity_providers[v.identity_provider].audiences, null
) )
identity_provider = try( identity_provider = try(
local.identity_providers[v.identity_provider].name, null local.identity_providers[v.identity_provider].name, null

View File

@ -20,13 +20,14 @@ default:
- "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
variables: variables:
AUDIENCE: ${audience}
GOOGLE_CREDENTIALS: cicd-sa-credentials.json GOOGLE_CREDENTIALS: cicd-sa-credentials.json
FAST_OUTPUTS_BUCKET: ${outputs_bucket} FAST_OUTPUTS_BUCKET: ${outputs_bucket}
FAST_SERVICE_ACCOUNT: ${service_account} FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider} FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock SSH_AUTH_SOCK: /tmp/ssh_agent.sock
%{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file} TF_PROVIDERS_FILE: ${tf_providers_file}
%{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)} TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
stages: stages:
@ -38,16 +39,27 @@ stages:
cache: cache:
key: gcp-auth key: gcp-auth
paths: paths:
- .tf-setup - cicd-sa-credentials.json
- token.txt
%{~ if tf_providers_file != "" ~}
- ${tf_providers_file}
%{~ endif ~}
%{~ for f in tf_var_files ~}
- ${f}
%{~ endfor ~}
gcp-auth: gcp-auth:
stage: gcp-auth
id_tokens: id_tokens:
GITLAB_TOKEN: GITLAB_TOKEN:
aud: "$${AUDIENCE}" aud:
%{~ for aud in audiences ~}
- ${aud}
%{~ endfor ~}
image: image:
name: google/cloud-sdk:slim name: google/cloud-sdk:slim
stage: gcp-auth
script: script:
- echo "$${GITLAB_TOKEN}" > token.txt
- | - |
gcloud iam workload-identity-pools create-cred-config \ gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \ $${FAST_WIF_PROVIDER} \
@ -55,30 +67,27 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \ --service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \ --output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt --credential-source-file=token.txt
- rm token.txt
artifacts:
untracked: true
tf-files: tf-files:
stage: tf-files dependencies:
- gcp-auth
image: image:
name: google/cloud-sdk:slim name: google/cloud-sdk:slim
stage: tf-files
script: script:
# - gcloud components install -q alpha # - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS} - gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- mkdir -p .tf-setup %{~ if tf_providers_file != "" ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
gcloud alpha storage cp -r \ %{~ endif ~}
"gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/ %{~ for f in tf_var_files ~}
- | - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
gcloud alpha storage cp -r \ %{~ endfor ~}
"gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/ - ls -l
artifacts:
untracked: true
dependencies:
- gcp-auth
tf-plan: tf-plan:
dependencies:
- tf-files
stage: tf-plan stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
@ -89,20 +98,13 @@ tf-plan:
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script: script:
- cp ".tf-setup/$${TF_PROVIDERS_FILE}" ./
- |
for f in "$${TF_VAR_FILES}"; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform plan - terraform plan
artifacts:
untracked: true
dependencies:
- tf-files
tf-apply: tf-apply:
dependencies:
- tf-files
stage: tf-apply stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo # uncomment the following lines and set the SSH key secret for private modules repo
# before_script: # before_script:
@ -113,18 +115,9 @@ tf-apply:
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts # ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts # ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script: script:
- cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- |
for f in $${TF_VAR_FILES}; do
ln -s ".tf-setup/tfvars/$f" ./
done
- terraform init - terraform init
- terraform validate - terraform validate
- terraform apply -input=false -auto-approve - terraform apply -input=false -auto-approve
artifacts:
untracked: true
dependencies:
- tf-files
when: manual when: manual
only: only:
variables: variables:

View File

@ -26,7 +26,7 @@ variable "automation" {
project_number = string project_number = string
federated_identity_pool = string federated_identity_pool = string
federated_identity_providers = map(object({ federated_identity_providers = map(object({
audience = string audiences = list(string)
issuer = string issuer = string
issuer_uri = string issuer_uri = string
name = string name = string

View File

@ -83,7 +83,7 @@ By default, the design assumes the following:
- cross-environment traffic and traffic from any untrusted network to any trusted network (and vice versa) pass through the NVAs. For demo purposes, the current NVA performs simple routing/natting only - cross-environment traffic and traffic from any untrusted network to any trusted network (and vice versa) pass through the NVAs. For demo purposes, the current NVA performs simple routing/natting only
- any traffic from a trusted network to an untrusted network (e.g. Internet) is natted by the NVAs. Users can configure further exclusions - any traffic from a trusted network to an untrusted network (e.g. Internet) is natted by the NVAs. Users can configure further exclusions
The trusted landing VPC acts as a hub: it bridges internal resources with the outside world and it hosts the shared services consumed by the spoke VPCs, connected to the hub thorugh VPC network peerings. Spokes are used to partition the environments. By default: The trusted landing VPC acts as a hub: it bridges internal resources with the outside world and it hosts the shared services consumed by the spoke VPCs, connected to the hub through VPC network peerings. Spokes are used to partition the environments. By default:
- one spoke VPC hosts the development environment resources - one spoke VPC hosts the development environment resources
- one spoke VPC hosts the production environment resources - one spoke VPC hosts the production environment resources

View File

@ -37,6 +37,7 @@ The final number of subnets, and their IP addressing will depend on the user-spe
- [Design overview and choices](#design-overview-and-choices) - [Design overview and choices](#design-overview-and-choices)
- [Multi-regional deployment](#multi-regional-deployment) - [Multi-regional deployment](#multi-regional-deployment)
- [VPC design](#vpc-design) - [VPC design](#vpc-design)
- [NCC, NVAs and BGP sessions](#ncc-nvas-and-bgp-sessions)
- [External connectivity](#external-connectivity) - [External connectivity](#external-connectivity)
- [Internal connectivity](#internal-connectivity) - [Internal connectivity](#internal-connectivity)
- [IP ranges, subnetting, routing](#ip-ranges-subnetting-routing) - [IP ranges, subnetting, routing](#ip-ranges-subnetting-routing)
@ -105,7 +106,7 @@ By default, the design assumes that:
- cross-spoke (environment) traffic and traffic from any untrusted network to any trusted network (and vice versa) pass through the NVAs. - cross-spoke (environment) traffic and traffic from any untrusted network to any trusted network (and vice versa) pass through the NVAs.
- any traffic from a trusted network to an untrusted network (e.g. Internet) is natted by the NVAs. Users can configure further exclusions. - any traffic from a trusted network to an untrusted network (e.g. Internet) is natted by the NVAs. Users can configure further exclusions.
The trusted landing VPC acts as a hub: it bridges internal resources with the outside world and it hosts the shared services consumed by the spoke VPCs, connected to the hub thorugh VPC network peerings. Spokes are used to partition the environments. By default: The trusted landing VPC acts as a hub: it bridges internal resources with the outside world and it hosts the shared services consumed by the spoke VPCs, connected to the hub through VPC network peerings. Spokes are used to partition the environments. By default:
- one spoke VPC hosts the development environment resources - one spoke VPC hosts the development environment resources
- one spoke VPC hosts the production environment resources - one spoke VPC hosts the production environment resources

View File

@ -95,12 +95,12 @@ The commands to link or copy the provider and terraform variable files can be ea
# copy and paste the following commands for '3-data-platform' # copy and paste the following commands for '3-data-platform'
ln -s /home/ludomagno/fast-config/providers/3-data-platform-providers.tf ./ ln -s ~/fast-config/providers/3-data-platform-providers.tf ./
ln -s /home/ludomagno/fast-config/tfvars/globals.auto.tfvars.json ./ ln -s ~/fast-config/tfvars/globals.auto.tfvars.json ./
ln -s /home/ludomagno/fast-config/tfvars/0-bootstrap.auto.tfvars.json ./ ln -s ~/fast-config/tfvars/0-bootstrap.auto.tfvars.json ./
ln -s /home/ludomagno/fast-config/tfvars/1-resman.auto.tfvars.json ./ ln -s ~/fast-config/tfvars/1-resman.auto.tfvars.json ./
ln -s /home/ludomagno/fast-config/tfvars/2-networking.auto.tfvars.json ./ ln -s ~/fast-config/tfvars/2-networking.auto.tfvars.json ./
ln -s /home/ludomagno/fast-config/tfvars/2-security.auto.tfvars.json ./ ln -s ~/fast-config/tfvars/2-security.auto.tfvars.json ./
``` ```
```bash ```bash

View File

@ -246,7 +246,7 @@ module "bigtable-instance" {
| name | description | sensitive | | name | description | sensitive |
|---|---|:---:| |---|---|:---:|
| [id](outputs.tf#L17) | Fully qualified instance id. | | | [id](outputs.tf#L17) | Fully qualified instance id. | |
| [instance](outputs.tf#L26) | BigTable intance. | | | [instance](outputs.tf#L26) | BigTable instance. | |
| [table_ids](outputs.tf#L35) | Map of fully qualified table ids keyed by table name. | | | [table_ids](outputs.tf#L35) | Map of fully qualified table ids keyed by table name. | |
| [tables](outputs.tf#L40) | Table resources. | | | [tables](outputs.tf#L40) | Table resources. | |

View File

@ -24,7 +24,7 @@ output "id" {
} }
output "instance" { output "instance" {
description = "BigTable intance." description = "BigTable instance."
value = google_bigtable_instance.default value = google_bigtable_instance.default
depends_on = [ depends_on = [
google_bigtable_instance_iam_binding.default, google_bigtable_instance_iam_binding.default,

View File

@ -352,10 +352,11 @@ module "cloud_run" {
| [revision_name](variables.tf#L177) | Revision name. | <code>string</code> | | <code>null</code> | | [revision_name](variables.tf#L177) | Revision name. | <code>string</code> | | <code>null</code> |
| [service_account](variables.tf#L183) | Service account email. Unused if service account is auto-created. | <code>string</code> | | <code>null</code> | | [service_account](variables.tf#L183) | Service account email. Unused if service account is auto-created. | <code>string</code> | | <code>null</code> |
| [service_account_create](variables.tf#L189) | Auto-create service account. | <code>bool</code> | | <code>false</code> | | [service_account_create](variables.tf#L189) | Auto-create service account. | <code>bool</code> | | <code>false</code> |
| [timeout_seconds](variables.tf#L195) | Maximum duration the instance is allowed for responding to a request. | <code>number</code> | | <code>null</code> | | [startup_cpu_boost](variables.tf#L195) | Enable startup cpu boost. | <code>bool</code> | | <code>false</code> |
| [traffic](variables.tf#L201) | Traffic steering configuration. If revision name is null the latest revision will be used. | <code title="map&#40;object&#40;&#123;&#10; percent &#61; number&#10; latest &#61; optional&#40;bool&#41;&#10; tag &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [timeout_seconds](variables.tf#L201) | Maximum duration the instance is allowed for responding to a request. | <code>number</code> | | <code>null</code> |
| [volumes](variables.tf#L212) | Named volumes in containers in name => attributes format. | <code title="map&#40;object&#40;&#123;&#10; secret_name &#61; string&#10; default_mode &#61; optional&#40;string&#41;&#10; items &#61; optional&#40;map&#40;object&#40;&#123;&#10; path &#61; string&#10; mode &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [traffic](variables.tf#L207) | Traffic steering configuration. If revision name is null the latest revision will be used. | <code title="map&#40;object&#40;&#123;&#10; percent &#61; number&#10; latest &#61; optional&#40;bool&#41;&#10; tag &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_connector_create](variables.tf#L226) | Populate this to create a VPC connector. You can then refer to it in the template annotations. | <code title="object&#40;&#123;&#10; ip_cidr_range &#61; optional&#40;string&#41;&#10; vpc_self_link &#61; optional&#40;string&#41;&#10; machine_type &#61; optional&#40;string&#41;&#10; name &#61; optional&#40;string&#41;&#10; instances &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; throughput &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; subnet &#61; optional&#40;object&#40;&#123;&#10; name &#61; optional&#40;string&#41;&#10; project_id &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | [volumes](variables.tf#L218) | Named volumes in containers in name => attributes format. | <code title="map&#40;object&#40;&#123;&#10; secret_name &#61; string&#10; default_mode &#61; optional&#40;string&#41;&#10; items &#61; optional&#40;map&#40;object&#40;&#123;&#10; path &#61; string&#10; mode &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [vpc_connector_create](variables.tf#L232) | Populate this to create a VPC connector. You can then refer to it in the template annotations. | <code title="object&#40;&#123;&#10; ip_cidr_range &#61; optional&#40;string&#41;&#10; vpc_self_link &#61; optional&#40;string&#41;&#10; machine_type &#61; optional&#40;string&#41;&#10; name &#61; optional&#40;string&#41;&#10; instances &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; throughput &#61; optional&#40;object&#40;&#123;&#10; max &#61; optional&#40;number&#41;&#10; min &#61; optional&#40;number&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; subnet &#61; optional&#40;object&#40;&#123;&#10; name &#61; optional&#40;string&#41;&#10; project_id &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
## Outputs ## Outputs

View File

@ -33,7 +33,7 @@ locals {
annotations = merge( annotations = merge(
var.ingress_settings == null ? {} : { var.ingress_settings == null ? {} : {
"run.googleapis.com/ingress" = var.ingress_settings "run.googleapis.com/ingress" = var.ingress_settings
} },
) )
_iam_run_invoker_members = concat( _iam_run_invoker_members = concat(
lookup(var.iam, "roles/run.invoker", []), lookup(var.iam, "roles/run.invoker", []),
@ -72,6 +72,9 @@ locals {
var.gen2_execution_environment ? { var.gen2_execution_environment ? {
"run.googleapis.com/execution-environment" = "gen2" "run.googleapis.com/execution-environment" = "gen2"
} : {}, } : {},
var.startup_cpu_boost ? {
"run.googleapis.com/startup-cpu-boost" = "true"
} : {},
) )
revision_name = ( revision_name = (
try(var.revision_name, null) == null try(var.revision_name, null) == null

View File

@ -192,6 +192,12 @@ variable "service_account_create" {
default = false default = false
} }
variable "startup_cpu_boost" {
description = "Enable startup cpu boost."
type = bool
default = false
}
variable "timeout_seconds" { variable "timeout_seconds" {
description = "Maximum duration the instance is allowed for responding to a request." description = "Maximum duration the instance is allowed for responding to a request."
type = number type = number

View File

@ -66,18 +66,18 @@ module "cmn-dc" {
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [name](variables.tf#L69) | Name of this taxonomy. | <code>string</code> | ✓ | | | [name](variables.tf#L74) | Name of this taxonomy. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L84) | GCP project id. | <code></code> | ✓ | | | [project_id](variables.tf#L89) | GCP project id. | <code></code> | ✓ | |
| [activated_policy_types](variables.tf#L17) | A list of policy types that are activated for this taxonomy. | <code>list&#40;string&#41;</code> | | <code>&#91;&#34;FINE_GRAINED_ACCESS_CONTROL&#34;&#93;</code> | | [activated_policy_types](variables.tf#L17) | A list of policy types that are activated for this taxonomy. | <code>list&#40;string&#41;</code> | | <code>&#91;&#34;FINE_GRAINED_ACCESS_CONTROL&#34;&#93;</code> |
| [description](variables.tf#L23) | Description of this taxonomy. | <code>string</code> | | <code>&#34;Taxonomy - Terraform managed&#34;</code> | | [description](variables.tf#L23) | Description of this taxonomy. | <code>string</code> | | <code>&#34;Taxonomy - Terraform managed&#34;</code> |
| [group_iam](variables.tf#L29) | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [group_iam](variables.tf#L29) | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam](variables.tf#L35) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam](variables.tf#L35) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive](variables.tf#L41) | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive](variables.tf#L41) | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive_members](variables.tf#L47) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive_members](variables.tf#L47) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_members](variables.tf#L53) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_members](variables.tf#L53) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [location](variables.tf#L63) | Data Catalog Taxonomy location. | <code>string</code> | | <code>&#34;eu&#34;</code> | | [location](variables.tf#L68) | Data Catalog Taxonomy location. | <code>string</code> | | <code>&#34;eu&#34;</code> |
| [prefix](variables.tf#L74) | Optional prefix used to generate project id and name. | <code>string</code> | | <code>null</code> | | [prefix](variables.tf#L79) | Optional prefix used to generate project id and name. | <code>string</code> | | <code>null</code> |
| [tags](variables.tf#L88) | List of Data Catalog Policy tags to be created with optional IAM binging configuration in {tag => {ROLE => [MEMBERS]}} format. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [tags](variables.tf#L93) | List of Data Catalog Policy tags to be created with optional IAM binging configuration in {tag => {ROLE => [MEMBERS]}} format. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
## Outputs ## Outputs

View File

@ -80,6 +80,14 @@ resource "google_data_catalog_taxonomy_iam_member" "members" {
taxonomy = google_data_catalog_taxonomy.default.id taxonomy = google_data_catalog_taxonomy.default.id
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }
resource "google_data_catalog_policy_tag_iam_binding" "authoritative" { resource "google_data_catalog_policy_tag_iam_binding" "authoritative" {

View File

@ -55,6 +55,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -433,9 +433,9 @@ module "dataplex-datascan" {
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [data](variables.tf#L17) | The data source for DataScan. The source can be either a Dataplex `entity` or a BigQuery `resource`. | <code title="object&#40;&#123;&#10; entity &#61; optional&#40;string&#41;&#10; resource &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | | [data](variables.tf#L17) | The data source for DataScan. The source can be either a Dataplex `entity` or a BigQuery `resource`. | <code title="object&#40;&#123;&#10; entity &#61; optional&#40;string&#41;&#10; resource &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [name](variables.tf#L156) | Name of Dataplex Scan. | <code>string</code> | ✓ | | | [name](variables.tf#L161) | Name of Dataplex Scan. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L167) | The ID of the project where the Dataplex DataScan will be created. | <code>string</code> | ✓ | | | [project_id](variables.tf#L172) | The ID of the project where the Dataplex DataScan will be created. | <code>string</code> | ✓ | |
| [region](variables.tf#L172) | Region for the Dataplex DataScan. | <code>string</code> | ✓ | | | [region](variables.tf#L177) | Region for the Dataplex DataScan. | <code>string</code> | ✓ | |
| [data_profile_spec](variables.tf#L29) | DataProfileScan related setting. Variable descriptions are provided in https://cloud.google.com/dataplex/docs/reference/rest/v1/DataProfileSpec. | <code title="object&#40;&#123;&#10; sampling_percent &#61; optional&#40;number&#41;&#10; row_filter &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | [data_profile_spec](variables.tf#L29) | DataProfileScan related setting. Variable descriptions are provided in https://cloud.google.com/dataplex/docs/reference/rest/v1/DataProfileSpec. | <code title="object&#40;&#123;&#10; sampling_percent &#61; optional&#40;number&#41;&#10; row_filter &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [data_quality_spec](variables.tf#L38) | DataQualityScan related setting. Variable descriptions are provided in https://cloud.google.com/dataplex/docs/reference/rest/v1/DataQualitySpec. | <code title="object&#40;&#123;&#10; sampling_percent &#61; optional&#40;number&#41;&#10; row_filter &#61; optional&#40;string&#41;&#10; rules &#61; list&#40;object&#40;&#123;&#10; column &#61; optional&#40;string&#41;&#10; ignore_null &#61; optional&#40;bool, null&#41;&#10; dimension &#61; string&#10; threshold &#61; optional&#40;number&#41;&#10; non_null_expectation &#61; optional&#40;object&#40;&#123;&#125;&#41;&#41;&#10; range_expectation &#61; optional&#40;object&#40;&#123;&#10; min_value &#61; optional&#40;number&#41;&#10; max_value &#61; optional&#40;number&#41;&#10; strict_min_enabled &#61; optional&#40;bool&#41;&#10; strict_max_enabled &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; regex_expectation &#61; optional&#40;object&#40;&#123;&#10; regex &#61; string&#10; &#125;&#41;&#41;&#10; set_expectation &#61; optional&#40;object&#40;&#123;&#10; values &#61; list&#40;string&#41;&#10; &#125;&#41;&#41;&#10; uniqueness_expectation &#61; optional&#40;object&#40;&#123;&#125;&#41;&#41;&#10; statistic_range_expectation &#61; optional&#40;object&#40;&#123;&#10; statistic &#61; string&#10; min_value &#61; optional&#40;number&#41;&#10; max_value &#61; optional&#40;number&#41;&#10; strict_min_enabled &#61; optional&#40;bool&#41;&#10; strict_max_enabled &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; row_condition_expectation &#61; optional&#40;object&#40;&#123;&#10; sql_expression &#61; string&#10; &#125;&#41;&#41;&#10; table_condition_expectation &#61; optional&#40;object&#40;&#123;&#10; sql_expression &#61; string&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | [data_quality_spec](variables.tf#L38) | DataQualityScan related setting. Variable descriptions are provided in https://cloud.google.com/dataplex/docs/reference/rest/v1/DataQualitySpec. | <code title="object&#40;&#123;&#10; sampling_percent &#61; optional&#40;number&#41;&#10; row_filter &#61; optional&#40;string&#41;&#10; rules &#61; list&#40;object&#40;&#123;&#10; column &#61; optional&#40;string&#41;&#10; ignore_null &#61; optional&#40;bool, null&#41;&#10; dimension &#61; string&#10; threshold &#61; optional&#40;number&#41;&#10; non_null_expectation &#61; optional&#40;object&#40;&#123;&#125;&#41;&#41;&#10; range_expectation &#61; optional&#40;object&#40;&#123;&#10; min_value &#61; optional&#40;number&#41;&#10; max_value &#61; optional&#40;number&#41;&#10; strict_min_enabled &#61; optional&#40;bool&#41;&#10; strict_max_enabled &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; regex_expectation &#61; optional&#40;object&#40;&#123;&#10; regex &#61; string&#10; &#125;&#41;&#41;&#10; set_expectation &#61; optional&#40;object&#40;&#123;&#10; values &#61; list&#40;string&#41;&#10; &#125;&#41;&#41;&#10; uniqueness_expectation &#61; optional&#40;object&#40;&#123;&#125;&#41;&#41;&#10; statistic_range_expectation &#61; optional&#40;object&#40;&#123;&#10; statistic &#61; string&#10; min_value &#61; optional&#40;number&#41;&#10; max_value &#61; optional&#40;number&#41;&#10; strict_min_enabled &#61; optional&#40;bool&#41;&#10; strict_max_enabled &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; row_condition_expectation &#61; optional&#40;object&#40;&#123;&#10; sql_expression &#61; string&#10; &#125;&#41;&#41;&#10; table_condition_expectation &#61; optional&#40;object&#40;&#123;&#10; sql_expression &#61; string&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [data_quality_spec_file](variables.tf#L80) | Path to a YAML file containing DataQualityScan related setting. Input content can use either camelCase or snake_case. Variables description are provided in https://cloud.google.com/dataplex/docs/reference/rest/v1/DataQualitySpec. | <code title="object&#40;&#123;&#10; path &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | [data_quality_spec_file](variables.tf#L80) | Path to a YAML file containing DataQualityScan related setting. Input content can use either camelCase or snake_case. Variables description are provided in https://cloud.google.com/dataplex/docs/reference/rest/v1/DataQualitySpec. | <code title="object&#40;&#123;&#10; path &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
@ -445,11 +445,11 @@ module "dataplex-datascan" {
| [iam](variables.tf#L107) | Dataplex DataScan IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam](variables.tf#L107) | Dataplex DataScan IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive](variables.tf#L114) | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive](variables.tf#L114) | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive_members](variables.tf#L121) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive_members](variables.tf#L121) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_members](variables.tf#L127) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_members](variables.tf#L127) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_policy](variables.tf#L137) | IAM authoritative policy in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared, use with extreme caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> | | [iam_policy](variables.tf#L142) | IAM authoritative policy in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared, use with extreme caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> |
| [incremental_field](variables.tf#L143) | The unnested field (of type Date or Timestamp) that contains values which monotonically increase over time. If not specified, a data scan will run for all data in the table. | <code>string</code> | | <code>null</code> | | [incremental_field](variables.tf#L148) | The unnested field (of type Date or Timestamp) that contains values which monotonically increase over time. If not specified, a data scan will run for all data in the table. | <code>string</code> | | <code>null</code> |
| [labels](variables.tf#L149) | Resource labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> | | [labels](variables.tf#L154) | Resource labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [prefix](variables.tf#L161) | Optional prefix used to generate Dataplex DataScan ID. | <code>string</code> | | <code>null</code> | | [prefix](variables.tf#L166) | Optional prefix used to generate Dataplex DataScan ID. | <code>string</code> | | <code>null</code> |
## Outputs ## Outputs

View File

@ -76,6 +76,14 @@ resource "google_dataplex_datascan_iam_member" "members" {
data_scan_id = google_dataplex_datascan.datascan.data_scan_id data_scan_id = google_dataplex_datascan.datascan.data_scan_id
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }
resource "google_dataplex_datascan_iam_policy" "authoritative_for_resource" { resource "google_dataplex_datascan_iam_policy" "authoritative_for_resource" {

View File

@ -129,6 +129,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

File diff suppressed because one or more lines are too long

View File

@ -72,4 +72,12 @@ resource "google_dataproc_cluster_iam_member" "members" {
cluster = google_dataproc_cluster.cluster.name cluster = google_dataproc_cluster.cluster.name
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }

View File

@ -208,6 +208,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -325,17 +325,17 @@ module "folder" {
| [iam](variables.tf#L44) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam](variables.tf#L44) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive](variables.tf#L51) | Non authoritative IAM bindings, in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive](variables.tf#L51) | Non authoritative IAM bindings, in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive_members](variables.tf#L58) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive_members](variables.tf#L58) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_members](variables.tf#L65) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_members](variables.tf#L65) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_policy](variables.tf#L75) | IAM authoritative policy in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared, use with extreme caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> | | [iam_policy](variables.tf#L80) | IAM authoritative policy in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared, use with extreme caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> |
| [id](variables.tf#L81) | Folder ID in case you use folder_create=false. | <code>string</code> | | <code>null</code> | | [id](variables.tf#L86) | Folder ID in case you use folder_create=false. | <code>string</code> | | <code>null</code> |
| [logging_data_access](variables.tf#L87) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [logging_data_access](variables.tf#L92) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_exclusions](variables.tf#L102) | Logging exclusions for this folder in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> | | [logging_exclusions](variables.tf#L107) | Logging exclusions for this folder in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L109) | Logging sinks to create for the organization. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [logging_sinks](variables.tf#L114) | Logging sinks to create for the organization. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [name](variables.tf#L139) | Folder name. | <code>string</code> | | <code>null</code> | | [name](variables.tf#L144) | Folder name. | <code>string</code> | | <code>null</code> |
| [org_policies](variables.tf#L145) | Organization policies applied to this folder 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; 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&#41; &#35; for boolean policies only.&#10; condition &#61; optional&#40;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;, &#123;&#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](variables.tf#L150) | Organization policies applied to this folder 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; 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&#41; &#35; for boolean policies only.&#10; condition &#61; optional&#40;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;, &#123;&#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#L172) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> | | [org_policies_data_path](variables.tf#L177) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
| [parent](variables.tf#L178) | Parent in folders/folder_id or organizations/org_id format. | <code>string</code> | | <code>null</code> | | [parent](variables.tf#L183) | Parent in folders/folder_id or organizations/org_id format. | <code>string</code> | | <code>null</code> |
| [tag_bindings](variables.tf#L188) | Tag bindings for this folder, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> | | [tag_bindings](variables.tf#L193) | Tag bindings for this folder, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
## Outputs ## Outputs

View File

@ -69,6 +69,14 @@ resource "google_folder_iam_member" "members" {
folder = local.folder.name folder = local.folder.name
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }
resource "google_folder_iam_policy" "authoritative" { resource "google_folder_iam_policy" "authoritative" {

View File

@ -67,6 +67,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -41,8 +41,8 @@ module "myproject-default-service-accounts" {
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [name](variables.tf#L101) | Name of the service account to create. | <code>string</code> | ✓ | | | [name](variables.tf#L106) | Name of the service account to create. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L116) | Project id where service account will be created. | <code>string</code> | ✓ | | | [project_id](variables.tf#L121) | Project id where service account will be created. | <code>string</code> | ✓ | |
| [description](variables.tf#L17) | Optional description. | <code>string</code> | | <code>null</code> | | [description](variables.tf#L17) | Optional description. | <code>string</code> | | <code>null</code> |
| [display_name](variables.tf#L23) | Display name of the service account to create. | <code>string</code> | | <code>&#34;Terraform-managed.&#34;</code> | | [display_name](variables.tf#L23) | Display name of the service account to create. | <code>string</code> | | <code>&#34;Terraform-managed.&#34;</code> |
| [generate_key](variables.tf#L29) | Generate a key for service account. | <code>bool</code> | | <code>false</code> | | [generate_key](variables.tf#L29) | Generate a key for service account. | <code>bool</code> | | <code>false</code> |
@ -50,14 +50,14 @@ module "myproject-default-service-accounts" {
| [iam_additive](variables.tf#L42) | IAM additive bindings on the service account in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive](variables.tf#L42) | IAM additive bindings on the service account in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_billing_roles](variables.tf#L49) | Billing account roles granted to this service account, by billing account id. Non-authoritative. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_billing_roles](variables.tf#L49) | Billing account roles granted to this service account, by billing account id. Non-authoritative. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_folder_roles](variables.tf#L56) | Folder roles granted to this service account, by folder id. Non-authoritative. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_folder_roles](variables.tf#L56) | Folder roles granted to this service account, by folder id. Non-authoritative. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_members](variables.tf#L63) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_members](variables.tf#L63) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_organization_roles](variables.tf#L73) | Organization roles granted to this service account, by organization id. Non-authoritative. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_organization_roles](variables.tf#L78) | Organization roles granted to this service account, by organization id. Non-authoritative. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_project_roles](variables.tf#L80) | Project roles granted to this service account, by project id. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_project_roles](variables.tf#L85) | Project roles granted to this service account, by project id. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_sa_roles](variables.tf#L87) | Service account roles granted to this service account, by service account name. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_sa_roles](variables.tf#L92) | Service account roles granted to this service account, by service account name. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_storage_roles](variables.tf#L94) | Storage roles granted to this service account, by bucket name. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_storage_roles](variables.tf#L99) | Storage roles granted to this service account, by bucket name. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [prefix](variables.tf#L106) | Prefix applied to service account names. | <code>string</code> | | <code>null</code> | | [prefix](variables.tf#L111) | Prefix applied to service account names. | <code>string</code> | | <code>null</code> |
| [public_keys_directory](variables.tf#L121) | Path to public keys data files to upload to the service account (should have `.pem` extension). | <code>string</code> | | <code>&#34;&#34;</code> | | [public_keys_directory](variables.tf#L126) | Path to public keys data files to upload to the service account (should have `.pem` extension). | <code>string</code> | | <code>&#34;&#34;</code> |
| [service_account_create](variables.tf#L127) | Create service account. When set to false, uses a data source to reference an existing service account. | <code>bool</code> | | <code>true</code> | | [service_account_create](variables.tf#L132) | Create service account. When set to false, uses a data source to reference an existing service account. | <code>bool</code> | | <code>true</code> |
## Outputs ## Outputs

View File

@ -139,6 +139,14 @@ resource "google_service_account_iam_member" "members" {
service_account_id = each.value.entity service_account_id = each.value.entity
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }
resource "google_storage_bucket_iam_member" "bucket-roles" { resource "google_storage_bucket_iam_member" "bucket-roles" {

View File

@ -65,6 +65,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -101,19 +101,19 @@ module "kms" {
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [keyring](variables.tf#L91) | Keyring attributes. | <code title="object&#40;&#123;&#10; location &#61; string&#10; name &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | | | [keyring](variables.tf#L101) | Keyring attributes. | <code title="object&#40;&#123;&#10; location &#61; string&#10; name &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | ✓ | |
| [project_id](variables.tf#L114) | Project id where the keyring will be created. | <code>string</code> | ✓ | | | [project_id](variables.tf#L124) | Project id where the keyring will be created. | <code>string</code> | ✓ | |
| [iam](variables.tf#L17) | Keyring IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam](variables.tf#L17) | Keyring IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive](variables.tf#L23) | Keyring IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive](variables.tf#L23) | Keyring IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_members](variables.tf#L29) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_members](variables.tf#L29) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [key_iam](variables.tf#L39) | Key IAM bindings in {KEY => {ROLE => [MEMBERS]}} format. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [key_iam](variables.tf#L44) | Key IAM bindings in {KEY => {ROLE => [MEMBERS]}} format. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [key_iam_additive](variables.tf#L45) | Key IAM additive bindings in {KEY => {ROLE => [MEMBERS]}} format. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [key_iam_additive](variables.tf#L50) | Key IAM additive bindings in {KEY => {ROLE => [MEMBERS]}} format. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [key_iam_members](variables.tf#L51) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; key &#61; string&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [key_iam_members](variables.tf#L56) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; key &#61; string&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [key_purpose](variables.tf#L62) | Per-key purpose, if not set defaults will be used. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | <code title="map&#40;object&#40;&#123;&#10; purpose &#61; string&#10; version_template &#61; object&#40;&#123;&#10; algorithm &#61; string&#10; protection_level &#61; string&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [key_purpose](variables.tf#L72) | Per-key purpose, if not set defaults will be used. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | <code title="map&#40;object&#40;&#123;&#10; purpose &#61; string&#10; version_template &#61; object&#40;&#123;&#10; algorithm &#61; string&#10; protection_level &#61; string&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [key_purpose_defaults](variables.tf#L74) | Defaults used for key purpose when not defined at the key level. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | <code title="object&#40;&#123;&#10; purpose &#61; string&#10; version_template &#61; object&#40;&#123;&#10; algorithm &#61; string&#10; protection_level &#61; string&#10; &#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; purpose &#61; null&#10; version_template &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> | | [key_purpose_defaults](variables.tf#L84) | Defaults used for key purpose when not defined at the key level. If purpose is not `ENCRYPT_DECRYPT` (the default), `version_template.algorithm` is required. | <code title="object&#40;&#123;&#10; purpose &#61; string&#10; version_template &#61; object&#40;&#123;&#10; algorithm &#61; string&#10; protection_level &#61; string&#10; &#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; purpose &#61; null&#10; version_template &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [keyring_create](variables.tf#L99) | Set to false to manage keys and IAM bindings in an existing keyring. | <code>bool</code> | | <code>true</code> | | [keyring_create](variables.tf#L109) | Set to false to manage keys and IAM bindings in an existing keyring. | <code>bool</code> | | <code>true</code> |
| [keys](variables.tf#L105) | Key names and base attributes. Set attributes to null if not needed. | <code title="map&#40;object&#40;&#123;&#10; rotation_period &#61; string&#10; labels &#61; map&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [keys](variables.tf#L115) | Key names and base attributes. Set attributes to null if not needed. | <code title="map&#40;object&#40;&#123;&#10; rotation_period &#61; string&#10; labels &#61; map&#40;string&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings](variables.tf#L119) | Tag bindings for this keyring, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> | | [tag_bindings](variables.tf#L129) | Tag bindings for this keyring, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
## Outputs ## Outputs

View File

@ -67,6 +67,14 @@ resource "google_kms_key_ring_iam_member" "members" {
key_ring_id = local.keyring.id key_ring_id = local.keyring.id
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }
resource "google_kms_crypto_key_iam_binding" "default" { resource "google_kms_crypto_key_iam_binding" "default" {
@ -94,4 +102,12 @@ resource "google_kms_crypto_key_iam_member" "members" {
crypto_key_id = google_kms_crypto_key.default[each.value.key].id crypto_key_id = google_kms_crypto_key.default[each.value.key].id
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }

View File

@ -31,6 +31,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}
@ -54,6 +59,11 @@ variable "key_iam_members" {
key = string key = string
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -541,11 +541,11 @@ module "vpc" {
| [shared_vpc_service_projects](variables.tf#L161) | Shared VPC service projects to register with this host. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [shared_vpc_service_projects](variables.tf#L161) | Shared VPC service projects to register with this host. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [subnet_iam](variables.tf#L167) | Subnet IAM bindings in {REGION/NAME => {ROLE => [MEMBERS]} format. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [subnet_iam](variables.tf#L167) | Subnet IAM bindings in {REGION/NAME => {ROLE => [MEMBERS]} format. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [subnet_iam_additive](variables.tf#L173) | Subnet IAM additive bindings in {REGION/NAME => {ROLE => [MEMBERS]}} format. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [subnet_iam_additive](variables.tf#L173) | Subnet IAM additive bindings in {REGION/NAME => {ROLE => [MEMBERS]}} format. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [subnet_iam_members](variables.tf#L180) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; subnet &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [subnet_iam_members](variables.tf#L180) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; subnet &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [subnets](variables.tf#L191) | Subnet configuration. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; enable_private_access &#61; optional&#40;bool, true&#41;&#10; flow_logs_config &#61; optional&#40;object&#40;&#123;&#10; aggregation_interval &#61; optional&#40;string&#41;&#10; filter_expression &#61; optional&#40;string&#41;&#10; flow_sampling &#61; optional&#40;number&#41;&#10; metadata &#61; optional&#40;string&#41;&#10; metadata_fields &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; ipv6 &#61; optional&#40;object&#40;&#123;&#10; access_type &#61; optional&#40;string, &#34;INTERNAL&#34;&#41;&#10; &#125;&#41;&#41;&#10; secondary_ip_ranges &#61; optional&#40;map&#40;string&#41;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> | | [subnets](variables.tf#L196) | Subnet configuration. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; enable_private_access &#61; optional&#40;bool, true&#41;&#10; flow_logs_config &#61; optional&#40;object&#40;&#123;&#10; aggregation_interval &#61; optional&#40;string&#41;&#10; filter_expression &#61; optional&#40;string&#41;&#10; flow_sampling &#61; optional&#40;number&#41;&#10; metadata &#61; optional&#40;string&#41;&#10; metadata_fields &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10; ipv6 &#61; optional&#40;object&#40;&#123;&#10; access_type &#61; optional&#40;string, &#34;INTERNAL&#34;&#41;&#10; &#125;&#41;&#41;&#10; secondary_ip_ranges &#61; optional&#40;map&#40;string&#41;&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_proxy_only](variables.tf#L217) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; active &#61; bool&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> | | [subnets_proxy_only](variables.tf#L222) | List of proxy-only subnets for Regional HTTPS or Internal HTTPS load balancers. Note: Only one proxy-only subnet for each VPC network in each region can be active. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10; active &#61; bool&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [subnets_psc](variables.tf#L229) | List of subnets for Private Service Connect service producers. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> | | [subnets_psc](variables.tf#L234) | List of subnets for Private Service Connect service producers. | <code title="list&#40;object&#40;&#123;&#10; name &#61; string&#10; ip_cidr_range &#61; string&#10; region &#61; string&#10; description &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [vpc_create](variables.tf#L240) | Create VPC. When set to false, uses a data source to reference existing VPC. | <code>bool</code> | | <code>true</code> | | [vpc_create](variables.tf#L245) | Create VPC. When set to false, uses a data source to reference existing VPC. | <code>bool</code> | | <code>true</code> |
## Outputs ## Outputs

View File

@ -197,4 +197,12 @@ resource "google_compute_subnetwork_iam_member" "members" {
region = google_compute_subnetwork.subnetwork[each.value.subnet].region region = google_compute_subnetwork.subnetwork[each.value.subnet].region
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }

View File

@ -183,6 +183,11 @@ variable "subnet_iam_members" {
member = string member = string
role = string role = string
subnet = string subnet = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -475,7 +475,7 @@ module "org" {
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [organization_id](variables.tf#L209) | Organization id in organizations/nnnnnn format. | <code>string</code> | ✓ | | | [organization_id](variables.tf#L214) | 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> | | [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> | | [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_policy_associations](variables.tf#L31) | Hierarchical firewall policies to associate to this folder, in association name => policy id format. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> | | [firewall_policy_associations](variables.tf#L31) | Hierarchical firewall policies to associate to this folder, in association name => policy id format. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
@ -483,18 +483,18 @@ module "org" {
| [iam](variables.tf#L45) | IAM bindings, in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam](variables.tf#L45) | IAM bindings, in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive](variables.tf#L52) | Non authoritative IAM bindings, in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive](variables.tf#L52) | Non authoritative IAM bindings, in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive_members](variables.tf#L59) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive_members](variables.tf#L59) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_members](variables.tf#L66) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_members](variables.tf#L66) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_policy](variables.tf#L76) | IAM authoritative policy in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared, use with extreme caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> | | [iam_policy](variables.tf#L81) | IAM authoritative policy in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared, use with extreme caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> |
| [logging_data_access](variables.tf#L82) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [logging_data_access](variables.tf#L87) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_exclusions](variables.tf#L97) | Logging exclusions for this organization in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> | | [logging_exclusions](variables.tf#L102) | Logging exclusions for this organization in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L104) | Logging sinks to create for the organization. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [logging_sinks](variables.tf#L109) | Logging sinks to create for the organization. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; include_children &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [network_tags](variables.tf#L134) | 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. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; id &#61; optional&#40;string&#41;&#10; network &#61; string &#35; project_id&#47;vpc_name&#10; values &#61; optional&#40;map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [network_tags](variables.tf#L139) | 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. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; id &#61; optional&#40;string&#41;&#10; network &#61; string &#35; project_id&#47;vpc_name&#10; values &#61; optional&#40;map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [org_policies](variables.tf#L156) | 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; 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&#41; &#35; for boolean policies only.&#10; condition &#61; optional&#40;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;, &#123;&#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](variables.tf#L161) | 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; 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&#41; &#35; for boolean policies only.&#10; condition &#61; optional&#40;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;, &#123;&#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#L183) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> | | [org_policies_data_path](variables.tf#L188) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
| [org_policy_custom_constraints](variables.tf#L189) | Organization policy 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](variables.tf#L194) | Organization policy 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#L203) | Path containing org policy custom constraints in YAML format. | <code>string</code> | | <code>null</code> | | [org_policy_custom_constraints_data_path](variables.tf#L208) | Path containing org policy custom constraints in YAML format. | <code>string</code> | | <code>null</code> |
| [tag_bindings](variables.tf#L218) | Tag bindings for this organization, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> | | [tag_bindings](variables.tf#L223) | Tag bindings for this organization, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L224) | 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. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; id &#61; optional&#40;string&#41;&#10; values &#61; optional&#40;map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; id &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [tags](variables.tf#L229) | 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. | <code title="map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; id &#61; optional&#40;string&#41;&#10; values &#61; optional&#40;map&#40;object&#40;&#123;&#10; description &#61; optional&#40;string, &#34;Managed by the Terraform organization module.&#34;&#41;&#10; iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; id &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
## Outputs ## Outputs

View File

@ -78,6 +78,14 @@ resource "google_organization_iam_member" "members" {
org_id = local.organization_id_numeric org_id = local.organization_id_numeric
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }
resource "google_organization_iam_policy" "authoritative" { resource "google_organization_iam_policy" "authoritative" {

View File

@ -68,6 +68,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -154,7 +154,7 @@ module "project" {
#### Additive IAM by Binding #### Additive IAM by Binding
When the above approaches to additive IAM are unworkable due to dynamically generated principals, the `iam_members` variable allows specifying individual role/principal pairs using arbitrary keys: When the above approaches to additive IAM are unworkable due to dynamically generated principals, the `iam_members` variable allows specifying individual role/principal pairs using arbitrary keys. This IAM variable also supports conditions.
```hcl ```hcl
module "project" { module "project" {
@ -173,10 +173,23 @@ module "project" {
member = "user:two@example.org" member = "user:two@example.org"
role = "roles/compute.admin" role = "roles/compute.admin"
} }
one-delegated-grant = {
member = "user:one@example.org"
role = "roles/resourcemanager.projectIamAdmin"
condition = {
title = "delegated_network_user_one"
expression = <<-END
api.getAttribute(
'iam.googleapis.com/modifiedGrantsByRole', []
).hasOnly([
'roles/compute.networkAdmin'
])
END
}
}
} }
} }
# tftest modules=1 resources=4 inventory=iam-members.yaml # tftest modules=1 resources=5 inventory=iam-members.yaml
``` ```
### Service Identities and Authoritative IAM ### Service Identities and Authoritative IAM
@ -658,7 +671,7 @@ output "compute_robot" {
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [name](variables.tf#L171) | Project name and id suffix. | <code>string</code> | ✓ | | | [name](variables.tf#L176) | Project name and id suffix. | <code>string</code> | ✓ | |
| [auto_create_network](variables.tf#L17) | Whether to create the default network for the project. | <code>bool</code> | | <code>false</code> | | [auto_create_network](variables.tf#L17) | Whether to create the default network for the project. | <code>bool</code> | | <code>false</code> |
| [billing_account](variables.tf#L23) | Billing account id. | <code>string</code> | | <code>null</code> | | [billing_account](variables.tf#L23) | Billing account id. | <code>string</code> | | <code>null</code> |
| [contacts](variables.tf#L29) | 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> | | [contacts](variables.tf#L29) | 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> |
@ -669,31 +682,31 @@ output "compute_robot" {
| [iam](variables.tf#L62) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam](variables.tf#L62) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive](variables.tf#L69) | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive](variables.tf#L69) | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive_members](variables.tf#L76) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive_members](variables.tf#L76) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_members](variables.tf#L82) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_members](variables.tf#L82) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_policy](variables.tf#L92) | IAM authoritative policy in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared, use with extreme caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> | | [iam_policy](variables.tf#L97) | IAM authoritative policy in {ROLE => [MEMBERS]} format. Roles and members not explicitly listed will be cleared, use with extreme caution. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>null</code> |
| [labels](variables.tf#L98) | Resource labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> | | [labels](variables.tf#L103) | Resource labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [lien_reason](variables.tf#L105) | If non-empty, creates a project lien with this description. | <code>string</code> | | <code>&#34;&#34;</code> | | [lien_reason](variables.tf#L110) | If non-empty, creates a project lien with this description. | <code>string</code> | | <code>&#34;&#34;</code> |
| [logging_data_access](variables.tf#L111) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [logging_data_access](variables.tf#L116) | Control activation of data access logs. Format is service => { log type => [exempted members]}. The special 'allServices' key denotes configuration for all services. | <code>map&#40;map&#40;list&#40;string&#41;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_exclusions](variables.tf#L126) | Logging exclusions for this project in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> | | [logging_exclusions](variables.tf#L131) | Logging exclusions for this project in the form {NAME -> FILTER}. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [logging_sinks](variables.tf#L133) | Logging sinks to create for this project. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; iam &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10; unique_writer &#61; optional&#40;bool&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [logging_sinks](variables.tf#L138) | Logging sinks to create for this project. | <code title="map&#40;object&#40;&#123;&#10; bq_partitioned_table &#61; optional&#40;bool&#41;&#10; description &#61; optional&#40;string&#41;&#10; destination &#61; string&#10; disabled &#61; optional&#40;bool, false&#41;&#10; exclusions &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; filter &#61; string&#10; iam &#61; optional&#40;bool, true&#41;&#10; type &#61; string&#10; unique_writer &#61; optional&#40;bool&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [metric_scopes](variables.tf#L164) | List of projects that will act as metric scopes for this project. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [metric_scopes](variables.tf#L169) | List of projects that will act as metric scopes for this project. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [org_policies](variables.tf#L176) | Organization policies applied to this project 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; 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&#41; &#35; for boolean policies only.&#10; condition &#61; optional&#40;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;, &#123;&#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](variables.tf#L181) | Organization policies applied to this project 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; 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&#41; &#35; for boolean policies only.&#10; condition &#61; optional&#40;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;, &#123;&#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#L203) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> | | [org_policies_data_path](variables.tf#L208) | Path containing org policies in YAML format. | <code>string</code> | | <code>null</code> |
| [oslogin](variables.tf#L209) | Enable OS Login. | <code>bool</code> | | <code>false</code> | | [oslogin](variables.tf#L214) | Enable OS Login. | <code>bool</code> | | <code>false</code> |
| [oslogin_admins](variables.tf#L215) | List of IAM-style identities that will be granted roles necessary for OS Login administrators. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [oslogin_admins](variables.tf#L220) | List of IAM-style identities that will be granted roles necessary for OS Login administrators. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [oslogin_users](variables.tf#L223) | List of IAM-style identities that will be granted roles necessary for OS Login users. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [oslogin_users](variables.tf#L228) | List of IAM-style identities that will be granted roles necessary for OS Login users. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [parent](variables.tf#L230) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | <code>string</code> | | <code>null</code> | | [parent](variables.tf#L235) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | <code>string</code> | | <code>null</code> |
| [prefix](variables.tf#L240) | Optional prefix used to generate project id and name. | <code>string</code> | | <code>null</code> | | [prefix](variables.tf#L245) | Optional prefix used to generate project id and name. | <code>string</code> | | <code>null</code> |
| [project_create](variables.tf#L250) | Create project. When set to false, uses a data source to reference existing project. | <code>bool</code> | | <code>true</code> | | [project_create](variables.tf#L255) | Create project. When set to false, uses a data source to reference existing project. | <code>bool</code> | | <code>true</code> |
| [service_config](variables.tf#L256) | Configure service API activation. | <code title="object&#40;&#123;&#10; disable_on_destroy &#61; bool&#10; disable_dependent_services &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; disable_on_destroy &#61; false&#10; disable_dependent_services &#61; false&#10;&#125;">&#123;&#8230;&#125;</code> | | [service_config](variables.tf#L261) | Configure service API activation. | <code title="object&#40;&#123;&#10; disable_on_destroy &#61; bool&#10; disable_dependent_services &#61; bool&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; disable_on_destroy &#61; false&#10; disable_dependent_services &#61; false&#10;&#125;">&#123;&#8230;&#125;</code> |
| [service_encryption_key_ids](variables.tf#L268) | Cloud KMS encryption key in {SERVICE => [KEY_URL]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [service_encryption_key_ids](variables.tf#L273) | Cloud KMS encryption key in {SERVICE => [KEY_URL]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [service_perimeter_bridges](variables.tf#L275) | Name of VPC-SC Bridge perimeters to add project into. See comment in the variables file for format. | <code>list&#40;string&#41;</code> | | <code>null</code> | | [service_perimeter_bridges](variables.tf#L280) | Name of VPC-SC Bridge perimeters to add project into. See comment in the variables file for format. | <code>list&#40;string&#41;</code> | | <code>null</code> |
| [service_perimeter_standard](variables.tf#L282) | Name of VPC-SC Standard perimeter to add project into. See comment in the variables file for format. | <code>string</code> | | <code>null</code> | | [service_perimeter_standard](variables.tf#L287) | Name of VPC-SC Standard perimeter to add project into. See comment in the variables file for format. | <code>string</code> | | <code>null</code> |
| [services](variables.tf#L288) | Service APIs to enable. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [services](variables.tf#L293) | Service APIs to enable. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [shared_vpc_host_config](variables.tf#L294) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | <code title="object&#40;&#123;&#10; enabled &#61; bool&#10; service_projects &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | | [shared_vpc_host_config](variables.tf#L299) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | <code title="object&#40;&#123;&#10; enabled &#61; bool&#10; service_projects &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [shared_vpc_service_config](variables.tf#L303) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | <code title="object&#40;&#123;&#10; host_project &#61; string&#10; service_identity_iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; service_iam_grants &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; host_project &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> | | [shared_vpc_service_config](variables.tf#L308) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | <code title="object&#40;&#123;&#10; host_project &#61; string&#10; service_identity_iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; service_iam_grants &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; host_project &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [skip_delete](variables.tf#L325) | Allows the underlying resources to be destroyed without destroying the project itself. | <code>bool</code> | | <code>false</code> | | [skip_delete](variables.tf#L330) | Allows the underlying resources to be destroyed without destroying the project itself. | <code>bool</code> | | <code>false</code> |
| [tag_bindings](variables.tf#L331) | Tag bindings for this project, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> | | [tag_bindings](variables.tf#L336) | Tag bindings for this project, in key => tag value id format. | <code>map&#40;string&#41;</code> | | <code>null</code> |
## Outputs ## Outputs

View File

@ -102,6 +102,14 @@ resource "google_project_iam_member" "members" {
project = local.project.project_id project = local.project.project_id
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
depends_on = [ depends_on = [
google_project_service.project_services, google_project_service.project_services,
google_project_iam_custom_role.roles google_project_iam_custom_role.roles

View File

@ -84,6 +84,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -80,7 +80,7 @@ output "filtered-projects" {
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [parent](variables.tf#L55) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | <code>string</code> | ✓ | | | [parent](variables.tf#L55) | Parent folder or organization in 'folders/folder_id' or 'organizations/org_id' format. | <code>string</code> | ✓ | |
| [ignore_folders](variables.tf#L17) | A list of folder IDs or numbers to be excluded from the output, all the subfolders and projects are exluded from the output regardless of the include_projects variable. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [ignore_folders](variables.tf#L17) | A list of folder IDs or numbers to be excluded from the output, all the subfolders and projects are excluded from the output regardless of the include_projects variable. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [ignore_projects](variables.tf#L28) | A list of project IDs, numbers or prefixes to exclude matching projects from the module output. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [ignore_projects](variables.tf#L28) | A list of project IDs, numbers or prefixes to exclude matching projects from the module output. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [include_projects](variables.tf#L41) | A list of project IDs/numbers to include to the output if some of them are excluded by `ignore_projects` wildcard entries. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> | | [include_projects](variables.tf#L41) | A list of project IDs/numbers to include to the output if some of them are excluded by `ignore_projects` wildcard entries. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [query](variables.tf#L64) | A string query as defined in the [Query Syntax](https://cloud.google.com/asset-inventory/docs/query-syntax). | <code>string</code> | | <code>&#34;state:ACTIVE&#34;</code> | | [query](variables.tf#L64) | A string query as defined in the [Query Syntax](https://cloud.google.com/asset-inventory/docs/query-syntax). | <code>string</code> | | <code>&#34;state:ACTIVE&#34;</code> |

View File

@ -15,7 +15,7 @@
*/ */
variable "ignore_folders" { variable "ignore_folders" {
description = "A list of folder IDs or numbers to be excluded from the output, all the subfolders and projects are exluded from the output regardless of the include_projects variable." description = "A list of folder IDs or numbers to be excluded from the output, all the subfolders and projects are excluded from the output regardless of the include_projects variable."
type = list(string) type = list(string)
default = [] default = []
# example exlusing a folder # example exlusing a folder

View File

@ -75,14 +75,14 @@ module "repo" {
| name | description | type | required | default | | name | description | type | required | default |
|---|---|:---:|:---:|:---:| |---|---|:---:|:---:|:---:|
| [name](variables.tf#L54) | Repository name. | <code>string</code> | ✓ | | | [name](variables.tf#L59) | Repository name. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L59) | Project used for resources. | <code>string</code> | ✓ | | | [project_id](variables.tf#L64) | Project used for resources. | <code>string</code> | ✓ | |
| [group_iam](variables.tf#L17) | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [group_iam](variables.tf#L17) | Authoritative IAM binding for organization groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam](variables.tf#L24) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam](variables.tf#L24) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive](variables.tf#L31) | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive](variables.tf#L31) | IAM additive bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_additive_members](variables.tf#L38) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_additive_members](variables.tf#L38) | IAM additive bindings in {MEMBERS => [ROLE]} format. This might break if members are dynamic values. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [iam_members](variables.tf#L44) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [iam_members](variables.tf#L44) | Individual additive IAM bindings, use this when iam_additive does not work due to dynamic resources. Keys are arbitrary and only used for the internal loop. | <code title="map&#40;object&#40;&#123;&#10; member &#61; string&#10; role &#61; string&#10; condition &#61; optional&#40;object&#40;&#123;&#10; expression &#61; string&#10; title &#61; string&#10; description &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [triggers](variables.tf#L64) | Cloud Build triggers. | <code title="map&#40;object&#40;&#123;&#10; filename &#61; string&#10; included_files &#61; list&#40;string&#41;&#10; service_account &#61; string&#10; substitutions &#61; map&#40;string&#41;&#10; template &#61; object&#40;&#123;&#10; branch_name &#61; string&#10; project_id &#61; string&#10; tag_name &#61; string&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> | | [triggers](variables.tf#L69) | Cloud Build triggers. | <code title="map&#40;object&#40;&#123;&#10; filename &#61; string&#10; included_files &#61; list&#40;string&#41;&#10; service_account &#61; string&#10; substitutions &#61; map&#40;string&#41;&#10; template &#61; object&#40;&#123;&#10; branch_name &#61; string&#10; project_id &#61; string&#10; tag_name &#61; string&#10; &#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
## Outputs ## Outputs

View File

@ -72,4 +72,12 @@ resource "google_sourcerepo_repository_iam_member" "members" {
repository = google_sourcerepo_repository.default.name repository = google_sourcerepo_repository.default.name
role = each.value.role role = each.value.role
member = each.value.member member = each.value.member
dynamic "condition" {
for_each = each.value.condition == null ? [] : [""]
content {
expression = each.value.condition.expression
title = each.value.condition.title
description = each.value.condition.description
}
}
} }

View File

@ -46,6 +46,11 @@ variable "iam_members" {
type = map(object({ type = map(object({
member = string member = string
role = string role = string
condition = optional(object({
expression = string
title = string
description = optional(string)
}))
})) }))
nullable = false nullable = false
default = {} default = {}

View File

@ -23,6 +23,15 @@ values:
project_id: project-example project_id: project-example
skip_delete: false skip_delete: false
timeouts: null timeouts: null
module.project.google_project_iam_member.members["one-delegated-grant"]:
condition:
- description: null
expression: "api.getAttribute(\n 'iam.googleapis.com/modifiedGrantsByRole',\
\ []\n).hasOnly([\n 'roles/compute.networkAdmin'\n])\n"
title: delegated_network_user_one
member: user:one@example.org
project: project-example
role: roles/resourcemanager.projectIamAdmin
module.project.google_project_iam_member.members["one-owner"]: module.project.google_project_iam_member.members["one-owner"]:
condition: [] condition: []
member: user:one@example.org member: user:one@example.org
@ -41,8 +50,9 @@ values:
counts: counts:
google_project: 1 google_project: 1
google_project_iam_member: 3 google_project_iam_member: 4
modules: 1 modules: 1
resources: 4 resources: 5
outputs: {} outputs: {}