Skip to content

Add variable to resman to control top-level folder IAM #2196

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

Merged
merged 1 commit into from
Apr 4, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions fast/stages/1-resman/README.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions fast/stages/1-resman/branch-data-platform.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module "branch-dp-folder" {
count = var.fast_features.data_platform ? 1 : 0
parent = "organizations/${var.organization.id}"
name = "Data Platform"
iam = var.folder_iam.data_platform
tag_bindings = {
context = try(
module.organization.tag_values["${var.tag_names.context}/data"].id, null
Expand Down
3 changes: 2 additions & 1 deletion fast/stages/1-resman/branch-gcve.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2022 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 @@ -21,6 +21,7 @@ module "branch-gcve-folder" {
count = var.fast_features.gcve ? 1 : 0
parent = "organizations/${var.organization.id}"
name = "GCVE"
iam = var.folder_iam.gcve
tag_bindings = {
context = try(
module.organization.tag_values["${var.tag_names.context}/gcve"].id, null
Expand Down
3 changes: 2 additions & 1 deletion fast/stages/1-resman/branch-gke.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright 2022 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 @@ -21,6 +21,7 @@ module "branch-gke-folder" {
count = var.fast_features.gke ? 1 : 0
parent = "organizations/${var.organization.id}"
name = "GKE"
iam = var.folder_iam.gke
tag_bindings = {
context = try(
module.organization.tag_values["${var.tag_names.context}/gke"].id, null
Expand Down
35 changes: 24 additions & 11 deletions fast/stages/1-resman/branch-networking.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,29 @@

# tfdoc:file:description Networking stage resources.

locals {
# FAST-specific IAM
_network_folder_fast_iam = {
# read-write (apply) automation service account
"roles/logging.admin" = [module.branch-network-sa.iam_email]
"roles/owner" = [module.branch-network-sa.iam_email]
"roles/resourcemanager.folderAdmin" = [module.branch-network-sa.iam_email]
"roles/resourcemanager.projectCreator" = [module.branch-network-sa.iam_email]
"roles/compute.xpnAdmin" = [module.branch-network-sa.iam_email]
# read-only (plan) automation service account
"roles/viewer" = [module.branch-network-r-sa.iam_email]
"roles/resourcemanager.folderViewer" = [module.branch-network-r-sa.iam_email]
}
# deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
_network_folder_iam = merge(
var.folder_iam.network,
{
for role, principals in local._network_folder_fast_iam :
role => distinct(concat(principals, lookup(var.folder_iam.network, role, [])))
}
)
}

module "branch-network-folder" {
source = "../../../modules/folder"
parent = "organizations/${var.organization.id}"
Expand All @@ -27,17 +50,7 @@ module "branch-network-folder" {
"roles/editor",
]
}
iam = {
# read-write (apply) automation service account
"roles/logging.admin" = [module.branch-network-sa.iam_email]
"roles/owner" = [module.branch-network-sa.iam_email]
"roles/resourcemanager.folderAdmin" = [module.branch-network-sa.iam_email]
"roles/resourcemanager.projectCreator" = [module.branch-network-sa.iam_email]
"roles/compute.xpnAdmin" = [module.branch-network-sa.iam_email]
# read-only (plan) automation service account
"roles/viewer" = [module.branch-network-r-sa.iam_email]
"roles/resourcemanager.folderViewer" = [module.branch-network-r-sa.iam_email]
}
iam = local._network_folder_iam
tag_bindings = {
context = try(
module.organization.tag_values["${var.tag_names.context}/networking"].id, null
Expand Down
28 changes: 21 additions & 7 deletions fast/stages/1-resman/branch-sandbox.tf
Original file line number Diff line number Diff line change
@@ -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 @@ -16,17 +16,31 @@

# tfdoc:file:description Sandbox stage resources.

module "branch-sandbox-folder" {
source = "../../../modules/folder"
count = var.fast_features.sandbox ? 1 : 0
parent = "organizations/${var.organization.id}"
name = "Sandbox"
iam = {
locals {
# FAST-specific IAM
_sandbox_folder_fast_iam = !var.fast_features.sandbox ? {} : {
"roles/logging.admin" = [module.branch-sandbox-sa.0.iam_email]
"roles/owner" = [module.branch-sandbox-sa.0.iam_email]
"roles/resourcemanager.folderAdmin" = [module.branch-sandbox-sa.0.iam_email]
"roles/resourcemanager.projectCreator" = [module.branch-sandbox-sa.0.iam_email]
}
# deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
_sandbox_folder_iam = merge(
var.folder_iam.sandbox,
{
for role, principals in local._sandbox_folder_fast_iam :
role => distinct(concat(principals, lookup(var.folder_iam.sandbox, role, [])))
}
)
}


module "branch-sandbox-folder" {
source = "../../../modules/folder"
count = var.fast_features.sandbox ? 1 : 0
parent = "organizations/${var.organization.id}"
name = "Sandbox"
iam = local._sandbox_folder_iam
org_policies = {
"sql.restrictPublicIp" = { rules = [{ enforce = false }] }
"compute.vmExternalIpAccess" = { rules = [{ allow = { all = true } }] }
Expand Down
33 changes: 23 additions & 10 deletions fast/stages/1-resman/branch-security.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,28 @@

# tfdoc:file:description Security stage resources.

locals {
# FAST-specific IAM
_security_folder_fast_iam = {
"roles/logging.admin" = [module.branch-security-sa.iam_email]
"roles/owner" = [module.branch-security-sa.iam_email]
"roles/resourcemanager.folderAdmin" = [module.branch-security-sa.iam_email]
"roles/resourcemanager.projectCreator" = [module.branch-security-sa.iam_email]
# read-only (plan) automation service account
"roles/viewer" = [module.branch-security-r-sa.iam_email]
"roles/resourcemanager.folderViewer" = [module.branch-security-r-sa.iam_email]
}

# deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
_security_folder_iam = merge(
var.folder_iam.security,
{
for role, principals in local._security_folder_fast_iam :
role => distinct(concat(principals, lookup(var.folder_iam.security, role, [])))
}
)
}

module "branch-security-folder" {
source = "../../../modules/folder"
parent = "organizations/${var.organization.id}"
Expand All @@ -27,16 +49,7 @@ module "branch-security-folder" {
"roles/editor"
]
}
iam = {
# read-write (apply) automation service account
"roles/logging.admin" = [module.branch-security-sa.iam_email]
"roles/owner" = [module.branch-security-sa.iam_email]
"roles/resourcemanager.folderAdmin" = [module.branch-security-sa.iam_email]
"roles/resourcemanager.projectCreator" = [module.branch-security-sa.iam_email]
# read-only (plan) automation service account
"roles/viewer" = [module.branch-security-r-sa.iam_email]
"roles/resourcemanager.folderViewer" = [module.branch-security-r-sa.iam_email]
}
iam = local._security_folder_iam
tag_bindings = {
context = try(
module.organization.tag_values["${var.tag_names.context}/security"].id, null
Expand Down
26 changes: 19 additions & 7 deletions fast/stages/1-resman/branch-teams.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,31 @@
# tfdoc:file:description Team stage resources.

# TODO(ludo): add support for CI/CD

module "branch-teams-folder" {
source = "../../../modules/folder"
count = var.fast_features.teams ? 1 : 0
parent = "organizations/${var.organization.id}"
name = "Teams"
iam = {
locals {
# FAST-specific IAM
_teams_folder_fast_iam = !var.fast_features.teams ? {} : {
"roles/logging.admin" = [module.branch-teams-sa.0.iam_email]
"roles/owner" = [module.branch-teams-sa.0.iam_email]
"roles/resourcemanager.folderAdmin" = [module.branch-teams-sa.0.iam_email]
"roles/resourcemanager.projectCreator" = [module.branch-teams-sa.0.iam_email]
"roles/compute.xpnAdmin" = [module.branch-teams-sa.0.iam_email]
}
# deep-merge FAST-specific IAM with user-provided bindings in var.folder_iam
_teams_folder_iam = merge(
var.folder_iam.teams,
{
for role, principals in local._teams_folder_fast_iam :
role => distinct(concat(principals, lookup(var.folder_iam.teams, role, [])))
}
)
}

module "branch-teams-folder" {
source = "../../../modules/folder"
count = var.fast_features.teams ? 1 : 0
parent = "organizations/${var.organization.id}"
name = "Teams"
iam = local._teams_folder_iam
tag_bindings = {
context = try(
module.organization.tag_values["${var.tag_names.context}/teams"].id, null
Expand Down
1 change: 1 addition & 0 deletions fast/stages/1-resman/branch-tenants.tf
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module "tenant-tenants-folder" {
source = "../../../modules/folder"
parent = "organizations/${var.organization.id}"
name = "Tenants"
iam = var.folder_iam.tenants
tag_bindings = {
context = module.organization.tag_values["${var.tag_names.context}/tenant"].id
}
Expand Down
16 changes: 16 additions & 0 deletions fast/stages/1-resman/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,22 @@ variable "fast_features" {
nullable = false
}

variable "folder_iam" {
description = "Authoritative IAM for top-level folders."
type = 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)), {})
teams = optional(map(list(string)), {})
tenants = optional(map(list(string)), {})
})
nullable = false
default = {}
}

variable "groups" {
# tfdoc:variable:source 0-bootstrap
# https://cloud.google.com/docs/enterprise/setup-checklist
Expand Down
34 changes: 34 additions & 0 deletions tests/fast/stages/s1_resman/simple.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,37 @@ organization = {
customer_id = "C00000000"
}
prefix = "fast2"
folder_iam = {
data_platform = {
"roles/owner" = ["user:[email protected]"]
"roles/browser" = ["user:[email protected]"]
}
gcve = {
"roles/owner" = ["user:[email protected]"]
"roles/browser" = ["user:[email protected]"]
}
gke = {
"roles/owner" = ["user:[email protected]"]
"roles/browser" = ["user:[email protected]"]
}
sandbox = {
"roles/owner" = ["user:[email protected]"]
"roles/browser" = ["user:[email protected]"]
}
security = {
"roles/owner" = ["user:[email protected]"]
"roles/browser" = ["user:[email protected]"]
}
network = {
"roles/owner" = ["user:[email protected]"]
"roles/browser" = ["user:[email protected]"]
}
teams = {
"roles/owner" = ["user:[email protected]"]
"roles/browser" = ["user:[email protected]"]
}
tenants = {
"roles/owner" = ["user:[email protected]"]
"roles/browser" = ["user:[email protected]"]
}
}
4 changes: 2 additions & 2 deletions tests/fast/stages/s1_resman/simple.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

counts:
google_folder: 5
google_folder_iam_binding: 21
google_folder_iam_binding: 25
google_organization_iam_member: 5
google_project_iam_member: 4
google_service_account: 4
Expand All @@ -27,4 +27,4 @@ counts:
google_tags_tag_key: 3
google_tags_tag_value: 10
modules: 12
resources: 76
resources: 80