Skip to content

Commit

Permalink
Add main project factory service account (GoogleCloudPlatform#2353)
Browse files Browse the repository at this point in the history
* add main project factory service account

* add main project factory service account
  • Loading branch information
ludoo authored and Alberto Geniola committed Jun 19, 2024
1 parent b26f62c commit 8c9207e
Show file tree
Hide file tree
Showing 36 changed files with 242 additions and 32 deletions.
38 changes: 19 additions & 19 deletions fast/stages/1-resman/README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions fast/stages/1-resman/billing.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ locals {
local.branch_optional_sa_lists.gke-prod,
local.branch_optional_sa_lists.gcve-dev,
local.branch_optional_sa_lists.gcve-prod,
local.branch_optional_sa_lists.pf,
local.branch_optional_sa_lists.pf-dev,
local.branch_optional_sa_lists.pf-prod,
)
Expand Down
4 changes: 4 additions & 0 deletions fast/stages/1-resman/branch-networking.tf
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ module "branch-network-prod-folder" {
local.branch_optional_sa_lists.dp-prod,
local.branch_optional_sa_lists.gke-prod,
local.branch_optional_sa_lists.gcve-prod,
local.branch_optional_sa_lists.pf,
local.branch_optional_sa_lists.pf-prod,
)
# read-only (plan) automation service accounts
"roles/compute.networkViewer" = concat(
local.branch_optional_r_sa_lists.dp-prod,
local.branch_optional_r_sa_lists.gke-prod,
local.branch_optional_r_sa_lists.gcve-prod,
local.branch_optional_r_sa_lists.pf,
local.branch_optional_r_sa_lists.pf-prod,
)
(local.custom_roles.gcve_network_admin) = local.branch_optional_sa_lists.gcve-prod
Expand All @@ -97,13 +99,15 @@ module "branch-network-dev-folder" {
local.branch_optional_sa_lists.dp-dev,
local.branch_optional_sa_lists.gke-dev,
local.branch_optional_sa_lists.gcve-dev,
local.branch_optional_sa_lists.pf,
local.branch_optional_sa_lists.pf-dev,
)
# read-only (plan) automation service accounts
"roles/compute.networkViewer" = concat(
local.branch_optional_r_sa_lists.dp-dev,
local.branch_optional_r_sa_lists.gke-dev,
local.branch_optional_r_sa_lists.gcve-dev,
local.branch_optional_r_sa_lists.pf,
local.branch_optional_r_sa_lists.pf-dev,
)
(local.custom_roles.gcve_network_admin) = local.branch_optional_sa_lists.gcve-dev
Expand Down
55 changes: 55 additions & 0 deletions fast/stages/1-resman/branch-project-factory.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,26 @@

# automation service accounts

module "branch-pf-sa" {
source = "../../../modules/iam-service-account"
count = var.fast_features.project_factory ? 1 : 0
project_id = var.automation.project_id
name = "resman-pf-0"
display_name = "Terraform project factory main service account."
prefix = var.prefix
iam = {
"roles/iam.serviceAccountTokenCreator" = compact([
try(module.branch-pf-sa-cicd[0].iam_email, null)
])
}
iam_project_roles = {
(var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
}
iam_storage_roles = {
(var.automation.outputs_bucket) = ["roles/storage.objectAdmin"]
}
}

module "branch-pf-dev-sa" {
source = "../../../modules/iam-service-account"
count = var.fast_features.project_factory ? 1 : 0
Expand Down Expand Up @@ -60,6 +80,26 @@ module "branch-pf-prod-sa" {

# automation read-only service accounts

module "branch-pf-r-sa" {
source = "../../../modules/iam-service-account"
count = var.fast_features.project_factory ? 1 : 0
project_id = var.automation.project_id
name = "resman-pf-0r"
display_name = "Terraform project factory main service account (read-only)."
prefix = var.prefix
iam = {
"roles/iam.serviceAccountTokenCreator" = compact([
try(module.branch-pf-r-sa-cicd[0].iam_email, null)
])
}
iam_project_roles = {
(var.automation.project_id) = ["roles/serviceusage.serviceUsageConsumer"]
}
iam_storage_roles = {
(var.automation.outputs_bucket) = [var.custom_roles["storage_viewer"]]
}
}

module "branch-pf-dev-r-sa" {
source = "../../../modules/iam-service-account"
count = var.fast_features.project_factory ? 1 : 0
Expand Down Expand Up @@ -102,6 +142,21 @@ module "branch-pf-prod-r-sa" {

# automation buckets

module "branch-pf-gcs" {
source = "../../../modules/gcs"
count = var.fast_features.project_factory ? 1 : 0
project_id = var.automation.project_id
name = "resman-pf-0"
prefix = var.prefix
location = var.locations.gcs
storage_class = local.gcs_storage_class
versioning = true
iam = {
"roles/storage.objectAdmin" = [module.branch-pf-sa[0].iam_email]
"roles/storage.objectViewer" = [module.branch-pf-r-sa[0].iam_email]
}
}

module "branch-pf-dev-gcs" {
source = "../../../modules/gcs"
count = var.fast_features.project_factory ? 1 : 0
Expand Down
63 changes: 63 additions & 0 deletions fast/stages/1-resman/cicd-project-factory.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,41 @@

# read-write (apply) SAs used by CI/CD workflows to impersonate automation SAs

module "branch-pf-sa-cicd" {
source = "../../../modules/iam-service-account"
for_each = (
try(local.cicd_repositories.project_factory.name, null) != null
? { 0 = local.cicd_repositories.project_factory }
: {}
)
project_id = var.automation.project_id
name = "pf-resman-pf-1"
display_name = "Terraform CI/CD project factory main service account."
prefix = var.prefix
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"]
}
iam_storage_roles = {
(var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
}
}

module "branch-pf-dev-sa-cicd" {
source = "../../../modules/iam-service-account"
for_each = (
Expand Down Expand Up @@ -90,6 +125,34 @@ module "branch-pf-prod-sa-cicd" {

# read-only (plan) SAs used by CI/CD workflows to impersonate automation SAs

module "branch-pf-r-sa-cicd" {
source = "../../../modules/iam-service-account"
for_each = (
try(local.cicd_repositories.project_factory.name, null) != null
? { 0 = local.cicd_repositories.project_factory }
: {}
)
project_id = var.automation.project_id
name = "resman-pf-1r"
display_name = "Terraform CI/CD project factory main service account (read-only)."
prefix = var.prefix
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"]
}
iam_storage_roles = {
(var.automation.outputs_bucket) = ["roles/storage.objectViewer"]
}
}

module "branch-pf-dev-r-sa-cicd" {
source = "../../../modules/iam-service-account"
for_each = (
Expand Down
21 changes: 20 additions & 1 deletion fast/stages/1-resman/iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,14 @@ locals {
},
# optional billing roles for project factory
local.billing_mode != "org" || !var.fast_features.project_factory ? {} : {
sa_pf_billing = {
member = module.branch-pf-sa[0].iam_email
role = "roles/billing.user"
}
sa_pf_costs_manager = {
member = module.branch-pf-sa[0].iam_email
role = "roles/billing.costsManager"
}
sa_pf_dev_billing = {
member = module.branch-pf-dev-sa[0].iam_email
role = "roles/billing.user"
Expand All @@ -90,8 +98,19 @@ locals {
}
},
# scoped org policy admin grants for project factory
# TODO: exclude security and networking
# TODO: change to use context and environment tags, and tag bindings in stage 2s
!var.fast_features.project_factory || var.root_node != null ? {} : {
sa_pf_conditional_org_policy = {
member = module.branch-pf-sa[0].iam_email
role = "roles/orgpolicy.policyAdmin"
condition = {
title = "org_policy_tag_pf_scoped"
description = "Org policy tag scoped grant for project factory main."
expression = <<-END
resource.matchTag('${local.tag_root}/${var.tag_names.context}', 'project-factory')
END
}
}
sa_pf_dev_conditional_org_policy = {
member = module.branch-pf-dev-sa[0].iam_email
role = "roles/orgpolicy.policyAdmin"
Expand Down
2 changes: 2 additions & 0 deletions fast/stages/1-resman/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ locals {
gcve-prod = compact([try(module.branch-gcve-prod-sa[0].iam_email, "")])
gke-dev = compact([try(module.branch-gke-dev-sa[0].iam_email, "")])
gke-prod = compact([try(module.branch-gke-prod-sa[0].iam_email, "")])
pf = compact([try(module.branch-pf-sa[0].iam_email, "")])
pf-dev = compact([try(module.branch-pf-dev-sa[0].iam_email, "")])
pf-prod = compact([try(module.branch-pf-prod-sa[0].iam_email, "")])
}
Expand All @@ -39,6 +40,7 @@ locals {
gcve-prod = compact([try(module.branch-gcve-prod-r-sa[0].iam_email, "")])
gke-dev = compact([try(module.branch-gke-dev-r-sa[0].iam_email, "")])
gke-prod = compact([try(module.branch-gke-prod-r-sa[0].iam_email, "")])
pf = compact([try(module.branch-pf-r-sa[0].iam_email, "")])
pf-dev = compact([try(module.branch-pf-dev-r-sa[0].iam_email, "")])
pf-prod = compact([try(module.branch-pf-prod-r-sa[0].iam_email, "")])
}
Expand Down
3 changes: 3 additions & 0 deletions fast/stages/1-resman/organization.tf
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ module "organization" {
networking = {
iam = try(local.tags.context.values.networking.iam, {})
}
project-factory = {
iam = try(local.tags.context.values.project-factory.iam, {})
}
sandbox = {
iam = try(local.tags.context.values.sandbox.iam, {})
}
Expand Down
37 changes: 33 additions & 4 deletions fast/stages/1-resman/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,17 @@ locals {
}
tf_var_files = local.cicd_workflow_var_files.stage_2
}
project_factory = {
service_accounts = {
apply = try(module.branch-pf-sa-cicd[0].email, null)
plan = try(module.branch-pf-r-sa-cicd[0].email, null)
}
tf_providers_files = {
apply = "3-project-factory-providers.tf"
plan = "3-project-factory-r-providers.tf"
}
tf_var_files = local.cicd_workflow_var_files.stage_3
}
project_factory_dev = {
service_accounts = {
apply = try(module.branch-pf-dev-sa-cicd[0].email, null)
Expand Down Expand Up @@ -276,28 +287,40 @@ locals {
})
},
!var.fast_features.project_factory ? {} : {
"3-project-factory" = templatefile(local._tpl_providers, {
backend_extra = null
bucket = module.branch-pf-gcs[0].name
name = "project-factory"
sa = module.branch-pf-sa[0].email
})
"3-project-factory-r" = templatefile(local._tpl_providers, {
backend_extra = null
bucket = module.branch-pf-gcs[0].name
name = "project-factory"
sa = module.branch-pf-r-sa[0].email
})
"3-project-factory-dev" = templatefile(local._tpl_providers, {
backend_extra = null
bucket = module.branch-pf-dev-gcs[0].name
name = "team-dev"
name = "project-factory-dev"
sa = module.branch-pf-dev-sa[0].email
})
"3-project-factory-dev-r" = templatefile(local._tpl_providers, {
backend_extra = null
bucket = module.branch-pf-dev-gcs[0].name
name = "team-dev"
name = "project-factory-dev"
sa = module.branch-pf-dev-r-sa[0].email
})
"3-project-factory-prod" = templatefile(local._tpl_providers, {
backend_extra = null
bucket = module.branch-pf-prod-gcs[0].name
name = "team-prod"
name = "project-factory-prod"
sa = module.branch-pf-prod-sa[0].email
})
"3-project-factory-prod-r" = templatefile(local._tpl_providers, {
backend_extra = null
bucket = module.branch-pf-prod-gcs[0].name
name = "team-prod"
name = "project-factory-prod"
sa = module.branch-pf-prod-r-sa[0].email
})
},
Expand Down Expand Up @@ -326,6 +349,8 @@ locals {
gke-prod-r = try(module.branch-gke-prod-r-sa[0].email, null)
networking = module.branch-network-sa.email
networking-r = module.branch-network-r-sa.email
project-factory = try(module.branch-pf-sa[0].email, null)
project-factory-r = try(module.branch-pf-r-sa[0].email, null)
project-factory-dev = try(module.branch-pf-dev-sa[0].email, null)
project-factory-dev-r = try(module.branch-pf-dev-r-sa[0].email, null)
project-factory-prod = try(module.branch-pf-prod-sa[0].email, null)
Expand Down Expand Up @@ -442,6 +467,10 @@ output "project_factories" {
bucket = module.branch-pf-dev-gcs[0].name
sa = module.branch-pf-dev-sa[0].email
}
main = {
bucket = module.branch-pf-gcs[0].name
sa = module.branch-pf-sa[0].email
}
prod = {
bucket = module.branch-pf-prod-gcs[0].name
sa = module.branch-pf-prod-sa[0].email
Expand Down
6 changes: 6 additions & 0 deletions fast/stages/1-resman/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ variable "cicd_repositories" {
branch = optional(string)
identity_provider = optional(string)
}))
project_factory = optional(object({
name = string
type = string
branch = optional(string)
identity_provider = optional(string)
}))
project_factory_dev = optional(object({
name = string
type = string
Expand Down
2 changes: 1 addition & 1 deletion fast/stages/2-networking-a-simple/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ DNS configurations are centralised in the `dns-*.tf` files. Spokes delegate DNS
| [outputs_location](variables.tf#L92) | Path where providers and tfvars files for the following stages are written. Leave empty to disable. | <code>string</code> | | <code>null</code> | |
| [psa_ranges](variables.tf#L98) | IP ranges used for Private Service Access (CloudSQL, etc.). | <code title="object&#40;&#123;&#10; dev &#61; optional&#40;list&#40;object&#40;&#123;&#10; ranges &#61; map&#40;string&#41;&#10; export_routes &#61; optional&#40;bool, false&#41;&#10; import_routes &#61; optional&#40;bool, false&#41;&#10; peered_domains &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10; prod &#61; optional&#40;list&#40;object&#40;&#123;&#10; ranges &#61; map&#40;string&#41;&#10; export_routes &#61; optional&#40;bool, false&#41;&#10; import_routes &#61; optional&#40;bool, false&#41;&#10; peered_domains &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10; &#125;&#41;&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> | |
| [regions](variables.tf#L118) | Region definitions. | <code title="object&#40;&#123;&#10; primary &#61; string&#10; secondary &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; primary &#61; &#34;europe-west1&#34;&#10; secondary &#61; &#34;europe-west4&#34;&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [service_accounts](variables-fast.tf#L89) | Automation service accounts in name => email format. | <code title="object&#40;&#123;&#10; data-platform-dev &#61; string&#10; data-platform-prod &#61; string&#10; gke-dev &#61; string&#10; gke-prod &#61; string&#10; project-factory-dev &#61; string&#10; project-factory-prod &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | <code>1-resman</code> |
| [service_accounts](variables-fast.tf#L89) | Automation service accounts in name => email format. | <code title="object&#40;&#123;&#10; data-platform-dev &#61; string&#10; data-platform-prod &#61; string&#10; gke-dev &#61; string&#10; gke-prod &#61; string&#10; project-factory &#61; string&#10; project-factory-dev &#61; string&#10; project-factory-prod &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | <code>1-resman</code> |
| [spoke_configs](variables.tf#L130) | Spoke connectivity configurations. | <code title="object&#40;&#123;&#10; peering_configs &#61; optional&#40;object&#40;&#123;&#10; dev &#61; optional&#40;object&#40;&#123;&#10; export &#61; optional&#40;bool, true&#41;&#10; import &#61; optional&#40;bool, true&#41;&#10; public_export &#61; optional&#40;bool&#41;&#10; public_import &#61; optional&#40;bool&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; prod &#61; optional&#40;object&#40;&#123;&#10; export &#61; optional&#40;bool, true&#41;&#10; import &#61; optional&#40;bool, true&#41;&#10; public_export &#61; optional&#40;bool&#41;&#10; public_import &#61; optional&#40;bool&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;&#10; vpn_configs &#61; optional&#40;object&#40;&#123;&#10; dev &#61; optional&#40;object&#40;&#123;&#10; asn &#61; optional&#40;number, 65501&#41;&#10; custom_advertise &#61; optional&#40;object&#40;&#123;&#10; all_subnets &#61; bool&#10; ip_ranges &#61; map&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; landing &#61; optional&#40;object&#40;&#123;&#10; asn &#61; optional&#40;number, 65500&#41;&#10; custom_advertise &#61; optional&#40;object&#40;&#123;&#10; all_subnets &#61; bool&#10; ip_ranges &#61; map&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; prod &#61; optional&#40;object&#40;&#123;&#10; asn &#61; optional&#40;number, 65502&#41;&#10; custom_advertise &#61; optional&#40;object&#40;&#123;&#10; all_subnets &#61; bool&#10; ip_ranges &#61; map&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; peering_configs &#61; &#123;&#125;&#10;&#125;">&#123;&#8230;&#125;</code> | |
| [vpn_onprem_primary_config](variables.tf#L180) | VPN gateway configuration for onprem interconnection in the primary region. | <code title="object&#40;&#123;&#10; peer_external_gateways &#61; map&#40;object&#40;&#123;&#10; redundancy_type &#61; string&#10; interfaces &#61; list&#40;string&#41;&#10; &#125;&#41;&#41;&#10; router_config &#61; object&#40;&#123;&#10; create &#61; optional&#40;bool, true&#41;&#10; asn &#61; number&#10; name &#61; optional&#40;string&#41;&#10; keepalive &#61; optional&#40;number&#41;&#10; custom_advertise &#61; optional&#40;object&#40;&#123;&#10; all_subnets &#61; bool&#10; ip_ranges &#61; map&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#10; tunnels &#61; map&#40;object&#40;&#123;&#10; bgp_peer &#61; object&#40;&#123;&#10; address &#61; string&#10; asn &#61; number&#10; route_priority &#61; optional&#40;number, 1000&#41;&#10; custom_advertise &#61; optional&#40;object&#40;&#123;&#10; all_subnets &#61; bool&#10; all_vpc_subnets &#61; bool&#10; all_peer_vpc_subnets &#61; bool&#10; ip_ranges &#61; map&#40;string&#41;&#10; &#125;&#41;&#41;&#10; &#125;&#41;&#10; bgp_session_range &#61; string&#10; ike_version &#61; optional&#40;number, 2&#41;&#10; peer_external_gateway_interface &#61; optional&#40;number&#41;&#10; peer_gateway &#61; optional&#40;string, &#34;default&#34;&#41;&#10; router &#61; optional&#40;string&#41;&#10; shared_secret &#61; optional&#40;string&#41;&#10; vpn_gateway_interface &#61; number&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> | |

Expand Down
Loading

0 comments on commit 8c9207e

Please sign in to comment.