206 lines
6.8 KiB
Terraform
206 lines
6.8 KiB
Terraform
|
/**
|
||
|
* Copyright 2022 Google LLC
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
# tfdoc:file:description Organization-level IAM and org policies.
|
||
|
|
||
|
locals {
|
||
|
# organization authoritative IAM bindings, in an easy to edit format before
|
||
|
# they are combined with var.iam a bit further in locals
|
||
|
_iam = {
|
||
|
"roles/browser" = [
|
||
|
"domain:${var.organization.domain}"
|
||
|
]
|
||
|
"roles/logging.admin" = [
|
||
|
module.automation-tf-bootstrap-sa.iam_email
|
||
|
]
|
||
|
"roles/owner" = local._iam_bootstrap_user
|
||
|
"roles/resourcemanager.folderAdmin" = [
|
||
|
module.automation-tf-resman-sa.iam_email
|
||
|
]
|
||
|
"roles/resourcemanager.organizationAdmin" = concat(
|
||
|
[module.automation-tf-bootstrap-sa.iam_email],
|
||
|
local._iam_bootstrap_user
|
||
|
)
|
||
|
"roles/resourcemanager.organizationViewer" = [
|
||
|
"domain:${var.organization.domain}"
|
||
|
]
|
||
|
}
|
||
|
# organization additive IAM bindings, in an easy to edit format before
|
||
|
# they are combined with var.iam_additive a bit further in locals
|
||
|
_iam_additive = merge(
|
||
|
{
|
||
|
"roles/accesscontextmanager.policyAdmin" = [
|
||
|
local.groups_iam.gcp-security-admins
|
||
|
]
|
||
|
"roles/compute.orgFirewallPolicyAdmin" = [
|
||
|
local.groups_iam.gcp-network-admins
|
||
|
]
|
||
|
"roles/compute.xpnAdmin" = [
|
||
|
local.groups_iam.gcp-network-admins
|
||
|
]
|
||
|
# use additive to support cross-org roles for billing
|
||
|
"roles/iam.organizationRoleAdmin" = [
|
||
|
local.groups_iam.gcp-security-admins,
|
||
|
module.automation-tf-bootstrap-sa.iam_email
|
||
|
]
|
||
|
"roles/orgpolicy.policyAdmin" = [
|
||
|
module.automation-tf-resman-sa.iam_email,
|
||
|
local.groups_iam.gcp-security-admins
|
||
|
]
|
||
|
},
|
||
|
local.billing_org ? {
|
||
|
"roles/billing.admin" = [
|
||
|
local.groups_iam.gcp-organization-admins,
|
||
|
module.automation-tf-bootstrap-sa.iam_email,
|
||
|
module.automation-tf-resman-sa.iam_email
|
||
|
]
|
||
|
} : {}
|
||
|
)
|
||
|
_iam_bootstrap_user = (
|
||
|
var.bootstrap_user == null ? [] : ["user:${var.bootstrap_user}"]
|
||
|
)
|
||
|
_log_sink_destinations = {
|
||
|
bigquery = try(module.log-export-dataset.0.id, null),
|
||
|
logging = try(module.log-export-logbucket.0.id, null),
|
||
|
storage = try(module.log-export-gcs.0.name, null)
|
||
|
}
|
||
|
iam = {
|
||
|
for role in local.iam_roles : role => distinct(concat(
|
||
|
try(sort(local._iam[role]), []),
|
||
|
try(sort(var.iam[role]), [])
|
||
|
))
|
||
|
}
|
||
|
iam_additive = {
|
||
|
for role in local.iam_roles_additive : role => distinct(concat(
|
||
|
try(sort(local._iam_additive[role]), []),
|
||
|
try(sort(var.iam_additive[role]), [])
|
||
|
))
|
||
|
}
|
||
|
iam_roles = distinct(concat(
|
||
|
keys(local._iam), keys(var.iam)
|
||
|
))
|
||
|
iam_roles_additive = distinct(concat(
|
||
|
keys(local._iam_additive), keys(var.iam_additive)
|
||
|
))
|
||
|
log_sink_destinations = {
|
||
|
for k, v in var.log_sinks : k => (
|
||
|
v.type == "pubsub"
|
||
|
? module.log-export-pubsub[k]
|
||
|
: local._log_sink_destinations[v.type]
|
||
|
)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
module "organization" {
|
||
|
source = "../../../modules/organization"
|
||
|
organization_id = "organizations/${var.organization.id}"
|
||
|
# human (groups) IAM bindings
|
||
|
group_iam = {
|
||
|
(local.groups.gcp-organization-admins) = [
|
||
|
"roles/cloudasset.owner",
|
||
|
"roles/cloudsupport.admin",
|
||
|
"roles/compute.osAdminLogin",
|
||
|
"roles/compute.osLoginExternalUser",
|
||
|
"roles/owner",
|
||
|
"roles/resourcemanager.folderAdmin",
|
||
|
"roles/resourcemanager.organizationAdmin",
|
||
|
"roles/resourcemanager.projectCreator",
|
||
|
],
|
||
|
(local.groups.gcp-network-admins) = [
|
||
|
"roles/cloudasset.owner",
|
||
|
"roles/cloudsupport.techSupportEditor",
|
||
|
]
|
||
|
(local.groups.gcp-security-admins) = [
|
||
|
"roles/cloudasset.owner",
|
||
|
"roles/cloudsupport.techSupportEditor",
|
||
|
"roles/iam.securityReviewer",
|
||
|
"roles/logging.admin",
|
||
|
"roles/securitycenter.admin",
|
||
|
],
|
||
|
(local.groups.gcp-support) = [
|
||
|
"roles/cloudsupport.techSupportEditor",
|
||
|
"roles/logging.viewer",
|
||
|
"roles/monitoring.viewer",
|
||
|
]
|
||
|
}
|
||
|
# machine (service accounts) IAM bindings
|
||
|
iam = local.iam
|
||
|
# additive bindings, used for roles co-managed by different stages
|
||
|
iam_additive = local.iam_additive
|
||
|
custom_roles = {
|
||
|
# this is needed for use in additive IAM bindings, to avoid conflicts
|
||
|
"organizationIamAdmin" = [
|
||
|
"resourcemanager.organizations.get",
|
||
|
"resourcemanager.organizations.getIamPolicy",
|
||
|
"resourcemanager.organizations.setIamPolicy"
|
||
|
]
|
||
|
"xpnServiceAdmin" = [
|
||
|
"compute.globalOperations.get",
|
||
|
"compute.organizations.disableXpnResource",
|
||
|
"compute.organizations.enableXpnResource",
|
||
|
"compute.projects.get",
|
||
|
"compute.subnetworks.getIamPolicy",
|
||
|
"compute.subnetworks.setIamPolicy",
|
||
|
"dns.networks.bindPrivateDNSZone",
|
||
|
"resourcemanager.projects.get",
|
||
|
]
|
||
|
}
|
||
|
logging_sinks = {
|
||
|
for name, attrs in var.log_sinks : name => {
|
||
|
bq_partitioned_table = attrs.type == "bigquery"
|
||
|
destination = local.log_sink_destinations[name]
|
||
|
exclusions = {}
|
||
|
filter = attrs.filter
|
||
|
iam = true
|
||
|
include_children = true
|
||
|
type = attrs.type
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
# assign the custom restricted Organization Admin role to the relevant service
|
||
|
# accounts, with a condition that only enables granting specific roles;
|
||
|
# these roles use additive bindings everywhere to avoid conflicts / permadiffs
|
||
|
|
||
|
resource "google_organization_iam_binding" "org_admin_delegated" {
|
||
|
org_id = var.organization.id
|
||
|
count = local.billing_org ? 1 : 0
|
||
|
role = module.organization.custom_role_id.organizationIamAdmin
|
||
|
members = [module.automation-tf-resman-sa.iam_email]
|
||
|
condition {
|
||
|
title = "automation_sa_delegated_grants"
|
||
|
description = "Automation service account delegated grants"
|
||
|
expression = format(
|
||
|
"api.getAttribute('iam.googleapis.com/modifiedGrantsByRole', []).hasOnly([%s])",
|
||
|
join(",", formatlist("'%s'", concat(
|
||
|
[
|
||
|
"roles/accesscontextmanager.policyAdmin",
|
||
|
"roles/compute.orgFirewallPolicyAdmin",
|
||
|
"roles/compute.xpnAdmin",
|
||
|
"roles/orgpolicy.policyAdmin",
|
||
|
module.organization.custom_role_id.xpnServiceAdmin
|
||
|
],
|
||
|
local.billing_org ? [
|
||
|
"roles/billing.admin",
|
||
|
"roles/billing.costsManager",
|
||
|
"roles/billing.user",
|
||
|
] : []
|
||
|
)))
|
||
|
)
|
||
|
}
|
||
|
depends_on = [module.organization]
|
||
|
}
|