Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add workforce_identity_federation in 0-bootstrap #2077

Merged
merged 8 commits into from Feb 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
65 changes: 45 additions & 20 deletions fast/stages/0-bootstrap/README.md

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions fast/stages/0-bootstrap/cicd.tf
Expand Up @@ -24,11 +24,11 @@ locals {
v.oidc[0].allowed_audiences,
["https://iam.googleapis.com/${v.name}"]
)
issuer = local.identity_providers[k].issuer
issuer = local.workload_identity_providers[k].issuer
issuer_uri = try(v.oidc[0].issuer_uri, null)
name = v.name
principal_branch = local.identity_providers[k].principal_branch
principal_repo = local.identity_providers[k].principal_repo
principal_branch = local.workload_identity_providers[k].principal_branch
principal_repo = local.workload_identity_providers[k].principal_repo
}
}
cicd_repositories = {
Expand All @@ -40,7 +40,7 @@ locals {
try(v.type, null) == "sourcerepo"
||
contains(
keys(local.identity_providers),
keys(local.workload_identity_providers),
coalesce(try(v.identity_provider, null), ":")
)
)
Expand Down Expand Up @@ -121,12 +121,12 @@ module "automation-tf-cicd-sa" {
"roles/iam.workloadIdentityUser" = [
each.value.branch == null
? format(
local.identity_providers_defs[each.value.type].principal_repo,
local.workload_identity_providers_defs[each.value.type].principal_repo,
google_iam_workload_identity_pool.default.0.name,
each.value.name
)
: format(
local.identity_providers_defs[each.value.type].principal_branch,
local.workload_identity_providers_defs[each.value.type].principal_branch,
google_iam_workload_identity_pool.default.0.name,
each.value.name,
each.value.branch
Expand Down Expand Up @@ -157,7 +157,7 @@ module "automation-tf-cicd-r-sa" {
: {
"roles/iam.workloadIdentityUser" = [
format(
local.identity_providers_defs[each.value.type].principal_repo,
local.workload_identity_providers_defs[each.value.type].principal_repo,
google_iam_workload_identity_pool.default.0.name,
each.value.name
)
Expand Down
54 changes: 47 additions & 7 deletions fast/stages/0-bootstrap/identity-providers.tf
@@ -1,5 +1,5 @@
/**
* Copyright 2023 Google LLC
* 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.
Expand All @@ -17,13 +17,31 @@
# tfdoc:file:description Workload Identity Federation provider definitions.

locals {
identity_providers = {
for k, v in var.federated_identity_providers : k => merge(
workforce_identity_providers = {
for k, v in var.workforce_identity_providers : k => merge(
v,
lookup(local.identity_providers_defs, v.issuer, {})
lookup(local.workforce_identity_providers_defs, v.issuer, {})
)
}
identity_providers_defs = {
workforce_identity_providers_defs = {
azuread = {
attribute_mapping = {
"google.subject" = "assertion.subject"
"google.display_name" = "assertion.attributes.userprincipalname[0]"
"google.groups" = "assertion.attributes.groups"
"attribute.first_name" = "assertion.attributes.givenname[0]"
"attribute.last_name" = "assertion.attributes.surname[0]"
"attribute.user_email" = "assertion.attributes.mail[0]"
}
}
}
workload_identity_providers = {
for k, v in var.workload_identity_providers : k => merge(
v,
lookup(local.workload_identity_providers_defs, v.issuer, {})
)
}
workload_identity_providers_defs = {
# https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
github = {
attribute_mapping = {
Expand Down Expand Up @@ -64,16 +82,38 @@ locals {
}
}

resource "google_iam_workforce_pool" "default" {
count = length(local.workforce_identity_providers) > 0 ? 1 : 0
parent = "organizations/${var.organization.id}"
location = "global"
workforce_pool_id = "${var.prefix}-bootstrap"
}

resource "google_iam_workforce_pool_provider" "default" {
for_each = local.workforce_identity_providers
attribute_condition = each.value.attribute_condition
attribute_mapping = each.value.attribute_mapping
description = each.value.description
disabled = each.value.disabled
display_name = each.value.display_name
location = google_iam_workforce_pool.default.0.location
provider_id = "${var.prefix}-bootstrap-${each.key}"
workforce_pool_id = google_iam_workforce_pool.default.0.workforce_pool_id
saml {
idp_metadata_xml = each.value.saml.idp_metadata_xml
}
}

resource "google_iam_workload_identity_pool" "default" {
provider = google-beta
count = length(local.identity_providers) > 0 ? 1 : 0
count = length(local.workload_identity_providers) > 0 ? 1 : 0
project = module.automation-project.project_id
workload_identity_pool_id = "${var.prefix}-bootstrap"
}

resource "google_iam_workload_identity_pool_provider" "default" {
provider = google-beta
for_each = local.identity_providers
for_each = local.workload_identity_providers
project = module.automation-project.project_id
workload_identity_pool_id = (
google_iam_workload_identity_pool.default.0.workload_identity_pool_id
Expand Down
3 changes: 2 additions & 1 deletion fast/stages/0-bootstrap/organization-iam.tf
Expand Up @@ -58,7 +58,8 @@ locals {
"roles/resourcemanager.folderAdmin",
"roles/resourcemanager.organizationAdmin",
"roles/resourcemanager.projectCreator",
"roles/resourcemanager.tagAdmin"
"roles/resourcemanager.tagAdmin",
"roles/iam.workforcePoolAdmin"
]
additive = concat(
[
Expand Down
29 changes: 19 additions & 10 deletions fast/stages/0-bootstrap/outputs.tf
Expand Up @@ -148,16 +148,6 @@ output "custom_roles" {
value = module.organization.custom_role_id
}

output "federated_identity" {
description = "Workload Identity Federation pool and providers."
value = {
pool = try(
google_iam_workload_identity_pool.default.0.name, null
)
providers = local.cicd_providers
}
}

output "outputs_bucket" {
description = "GCS bucket where generated output files are stored."
value = module.automation-tf-output-gcs.name
Expand Down Expand Up @@ -203,3 +193,22 @@ output "tfvars" {
sensitive = true
value = local.tfvars
}

output "workforce_identity_pool" {
description = "Workforce Identity Federation pool."
value = {
pool = try(
google_iam_workforce_pool.default.0.name, null
)
}
}

output "workload_identity_pool" {
description = "Workload Identity Federation pool and providers."
value = {
pool = try(
google_iam_workload_identity_pool.default.0.name, null
)
providers = local.cicd_providers
}
}
59 changes: 41 additions & 18 deletions fast/stages/0-bootstrap/variables.tf
Expand Up @@ -114,24 +114,11 @@ variable "fast_features" {
nullable = false
}

variable "federated_identity_providers" {
description = "Workload Identity Federation pools. The `cicd_repositories` variable references keys here."
type = map(object({
attribute_condition = optional(string)
issuer = string
custom_settings = optional(object({
issuer_uri = optional(string)
audiences = optional(list(string), [])
jwks_json = optional(string)
}), {})
}))
default = {}
nullable = false
# TODO: fix validation
# validation {
# condition = var.federated_identity_providers.custom_settings == null
# error_message = "Custom settings cannot be null."
# }
variable "group_iam" {
description = "Organization-level authoritative IAM binding for groups, in {GROUP_EMAIL => [ROLES]} format. Group emails need to be static. Can be used in combination with the `iam` variable."
type = map(list(string))
default = {}
nullable = false
}

variable "groups" {
Expand Down Expand Up @@ -277,3 +264,39 @@ variable "project_parent_ids" {
}
nullable = false
}

variable "workforce_identity_providers" {
description = "Workforce Identity Federation pools."
type = 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)
}))
default = {}
nullable = false
}

variable "workload_identity_providers" {
description = "Workload Identity Federation pools. The `cicd_repositories` variable references keys here."
type = map(object({
attribute_condition = optional(string)
issuer = string
custom_settings = optional(object({
issuer_uri = optional(string)
audiences = optional(list(string), [])
jwks_json = optional(string)
}), {})
}))
default = {}
nullable = false
# TODO: fix validation
# validation {
# condition = var.federated_identity_providers.custom_settings == null
# error_message = "Custom settings cannot be null."
# }
}
4 changes: 2 additions & 2 deletions tests/fast/stages/s0_bootstrap/checklist.yaml
Expand Up @@ -363,7 +363,7 @@ counts:
google_logging_organization_sink: 3
google_logging_project_bucket_config: 3
google_org_policy_policy: 20
google_organization_iam_binding: 25
google_organization_iam_binding: 26
google_organization_iam_custom_role: 6
google_organization_iam_member: 35
google_project: 3
Expand All @@ -381,4 +381,4 @@ counts:
google_tags_tag_key: 1
google_tags_tag_value: 1
modules: 16
resources: 189
resources: 190
4 changes: 2 additions & 2 deletions tests/fast/stages/s0_bootstrap/simple.yaml
Expand Up @@ -42,7 +42,7 @@ counts:
google_logging_organization_sink: 3
google_logging_project_bucket_config: 3
google_org_policy_policy: 20
google_organization_iam_binding: 25
google_organization_iam_binding: 26
google_organization_iam_custom_role: 6
google_organization_iam_member: 22
google_project: 3
Expand All @@ -61,7 +61,7 @@ counts:
google_tags_tag_value: 1
local_file: 7
modules: 15
resources: 180
resources: 181

outputs:
custom_roles:
Expand Down