diff --git a/fast/assets/templates/workflow-gitlab.yaml b/fast/assets/templates/workflow-gitlab.yaml
index 8981e70b..13057e11 100644
--- a/fast/assets/templates/workflow-gitlab.yaml
+++ b/fast/assets/templates/workflow-gitlab.yaml
@@ -1,4 +1,4 @@
-# Copyright 2022 Google LLC
+# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,8 +13,6 @@
# limitations under the License.
default:
- before_script:
- - echo "$${CI_JOB_JWT_V2}" > token.txt
image:
name: hashicorp/terraform
entrypoint:
@@ -27,7 +25,9 @@ variables:
FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
+ %{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file}
+ %{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
stages:
@@ -40,13 +40,26 @@ cache:
key: gcp-auth
paths:
- 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:
+ id_tokens:
+ GITLAB_TOKEN:
+ aud:
+ %{~ for aud in audiences ~}
+ - ${aud}
+ %{~ endfor ~}
image:
name: google/cloud-sdk:slim
stage: gcp-auth
script:
+ - echo "$${GITLAB_TOKEN}" > token.txt
- |
gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \
@@ -54,6 +67,7 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt
+
tf-files:
dependencies:
- gcp-auth
@@ -63,15 +77,18 @@ tf-files:
script:
# - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- - mkdir -p .tf-setup
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/
+ %{~ if tf_providers_file != "" ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
+ %{~ endif ~}
+ %{~ for f in tf_var_files ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
+ %{~ endfor ~}
+ - ls -l
tf-plan:
+ dependencies:
+ - tf-files
+ stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
# - |
@@ -80,20 +97,15 @@ tf-plan:
# mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
- stage: tf-plan
script:
- - cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- - |
- for f in $${TF_VAR_FILES}; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform plan
- dependencies:
- - tf-files
tf-apply:
+ dependencies:
+ - tf-files
+ stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
# - |
@@ -102,18 +114,10 @@ tf-apply:
# mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
- stage: tf-apply
script:
- - cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- - |
- for f in $${TF_VAR_FILES}; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform apply -input=false -auto-approve
- dependencies:
- - tf-files
when: manual
only:
variables:
diff --git a/fast/stages-multitenant/0-bootstrap-tenant/README.md b/fast/stages-multitenant/0-bootstrap-tenant/README.md
index a10b808d..f831f9af 100644
--- a/fast/stages-multitenant/0-bootstrap-tenant/README.md
+++ b/fast/stages-multitenant/0-bootstrap-tenant/README.md
@@ -175,7 +175,6 @@ This configuration is possible but unsupported and only exists for development p
-
## Files
| 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 |
|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables.tf#L20) | Automation resources created by the organization-level bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
-| [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`. | object({…})
| ✓ | | |
-| [organization](variables.tf#L191) | Organization details. | object({…})
| ✓ | | 0-bootstrap
|
-| [prefix](variables.tf#L207) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | 0-bootstrap
|
-| [tag_keys](variables.tf#L230) | Organization tag keys. | object({…})
| ✓ | | 1-resman
|
-| [tag_names](variables.tf#L241) | Customized names for resource management tags. | object({…})
| ✓ | | 1-resman
|
-| [tag_values](variables.tf#L252) | Organization resource management tag values. | map(string)
| ✓ | | 1-resman
|
-| [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. | object({…})
| ✓ | | |
-| [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. | object({…})
| | null
| |
-| [custom_roles](variables.tf#L94) | Custom roles defined at the organization level, in key => id format. | object({…})
| | null
| 0-bootstrap
|
-| [fast_features](variables.tf#L104) | Selective control for top-level FAST features. | object({…})
| | {}
| 0-bootstrap
|
-| [federated_identity_providers](variables.tf#L118) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…}))
| | {}
| |
-| [group_iam](variables.tf#L132) | Tenant-level custom group IAM settings in group => [roles] format. | map(list(string))
| | {}
| |
-| [iam](variables.tf#L138) | Tenant-level custom IAM settings in role => [principal] format. | map(list(string))
| | {}
| |
-| [iam_additive](variables.tf#L144) | Tenant-level custom IAM settings in role => [principal] format for non-authoritative bindings. | map(list(string))
| | {}
| |
-| [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. | object({…})
| | {…}
| 0-bootstrap
|
-| [log_sinks](variables.tf#L170) | Tenant-level log sinks, in name => {type, filter} format. | map(object({…}))
| | {…}
| |
-| [outputs_location](variables.tf#L201) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string
| | null
| |
-| [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. | object({…})
| | {…}
| |
-| [test_principal](variables.tf#L300) | Used when testing to bypass the data source returning the current identity. | string
| | null
| |
+| [automation](variables.tf#L20) | Automation resources created by the organization-level bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
+| [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`. | object({…})
| ✓ | | |
+| [organization](variables.tf#L192) | Organization details. | object({…})
| ✓ | | 0-bootstrap
|
+| [prefix](variables.tf#L208) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | 0-bootstrap
|
+| [tag_keys](variables.tf#L231) | Organization tag keys. | object({…})
| ✓ | | 1-resman
|
+| [tag_names](variables.tf#L242) | Customized names for resource management tags. | object({…})
| ✓ | | 1-resman
|
+| [tag_values](variables.tf#L253) | Organization resource management tag values. | map(string)
| ✓ | | 1-resman
|
+| [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. | object({…})
| ✓ | | |
+| [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. | object({…})
| | null
| |
+| [custom_roles](variables.tf#L95) | Custom roles defined at the organization level, in key => id format. | object({…})
| | null
| 0-bootstrap
|
+| [fast_features](variables.tf#L105) | Selective control for top-level FAST features. | object({…})
| | {}
| 0-bootstrap
|
+| [federated_identity_providers](variables.tf#L119) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…}))
| | {}
| |
+| [group_iam](variables.tf#L133) | Tenant-level custom group IAM settings in group => [roles] format. | map(list(string))
| | {}
| |
+| [iam](variables.tf#L139) | Tenant-level custom IAM settings in role => [principal] format. | map(list(string))
| | {}
| |
+| [iam_additive](variables.tf#L145) | Tenant-level custom IAM settings in role => [principal] format for non-authoritative bindings. | map(list(string))
| | {}
| |
+| [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. | object({…})
| | {…}
| 0-bootstrap
|
+| [log_sinks](variables.tf#L171) | Tenant-level log sinks, in name => {type, filter} format. | map(object({…}))
| | {…}
| |
+| [outputs_location](variables.tf#L202) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string
| | null
| |
+| [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. | object({…})
| | {…}
| |
+| [test_principal](variables.tf#L301) | Used when testing to bypass the data source returning the current identity. | string
| | null
| |
## Outputs
| name | description | sensitive | consumers |
|---|---|:---:|---|
-| [cicd_workflows](outputs.tf#L107) | CI/CD workflows for tenant bootstrap and resource management stages. | ✓ | |
-| [federated_identity](outputs.tf#L113) | Workload Identity Federation pool and providers. | | |
-| [provider](outputs.tf#L123) | Terraform provider file for tenant resource management stage. | ✓ | stage-01
|
-| [tenant_resources](outputs.tf#L130) | Tenant-level resources. | | |
-| [tfvars](outputs.tf#L141) | Terraform variable files for the following tenant stages. | ✓ | |
-
+| [cicd_workflows](outputs.tf#L109) | CI/CD workflows for tenant bootstrap and resource management stages. | ✓ | |
+| [federated_identity](outputs.tf#L115) | Workload Identity Federation pool and providers. | | |
+| [provider](outputs.tf#L125) | Terraform provider file for tenant resource management stage. | ✓ | stage-01
|
+| [tenant_resources](outputs.tf#L132) | Tenant-level resources. | | |
+| [tfvars](outputs.tf#L143) | Terraform variable files for the following tenant stages. | ✓ | |
diff --git a/fast/stages-multitenant/0-bootstrap-tenant/cicd.tf b/fast/stages-multitenant/0-bootstrap-tenant/cicd.tf
index a25215af..fd0ec167 100644
--- a/fast/stages-multitenant/0-bootstrap-tenant/cicd.tf
+++ b/fast/stages-multitenant/0-bootstrap-tenant/cicd.tf
@@ -20,23 +20,27 @@ locals {
_file_prefix = "tenants/${var.tenant_config.short_name}"
# derive identity pool names from identity providers for easy reference
cicd_identity_pools = {
- for k, v in local.cicd_identity_providers :
+ for k, v in local.cicd_providers :
k => split("/providers/", v.name)[0]
}
# merge org-level and tenant-level identity providers
- cicd_identity_providers = merge(
+ cicd_providers = merge(
var.automation.federated_identity_providers,
{
for k, v in google_iam_workload_identity_pool_provider.default :
k => {
+ audiences = concat(
+ v.oidc[0].allowed_audiences,
+ ["https://iam.googleapis.com/${v.name}"]
+ )
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
principal_tpl = local.identity_providers[k].principal_tpl
principalset_tpl = local.identity_providers[k].principalset_tpl
}
- })
- # filter CI/CD repositories to only keep valid ones
+ }
+ )
cicd_repositories = {
for k, v in coalesce(var.cicd_repositories, {}) : k => v
if(
@@ -46,7 +50,7 @@ locals {
try(v.type, null) == "sourcerepo"
||
contains(
- keys(local.cicd_identity_providers),
+ keys(local.cicd_providers),
coalesce(try(v.identity_provider, null), ":")
)
)
@@ -111,12 +115,12 @@ module "automation-tf-cicd-sa-bootstrap" {
"roles/iam.workloadIdentityUser" = [
each.value.branch == null
? 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],
each.value.name
)
: 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],
each.value.name,
each.value.branch
@@ -201,12 +205,12 @@ module "automation-tf-cicd-sa-resman" {
"roles/iam.workloadIdentityUser" = [
each.value.branch == null
? 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],
each.value.name
)
: 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],
each.value.name,
each.value.branch
diff --git a/fast/stages-multitenant/0-bootstrap-tenant/identity-providers.tf b/fast/stages-multitenant/0-bootstrap-tenant/identity-providers.tf
index 3f8499b7..085a30f0 100644
--- a/fast/stages-multitenant/0-bootstrap-tenant/identity-providers.tf
+++ b/fast/stages-multitenant/0-bootstrap-tenant/identity-providers.tf
@@ -38,7 +38,7 @@ locals {
principal_tpl = "principal://iam.googleapis.com/%s/subject/repo:%s:ref:refs/heads/%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 = {
attribute_mapping = {
"google.subject" = "assertion.sub"
@@ -56,10 +56,9 @@ locals {
"attribute.ref_protected" = "assertion.ref_protected"
"attribute.ref_type" = "assertion.ref_type"
}
- allowed_audiences = ["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"
- principalset_tpl = "principalSet://iam.googleapis.com/%s/attribute.repository/%s"
+ issuer_uri = "https://gitlab.com"
+ 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"
}
}
}
@@ -82,13 +81,11 @@ resource "google_iam_workload_identity_pool_provider" "default" {
attribute_condition = each.value.attribute_condition
attribute_mapping = each.value.attribute_mapping
oidc {
- allowed_audiences = (
- try(each.value.custom_settings.allowed_audiences, null) != null
- ? each.value.custom_settings.allowed_audiences
- : try(each.value.allowed_audiences, null)
- )
+ # Setting an empty list configures allowed_audiences to the url of the provider
+ allowed_audiences = each.value.custom_settings.audiences
+ # If users don't provide an issuer_uri, we set the public one for the plaform choosed.
issuer_uri = (
- try(each.value.custom_settings.issuer_uri, null) != null
+ each.value.custom_settings.issuer_uri != null
? each.value.custom_settings.issuer_uri
: try(each.value.issuer_uri, null)
)
diff --git a/fast/stages-multitenant/0-bootstrap-tenant/outputs.tf b/fast/stages-multitenant/0-bootstrap-tenant/outputs.tf
index c61c584e..883acac9 100644
--- a/fast/stages-multitenant/0-bootstrap-tenant/outputs.tf
+++ b/fast/stages-multitenant/0-bootstrap-tenant/outputs.tf
@@ -20,8 +20,9 @@ locals {
"${path.module}/templates/workflow-${v.type}.yaml", (
k == "bootstrap"
? {
+ audiences = local.cicd_providers[v["identity_provider"]].audiences
identity_provider = try(
- local.cicd_identity_providers[v["identity_provider"]].name, ""
+ local.cicd_providers[v["identity_provider"]].name, ""
)
outputs_bucket = var.automation.outputs_bucket
service_account = try(
@@ -36,8 +37,9 @@ locals {
]
}
: {
+ audiences = local.cicd_providers[v["identity_provider"]].audiences
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
service_account = try(
@@ -70,7 +72,7 @@ locals {
try(google_iam_workload_identity_pool.default.0.name, null),
var.automation.federated_identity_pool,
])
- federated_identity_providers = local.cicd_identity_providers
+ federated_identity_providers = local.cicd_providers
service_accounts = merge(
{ resman = module.automation-tf-resman-sa.email },
{
@@ -116,7 +118,7 @@ output "federated_identity" {
pool = try(
google_iam_workload_identity_pool.default.0.name, null
)
- providers = local.cicd_identity_providers
+ providers = local.cicd_providers
}
}
diff --git a/fast/stages-multitenant/0-bootstrap-tenant/templates/workflow-gitlab.yaml b/fast/stages-multitenant/0-bootstrap-tenant/templates/workflow-gitlab.yaml
index 739e7485..13057e11 100644
--- a/fast/stages-multitenant/0-bootstrap-tenant/templates/workflow-gitlab.yaml
+++ b/fast/stages-multitenant/0-bootstrap-tenant/templates/workflow-gitlab.yaml
@@ -1,4 +1,4 @@
-# Copyright 2022 Google LLC
+# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,8 +13,6 @@
# limitations under the License.
default:
- before_script:
- - echo "$${CI_JOB_JWT_V2}" > token.txt
image:
name: hashicorp/terraform
entrypoint:
@@ -42,13 +40,26 @@ cache:
key: gcp-auth
paths:
- 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:
+ id_tokens:
+ GITLAB_TOKEN:
+ aud:
+ %{~ for aud in audiences ~}
+ - ${aud}
+ %{~ endfor ~}
image:
name: google/cloud-sdk:slim
stage: gcp-auth
script:
+ - echo "$${GITLAB_TOKEN}" > token.txt
- |
gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \
@@ -56,6 +67,7 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt
+
tf-files:
dependencies:
- gcp-auth
@@ -65,17 +77,18 @@ tf-files:
script:
# - gcloud components install -q alpha
- 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}" .tf-setup/
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
%{~ endif ~}
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/
+ %{~ for f in tf_var_files ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
+ %{~ endfor ~}
+ - ls -l
tf-plan:
+ dependencies:
+ - tf-files
+ stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
# - |
@@ -84,20 +97,15 @@ tf-plan:
# mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
- stage: tf-plan
script:
- - cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- - |
- for f in $${TF_VAR_FILES}; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform plan
- dependencies:
- - tf-files
tf-apply:
+ dependencies:
+ - tf-files
+ stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
# - |
@@ -106,18 +114,10 @@ tf-apply:
# mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
- stage: tf-apply
script:
- - cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- - |
- for f in $${TF_VAR_FILES}; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform apply -input=false -auto-approve
- dependencies:
- - tf-files
when: manual
only:
variables:
diff --git a/fast/stages-multitenant/0-bootstrap-tenant/variables.tf b/fast/stages-multitenant/0-bootstrap-tenant/variables.tf
index 718818ea..af56db39 100644
--- a/fast/stages-multitenant/0-bootstrap-tenant/variables.tf
+++ b/fast/stages-multitenant/0-bootstrap-tenant/variables.tf
@@ -26,6 +26,7 @@ variable "automation" {
project_number = string
federated_identity_pool = string
federated_identity_providers = map(object({
+ audiences = list(string)
issuer = string
issuer_uri = string
name = string
@@ -118,12 +119,12 @@ variable "fast_features" {
variable "federated_identity_providers" {
description = "Workload Identity Federation pools. The `cicd_repositories` variable references keys here."
type = map(object({
- attribute_condition = string
+ attribute_condition = optional(string)
issuer = string
- custom_settings = object({
- issuer_uri = string
- allowed_audiences = list(string)
- })
+ custom_settings = optional(object({
+ issuer_uri = optional(string)
+ audiences = optional(list(string), [])
+ }), {})
}))
default = {}
nullable = false
diff --git a/fast/stages-multitenant/1-resman-tenant/README.md b/fast/stages-multitenant/1-resman-tenant/README.md
index 9e1188bb..c38f173f 100644
--- a/fast/stages-multitenant/1-resman-tenant/README.md
+++ b/fast/stages-multitenant/1-resman-tenant/README.md
@@ -126,7 +126,6 @@ Once the configuration is done just go through the usual `init/apply` cycle. On
-
## Files
| 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 |
|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
-| [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`. | object({…})
| ✓ | | 0-bootstrap
|
-| [organization](variables.tf#L204) | Organization details. | object({…})
| ✓ | | 0-bootstrap
|
-| [prefix](variables.tf#L226) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | 0-bootstrap
|
+| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
+| [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`. | object({…})
| ✓ | | 0-bootstrap
|
+| [organization](variables.tf#L205) | Organization details. | object({…})
| ✓ | | 0-bootstrap
|
+| [prefix](variables.tf#L227) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | 0-bootstrap
|
| [root_node](variables.tf#L237) | Root folder node for the tenant, in folders/nnnnnn format. | string
| ✓ | | |
| [short_name](variables.tf#L242) | Short name used to identify the tenant. | string
| ✓ | | |
| [tags](variables.tf#L247) | Resource management tags. | object({…})
| ✓ | | |
-| [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. | object({…})
| | null
| |
-| [custom_roles](variables.tf#L144) | Custom roles defined at the org level, in key => id format. | object({…})
| | null
| 0-bootstrap
|
-| [data_dir](variables.tf#L153) | Relative path for the folder storing configuration data. | string
| | "data"
| |
-| [fast_features](variables.tf#L159) | Selective control for top-level FAST features. | object({…})
| | {}
| 0-0-bootstrap
|
-| [groups](variables.tf#L173) | Group names to grant organization-level permissions. | object({…})
| | {}
| 0-bootstrap
|
-| [locations](variables.tf#L186) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…})
| | {…}
| 0-bootstrap
|
-| [organization_policy_data_path](variables.tf#L214) | Path for the data folder used by the organization policies factory. | string
| | null
| |
-| [outputs_location](variables.tf#L220) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string
| | null
| |
+| [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. | object({…})
| | null
| |
+| [custom_roles](variables.tf#L145) | Custom roles defined at the org level, in key => id format. | object({…})
| | null
| 0-bootstrap
|
+| [data_dir](variables.tf#L154) | Relative path for the folder storing configuration data. | string
| | "data"
| |
+| [fast_features](variables.tf#L160) | Selective control for top-level FAST features. | object({…})
| | {}
| 0-0-bootstrap
|
+| [groups](variables.tf#L174) | Group names to grant organization-level permissions. | object({…})
| | {}
| 0-bootstrap
|
+| [locations](variables.tf#L187) | Optional locations for GCS, BigQuery, and logging buckets created here. | object({…})
| | {…}
| 0-bootstrap
|
+| [organization_policy_data_path](variables.tf#L215) | Path for the data folder used by the organization policies factory. | string
| | null
| |
+| [outputs_location](variables.tf#L221) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | string
| | null
| |
| [team_folders](variables.tf#L265) | Team folders to be created. Format is described in a code comment. | map(object({…}))
| | null
| |
| [test_skip_data_sources](variables.tf#L275) | Used when testing to bypass data sources. | bool
| | false
| |
@@ -176,15 +175,14 @@ Once the configuration is done just go through the usual `init/apply` cycle. On
| name | description | sensitive | consumers |
|---|---|:---:|---|
-| [cicd_repositories](outputs.tf#L189) | WIF configuration for CI/CD repositories. | | |
-| [dataplatform](outputs.tf#L203) | Data for the Data Platform stage. | | |
-| [gke_multitenant](outputs.tf#L219) | Data for the GKE multitenant stage. | | 03-gke-multitenant
|
-| [networking](outputs.tf#L240) | Data for the networking stage. | | |
-| [project_factories](outputs.tf#L249) | Data for the project factories stage. | | |
-| [providers](outputs.tf#L264) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking
· 02-security
· 03-dataplatform
· xx-sandbox
· xx-teams
|
-| [sandbox](outputs.tf#L271) | Data for the sandbox stage. | | xx-sandbox
|
-| [security](outputs.tf#L285) | Data for the networking stage. | | 02-security
|
-| [teams](outputs.tf#L295) | Data for the teams stage. | | |
-| [tfvars](outputs.tf#L307) | Terraform variable files for the following stages. | ✓ | |
-
+| [cicd_repositories](outputs.tf#L192) | WIF configuration for CI/CD repositories. | | |
+| [dataplatform](outputs.tf#L206) | Data for the Data Platform stage. | | |
+| [gke_multitenant](outputs.tf#L222) | Data for the GKE multitenant stage. | | 03-gke-multitenant
|
+| [networking](outputs.tf#L243) | Data for the networking stage. | | |
+| [project_factories](outputs.tf#L252) | Data for the project factories stage. | | |
+| [providers](outputs.tf#L267) | Terraform provider files for this stage and dependent stages. | ✓ | 02-networking
· 02-security
· 03-dataplatform
· xx-sandbox
· xx-teams
|
+| [sandbox](outputs.tf#L274) | Data for the sandbox stage. | | xx-sandbox
|
+| [security](outputs.tf#L288) | Data for the networking stage. | | 02-security
|
+| [teams](outputs.tf#L298) | Data for the teams stage. | | |
+| [tfvars](outputs.tf#L310) | Terraform variable files for the following stages. | ✓ | |
diff --git a/fast/stages-multitenant/1-resman-tenant/outputs.tf b/fast/stages-multitenant/1-resman-tenant/outputs.tf
index 592f995e..dadfb057 100644
--- a/fast/stages-multitenant/1-resman-tenant/outputs.tf
+++ b/fast/stages-multitenant/1-resman-tenant/outputs.tf
@@ -62,6 +62,9 @@ locals {
for k, v in local.cicd_repositories : k => templatefile(
"${path.module}/templates/workflow-${v.type}.yaml",
merge(local.cicd_workflow_attrs[k], {
+ audiences = try(
+ local.cicd_identity_providers[v.identity_provider].audiences, null
+ )
identity_provider = try(
local.cicd_identity_providers[v.identity_provider].name, null
)
diff --git a/fast/stages-multitenant/1-resman-tenant/templates/workflow-gitlab.yaml b/fast/stages-multitenant/1-resman-tenant/templates/workflow-gitlab.yaml
index 8981e70b..13057e11 100644
--- a/fast/stages-multitenant/1-resman-tenant/templates/workflow-gitlab.yaml
+++ b/fast/stages-multitenant/1-resman-tenant/templates/workflow-gitlab.yaml
@@ -1,4 +1,4 @@
-# Copyright 2022 Google LLC
+# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -13,8 +13,6 @@
# limitations under the License.
default:
- before_script:
- - echo "$${CI_JOB_JWT_V2}" > token.txt
image:
name: hashicorp/terraform
entrypoint:
@@ -27,7 +25,9 @@ variables:
FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
+ %{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file}
+ %{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
stages:
@@ -40,13 +40,26 @@ cache:
key: gcp-auth
paths:
- 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:
+ id_tokens:
+ GITLAB_TOKEN:
+ aud:
+ %{~ for aud in audiences ~}
+ - ${aud}
+ %{~ endfor ~}
image:
name: google/cloud-sdk:slim
stage: gcp-auth
script:
+ - echo "$${GITLAB_TOKEN}" > token.txt
- |
gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \
@@ -54,6 +67,7 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt
+
tf-files:
dependencies:
- gcp-auth
@@ -63,15 +77,18 @@ tf-files:
script:
# - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- - mkdir -p .tf-setup
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/
+ %{~ if tf_providers_file != "" ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
+ %{~ endif ~}
+ %{~ for f in tf_var_files ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
+ %{~ endfor ~}
+ - ls -l
tf-plan:
+ dependencies:
+ - tf-files
+ stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
# - |
@@ -80,20 +97,15 @@ tf-plan:
# mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
- stage: tf-plan
script:
- - cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- - |
- for f in $${TF_VAR_FILES}; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform plan
- dependencies:
- - tf-files
tf-apply:
+ dependencies:
+ - tf-files
+ stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
# - |
@@ -102,18 +114,10 @@ tf-apply:
# mkdir -p ~/.ssh
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
- stage: tf-apply
script:
- - cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- - |
- for f in $${TF_VAR_FILES}; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform apply -input=false -auto-approve
- dependencies:
- - tf-files
when: manual
only:
variables:
diff --git a/fast/stages-multitenant/1-resman-tenant/variables.tf b/fast/stages-multitenant/1-resman-tenant/variables.tf
index 1c399be2..bcda7fd6 100644
--- a/fast/stages-multitenant/1-resman-tenant/variables.tf
+++ b/fast/stages-multitenant/1-resman-tenant/variables.tf
@@ -26,6 +26,7 @@ variable "automation" {
project_number = string
federated_identity_pools = list(string)
federated_identity_providers = map(object({
+ audiences = list(string)
issuer = string
issuer_uri = string
name = string
@@ -227,7 +228,6 @@ variable "prefix" {
# tfdoc:variable:source 0-bootstrap
description = "Prefix used for resources that need unique names. Use 9 characters or less."
type = string
-
validation {
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)."
diff --git a/fast/stages/0-bootstrap/README.md b/fast/stages/0-bootstrap/README.md
index 105b044f..a9a28b1b 100644
--- a/fast/stages/0-bootstrap/README.md
+++ b/fast/stages/0-bootstrap/README.md
@@ -209,10 +209,10 @@ Then make sure you have configured the correct values for the following variable
- `organization.id`, `organization.domain`, `organization.customer_id`
the id, domain and customer id of your organization, derived from the Cloud Console UI or by running `gcloud organizations list`
- `prefix`
- the fixed org-level prefix used in your naming, maximum 9 characters long. Note that if you are using multitenant stages, then you will later need to configure a `tenant prefix`.
- This `tenant prefix` can have a maximum length of 2 characters,
- plus any unused characters from the from the `prefix`.
- For example, if you specify a `prefix` that is 7 characters long,
+ the fixed org-level prefix used in your naming, maximum 9 characters long. Note that if you are using multitenant stages, then you will later need to configure a `tenant prefix`.
+ This `tenant prefix` can have a maximum length of 2 characters,
+ plus any unused characters from the from the `prefix`.
+ For example, if you specify a `prefix` that is 7 characters long,
then your `tenant prefix` can have a maximum of 4 characters.
You can also adapt the example that follows to your needs:
@@ -421,7 +421,7 @@ federated_identity_providers = {
attribute_condition = "attribute.namespace_path==\"my-gitlab-org\""
issuer = "gitlab"
custom_settings = {
- allowed_audiences = ["https://gitlab.fast.example.com"]
+ audiences = ["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. | object({…})
| | {…}
| |
| [custom_roles](variables.tf#L93) | Map of role names => list of permissions to additionally create at the organization level. | map(list(string))
| | {}
| |
| [fast_features](variables.tf#L100) | Selective control for top-level FAST features. | object({…})
| | {}
| |
-| [federated_identity_providers](variables.tf#L113) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…}))
| | {}
| |
+| [federated_identity_providers](variables.tf#L113) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | map(object({…}))
| | {}
| |
| [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. | map(string)
| | {…}
| |
| [iam](variables.tf#L150) | Organization-level custom IAM settings in role => [principal] format. | map(list(string))
| | {}
| |
| [iam_additive](variables.tf#L156) | Organization-level custom IAM settings in role => [principal] format for non-authoritative bindings. | map(list(string))
| | {}
| |
diff --git a/fast/stages/0-bootstrap/cicd.tf b/fast/stages/0-bootstrap/cicd.tf
index f0b321d9..96839ec3 100644
--- a/fast/stages/0-bootstrap/cicd.tf
+++ b/fast/stages/0-bootstrap/cicd.tf
@@ -20,9 +20,9 @@ locals {
cicd_providers = {
for k, v in google_iam_workload_identity_pool_provider.default :
k => {
- audience = try(
- v.oidc[0].allowed_audiences[0],
- "https://iam.googleapis.com/${v.name}"
+ audiences = concat(
+ v.oidc[0].allowed_audiences,
+ ["https://iam.googleapis.com/${v.name}"]
)
issuer = local.identity_providers[k].issuer
issuer_uri = try(v.oidc[0].issuer_uri, null)
@@ -39,10 +39,15 @@ locals {
(
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 = {
diff --git a/fast/stages/0-bootstrap/identity-providers.tf b/fast/stages/0-bootstrap/identity-providers.tf
index 1c1c8b20..085a30f0 100644
--- a/fast/stages/0-bootstrap/identity-providers.tf
+++ b/fast/stages/0-bootstrap/identity-providers.tf
@@ -82,7 +82,7 @@ resource "google_iam_workload_identity_pool_provider" "default" {
attribute_mapping = each.value.attribute_mapping
oidc {
# 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.
issuer_uri = (
each.value.custom_settings.issuer_uri != null
diff --git a/fast/stages/0-bootstrap/outputs.tf b/fast/stages/0-bootstrap/outputs.tf
index 1db70bc4..ea980fca 100644
--- a/fast/stages/0-bootstrap/outputs.tf
+++ b/fast/stages/0-bootstrap/outputs.tf
@@ -22,7 +22,7 @@ locals {
"${path.module}/templates/workflow-${v.type}.yaml", {
# 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}
- audience = local.cicd_providers[v["identity_provider"]].audience
+ audiences = local.cicd_providers[v["identity_provider"]].audiences
identity_provider = try(
local.cicd_providers[v["identity_provider"]].name, ""
)
diff --git a/fast/stages/0-bootstrap/templates/workflow-gitlab.yaml b/fast/stages/0-bootstrap/templates/workflow-gitlab.yaml
index 33e55d21..13057e11 100644
--- a/fast/stages/0-bootstrap/templates/workflow-gitlab.yaml
+++ b/fast/stages/0-bootstrap/templates/workflow-gitlab.yaml
@@ -20,13 +20,14 @@ default:
- "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
variables:
- AUDIENCE: ${audience}
GOOGLE_CREDENTIALS: cicd-sa-credentials.json
FAST_OUTPUTS_BUCKET: ${outputs_bucket}
FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
+ %{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file}
+ %{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
stages:
@@ -38,16 +39,27 @@ stages:
cache:
key: gcp-auth
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:
- stage: gcp-auth
id_tokens:
GITLAB_TOKEN:
- aud: "$${AUDIENCE}"
+ aud:
+ %{~ for aud in audiences ~}
+ - ${aud}
+ %{~ endfor ~}
image:
name: google/cloud-sdk:slim
+ stage: gcp-auth
script:
+ - echo "$${GITLAB_TOKEN}" > token.txt
- |
gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \
@@ -55,30 +67,27 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt
- - rm token.txt
- artifacts:
- untracked: true
tf-files:
- stage: tf-files
+ dependencies:
+ - gcp-auth
image:
name: google/cloud-sdk:slim
+ stage: tf-files
script:
# - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- - mkdir -p .tf-setup
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/
- artifacts:
- untracked: true
- dependencies:
- - gcp-auth
+ %{~ if tf_providers_file != "" ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
+ %{~ endif ~}
+ %{~ for f in tf_var_files ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
+ %{~ endfor ~}
+ - ls -l
tf-plan:
+ dependencies:
+ - tf-files
stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
@@ -89,20 +98,13 @@ tf-plan:
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script:
- - cp ".tf-setup/$${TF_PROVIDERS_FILE}" ./
- - |
- for f in "$${TF_VAR_FILES}"; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform plan
- artifacts:
- untracked: true
- dependencies:
- - tf-files
tf-apply:
+ dependencies:
+ - tf-files
stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
@@ -113,18 +115,9 @@ tf-apply:
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script:
- - cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- - |
- for f in $${TF_VAR_FILES}; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform apply -input=false -auto-approve
- artifacts:
- untracked: true
- dependencies:
- - tf-files
when: manual
only:
variables:
diff --git a/fast/stages/0-bootstrap/variables.tf b/fast/stages/0-bootstrap/variables.tf
index f41d6dfa..1008c240 100644
--- a/fast/stages/0-bootstrap/variables.tf
+++ b/fast/stages/0-bootstrap/variables.tf
@@ -116,8 +116,8 @@ variable "federated_identity_providers" {
attribute_condition = optional(string)
issuer = string
custom_settings = optional(object({
- issuer_uri = optional(string)
- allowed_audiences = optional(list(string), [])
+ issuer_uri = optional(string)
+ audiences = optional(list(string), [])
}), {})
}))
default = {}
diff --git a/fast/stages/1-resman/README.md b/fast/stages/1-resman/README.md
index 4dec2945..d938020f 100644
--- a/fast/stages/1-resman/README.md
+++ b/fast/stages/1-resman/README.md
@@ -365,7 +365,7 @@ Due to its simplicity, this stage lends itself easily to customizations: adding
| name | description | type | required | default | producer |
|---|---|:---:|:---:|:---:|:---:|
-| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
+| [automation](variables.tf#L20) | Automation resources created by the bootstrap stage. | object({…})
| ✓ | | 0-bootstrap
|
| [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`. | object({…})
| ✓ | | 0-bootstrap
|
| [organization](variables.tf#L192) | Organization details. | object({…})
| ✓ | | 0-bootstrap
|
| [prefix](variables.tf#L216) | Prefix used for resources that need unique names. Use 9 characters or less. | string
| ✓ | | 0-bootstrap
|
diff --git a/fast/stages/1-resman/outputs.tf b/fast/stages/1-resman/outputs.tf
index 552d42d7..41994e98 100644
--- a/fast/stages/1-resman/outputs.tf
+++ b/fast/stages/1-resman/outputs.tf
@@ -62,8 +62,8 @@ locals {
for k, v in local.cicd_repositories : k => templatefile(
"${path.module}/templates/workflow-${v.type}.yaml",
merge(local.cicd_workflow_attrs[k], {
- audience = try(
- local.identity_providers[v.identity_provider].audience, null
+ audiences = try(
+ local.identity_providers[v.identity_provider].audiences, null
)
identity_provider = try(
local.identity_providers[v.identity_provider].name, null
diff --git a/fast/stages/1-resman/templates/workflow-gitlab.yaml b/fast/stages/1-resman/templates/workflow-gitlab.yaml
index 33e55d21..13057e11 100644
--- a/fast/stages/1-resman/templates/workflow-gitlab.yaml
+++ b/fast/stages/1-resman/templates/workflow-gitlab.yaml
@@ -20,13 +20,14 @@ default:
- "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
variables:
- AUDIENCE: ${audience}
GOOGLE_CREDENTIALS: cicd-sa-credentials.json
FAST_OUTPUTS_BUCKET: ${outputs_bucket}
FAST_SERVICE_ACCOUNT: ${service_account}
FAST_WIF_PROVIDER: ${identity_provider}
SSH_AUTH_SOCK: /tmp/ssh_agent.sock
+ %{~ if tf_providers_file != "" ~}
TF_PROVIDERS_FILE: ${tf_providers_file}
+ %{~ endif ~}
TF_VAR_FILES: ${tf_var_files == [] ? "''" : join("\n ", tf_var_files)}
stages:
@@ -38,16 +39,27 @@ stages:
cache:
key: gcp-auth
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:
- stage: gcp-auth
id_tokens:
GITLAB_TOKEN:
- aud: "$${AUDIENCE}"
+ aud:
+ %{~ for aud in audiences ~}
+ - ${aud}
+ %{~ endfor ~}
image:
name: google/cloud-sdk:slim
+ stage: gcp-auth
script:
+ - echo "$${GITLAB_TOKEN}" > token.txt
- |
gcloud iam workload-identity-pools create-cred-config \
$${FAST_WIF_PROVIDER} \
@@ -55,30 +67,27 @@ gcp-auth:
--service-account-token-lifetime-seconds=3600 \
--output-file=$${GOOGLE_CREDENTIALS} \
--credential-source-file=token.txt
- - rm token.txt
- artifacts:
- untracked: true
tf-files:
- stage: tf-files
+ dependencies:
+ - gcp-auth
image:
name: google/cloud-sdk:slim
+ stage: tf-files
script:
# - gcloud components install -q alpha
- gcloud config set auth/credential_file_override $${GOOGLE_CREDENTIALS}
- - mkdir -p .tf-setup
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/providers/$${TF_PROVIDERS_FILE}" .tf-setup/
- - |
- gcloud alpha storage cp -r \
- "gs://$${FAST_OUTPUTS_BUCKET}/tfvars" .tf-setup/
- artifacts:
- untracked: true
- dependencies:
- - gcp-auth
+ %{~ if tf_providers_file != "" ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/providers/${tf_providers_file}" ./
+ %{~ endif ~}
+ %{~ for f in tf_var_files ~}
+ - gcloud alpha storage cp -r "gs://$${FAST_OUTPUTS_BUCKET}/tfvars/${f}" ./
+ %{~ endfor ~}
+ - ls -l
tf-plan:
+ dependencies:
+ - tf-files
stage: tf-plan
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
@@ -89,20 +98,13 @@ tf-plan:
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script:
- - cp ".tf-setup/$${TF_PROVIDERS_FILE}" ./
- - |
- for f in "$${TF_VAR_FILES}"; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform plan
- artifacts:
- untracked: true
- dependencies:
- - tf-files
tf-apply:
+ dependencies:
+ - tf-files
stage: tf-apply
# uncomment the following lines and set the SSH key secret for private modules repo
# before_script:
@@ -113,18 +115,9 @@ tf-apply:
# ssh-keyscan -H 'gitlab.com' >> ~/.ssh/known_hosts
# ssh-keyscan gitlab.com | sort -u - ~/.ssh/known_hosts -o ~/.ssh/known_hosts
script:
- - cp .tf-setup/$${TF_PROVIDERS_FILE} ./
- - |
- for f in $${TF_VAR_FILES}; do
- ln -s ".tf-setup/tfvars/$f" ./
- done
- terraform init
- terraform validate
- terraform apply -input=false -auto-approve
- artifacts:
- untracked: true
- dependencies:
- - tf-files
when: manual
only:
variables:
diff --git a/fast/stages/1-resman/variables.tf b/fast/stages/1-resman/variables.tf
index a613e5ad..f255423a 100644
--- a/fast/stages/1-resman/variables.tf
+++ b/fast/stages/1-resman/variables.tf
@@ -26,7 +26,7 @@ variable "automation" {
project_number = string
federated_identity_pool = string
federated_identity_providers = map(object({
- audience = string
+ audiences = list(string)
issuer = string
issuer_uri = string
name = string