Grant IAM rights to service identities in host project (#1542)
* [module/project] Grant IAM rights to service identities based on used services in host project * [blueprints/factories/project-factory] enable granting IAM permissions in host VPC for service identities directly or by specifying services in use
This commit is contained in:
committed by
GitHub
parent
fdd53624f1
commit
4998f1d376
@@ -259,6 +259,30 @@ module "service-project" {
|
||||
# tftest modules=2 resources=8 inventory=shared-vpc.yaml
|
||||
```
|
||||
|
||||
The module allows also granting necessary permissions in host project to service identities by specifying which services will be used in service project in `grant_iam_for_services`.
|
||||
```hcl
|
||||
module "host-project" {
|
||||
source = "./fabric/modules/project"
|
||||
name = "my-host-project"
|
||||
shared_vpc_host_config = {
|
||||
enabled = true
|
||||
}
|
||||
}
|
||||
|
||||
module "service-project" {
|
||||
source = "./fabric/modules/project"
|
||||
name = "my-service-project"
|
||||
services = [
|
||||
"container.googleapis.com",
|
||||
]
|
||||
shared_vpc_service_config = {
|
||||
host_project = module.host-project.project_id
|
||||
service_iam_grants = module.service-project.services
|
||||
}
|
||||
}
|
||||
# tftest modules=2 resources=9 inventory=shared-vpc-auto-grants.yaml
|
||||
```
|
||||
|
||||
## Organization Policies
|
||||
|
||||
To manage organization policies, the `orgpolicy.googleapis.com` service should be enabled in the quota project.
|
||||
@@ -577,7 +601,6 @@ output "compute_robot" {
|
||||
```
|
||||
|
||||
<!-- TFDOC OPTS files:1 -->
|
||||
|
||||
<!-- BEGIN TFDOC -->
|
||||
## Files
|
||||
|
||||
@@ -631,9 +654,9 @@ output "compute_robot" {
|
||||
| [service_perimeter_standard](variables.tf#L272) | Name of VPC-SC Standard perimeter to add project into. See comment in the variables file for format. | <code>string</code> | | <code>null</code> |
|
||||
| [services](variables.tf#L278) | Service APIs to enable. | <code>list(string)</code> | | <code>[]</code> |
|
||||
| [shared_vpc_host_config](variables.tf#L284) | Configures this project as a Shared VPC host project (mutually exclusive with shared_vpc_service_project). | <code title="object({ enabled = bool service_projects = optional(list(string), []) })">object({…})</code> | | <code>null</code> |
|
||||
| [shared_vpc_service_config](variables.tf#L293) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | <code title="object({ host_project = string service_identity_iam = optional(map(list(string))) })">object({…})</code> | | <code>null</code> |
|
||||
| [skip_delete](variables.tf#L303) | Allows the underlying resources to be destroyed without destroying the project itself. | <code>bool</code> | | <code>false</code> |
|
||||
| [tag_bindings](variables.tf#L309) | Tag bindings for this project, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
| [shared_vpc_service_config](variables.tf#L293) | Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config). | <code title="object({ host_project = string service_identity_iam = optional(map(list(string)), {}) service_iam_grants = optional(list(string), []) })">object({…})</code> | | <code title="{ host_project = null }">{…}</code> |
|
||||
| [skip_delete](variables.tf#L315) | Allows the underlying resources to be destroyed without destroying the project itself. | <code>bool</code> | | <code>false</code> |
|
||||
| [tag_bindings](variables.tf#L321) | Tag bindings for this project, in key => tag value id format. | <code>map(string)</code> | | <code>null</code> |
|
||||
|
||||
## Outputs
|
||||
|
||||
@@ -645,6 +668,6 @@ output "compute_robot" {
|
||||
| [number](outputs.tf#L56) | Project number. | |
|
||||
| [project_id](outputs.tf#L75) | Project id. | |
|
||||
| [service_accounts](outputs.tf#L94) | Product robot service accounts in project. | |
|
||||
| [sink_writer_identities](outputs.tf#L110) | Writer identities created for each sink. | |
|
||||
| [services](outputs.tf#L110) | Service APIs to enabled in the project. | |
|
||||
| [sink_writer_identities](outputs.tf#L119) | Writer identities created for each sink. | |
|
||||
<!-- END TFDOC -->
|
||||
|
||||
|
||||
@@ -107,6 +107,15 @@ output "service_accounts" {
|
||||
]
|
||||
}
|
||||
|
||||
output "services" {
|
||||
description = "Service APIs to enabled in the project."
|
||||
value = var.services
|
||||
depends_on = [
|
||||
google_project_service.project_services,
|
||||
google_project_service_identity.jit_si,
|
||||
]
|
||||
}
|
||||
|
||||
output "sink_writer_identities" {
|
||||
description = "Writer identities created for each sink."
|
||||
value = {
|
||||
|
||||
@@ -17,15 +17,25 @@
|
||||
# tfdoc:file:description Shared VPC project-level configuration.
|
||||
|
||||
locals {
|
||||
_shared_vpc_agent_config = yamldecode(file("${path.module}/sharedvpc-agent-iam.yaml"))
|
||||
_shared_vpc_agent_config_filtered = [
|
||||
for config in local._shared_vpc_agent_config : config
|
||||
if contains(var.shared_vpc_service_config.service_iam_grants, config.service)
|
||||
]
|
||||
_shared_vpc_agent_grants = flatten(flatten([
|
||||
for api in local._shared_vpc_agent_config_filtered : [
|
||||
for service, roles in api.agents : [
|
||||
for role in roles : { role = role, service = service }
|
||||
]
|
||||
]
|
||||
]))
|
||||
|
||||
# compute the host project IAM bindings for this project's service identities
|
||||
_svpc_service_iam = flatten([
|
||||
for role, services in local._svpc_service_identity_iam : [
|
||||
for role, services in var.shared_vpc_service_config.service_identity_iam : [
|
||||
for service in services : { role = role, service = service }
|
||||
]
|
||||
])
|
||||
_svpc_service_identity_iam = coalesce(
|
||||
local.svpc_service_config.service_identity_iam, {}
|
||||
)
|
||||
svpc_host_config = {
|
||||
enabled = coalesce(
|
||||
try(var.shared_vpc_host_config.enabled, null), false
|
||||
@@ -34,11 +44,9 @@ locals {
|
||||
try(var.shared_vpc_host_config.service_projects, null), []
|
||||
)
|
||||
}
|
||||
svpc_service_config = coalesce(var.shared_vpc_service_config, {
|
||||
host_project = null, service_identity_iam = {}
|
||||
})
|
||||
|
||||
svpc_service_iam = {
|
||||
for b in local._svpc_service_iam : "${b.role}:${b.service}" => b
|
||||
for b in setunion(local._svpc_service_iam, local._shared_vpc_agent_grants) : "${b.role}:${b.service}" => b
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +67,7 @@ resource "google_compute_shared_vpc_service_project" "service_projects" {
|
||||
|
||||
resource "google_compute_shared_vpc_service_project" "shared_vpc_service" {
|
||||
provider = google-beta
|
||||
count = local.svpc_service_config.host_project != null ? 1 : 0
|
||||
count = var.shared_vpc_service_config.host_project != null ? 1 : 0
|
||||
host_project = var.shared_vpc_service_config.host_project
|
||||
service_project = local.project.project_id
|
||||
}
|
||||
|
||||
97
modules/project/sharedvpc-agent-iam.yaml
Normal file
97
modules/project/sharedvpc-agent-iam.yaml
Normal file
@@ -0,0 +1,97 @@
|
||||
# Copyright 2023 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.
|
||||
|
||||
# Cloud Composer
|
||||
# https://cloud.google.com/composer/docs/how-to/managing/configuring-shared-vpc#edit_permissions_for_the_composer_agent_service_account
|
||||
- service: composer.googleapis.com
|
||||
agents:
|
||||
composer:
|
||||
- roles/compute.networkUser
|
||||
- roles/composer.sharedVpcAgent
|
||||
|
||||
# Compute Engine
|
||||
# TODO: identify docs
|
||||
- service: compute.googleapis.com
|
||||
agents:
|
||||
cloudservices:
|
||||
- roles/compute.networkUser
|
||||
|
||||
# Google Kubernetes Engine
|
||||
# https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-shared-vpc#enabling_and_granting_roles
|
||||
- service: container.googleapis.com
|
||||
agents:
|
||||
container:
|
||||
- roles/compute.networkUser
|
||||
- roles/container.hostServiceAgentUser
|
||||
- roles/compute.securityAdmin # to manage firewall rules
|
||||
cloudservices:
|
||||
- roles/compute.networkUser
|
||||
|
||||
# Dataflow
|
||||
# https://cloud.google.com/dataflow/docs/guides/specifying-networks#shared
|
||||
- service: dataflow.googleapis.com
|
||||
agents:
|
||||
dataflow:
|
||||
- roles/compute.networkUser
|
||||
|
||||
# Cloud Data Fusion
|
||||
# https://cloud.google.com/data-fusion/docs/how-to/create-private-ip#shared-vpc-network_1
|
||||
- service: datafusion.googleapis.com
|
||||
agents:
|
||||
datafusion:
|
||||
- roles/compute.networkUser
|
||||
dataproc:
|
||||
- roles/compute.networkUser
|
||||
|
||||
# Dataproc
|
||||
# https://cloud.google.com/dataproc/docs/concepts/configuring-clusters/network#create_a_cluster_that_uses_a_network_in_another_project
|
||||
- service: dataproc.googleapis.com
|
||||
agents:
|
||||
dataproc:
|
||||
- roles/compute.networkUser
|
||||
cloudservices:
|
||||
- roles/compute.networkUser
|
||||
|
||||
# Change Data Capture | Datastream
|
||||
# https://cloud.google.com/datastream/docs/create-a-private-connectivity-configuration
|
||||
- service: datastream.googleapis.com
|
||||
agents:
|
||||
datastream:
|
||||
- roles/compute.networkAdmin
|
||||
|
||||
# Cloud Functions
|
||||
# For shared connectors in host project
|
||||
# https://cloud.google.com/functions/docs/networking/shared-vpc-host-project
|
||||
- service: cloudfunctions.googleapis.com
|
||||
agents:
|
||||
cloudfunctions:
|
||||
- roles/vpcaccess.user
|
||||
|
||||
# Cloud Run
|
||||
# For shared connectors in host project
|
||||
# https://cloud.google.com/run/docs/configuring/shared-vpc-host-project
|
||||
- service: run.googleapis.com
|
||||
agents:
|
||||
run:
|
||||
- roles/vpcaccess.user
|
||||
|
||||
# Cloud Run / Cloud Functions
|
||||
# For connectors in service project
|
||||
# https://cloud.google.com/functions/docs/networking/shared-vpc-service-projects#grant-permissions
|
||||
- service: vpcaccess.googleapis.com
|
||||
agents:
|
||||
vpcaccess:
|
||||
- roles/compute.networkUser
|
||||
cloudservices:
|
||||
- roles/compute.networkUser
|
||||
@@ -292,12 +292,24 @@ variable "shared_vpc_host_config" {
|
||||
|
||||
variable "shared_vpc_service_config" {
|
||||
description = "Configures this project as a Shared VPC service project (mutually exclusive with shared_vpc_host_config)."
|
||||
# the list of valid service identities is in service-accounts.tf
|
||||
# the list of valid service identities is in service-agents.yaml
|
||||
type = object({
|
||||
host_project = string
|
||||
service_identity_iam = optional(map(list(string)))
|
||||
service_identity_iam = optional(map(list(string)), {})
|
||||
service_iam_grants = optional(list(string), [])
|
||||
})
|
||||
default = null
|
||||
default = {
|
||||
host_project = null
|
||||
}
|
||||
nullable = false
|
||||
validation {
|
||||
condition = var.shared_vpc_service_config.host_project != null || (
|
||||
var.shared_vpc_service_config.host_project == null &&
|
||||
length(var.shared_vpc_service_config.service_iam_grants) == 0 &&
|
||||
length(var.shared_vpc_service_config.service_iam_grants) == 0
|
||||
)
|
||||
error_message = "You need to provide host_project when providing service_identity_iam or service_iam_grants"
|
||||
}
|
||||
}
|
||||
|
||||
variable "skip_delete" {
|
||||
|
||||
Reference in New Issue
Block a user