Remove support for source repositories from FAST CI/CD (#2352)
* stage 0 * stage 1 * stage 1 mt * remove unused locals from resman * remove unused locals from resman * tfdoc
This commit is contained in:
committed by
GitHub
parent
8e861f5e74
commit
b13b6032d3
@@ -80,7 +80,7 @@ The only current exception to the factory approach is the `iam.allowedPolicyMemb
|
||||
|
||||
Organization policy exceptions are managed via a dedicated resource management tag hierarchy, rooted in the `org-policies` tag key. A default condition is already present for the the `iam.allowedPolicyMemberDomains` constraint, that relaxes the policy on resources that have the `org-policies/allowed-policy-member-domains-all` tag value bound or inherited.
|
||||
|
||||
Further tag values can be defined via the `org_policies_config.tag_values` variable, and IAM access can be granted on them via the same variable. Once a tag value has been created, its id can be used in constraint rule conditions. Note that only one tag value from a given tag key can be bound to a node (organization, folder, or project) in the resource hierarchy. Since these tag values are all rooted in the `org-policies` key, this limits the ability to apply fine-grained policy constraints. It may be more desirable to model policy overrides using coarser groups of tag values to create a policy "profile". For example, instead of separating `compute.skipDefaultNetworkCreation` and `compute.vmExternalIpAccess`, enforce both constraints by default and relax them both using the same tag value such as `sandbox`. See [tags overview](https://cloud.google.com/resource-manager/docs/tags/tags-overview) for more information.
|
||||
Further tag values can be defined via the `org_policies_config.tag_values` variable, and IAM access can be granted on them via the same variable. Once a tag value has been created, its id can be used in constraint rule conditions. Note that only one tag value from a given tag key can be bound to a node (organization, folder, or project) in the resource hierarchy. Since these tag values are all rooted in the `org-policies` key, this limits the ability to apply fine-grained policy constraints. It may be more desirable to model policy overrides using coarser groups of tag values to create a policy "profile". For example, instead of separating `compute.skipDefaultNetworkCreation` and `compute.vmExternalIpAccess`, enforce both constraints by default and relax them both using the same tag value such as `sandbox`. See [tags overview](https://cloud.google.com/resource-manager/docs/tags/tags-overview) for more information.
|
||||
|
||||
Management of the rest of the tag hierarchy is delegated to the resource management stage, as that is often intimately tied to the folder hierarchy design.
|
||||
|
||||
@@ -575,7 +575,7 @@ cicd_repositories = {
|
||||
}
|
||||
```
|
||||
|
||||
The `type` attribute can be set to one of the supported repository types: `github`, `gitlab`, or `sourcerepo`.
|
||||
The `type` attribute can be set to one of the supported repository types: `github` or `gitlab`.
|
||||
|
||||
Once the stage is applied the generated output files will contain pre-configured workflow files for each repository, that will use Workload Identity Federation via a dedicated service account for each repository to impersonate the automation service account for the stage.
|
||||
|
||||
@@ -617,7 +617,7 @@ The remaining configuration is manual, as it regards the repositories themselves
|
||||
| [automation.tf](./automation.tf) | Automation project and resources. | <code>gcs</code> · <code>iam-service-account</code> · <code>project</code> | |
|
||||
| [billing.tf](./billing.tf) | Billing export project and dataset. | <code>bigquery-dataset</code> · <code>project</code> | <code>google_billing_account_iam_member</code> |
|
||||
| [checklist.tf](./checklist.tf) | None | <code>gcs</code> | <code>google_storage_bucket_object</code> |
|
||||
| [cicd.tf](./cicd.tf) | Workload Identity Federation configurations for CI/CD. | <code>iam-service-account</code> · <code>source-repository</code> | |
|
||||
| [cicd.tf](./cicd.tf) | Workload Identity Federation configurations for CI/CD. | <code>iam-service-account</code> | |
|
||||
| [identity-providers-defs.tf](./identity-providers-defs.tf) | Identity provider definitions. | | |
|
||||
| [identity-providers.tf](./identity-providers.tf) | Workload Identity Federation provider definitions. | | <code>google_iam_workforce_pool</code> · <code>google_iam_workforce_pool_provider</code> · <code>google_iam_workload_identity_pool</code> · <code>google_iam_workload_identity_pool_provider</code> |
|
||||
| [log-export.tf](./log-export.tf) | Audit log project and sink. | <code>bigquery-dataset</code> · <code>gcs</code> · <code>logging-bucket</code> · <code>project</code> · <code>pubsub</code> | |
|
||||
@@ -634,24 +634,24 @@ The remaining configuration is manual, as it regards the repositories themselves
|
||||
| name | description | type | required | default | producer |
|
||||
|---|---|:---:|:---:|:---:|:---:|
|
||||
| [billing_account](variables.tf#L17) | 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({ id = string is_org_level = optional(bool, true) no_iam = optional(bool, false) })">object({…})</code> | ✓ | | |
|
||||
| [organization](variables.tf#L234) | Organization details. | <code title="object({ id = number domain = optional(string) customer_id = optional(string) })">object({…})</code> | ✓ | | |
|
||||
| [prefix](variables.tf#L249) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | |
|
||||
| [organization](variables.tf#L230) | Organization details. | <code title="object({ id = number domain = optional(string) customer_id = optional(string) })">object({…})</code> | ✓ | | |
|
||||
| [prefix](variables.tf#L245) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | |
|
||||
| [bootstrap_user](variables.tf#L27) | Email of the nominal user running this stage for the first time. | <code>string</code> | | <code>null</code> | |
|
||||
| [cicd_repositories](variables.tf#L33) | 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({ bootstrap = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) resman = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) tenants = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [custom_roles](variables.tf#L85) | Map of role names => list of permissions to additionally create at the organization level. | <code>map(list(string))</code> | | <code>{}</code> | |
|
||||
| [essential_contacts](variables.tf#L92) | Email used for essential contacts, unset if null. | <code>string</code> | | <code>null</code> | |
|
||||
| [factories_config](variables.tf#L98) | Configuration for the resource factories or external data. | <code title="object({ checklist_data = optional(string) checklist_org_iam = optional(string) custom_roles = optional(string, "data/custom-roles") org_policy = optional(string, "data/org-policies") })">object({…})</code> | | <code>{}</code> | |
|
||||
| [groups](variables.tf#L110) | Group names or IAM-format principals to grant organization-level permissions. If just the name is provided, the 'group:' principal and organization domain are interpolated. | <code title="object({ gcp-billing-admins = optional(string, "gcp-billing-admins") gcp-devops = optional(string, "gcp-devops") gcp-network-admins = optional(string, "gcp-vpc-network-admins") gcp-organization-admins = optional(string, "gcp-organization-admins") gcp-security-admins = optional(string, "gcp-security-admins") gcp-support = optional(string, "gcp-devops") })">object({…})</code> | | <code>{}</code> | |
|
||||
| [iam](variables.tf#L126) | Organization-level custom IAM settings in role => [principal] format. | <code>map(list(string))</code> | | <code>{}</code> | |
|
||||
| [iam_bindings_additive](variables.tf#L133) | Organization-level custom additive IAM bindings. Keys are arbitrary. | <code title="map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [iam_by_principals](variables.tf#L148) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | <code>map(list(string))</code> | | <code>{}</code> | |
|
||||
| [locations](variables.tf#L155) | Optional locations for GCS, BigQuery, and logging buckets created here. | <code title="object({ bq = optional(string, "EU") gcs = optional(string, "EU") logging = optional(string, "global") pubsub = optional(list(string), []) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [log_sinks](variables.tf#L169) | Org-level log sinks, in name => {type, filter} format. | <code title="map(object({ filter = string type = string }))">map(object({…}))</code> | | <code title="{ audit-logs = { filter = <<-FILTER log_id("cloudaudit.googleapis.com/activity") OR log_id("cloudaudit.googleapis.com/system_event") OR log_id("cloudaudit.googleapis.com/policy") OR log_id("cloudaudit.googleapis.com/access_transparency") FILTER type = "logging" } iam = { filter = <<-FILTER protoPayload.serviceName="iamcredentials.googleapis.com" OR protoPayload.serviceName="iam.googleapis.com" OR protoPayload.serviceName="sts.googleapis.com" FILTER type = "logging" } vpc-sc = { filter = <<-FILTER protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata" FILTER type = "logging" } workspace-audit-logs = { filter = <<-FILTER log_id("cloudaudit.googleapis.com/data_access") AND protoPayload.serviceName="login.googleapis.com" FILTER type = "logging" } }">{…}</code> | |
|
||||
| [org_policies_config](variables.tf#L217) | Organization policies customization. | <code title="object({ constraints = optional(object({ allowed_policy_member_domains = optional(list(string), []) }), {}) import_defaults = optional(bool, false) tag_name = optional(string, "org-policies") tag_values = optional(map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) id = optional(string) })), {}) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [outputs_location](variables.tf#L243) | 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#L258) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the organization as parent. | <code title="object({ automation = optional(string) billing = optional(string) logging = optional(string) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [workforce_identity_providers](variables.tf#L269) | Workforce Identity Federation pools. | <code title="map(object({ attribute_condition = optional(string) issuer = string display_name = string description = string disabled = optional(bool, false) saml = optional(object({ idp_metadata_xml = string }), null) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [workload_identity_providers](variables.tf#L285) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | <code title="map(object({ attribute_condition = optional(string) issuer = string custom_settings = optional(object({ issuer_uri = optional(string) audiences = optional(list(string), []) jwks_json = optional(string) }), {}) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [custom_roles](variables.tf#L81) | Map of role names => list of permissions to additionally create at the organization level. | <code>map(list(string))</code> | | <code>{}</code> | |
|
||||
| [essential_contacts](variables.tf#L88) | Email used for essential contacts, unset if null. | <code>string</code> | | <code>null</code> | |
|
||||
| [factories_config](variables.tf#L94) | Configuration for the resource factories or external data. | <code title="object({ checklist_data = optional(string) checklist_org_iam = optional(string) custom_roles = optional(string, "data/custom-roles") org_policy = optional(string, "data/org-policies") })">object({…})</code> | | <code>{}</code> | |
|
||||
| [groups](variables.tf#L106) | Group names or IAM-format principals to grant organization-level permissions. If just the name is provided, the 'group:' principal and organization domain are interpolated. | <code title="object({ gcp-billing-admins = optional(string, "gcp-billing-admins") gcp-devops = optional(string, "gcp-devops") gcp-network-admins = optional(string, "gcp-vpc-network-admins") gcp-organization-admins = optional(string, "gcp-organization-admins") gcp-security-admins = optional(string, "gcp-security-admins") gcp-support = optional(string, "gcp-devops") })">object({…})</code> | | <code>{}</code> | |
|
||||
| [iam](variables.tf#L122) | Organization-level custom IAM settings in role => [principal] format. | <code>map(list(string))</code> | | <code>{}</code> | |
|
||||
| [iam_bindings_additive](variables.tf#L129) | Organization-level custom additive IAM bindings. Keys are arbitrary. | <code title="map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [iam_by_principals](variables.tf#L144) | Authoritative IAM binding in {PRINCIPAL => [ROLES]} format. Principals need to be statically defined to avoid cycle errors. Merged internally with the `iam` variable. | <code>map(list(string))</code> | | <code>{}</code> | |
|
||||
| [locations](variables.tf#L151) | Optional locations for GCS, BigQuery, and logging buckets created here. | <code title="object({ bq = optional(string, "EU") gcs = optional(string, "EU") logging = optional(string, "global") pubsub = optional(list(string), []) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [log_sinks](variables.tf#L165) | Org-level log sinks, in name => {type, filter} format. | <code title="map(object({ filter = string type = string }))">map(object({…}))</code> | | <code title="{ audit-logs = { filter = <<-FILTER log_id("cloudaudit.googleapis.com/activity") OR log_id("cloudaudit.googleapis.com/system_event") OR log_id("cloudaudit.googleapis.com/policy") OR log_id("cloudaudit.googleapis.com/access_transparency") FILTER type = "logging" } iam = { filter = <<-FILTER protoPayload.serviceName="iamcredentials.googleapis.com" OR protoPayload.serviceName="iam.googleapis.com" OR protoPayload.serviceName="sts.googleapis.com" FILTER type = "logging" } vpc-sc = { filter = <<-FILTER protoPayload.metadata.@type="type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata" FILTER type = "logging" } workspace-audit-logs = { filter = <<-FILTER log_id("cloudaudit.googleapis.com/data_access") AND protoPayload.serviceName="login.googleapis.com" FILTER type = "logging" } }">{…}</code> | |
|
||||
| [org_policies_config](variables.tf#L213) | Organization policies customization. | <code title="object({ constraints = optional(object({ allowed_policy_member_domains = optional(list(string), []) }), {}) import_defaults = optional(bool, false) tag_name = optional(string, "org-policies") tag_values = optional(map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) id = optional(string) })), {}) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [outputs_location](variables.tf#L239) | 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#L254) | Optional parents for projects created here in folders/nnnnnnn format. Null values will use the organization as parent. | <code title="object({ automation = optional(string) billing = optional(string) logging = optional(string) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [workforce_identity_providers](variables.tf#L265) | Workforce Identity Federation pools. | <code title="map(object({ attribute_condition = optional(string) issuer = string display_name = string description = string disabled = optional(bool, false) saml = optional(object({ idp_metadata_xml = string }), null) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [workload_identity_providers](variables.tf#L281) | Workload Identity Federation pools. The `cicd_repositories` variable references keys here. | <code title="map(object({ attribute_condition = optional(string) issuer = string custom_settings = optional(object({ issuer_uri = optional(string) audiences = optional(list(string), []) jwks_json = optional(string) }), {}) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
||||
@@ -145,7 +145,6 @@ module "automation-project" {
|
||||
"pubsub.googleapis.com",
|
||||
"servicenetworking.googleapis.com",
|
||||
"serviceusage.googleapis.com",
|
||||
"sourcerepo.googleapis.com",
|
||||
"stackdriver.googleapis.com",
|
||||
"storage-component.googleapis.com",
|
||||
"storage.googleapis.com",
|
||||
|
||||
@@ -36,13 +36,9 @@ locals {
|
||||
if(
|
||||
v != null
|
||||
&&
|
||||
(
|
||||
try(v.type, null) == "sourcerepo"
|
||||
||
|
||||
contains(
|
||||
keys(local.workload_identity_providers),
|
||||
coalesce(try(v.identity_provider, null), ":")
|
||||
)
|
||||
contains(
|
||||
keys(local.workload_identity_providers),
|
||||
coalesce(try(v.identity_provider, null), ":")
|
||||
)
|
||||
&&
|
||||
fileexists(
|
||||
@@ -71,44 +67,6 @@ locals {
|
||||
}
|
||||
}
|
||||
|
||||
# source repository
|
||||
|
||||
module "automation-tf-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = {
|
||||
for k, v in local.cicd_repositories : k => v if v.type == "sourcerepo"
|
||||
}
|
||||
project_id = module.automation-project.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = [
|
||||
each.key == "bootstrap"
|
||||
? module.automation-tf-bootstrap-sa.iam_email
|
||||
: module.automation-tf-resman-sa.iam_email
|
||||
]
|
||||
"roles/source.reader" = concat(
|
||||
[module.automation-tf-cicd-sa[each.key].iam_email],
|
||||
each.key == "bootstrap"
|
||||
? [module.automation-tf-bootstrap-r-sa.iam_email]
|
||||
: [module.automation-tf-resman-r-sa.iam_email]
|
||||
)
|
||||
}
|
||||
triggers = {
|
||||
"fast-0-${each.key}" = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = ["**/*tf", ".cloudbuild/workflow.yaml"]
|
||||
service_account = module.automation-tf-cicd-sa[each.key].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# SAs used by CI/CD workflows to impersonate automation SAs
|
||||
|
||||
module "automation-tf-cicd-sa" {
|
||||
@@ -118,28 +76,22 @@ module "automation-tf-cicd-sa" {
|
||||
name = "${each.key}-1"
|
||||
display_name = "Terraform CI/CD ${each.key} service account."
|
||||
prefix = local.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.workload_identity_providers_defs[each.value.type].principal_repo,
|
||||
google_iam_workload_identity_pool.default[0].name,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.workload_identity_providers_defs[each.value.type].principal_branch,
|
||||
google_iam_workload_identity_pool.default[0].name,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.workload_identity_providers_defs[each.value.type].principal_repo,
|
||||
google_iam_workload_identity_pool.default[0].name,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.workload_identity_providers_defs[each.value.type].principal_branch,
|
||||
google_iam_workload_identity_pool.default[0].name,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(module.automation-project.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -155,21 +107,15 @@ module "automation-tf-cicd-r-sa" {
|
||||
name = "${each.key}-1r"
|
||||
display_name = "Terraform CI/CD ${each.key} service account (read-only)."
|
||||
prefix = local.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.workload_identity_providers_defs[each.value.type].principal_repo,
|
||||
google_iam_workload_identity_pool.default[0].name,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.workload_identity_providers_defs[each.value.type].principal_repo,
|
||||
google_iam_workload_identity_pool.default[0].name,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(module.automation-project.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
|
||||
@@ -63,22 +63,18 @@ variable "cicd_repositories" {
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in coalesce(var.cicd_repositories, {}) :
|
||||
v == null || (
|
||||
try(v.identity_provider, null) != null
|
||||
||
|
||||
try(v.type, null) == "sourcerepo"
|
||||
)
|
||||
v == null || try(v.identity_provider, null) != null
|
||||
])
|
||||
error_message = "Non-null repositories need a non-null provider unless type is 'sourcerepo'."
|
||||
error_message = "Non-null repositories need a non-null provider."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in coalesce(var.cicd_repositories, {}) :
|
||||
v == null || (
|
||||
contains(["github", "gitlab", "sourcerepo"], coalesce(try(v.type, null), "null"))
|
||||
contains(["github", "gitlab"], coalesce(try(v.type, null), "null"))
|
||||
)
|
||||
])
|
||||
error_message = "Invalid repository type, supported types: 'github' 'gitlab' or 'sourcerepo'."
|
||||
error_message = "Invalid repository type, supported types: 'github' or 'gitlab'."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -241,12 +241,12 @@ A full reference of IAM roles managed by this stage [is available here](./IAM.md
|
||||
| [branch-sandbox.tf](./branch-sandbox.tf) | Sandbox stage resources. | <code>folder</code> · <code>gcs</code> · <code>iam-service-account</code> | |
|
||||
| [branch-security.tf](./branch-security.tf) | Security stage resources. | <code>folder</code> · <code>gcs</code> · <code>iam-service-account</code> | |
|
||||
| [checklist.tf](./checklist.tf) | None | <code>folder</code> | |
|
||||
| [cicd-data-platform.tf](./cicd-data-platform.tf) | CI/CD resources for the data platform branch. | <code>iam-service-account</code> · <code>source-repository</code> | |
|
||||
| [cicd-gcve.tf](./cicd-gcve.tf) | CI/CD resources for the GCVE branch. | <code>iam-service-account</code> · <code>source-repository</code> | |
|
||||
| [cicd-gke.tf](./cicd-gke.tf) | CI/CD resources for the GKE multitenant branch. | <code>iam-service-account</code> · <code>source-repository</code> | |
|
||||
| [cicd-networking.tf](./cicd-networking.tf) | CI/CD resources for the networking branch. | <code>iam-service-account</code> · <code>source-repository</code> | |
|
||||
| [cicd-project-factory.tf](./cicd-project-factory.tf) | CI/CD resources for the project factories. | <code>iam-service-account</code> · <code>source-repository</code> | |
|
||||
| [cicd-security.tf](./cicd-security.tf) | CI/CD resources for the security branch. | <code>iam-service-account</code> · <code>source-repository</code> | |
|
||||
| [cicd-data-platform.tf](./cicd-data-platform.tf) | CI/CD resources for the data platform branch. | <code>iam-service-account</code> | |
|
||||
| [cicd-gcve.tf](./cicd-gcve.tf) | CI/CD resources for the GCVE branch. | <code>iam-service-account</code> | |
|
||||
| [cicd-gke.tf](./cicd-gke.tf) | CI/CD resources for the GKE multitenant branch. | <code>iam-service-account</code> | |
|
||||
| [cicd-networking.tf](./cicd-networking.tf) | CI/CD resources for the networking branch. | <code>iam-service-account</code> | |
|
||||
| [cicd-project-factory.tf](./cicd-project-factory.tf) | CI/CD resources for the project factories. | <code>iam-service-account</code> | |
|
||||
| [cicd-security.tf](./cicd-security.tf) | CI/CD resources for the security branch. | <code>iam-service-account</code> | |
|
||||
| [iam.tf](./iam.tf) | Organization or root node-level IAM bindings. | | |
|
||||
| [main.tf](./main.tf) | Module-level locals and resources. | | |
|
||||
| [organization.tf](./organization.tf) | Organization policies. | <code>organization</code> | |
|
||||
@@ -270,16 +270,16 @@ A full reference of IAM roles managed by this stage [is available here](./IAM.md
|
||||
| [prefix](variables-fast.tf#L124) | Prefix used for resources that need unique names. Use 9 characters or less. | <code>string</code> | ✓ | | <code>0-bootstrap</code> |
|
||||
| [cicd_repositories](variables.tf#L20) | 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({ data_platform_dev = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) data_platform_prod = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) gke_dev = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) gke_prod = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) gcve_dev = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) gcve_prod = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) networking = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) project_factory_dev = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) project_factory_prod = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) security = optional(object({ name = string type = string branch = optional(string) identity_provider = optional(string) })) })">object({…})</code> | | <code>null</code> | |
|
||||
| [custom_roles](variables-fast.tf#L53) | Custom roles defined at the org level, in key => id format. | <code title="object({ gcve_network_admin = string organization_admin_viewer = string service_project_network_admin = string storage_viewer = string })">object({…})</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [factories_config](variables.tf#L114) | Configuration for the resource factories or external data. | <code title="object({ checklist_data = optional(string) org_policies = optional(string, "data/org-policies") top_level_folders = optional(string) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [fast_features](variables.tf#L125) | Selective control for top-level FAST features. | <code title="object({ data_platform = optional(bool, false) gke = optional(bool, false) gcve = optional(bool, false) project_factory = optional(bool, false) sandbox = optional(bool, false) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [folder_iam](variables.tf#L138) | Authoritative IAM for top-level folders. | <code title="object({ data_platform = optional(map(list(string)), {}) gcve = optional(map(list(string)), {}) gke = optional(map(list(string)), {}) sandbox = optional(map(list(string)), {}) security = optional(map(list(string)), {}) network = optional(map(list(string)), {}) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [factories_config](variables.tf#L110) | Configuration for the resource factories or external data. | <code title="object({ checklist_data = optional(string) org_policies = optional(string, "data/org-policies") top_level_folders = optional(string) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [fast_features](variables.tf#L121) | Selective control for top-level FAST features. | <code title="object({ data_platform = optional(bool, false) gke = optional(bool, false) gcve = optional(bool, false) project_factory = optional(bool, false) sandbox = optional(bool, false) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [folder_iam](variables.tf#L134) | Authoritative IAM for top-level folders. | <code title="object({ data_platform = optional(map(list(string)), {}) gcve = optional(map(list(string)), {}) gke = optional(map(list(string)), {}) sandbox = optional(map(list(string)), {}) security = optional(map(list(string)), {}) network = optional(map(list(string)), {}) })">object({…})</code> | | <code>{}</code> | |
|
||||
| [groups](variables-fast.tf#L65) | Group names or IAM-format principals to grant organization-level permissions. If just the name is provided, the 'group:' principal and organization domain are interpolated. | <code title="object({ gcp-billing-admins = optional(string, "gcp-billing-admins") gcp-devops = optional(string, "gcp-devops") gcp-network-admins = optional(string, "gcp-vpc-network-admins") gcp-organization-admins = optional(string, "gcp-organization-admins") gcp-security-admins = optional(string, "gcp-security-admins") })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [locations](variables-fast.tf#L80) | Optional locations for GCS, BigQuery, and logging buckets created here. | <code title="object({ bq = optional(string, "EU") gcs = optional(string, "EU") logging = optional(string, "global") pubsub = optional(list(string), []) })">object({…})</code> | | <code>{}</code> | <code>0-bootstrap</code> |
|
||||
| [outputs_location](variables.tf#L152) | 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#L148) | Enable writing provider, tfvars and CI/CD workflow files to local filesystem. Leave null to disable. | <code>string</code> | | <code>null</code> | |
|
||||
| [root_node](variables-fast.tf#L130) | Root node for the hierarchy, if running in tenant mode. | <code>string</code> | | <code>null</code> | <code>0-bootstrap</code> |
|
||||
| [tag_names](variables.tf#L158) | Customized names for resource management tags. | <code title="object({ context = optional(string, "context") environment = optional(string, "environment") })">object({…})</code> | | <code>{}</code> | |
|
||||
| [tags](variables.tf#L172) | Custom secure tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) values = optional(map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) id = optional(string) })), {}) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [top_level_folders](variables.tf#L193) | Additional top-level folders. Keys are used for service account and bucket names, values implement the folders module interface with the addition of the 'automation' attribute. | <code title="map(object({ name = string automation = optional(object({ enable = optional(bool, true) sa_impersonation_principals = optional(list(string), []) }), {}) contacts = optional(map(list(string)), {}) firewall_policy = optional(object({ name = string policy = string })) logging_data_access = optional(map(map(list(string))), {}) logging_exclusions = optional(map(string), {}) logging_settings = optional(object({ disable_default_sink = optional(bool) storage_location = optional(string) })) logging_sinks = optional(map(object({ bq_partitioned_table = optional(bool, false) description = optional(string) destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) filter = optional(string) iam = optional(bool, true) include_children = optional(bool, true) type = string })), {}) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) iam_bindings_additive = optional(map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) iam_by_principals = optional(map(list(string)), {}) org_policies = optional(map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) rules = optional(list(object({ allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool) # for boolean policies only. condition = optional(object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) }), {}) })), []) })), {}) tag_bindings = optional(map(string), {}) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [tag_names](variables.tf#L154) | Customized names for resource management tags. | <code title="object({ context = optional(string, "context") environment = optional(string, "environment") })">object({…})</code> | | <code>{}</code> | |
|
||||
| [tags](variables.tf#L168) | Custom secure tags by key name. The `iam` attribute behaves like the similarly named one at module level. | <code title="map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) values = optional(map(object({ description = optional(string, "Managed by the Terraform organization module.") iam = optional(map(list(string)), {}) id = optional(string) })), {}) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
| [top_level_folders](variables.tf#L189) | Additional top-level folders. Keys are used for service account and bucket names, values implement the folders module interface with the addition of the 'automation' attribute. | <code title="map(object({ name = string automation = optional(object({ enable = optional(bool, true) sa_impersonation_principals = optional(list(string), []) }), {}) contacts = optional(map(list(string)), {}) firewall_policy = optional(object({ name = string policy = string })) logging_data_access = optional(map(map(list(string))), {}) logging_exclusions = optional(map(string), {}) logging_settings = optional(object({ disable_default_sink = optional(bool) storage_location = optional(string) })) logging_sinks = optional(map(object({ bq_partitioned_table = optional(bool, false) description = optional(string) destination = string disabled = optional(bool, false) exclusions = optional(map(string), {}) filter = optional(string) iam = optional(bool, true) include_children = optional(bool, true) type = string })), {}) iam = optional(map(list(string)), {}) iam_bindings = optional(map(object({ members = list(string) role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) iam_bindings_additive = optional(map(object({ member = string role = string condition = optional(object({ expression = string title = string description = optional(string) })) })), {}) iam_by_principals = optional(map(list(string)), {}) org_policies = optional(map(object({ inherit_from_parent = optional(bool) # for list policies only. reset = optional(bool) rules = optional(list(object({ allow = optional(object({ all = optional(bool) values = optional(list(string)) })) deny = optional(object({ all = optional(bool) values = optional(list(string)) })) enforce = optional(bool) # for boolean policies only. condition = optional(object({ description = optional(string) expression = optional(string) location = optional(string) title = optional(string) }), {}) })), []) })), {}) tag_bindings = optional(map(string), {}) }))">map(object({…}))</code> | | <code>{}</code> | |
|
||||
|
||||
## Outputs
|
||||
|
||||
|
||||
@@ -16,76 +16,6 @@
|
||||
|
||||
# tfdoc:file:description CI/CD resources for the data platform branch.
|
||||
|
||||
# source repositories
|
||||
|
||||
module "branch-dp-dev-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.data_platform_dev.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.data_platform_dev }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = compact([
|
||||
try(module.branch-dp-dev-sa[0].iam_email, "")
|
||||
])
|
||||
"roles/source.reader" = compact([
|
||||
try(module.branch-dp-dev-sa-cicd[0].iam_email, "")
|
||||
])
|
||||
}
|
||||
triggers = {
|
||||
fast-03-dp-dev = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = [
|
||||
"**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
|
||||
]
|
||||
service_account = module.branch-dp-dev-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-dp-dev-sa-cicd]
|
||||
}
|
||||
|
||||
module "branch-dp-prod-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.data_platform_prod.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.data_platform_prod }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = [module.branch-dp-prod-sa[0].iam_email]
|
||||
"roles/source.reader" = [module.branch-dp-prod-sa-cicd[0].iam_email]
|
||||
}
|
||||
triggers = {
|
||||
fast-03-dp-prod = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = [
|
||||
"**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
|
||||
]
|
||||
service_account = module.branch-dp-prod-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-dp-prod-sa-cicd]
|
||||
}
|
||||
|
||||
# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs
|
||||
|
||||
module "branch-dp-dev-sa-cicd" {
|
||||
@@ -99,30 +29,22 @@ module "branch-dp-dev-sa-cicd" {
|
||||
name = "dev-resman-dp-1"
|
||||
display_name = "Terraform CI/CD data platform development service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -142,30 +64,22 @@ module "branch-dp-prod-sa-cicd" {
|
||||
name = "prod-resman-dp-1"
|
||||
display_name = "Terraform CI/CD data platform production service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -187,21 +101,15 @@ module "branch-dp-dev-r-sa-cicd" {
|
||||
name = "dev-resman-dp-1r"
|
||||
display_name = "Terraform CI/CD data platform development service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -221,21 +129,15 @@ module "branch-dp-prod-r-sa-cicd" {
|
||||
name = "prod-resman-dp-1r"
|
||||
display_name = "Terraform CI/CD data platform production service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
|
||||
@@ -16,76 +16,6 @@
|
||||
|
||||
# tfdoc:file:description CI/CD resources for the GCVE branch.
|
||||
|
||||
# source repositories
|
||||
|
||||
module "branch-gcve-dev-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.gcve_dev.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.gcve_dev }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = compact([
|
||||
try(module.branch-gcve-dev-sa[0].iam_email, "")
|
||||
])
|
||||
"roles/source.reader" = compact([
|
||||
try(module.branch-gcve-dev-sa-cicd[0].iam_email, "")
|
||||
])
|
||||
}
|
||||
triggers = {
|
||||
fast-03-gcve-dev = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = [
|
||||
"**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
|
||||
]
|
||||
service_account = module.branch-gcve-dev-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-gcve-dev-sa-cicd]
|
||||
}
|
||||
|
||||
module "branch-gcve-prod-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.gcve_prod.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.gcve_prod }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = [module.branch-gcve-prod-sa[0].iam_email]
|
||||
"roles/source.reader" = [module.branch-gcve-prod-sa-cicd[0].iam_email]
|
||||
}
|
||||
triggers = {
|
||||
fast-03-gcve-prod = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = [
|
||||
"**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
|
||||
]
|
||||
service_account = module.branch-gcve-prod-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-gcve-prod-sa-cicd]
|
||||
}
|
||||
|
||||
# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs
|
||||
|
||||
module "branch-gcve-dev-sa-cicd" {
|
||||
@@ -99,30 +29,22 @@ module "branch-gcve-dev-sa-cicd" {
|
||||
name = "dev-resman-gcve-1"
|
||||
display_name = "Terraform CI/CD GCVE development service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -142,30 +64,22 @@ module "branch-gcve-prod-sa-cicd" {
|
||||
name = "prod-resman-gcve-1"
|
||||
display_name = "Terraform CI/CD GCVE production service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -187,21 +101,15 @@ module "branch-gcve-dev-r-sa-cicd" {
|
||||
name = "dev-resman-gcve-1r"
|
||||
display_name = "Terraform CI/CD GCVE development service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -221,21 +129,15 @@ module "branch-gcve-prod-r-sa-cicd" {
|
||||
name = "prod-resman-gcve-1r"
|
||||
display_name = "Terraform CI/CD GCVE production service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
|
||||
@@ -16,76 +16,6 @@
|
||||
|
||||
# tfdoc:file:description CI/CD resources for the GKE multitenant branch.
|
||||
|
||||
# source repositories
|
||||
|
||||
module "branch-gke-dev-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.gke_dev.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.gke_dev }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = compact([
|
||||
try(module.branch-gke-dev-sa[0].iam_email, "")
|
||||
])
|
||||
"roles/source.reader" = compact([
|
||||
try(module.branch-gke-dev-sa-cicd[0].iam_email, "")
|
||||
])
|
||||
}
|
||||
triggers = {
|
||||
fast-03-gke-dev = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = [
|
||||
"**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
|
||||
]
|
||||
service_account = module.branch-gke-dev-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-gke-dev-sa-cicd]
|
||||
}
|
||||
|
||||
module "branch-gke-prod-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.gke_prod.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.gke_prod }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = [module.branch-gke-prod-sa[0].iam_email]
|
||||
"roles/source.reader" = [module.branch-gke-prod-sa-cicd[0].iam_email]
|
||||
}
|
||||
triggers = {
|
||||
fast-03-gke-prod = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = [
|
||||
"**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
|
||||
]
|
||||
service_account = module.branch-gke-prod-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-gke-prod-sa-cicd]
|
||||
}
|
||||
|
||||
# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs
|
||||
|
||||
module "branch-gke-dev-sa-cicd" {
|
||||
@@ -99,30 +29,22 @@ module "branch-gke-dev-sa-cicd" {
|
||||
name = "dev-resman-gke-1"
|
||||
display_name = "Terraform CI/CD GKE development service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -142,30 +64,22 @@ module "branch-gke-prod-sa-cicd" {
|
||||
name = "prod-resman-gke-1"
|
||||
display_name = "Terraform CI/CD GKE production service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -187,21 +101,15 @@ module "branch-gke-dev-r-sa-cicd" {
|
||||
name = "dev-resman-gke-1r"
|
||||
display_name = "Terraform CI/CD gke multitenant development service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -221,21 +129,15 @@ module "branch-gke-prod-r-sa-cicd" {
|
||||
name = "prod-resman-gke-1r"
|
||||
display_name = "Terraform CI/CD gke multitenant production service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
|
||||
@@ -16,38 +16,6 @@
|
||||
|
||||
# tfdoc:file:description CI/CD resources for the networking branch.
|
||||
|
||||
# source repository
|
||||
|
||||
module "branch-network-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.networking.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.networking }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = [module.branch-network-sa.iam_email]
|
||||
"roles/source.reader" = [module.branch-network-sa-cicd[0].iam_email]
|
||||
}
|
||||
triggers = {
|
||||
fast-02-networking = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = ["**/*tf", ".cloudbuild/workflow.yaml"]
|
||||
service_account = module.branch-network-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-network-sa-cicd]
|
||||
}
|
||||
|
||||
# read-write (apply) SA used by CI/CD workflows to impersonate automation SA
|
||||
|
||||
module "branch-network-sa-cicd" {
|
||||
@@ -61,30 +29,22 @@ module "branch-network-sa-cicd" {
|
||||
name = "prod-resman-net-1"
|
||||
display_name = "Terraform CI/CD stage 2 networking service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -106,21 +66,15 @@ module "branch-network-r-sa-cicd" {
|
||||
name = "prod-resman-net-1r"
|
||||
display_name = "Terraform CI/CD stage 2 networking service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
|
||||
@@ -16,72 +16,6 @@
|
||||
|
||||
# tfdoc:file:description CI/CD resources for the project factories.
|
||||
|
||||
# source repositories
|
||||
|
||||
module "branch-pf-dev-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.project_factory_dev.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.project_factory_dev }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = [module.branch-pf-dev-sa[0].iam_email]
|
||||
"roles/source.reader" = [module.branch-pf-dev-sa-cicd[0].iam_email]
|
||||
}
|
||||
triggers = {
|
||||
fast-03-pf-dev = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = [
|
||||
"**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
|
||||
]
|
||||
service_account = module.branch-pf-dev-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-pf-dev-sa-cicd]
|
||||
}
|
||||
|
||||
module "branch-pf-prod-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.project_factory_prod.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.project_factory_prod }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = [module.branch-pf-prod-sa[0].iam_email]
|
||||
"roles/source.reader" = [module.branch-pf-prod-sa-cicd[0].iam_email]
|
||||
}
|
||||
triggers = {
|
||||
fast-03-pf-prod = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = [
|
||||
"**/*json", "**/*tf", "**/*yaml", ".cloudbuild/workflow.yaml"
|
||||
]
|
||||
service_account = module.branch-pf-prod-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-pf-prod-sa-cicd]
|
||||
}
|
||||
|
||||
# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs
|
||||
|
||||
module "branch-pf-dev-sa-cicd" {
|
||||
@@ -95,30 +29,22 @@ module "branch-pf-dev-sa-cicd" {
|
||||
name = "dev-pf-resman-pf-1"
|
||||
display_name = "Terraform CI/CD project factory development service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -138,30 +64,22 @@ module "branch-pf-prod-sa-cicd" {
|
||||
name = "prod-pf-resman-pf-1"
|
||||
display_name = "Terraform CI/CD project factory production service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -183,21 +101,15 @@ module "branch-pf-dev-r-sa-cicd" {
|
||||
name = "dev-resman-pf-1r"
|
||||
display_name = "Terraform CI/CD project factory development service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -217,21 +129,15 @@ module "branch-pf-prod-r-sa-cicd" {
|
||||
name = "prod-resman-pf-1r"
|
||||
display_name = "Terraform CI/CD project factory production service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
|
||||
@@ -16,38 +16,6 @@
|
||||
|
||||
# tfdoc:file:description CI/CD resources for the security branch.
|
||||
|
||||
# source repository
|
||||
|
||||
module "branch-security-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = (
|
||||
try(local.cicd_repositories.security.type, null) == "sourcerepo"
|
||||
? { 0 = local.cicd_repositories.security }
|
||||
: {}
|
||||
)
|
||||
project_id = var.automation.project_id
|
||||
name = each.value.name
|
||||
iam = {
|
||||
"roles/source.admin" = [module.branch-security-sa.iam_email]
|
||||
"roles/source.reader" = [module.branch-security-sa-cicd[0].iam_email]
|
||||
}
|
||||
triggers = {
|
||||
fast-02-security = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = ["**/*tf", ".cloudbuild/workflow.yaml"]
|
||||
service_account = module.branch-security-sa-cicd[0].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.branch-security-sa-cicd]
|
||||
}
|
||||
|
||||
# read-write (apply) SA used by CI/CD workflows to impersonate automation SA
|
||||
|
||||
module "branch-security-sa-cicd" {
|
||||
@@ -61,30 +29,22 @@ module "branch-security-sa-cicd" {
|
||||
name = "prod-resman-sec-1"
|
||||
display_name = "Terraform CI/CD stage 2 security service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {
|
||||
"roles/iam.serviceAccountUser" = local.automation_resman_sa_iam
|
||||
}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
each.value.branch == null
|
||||
? format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
: format(
|
||||
local.identity_providers[each.value.identity_provider].principal_branch,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name,
|
||||
each.value.branch
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
@@ -106,21 +66,15 @@ module "branch-security-r-sa-cicd" {
|
||||
name = "prod-resman-sec-1r"
|
||||
display_name = "Terraform CI/CD stage 2 security service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
)
|
||||
iam = {
|
||||
"roles/iam.workloadIdentityUser" = [
|
||||
format(
|
||||
local.identity_providers[each.value.identity_provider].principal_repo,
|
||||
var.automation.federated_identity_pool,
|
||||
each.value.name
|
||||
)
|
||||
]
|
||||
}
|
||||
iam_project_roles = {
|
||||
(var.automation.project_id) = ["roles/logging.logWriter"]
|
||||
}
|
||||
|
||||
@@ -15,15 +15,12 @@
|
||||
*/
|
||||
|
||||
locals {
|
||||
# convenience flags that express where billing account resides
|
||||
automation_resman_sa = try(
|
||||
data.google_client_openid_userinfo.provider_identity[0].email, null
|
||||
)
|
||||
automation_resman_sa_iam = (
|
||||
local.automation_resman_sa == null
|
||||
? []
|
||||
: ["serviceAccount:${local.automation_resman_sa}"]
|
||||
)
|
||||
# leaving this here to document how to get self identity in a stage
|
||||
|
||||
# automation_resman_sa = try(
|
||||
# data.google_client_openid_userinfo.provider_identity[0].email, null
|
||||
# )
|
||||
|
||||
# service accounts that receive additional grants on networking/security
|
||||
branch_optional_sa_lists = {
|
||||
dp-dev = compact([try(module.branch-dp-dev-sa[0].iam_email, "")])
|
||||
@@ -50,13 +47,9 @@ locals {
|
||||
for k, v in coalesce(var.cicd_repositories, {}) : k => v
|
||||
if(
|
||||
v != null &&
|
||||
(
|
||||
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("${path.module}/templates/workflow-${try(v.type, "")}.yaml")
|
||||
)
|
||||
@@ -113,6 +106,6 @@ locals {
|
||||
)
|
||||
}
|
||||
|
||||
data "google_client_openid_userinfo" "provider_identity" {
|
||||
count = length(local.cicd_repositories) > 0 ? 1 : 0
|
||||
}
|
||||
# data "google_client_openid_userinfo" "provider_identity" {
|
||||
# count = length(local.cicd_repositories) > 0 ? 1 : 0
|
||||
# }
|
||||
|
||||
@@ -92,22 +92,18 @@ variable "cicd_repositories" {
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in coalesce(var.cicd_repositories, {}) :
|
||||
v == null || (
|
||||
try(v.identity_provider, null) != null
|
||||
||
|
||||
try(v.type, null) == "sourcerepo"
|
||||
)
|
||||
v == null || try(v.identity_provider, null) != null
|
||||
])
|
||||
error_message = "Non-null repositories need a non-null provider unless type is 'sourcerepo'."
|
||||
error_message = "Non-null repositories need a non-null provider."
|
||||
}
|
||||
validation {
|
||||
condition = alltrue([
|
||||
for k, v in coalesce(var.cicd_repositories, {}) :
|
||||
v == null || (
|
||||
contains(["github", "gitlab", "sourcerepo"], coalesce(try(v.type, null), "null"))
|
||||
contains(["github", "gitlab"], coalesce(try(v.type, null), "null"))
|
||||
)
|
||||
])
|
||||
error_message = "Invalid repository type, supported types: 'github' 'gitlab' or 'sourcerepo'."
|
||||
error_message = "Invalid repository type, supported types: 'github' or 'gitlab'."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -295,7 +295,7 @@ gcloud alpha storage cp gs://{prefix}-{tenant-shortname}-prod-iac-core-0/tfvars/
|
||||
| [tenant-billing-iam.tf](./tenant-billing-iam.tf) | Per-tenant billing IAM. | <code>billing-account</code> · <code>organization</code> | |
|
||||
| [tenant-core.tf](./tenant-core.tf) | Per-tenant centrally managed resources. | <code>folder</code> · <code>logging-bucket</code> | |
|
||||
| [tenant-fast-automation.tf](./tenant-fast-automation.tf) | Per-tenant FAST bootstrap emulation (automation). | <code>gcs</code> · <code>iam-service-account</code> · <code>project</code> | |
|
||||
| [tenant-fast-cicd.tf](./tenant-fast-cicd.tf) | Per-tenant CI/CD resources. | <code>iam-service-account</code> · <code>source-repository</code> | |
|
||||
| [tenant-fast-cicd.tf](./tenant-fast-cicd.tf) | Per-tenant CI/CD resources. | <code>iam-service-account</code> | |
|
||||
| [tenant-fast-identity-providers.tf](./tenant-fast-identity-providers.tf) | Per-tenant Workload Identity Federation providers. | | <code>google_iam_workload_identity_pool</code> · <code>google_iam_workload_identity_pool_provider</code> |
|
||||
| [tenant-fast-logging.tf](./tenant-fast-logging.tf) | Per-tenant FAST bootstrap emulation (logging). | <code>project</code> | |
|
||||
| [tenant-fast-vpcsc.tf](./tenant-fast-vpcsc.tf) | Per-tenant VPC-SC resources. | <code>vpc-sc</code> | |
|
||||
|
||||
@@ -71,7 +71,6 @@ module "tenant-automation-project" {
|
||||
"pubsub.googleapis.com",
|
||||
"servicenetworking.googleapis.com",
|
||||
"serviceusage.googleapis.com",
|
||||
"sourcerepo.googleapis.com",
|
||||
"stackdriver.googleapis.com",
|
||||
"storage-component.googleapis.com",
|
||||
"storage.googleapis.com",
|
||||
|
||||
@@ -65,9 +65,6 @@ locals {
|
||||
&&
|
||||
# either
|
||||
(
|
||||
# don't need a WIF provider, or
|
||||
try(v.fast_config.cicd_config.type, null) == "sourcerepo"
|
||||
||
|
||||
# use an org-level WIF provider, or
|
||||
try(var.automation.federated_identity_providers[v.wif_provider], null) != null
|
||||
||
|
||||
@@ -85,39 +82,6 @@ locals {
|
||||
}
|
||||
}
|
||||
|
||||
module "tenant-cicd-repo" {
|
||||
source = "../../../modules/source-repository"
|
||||
for_each = {
|
||||
for k, v in local.cicd_repositories :
|
||||
k => v if v.type == "sourcerepo"
|
||||
}
|
||||
project_id = module.tenant-automation-project[each.key].project_id
|
||||
name = "tenant-${each.key}-resman"
|
||||
iam = {
|
||||
"roles/source.admin" = [
|
||||
module.tenant-automation-tf-resman-sa[each.key].iam_email
|
||||
]
|
||||
"roles/source.reader" = [
|
||||
module.tenant-automation-tf-cicd-sa[each.key].iam_email
|
||||
]
|
||||
}
|
||||
triggers = {
|
||||
fast-02-security = {
|
||||
filename = ".cloudbuild/workflow.yaml"
|
||||
included_files = ["**/*tf", ".cloudbuild/workflow.yaml"]
|
||||
service_account = module.tenant-automation-tf-cicd-sa[each.key].id
|
||||
substitutions = {}
|
||||
template = {
|
||||
project_id = null
|
||||
branch_name = each.value.branch
|
||||
repo_name = each.value.name
|
||||
tag_name = null
|
||||
}
|
||||
}
|
||||
}
|
||||
depends_on = [module.tenant-automation-tf-cicd-sa]
|
||||
}
|
||||
|
||||
# read-write (apply) SA used by CI/CD workflows to impersonate automation SA
|
||||
|
||||
module "tenant-automation-tf-cicd-sa" {
|
||||
@@ -127,28 +91,22 @@ module "tenant-automation-tf-cicd-sa" {
|
||||
name = "${each.key}-1"
|
||||
display_name = "Terraform CI/CD ${each.key} service account."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# used directly from the cloud build trigger for source repos
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"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
|
||||
)
|
||||
: 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 = {
|
||||
"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
|
||||
)
|
||||
: 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"
|
||||
@@ -170,21 +128,15 @@ module "automation-tf-cicd-r-sa" {
|
||||
name = "tenant-${each.key}-1r"
|
||||
display_name = "Terraform CI/CD ${each.key} service account (read-only)."
|
||||
prefix = var.prefix
|
||||
iam = (
|
||||
each.value.type == "sourcerepo"
|
||||
# build trigger for read-only SA is optionally defined by users
|
||||
? {}
|
||||
# impersonated via workload identity federation for external repos
|
||||
: {
|
||||
"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 = {
|
||||
"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"
|
||||
|
||||
@@ -383,7 +383,7 @@ counts:
|
||||
google_project_iam_audit_config: 1
|
||||
google_project_iam_binding: 19
|
||||
google_project_iam_member: 7
|
||||
google_project_service: 31
|
||||
google_project_service: 30
|
||||
google_project_service_identity: 4
|
||||
google_service_account: 4
|
||||
google_service_account_iam_binding: 2
|
||||
@@ -395,4 +395,4 @@ counts:
|
||||
google_tags_tag_key: 1
|
||||
google_tags_tag_value: 1
|
||||
modules: 18
|
||||
resources: 206
|
||||
resources: 205
|
||||
|
||||
@@ -50,7 +50,7 @@ counts:
|
||||
google_project_iam_audit_config: 1
|
||||
google_project_iam_binding: 19
|
||||
google_project_iam_member: 7
|
||||
google_project_service: 31
|
||||
google_project_service: 30
|
||||
google_project_service_identity: 4
|
||||
google_service_account: 4
|
||||
google_service_account_iam_binding: 2
|
||||
@@ -63,7 +63,7 @@ counts:
|
||||
google_tags_tag_value: 1
|
||||
local_file: 8
|
||||
modules: 17
|
||||
resources: 198
|
||||
resources: 197
|
||||
|
||||
outputs:
|
||||
custom_roles:
|
||||
|
||||
@@ -29,7 +29,7 @@ counts:
|
||||
google_project_iam_audit_config: 2
|
||||
google_project_iam_binding: 32
|
||||
google_project_iam_member: 18
|
||||
google_project_service: 56
|
||||
google_project_service: 54
|
||||
google_project_service_identity: 8
|
||||
google_service_account: 16
|
||||
google_service_account_iam_binding: 6
|
||||
@@ -43,4 +43,4 @@ counts:
|
||||
google_tags_tag_key: 1
|
||||
google_tags_tag_value: 4
|
||||
modules: 50
|
||||
resources: 274
|
||||
resources: 272
|
||||
|
||||
Reference in New Issue
Block a user