fast/addons/1-resman-tenants/tenant-fast-cicd.tf (135 lines of code) (raw):
/**
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
# tfdoc:file:description Per-tenant CI/CD resources.
locals {
# alias resources for readability
_wif_providers = {
for k, v in google_iam_workload_identity_pool_provider.default : k => v
}
# aggregate provider data from configurations and resources
_cicd_providers = [
for k, v in local.workload_identity_providers : {
audiences = concat(
local._wif_providers[k].oidc[0].allowed_audiences,
["https://iam.googleapis.com/${local._wif_providers[k].name}"]
)
issuer = v.issuer
issuer_uri = try(local._wif_providers[k].oidc[0].issuer_uri, null)
name = local._wif_providers[k].name
principal_branch = v.principal_branch
principal_repo = v.principal_repo
provider = v.provider
tenant = v.tenant
}
]
# group provider data by tenant
_cicd_tenant_providers = {
for v in local._cicd_providers : v.tenant => v...
}
# reconstitue per-tenant provider lists as maps
cicd_tenant_providers = {
for k, v in local._cicd_tenant_providers : k => {
for pv in v : pv.provider => pv
}
}
# filter tenant provider definitions to only keep valid ones
cicd_repositories = {
for k, v in local.fast_tenants :
k => merge(v.fast_config.cicd_config, {
tenant = k
})
# only keep CI/CD configurations that
if(
# are not null
try(v.fast_config.cicd_config, null) != null
&&
# are of a valid type (a template file exists for the type)
fileexists(
"${path.module}/templates/workflow-${try(v.fast_config.cicd_config.type, "")}.yaml"
)
&&
# either
(
# use an org-level WIF provider, or
try(var.automation.federated_identity_providers[v.wif_provider], null) != null
||
# use a tenant-level WIF provider
try(v.fast_config.workload_identity_providers[v.wif_provider], null) != null
)
)
}
# merge org-level and tenant-level providers for each tenant
identity_providers = {
for k, v in local.fast_tenants : k => merge(
try(var.automation.federated_identity_providers, {}),
try(local.cicd_tenant_providers[k], {})
)
}
}
# read-write (apply) SA used by CI/CD workflows to impersonate automation SA
module "tenant-automation-tf-cicd-sa" {
source = "../../../modules/iam-service-account"
for_each = local.cicd_repositories
project_id = var.automation.project_id
name = "${each.key}-1"
display_name = "Terraform CI/CD ${each.key} service account."
prefix = var.prefix
iam = {
"roles/iam.workloadIdentityUser" = [
each.value.branch == null
? format(
local.identity_providers[each.value.tenant][each.value.identity_provider].principal_repo,
var.automation.federated_identity_pool,
each.value.name
)
: length(regexall("%s", local.workload_identity_providers_defs[each.value.type].principal_branch)) == 2
? format(
local.identity_providers[each.value.tenant][each.value.identity_provider].principal_branch,
var.automation.federated_identity_pool,
each.value.branch
)
: format(
local.identity_providers[each.value.tenant][each.value.identity_provider].principal_branch,
var.automation.federated_identity_pool,
each.value.name,
each.value.branch
)
]
}
iam_project_roles = {
(module.tenant-automation-project[each.key].project_id) = [
"roles/logging.logWriter"
]
}
iam_storage_roles = {
(module.tenant-automation-tf-output-gcs[each.key].name) = [
"roles/storage.objectViewer"
]
}
}
# read-only (plan) SA used by CI/CD workflows to impersonate automation SA
module "automation-tf-cicd-r-sa" {
source = "../../../modules/iam-service-account"
for_each = local.cicd_repositories
project_id = var.automation.project_id
name = "${each.key}-1r"
display_name = "Terraform CI/CD ${each.key} service account (read-only)."
prefix = var.prefix
iam = {
"roles/iam.workloadIdentityUser" = [
format(
local.identity_providers[each.value.tenant][each.value.identity_provider].principal_repo,
var.automation.federated_identity_pool,
each.value.name
)
]
}
iam_project_roles = {
(module.tenant-automation-project[each.key].project_id) = [
"roles/logging.logWriter"
]
}
iam_storage_roles = {
(module.tenant-automation-tf-output-gcs[each.key].name) = [
"roles/storage.objectViewer"
]
}
}