Skip to content

Commit

Permalink
feat: Fleet app operator permissions (#1986)
Browse files Browse the repository at this point in the history
Co-authored-by: Andrew Peabody <[email protected]>
  • Loading branch information
hosseingolestani and apeabody authored Jul 19, 2024
1 parent 2834461 commit e0fd03a
Show file tree
Hide file tree
Showing 18 changed files with 580 additions and 1 deletion.
20 changes: 20 additions & 0 deletions build/int.cloudbuild.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,26 @@ steps:
- verify simple-autopilot-private-non-default-sa
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleAutopilotPrivateNonDefaultSA --stage teardown --verbose']
- id: init simple-fleet-app-operator-permissions
waitFor:
- create-all
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleFleetAppOperatorPermissions --stage init --verbose']
- id: apply simple-fleet-app-operator-permissions
waitFor:
- init simple-fleet-app-operator-permissions
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleFleetAppOperatorPermissions --stage apply --verbose']
- id: verify simple-fleet-app-operator-permissions
waitFor:
- apply simple-fleet-app-operator-permissions
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleFleetAppOperatorPermissions --stage verify --verbose']
- id: teardown simple-fleet-app-operator-permissions
waitFor:
- verify simple-fleet-app-operator-permissions
name: 'gcr.io/cloud-foundation-cicd/$_DOCKER_IMAGE_DEVELOPER_TOOLS:$_DOCKER_TAG_VERSION_DEVELOPER_TOOLS'
args: ['/bin/bash', '-c', 'cft test run TestSimpleFleetAppOperatorPermissions --stage teardown --verbose']
tags:
- 'ci'
- 'integration'
Expand Down
26 changes: 26 additions & 0 deletions examples/simple_fleet_app_operator_permissions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Simple App Operator Permissions Setup for a Fleet Scope

This example illustrates how to create a Fleet Scope for a [team](https://cloud.google.com/kubernetes-engine/fleet-management/docs/team-management) and set up permissions for an app operator in the team.

<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| fleet\_project\_id | The project to which the Fleet belongs. | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| fleet\_project\_id | The project to which the Fleet belongs. |
| wait | An output (Fleet Scope RBAC Role Binding IDs) to use when you want to depend on granting permissions finishing. |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->

To provision this example, run the following from within this directory:
- `terraform init` to get the plugins
- `terraform plan` to see the infrastructure plan
- `terraform apply` to apply the infrastructure build
- `terraform destroy` to destroy the built infrastructure

50 changes: 50 additions & 0 deletions examples/simple_fleet_app_operator_permissions/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* 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.
* 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.
*/

locals {
app_operator_id = "app-operator-id"
app_operator_team = "app-operator-team"
app_operator_role = "VIEW"
}

# Create a Service Account, which can be used as an app operator.
resource "google_service_account" "service_account" {
project = var.fleet_project_id
account_id = local.app_operator_id
display_name = "Test App Operator Service Account"
}

# Create a Fleet Scope for the app operator's team.
resource "google_gke_hub_scope" "scope" {
project = var.fleet_project_id
scope_id = local.app_operator_team
}

# Grant permissions to the app operator to work with the Fleet Scope.
module "permissions" {
source = "../../modules/fleet-app-operator-permissions"

fleet_project_id = var.fleet_project_id
scope_id = google_gke_hub_scope.scope.scope_id
users = ["${local.app_operator_id}@${var.fleet_project_id}.iam.gserviceaccount.com"]
groups = []
role = local.app_operator_role

depends_on = [
google_service_account.service_account
]
}

26 changes: 26 additions & 0 deletions examples/simple_fleet_app_operator_permissions/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* 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.
* 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.
*/

output "fleet_project_id" {
description = "The project to which the Fleet belongs."
value = var.fleet_project_id
}

output "wait" {
description = "An output (Fleet Scope RBAC Role Binding IDs) to use when you want to depend on granting permissions finishing."
value = module.permissions.wait
}

21 changes: 21 additions & 0 deletions examples/simple_fleet_app_operator_permissions/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* 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.
* 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.
*/

variable "fleet_project_id" {
description = "The project to which the Fleet belongs."
type = string
}

31 changes: 31 additions & 0 deletions examples/simple_fleet_app_operator_permissions/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* 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.
* 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.
*/

terraform {
required_version = ">= 1.2.0"

required_providers {
google = {
source = "hashicorp/google"
version = ">= 4.81.0"
}
google-beta = {
source = "hashicorp/google-beta"
version = ">= 4.81.0"
}
}
}

44 changes: 44 additions & 0 deletions modules/fleet-app-operator-permissions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Terrafrom Module for Fleet App Operator Permissions

This module bundles different permissions (IAM and RBAC Role Bindings) required for [Fleet team management](https://cloud.google.com/kubernetes-engine/fleet-management/docs/team-management). A platform admin can use this module to set up permissions for an app operator (user or group) in a team--including usage of Fleet Scopes, Connect Gateway, logging, and metrics--based on predefined roles (VIEW, EDIT, ADMIN).

## Usage
```tf
Example:
module "fleet_app_operator_permissions" {
source = "terraform-google-modules/kubernetes-engine/google//modules/fleet-app-operator-permissions"
fleet_project_id = "my-project-id"
scope_id = "frontend-team"
users = ["[email protected]", "[email protected]"]
groups = ["[email protected]"]
role = "EDIT"
}
```

To deploy this config, run:
- `terraform init` to get the plugins
- `terraform plan` to see the infrastructure plan
- `terraform apply` to apply the infrastructure build
- `terraform destroy` to destroy the built infrastructure


<!-- BEGINNING OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| fleet\_project\_id | The project to which the Fleet belongs. | `string` | n/a | yes |
| groups | The list of app operator group principals, e.g., `[email protected]`, `principalSet://iam.googleapis.com/locations/global/workforcePools/my-pool/group/people`. | `list(string)` | n/a | yes |
| role | The principals role for the Fleet Scope (`VIEW`/`EDIT`/`ADMIN`). | `string` | n/a | yes |
| scope\_id | The scope for which IAM and RBAC role bindings are created. | `string` | n/a | yes |
| users | The list of app operator user principals, e.g., `[email protected]`, `principal://iam.googleapis.com/locations/global/workforcePools/my-pool/subject/person`, `serviceAccount:[email protected]`. | `list(string)` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| fleet\_project\_id | The project to which the Fleet belongs. |
| wait | An output to use when you want to depend on Scope RBAC Role Binding creation finishing. |

<!-- END OF PRE-COMMIT-TERRAFORM DOCS HOOK -->
97 changes: 97 additions & 0 deletions modules/fleet-app-operator-permissions/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* 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.
* 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.
*/

locals {
user_principals = [for name in var.users : (
startswith(name, "principal://") ? name : (
endswith(name, "gserviceaccount.com") ? "serviceAccount:${name}" : (
"user:${name}"
)))]

group_principals = [for name in var.groups : (
startswith(name, "principalSet://") ? name : (
"group:${name}"
))]

project_level_scope_role = {
"VIEW" = "roles/gkehub.scopeViewerProjectLevel"
"EDIT" = "roles/gkehub.scopeEditorProjectLevel"
"ADMIN" = "roles/gkehub.scopeEditorProjectLevel" # Same as EDIT
}

resource_level_scope_role = {
"VIEW" = "roles/gkehub.scopeViewer"
"EDIT" = "roles/gkehub.scopeEditor"
"ADMIN" = "roles/gkehub.scopeAdmin"
}
}

resource "google_project_iam_binding" "log_view_permissions" {
project = var.fleet_project_id
role = "roles/logging.viewAccessor"
members = concat(local.user_principals, local.group_principals)
condition {
title = "conditional log view access"
description = "log view access for scope ${var.scope_id}"
expression = "resource.name == \"projects/${var.fleet_project_id}/locations/global/buckets/fleet-o11y-scope-${var.scope_id}/views/fleet-o11y-scope-${var.scope_id}-k8s_container\" || resource.name == \"projects/${var.fleet_project_id}/locations/global/buckets/fleet-o11y-scope-${var.scope_id}/views/fleet-o11y-scope-${var.scope_id}-k8s_pod\""
}
}

resource "google_project_iam_binding" "project_level_scope_permissions" {
project = var.fleet_project_id
role = local.project_level_scope_role[var.role]
members = concat(local.user_principals, local.group_principals)
}

resource "google_gke_hub_scope_iam_binding" "resource_level_scope_permissions" {
project = var.fleet_project_id
scope_id = var.scope_id
role = local.resource_level_scope_role[var.role]
members = concat(local.user_principals, local.group_principals)
}

resource "random_id" "user_rand_suffix" {
for_each = toset(var.users)
byte_length = 4
}

resource "google_gke_hub_scope_rbac_role_binding" "scope_rbac_user_role_bindings" {
for_each = toset(var.users)
project = var.fleet_project_id
scope_rbac_role_binding_id = "tf-${substr(join("", regexall("[a-z0-9]+", each.key)), 0, 16)}-${random_id.user_rand_suffix[each.key].hex}"
scope_id = var.scope_id
user = each.key
role {
predefined_role = var.role
}
}

resource "random_id" "group_rand_suffix" {
for_each = toset(var.groups)
byte_length = 4
}

resource "google_gke_hub_scope_rbac_role_binding" "scope_rbac_group_role_bindings" {
for_each = toset(var.groups)
project = var.fleet_project_id
scope_rbac_role_binding_id = "tf-${substr(join("", regexall("[a-z0-9]+", each.key)), 0, 16)}-${random_id.group_rand_suffix[each.key].hex}"
scope_id = var.scope_id
group = each.key
role {
predefined_role = var.role
}
}

28 changes: 28 additions & 0 deletions modules/fleet-app-operator-permissions/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* 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.
* 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.
*/

output "fleet_project_id" {
description = "The project to which the Fleet belongs."
value = var.fleet_project_id
}

output "wait" {
description = "An output to use when you want to depend on Scope RBAC Role Binding creation finishing."
value = {
for k, v in merge(google_gke_hub_scope_rbac_role_binding.scope_rbac_user_role_bindings, google_gke_hub_scope_rbac_role_binding.scope_rbac_group_role_bindings) : k => v.scope_rbac_role_binding_id
}
}

Loading

0 comments on commit e0fd03a

Please sign in to comment.