diff --git a/aws_gke_oidc_role/README.md b/aws_gke_oidc_role/README.md index 30c00aca..04efd449 100644 --- a/aws_gke_oidc_role/README.md +++ b/aws_gke_oidc_role/README.md @@ -49,16 +49,27 @@ module "oidc_config" { } module "oidc_role" { - depends_on = [module.oidc_config] - source = "../.././" - role_name = "opst-1509-oidc-test" - aws_region = "us-west-1" - gcp_region = "us-west1" - gke_cluster_name = "global-platform-admin-mgmt" - gcp_project_id = "moz-fx-platform-mgmt-global" - gke_namespace = "atlantis-sandbox" - gke_service_account = "atlantis-sandbox" - iam_policy_arns = {} + depends_on = [module.oidc_config] + source = "../.././" + role_name = "opst-1509-oidc-test" + aws_region = "us-west-1" + + gke_clusters = { + mgmt = { + gcp_project_id = "moz-fx-platform-mgmt-global" + gcp_region = "us-west1" + gke_cluster_name = "global-platform-admin-mgmt" + } + } + + k8s_service_accounts = { + atlantis-sandbox = { + namespace = "atlantis-sandbox" + service_account = "atlantis-sandbox" + } + } + + iam_policy_arns = {} } ``` @@ -70,14 +81,25 @@ module "oidc_role" { */ module "oidc_role" { - source = "../.././" - role_name = "oidc-example-role" - aws_region = "us-west-1" - gcp_region = "us-west1" - gke_cluster_name = "baz" - gcp_project_id = "example-project" - gke_namespace = "bar" - gke_service_account = "foo" + source = "../.././" + role_name = "oidc-example-role" + aws_region = "us-west-1" + + gke_clusters = { + baz = { + gcp_region = "us-west1" + gke_cluster_name = "baz" + gcp_project_id = "example-project" + } + } + + k8s_service_accounts = { + foobar = { + namespace = "foo" + service_account = "bar" + } + } + iam_policy_arns = { example_policy = aws_iam_policy.example_policy.arn ViewOnlyAccess = data.aws_iam_policy.view_only.arn @@ -115,12 +137,9 @@ data "aws_iam_policy" "view_only" { | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [aws\_region](#input\_aws\_region) | AWS region | `string` | n/a | yes | -| [gcp\_project\_id](#input\_gcp\_project\_id) | GKE cluster's project ID | `string` | n/a | yes | -| [gcp\_region](#input\_gcp\_region) | GKE cluster's GCP region | `string` | n/a | yes | -| [gke\_cluster\_name](#input\_gke\_cluster\_name) | GKE cluster name | `string` | n/a | yes | -| [gke\_namespace](#input\_gke\_namespace) | Namespace for GKE workload | `string` | n/a | yes | -| [gke\_service\_account](#input\_gke\_service\_account) | GKE service account to grant role assumption privilleges | `string` | n/a | yes | +| [gke\_clusters](#input\_gke\_clusters) | GKE clusters to grant role assumption privileges |
map(object({
gcp_project_id = string
gcp_region = string
gke_cluster_name = string
}))
| `{}` | no | | [iam\_policy\_arns](#input\_iam\_policy\_arns) | One or more policy arns to attach to created AWS role | `map(string)` | n/a | yes | +| [k8s\_service\_accounts](#input\_k8s\_service\_accounts) | Map of Kubernetes service accounts that are allowed to assume role. Sub claim format is `system:serviceaccount:${namespace}:${service_account}` |
map(object({
namespace = string
service_account = string
}))
| `{}` | no | | [role\_name](#input\_role\_name) | Name to give the AWS role | `string` | n/a | yes | | [spacelift\_instance](#input\_spacelift\_instance) | Spacelift instance to grant role assumption privilleges | `string` | `"mozilla.app.spacelift.io"` | no | | [spacelift\_prefixes](#input\_spacelift\_prefixes) | List of prefixes for Spacelift spaces/stacks that are allowed to assume role. See sub claim at https://docs.spacelift.io/integrations/cloud-providers/oidc#standard-claims for format | `list(string)` | `[]` | no | diff --git a/aws_gke_oidc_role/examples/role_and_config/main.tf b/aws_gke_oidc_role/examples/role_and_config/main.tf index 9b5ecb75..a48636f1 100644 --- a/aws_gke_oidc_role/examples/role_and_config/main.tf +++ b/aws_gke_oidc_role/examples/role_and_config/main.tf @@ -10,14 +10,25 @@ module "oidc_config" { } module "oidc_role" { - depends_on = [module.oidc_config] - source = "../.././" - role_name = "opst-1509-oidc-test" - aws_region = "us-west-1" - gcp_region = "us-west1" - gke_cluster_name = "global-platform-admin-mgmt" - gcp_project_id = "moz-fx-platform-mgmt-global" - gke_namespace = "atlantis-sandbox" - gke_service_account = "atlantis-sandbox" - iam_policy_arns = {} + depends_on = [module.oidc_config] + source = "../.././" + role_name = "opst-1509-oidc-test" + aws_region = "us-west-1" + + gke_clusters = { + mgmt = { + gcp_project_id = "moz-fx-platform-mgmt-global" + gcp_region = "us-west1" + gke_cluster_name = "global-platform-admin-mgmt" + } + } + + k8s_service_accounts = { + atlantis-sandbox = { + namespace = "atlantis-sandbox" + service_account = "atlantis-sandbox" + } + } + + iam_policy_arns = {} } diff --git a/aws_gke_oidc_role/examples/role_with_policy/main.tf b/aws_gke_oidc_role/examples/role_with_policy/main.tf index 9811ca75..39636277 100644 --- a/aws_gke_oidc_role/examples/role_with_policy/main.tf +++ b/aws_gke_oidc_role/examples/role_with_policy/main.tf @@ -5,14 +5,25 @@ */ module "oidc_role" { - source = "../.././" - role_name = "oidc-example-role" - aws_region = "us-west-1" - gcp_region = "us-west1" - gke_cluster_name = "baz" - gcp_project_id = "example-project" - gke_namespace = "bar" - gke_service_account = "foo" + source = "../.././" + role_name = "oidc-example-role" + aws_region = "us-west-1" + + gke_clusters = { + baz = { + gcp_region = "us-west1" + gke_cluster_name = "baz" + gcp_project_id = "example-project" + } + } + + k8s_service_accounts = { + foobar = { + namespace = "foo" + service_account = "bar" + } + } + iam_policy_arns = { example_policy = aws_iam_policy.example_policy.arn ViewOnlyAccess = data.aws_iam_policy.view_only.arn diff --git a/aws_gke_oidc_role/main.tf b/aws_gke_oidc_role/main.tf index 2fef871d..98a3bf98 100644 --- a/aws_gke_oidc_role/main.tf +++ b/aws_gke_oidc_role/main.tf @@ -35,26 +35,38 @@ * ``` */ +locals { + k8s_service_accounts = [for k, v in var.k8s_service_accounts : "system:serviceaccount:${v.namespace}:${v.service_account}"] + + oidc_provider_urls = concat([ + for k, v in data.aws_iam_openid_connect_provider.gke_oidc : replace(v.url, "https://", "") + ], [data.aws_iam_openid_connect_provider.spacelift.url]) +} + module "iam_assumable_role_for_oidc" { source = "terraform-aws-modules/iam/aws//modules/iam-role" version = "~> v6.2.1" - description = "Role for ${var.gke_cluster_name}/${var.gke_namespace}/${var.gke_service_account} and Spacelift to assume" + description = "Role for GKE clusters and Spacelift to assume" enable_oidc = true name = var.role_name - oidc_provider_urls = [replace(data.aws_iam_openid_connect_provider.gke_oidc.url, "https://", ""), data.aws_iam_openid_connect_provider.spacelift.url] + oidc_provider_urls = local.oidc_provider_urls # TODO - look into using https://registry.terraform.io/modules/terraform-aws-modules/iam/aws/latest/submodules/iam-role#input_trust_policy_conditions for the Spacelift subject # GKE subject doesn't need wildcards so it can be an `oidc_subject`, but setting both `oidc_subjects` and `wilcard_subjects` results in an AND oidc_wildcard_subjects = setunion( - ["system:serviceaccount:${var.gke_namespace}:${var.gke_service_account}"], - var.spacelift_prefixes + local.k8s_service_accounts, + var.spacelift_prefixes, ) policies = var.iam_policy_arns use_name_prefix = false } + + data "aws_iam_openid_connect_provider" "gke_oidc" { - url = "https://container.googleapis.com/v1/projects/${var.gcp_project_id}/locations/${var.gcp_region}/clusters/${var.gke_cluster_name}" + for_each = var.gke_clusters + + url = "https://container.googleapis.com/v1/projects/${each.value.gcp_project_id}/locations/${each.value.gcp_region}/clusters/${each.value.gke_cluster_name}" } data "aws_iam_openid_connect_provider" "spacelift" { diff --git a/aws_gke_oidc_role/variables.tf b/aws_gke_oidc_role/variables.tf index 6d56324f..4c9f4d21 100644 --- a/aws_gke_oidc_role/variables.tf +++ b/aws_gke_oidc_role/variables.tf @@ -15,29 +15,23 @@ variable "aws_region" { type = string } -variable "gcp_project_id" { - description = "GKE cluster's project ID" - type = string -} - -variable "gcp_region" { - description = "GKE cluster's GCP region" - type = string -} - -variable "gke_cluster_name" { - description = "GKE cluster name" - type = string -} - -variable "gke_namespace" { - description = "Namespace for GKE workload" - type = string -} - -variable "gke_service_account" { - description = "GKE service account to grant role assumption privilleges" - type = string +variable "gke_clusters" { + default = {} + description = "GKE clusters to grant role assumption privileges" + type = map(object({ + gcp_project_id = string + gcp_region = string + gke_cluster_name = string + })) +} + +variable "k8s_service_accounts" { + default = {} + description = "Map of Kubernetes service accounts that are allowed to assume role. Sub claim format is `system:serviceaccount:$${namespace}:$${service_account}`" + type = map(object({ + namespace = string + service_account = string + })) } variable "spacelift_instance" {