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

Grant IAM rights to service identities in host project #1542

Merged
merged 10 commits into from
Jul 29, 2023
29 changes: 26 additions & 3 deletions modules/project/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,29 @@ 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"
shared_vpc_service_config = {
host_project = module.host-project.project_id
grant_iam_for_services = [
"container.googleapis.com",
ludoo marked this conversation as resolved.
Show resolved Hide resolved
]
}
}
# tftest modules=2 resources=8 inventory=shared-vpc-auto-grants.yaml
```

## Organization Policies

To manage organization policies, the `orgpolicy.googleapis.com` service should be enabled in the quota project.
Expand Down Expand Up @@ -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&#40;string&#41;</code> | | <code>&#91;&#93;</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&#40;&#123;&#10; enabled &#61; bool&#10; service_projects &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</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&#40;&#123;&#10; host_project &#61; string&#10; service_identity_iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</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&#40;string&#41;</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&#40;&#123;&#10; host_project &#61; string&#10; service_identity_iam &#61; optional&#40;map&#40;list&#40;string&#41;&#41;, &#123;&#125;&#41;&#10; grant_iam_for_services &#61; optional&#40;list&#40;string&#41;, &#91;&#93;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; host_project &#61; null&#10;&#125;">&#123;&#8230;&#125;</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&#40;string&#41;</code> | | <code>null</code> |

## Outputs

Expand Down
26 changes: 17 additions & 9 deletions modules/project/shared-vpc.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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.grant_iam_for_services, config.service)
ludoo marked this conversation as resolved.
Show resolved Hide resolved
]
_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
Expand All @@ -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 distinct(concat(local._svpc_service_iam, local._shared_vpc_agent_grants)) : "${b.role}:${b.service}" => b
wiktorn marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -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
ludoo marked this conversation as resolved.
Show resolved Hide resolved
host_project = var.shared_vpc_service_config.host_project
service_project = local.project.project_id
}
Expand Down
90 changes: 90 additions & 0 deletions modules/project/sharedvpc-agent-iam.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# 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

# 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
20 changes: 16 additions & 4 deletions modules/project/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
host_project = string
service_identity_iam = optional(map(list(string)), {})
grant_iam_for_services = optional(list(string), [])
wiktorn marked this conversation as resolved.
Show resolved Hide resolved
})
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.grant_iam_for_services) == 0 &&
length(var.shared_vpc_service_config.grant_iam_for_services) == 0
)
error_message = "You need to provide host_project when providing service_identity_iam or grant_iam_for_services"
}
}

variable "skip_delete" {
Expand Down
42 changes: 42 additions & 0 deletions tests/modules/project/examples/shared-vpc-auto-grants.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# 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.

values:
module.host-project.google_compute_shared_vpc_host_project.shared_vpc_host[0]:
project: my-host-project
module.host-project.google_project.project[0]:
project_id: my-host-project
module.service-project.google_compute_shared_vpc_service_project.shared_vpc_service[0]:
host_project: my-host-project
service_project: my-service-project
module.service-project.google_project.project[0]:
project_id: my-service-project
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:cloudservices"]:
condition: []
project: my-host-project
role: roles/compute.networkUser
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/compute.networkUser:container"]:
condition: []
project: my-host-project
role: roles/compute.networkUser
module.service-project.google_project_iam_member.shared_vpc_host_robots["roles/container.hostServiceAgentUser:container"]:
condition: []
project: my-host-project
role: roles/container.hostServiceAgentUser

counts:
google_compute_shared_vpc_host_project: 1
google_compute_shared_vpc_service_project: 1
google_project: 2
google_project_iam_member: 4