From 0c9d965f4f9ee6cd2aacb481b50ded2aa3933b13 Mon Sep 17 00:00:00 2001 From: Austin Mitchell Date: Tue, 3 Dec 2024 11:18:35 -0800 Subject: [PATCH] add aws_gke_oidc modules --- aws_gke_oidc_config/.terraform-docs.yml | 12 ++ aws_gke_oidc_config/CHANGELOG.md | 6 + aws_gke_oidc_config/README.md | 36 +++++ aws_gke_oidc_config/examples/main.tf | 10 ++ aws_gke_oidc_config/main.tf | 25 ++++ aws_gke_oidc_config/variables.tf | 16 +++ aws_gke_oidc_config/versions.tf | 9 ++ aws_gke_oidc_role/.terraform-docs.yml | 16 +++ aws_gke_oidc_role/CHANGELOG.md | 6 + aws_gke_oidc_role/README.md | 128 ++++++++++++++++++ .../examples/role_and_config/main.tf | 23 ++++ .../examples/role_and_config/providers.tf | 13 ++ .../examples/role_with_policy/main.tf | 42 ++++++ .../examples/role_with_policy/providers.tf | 13 ++ aws_gke_oidc_role/main.tf | 51 +++++++ aws_gke_oidc_role/outputs.tf | 4 + aws_gke_oidc_role/variables.tf | 41 ++++++ aws_gke_oidc_role/versions.tf | 9 ++ 18 files changed, 460 insertions(+) create mode 100644 aws_gke_oidc_config/.terraform-docs.yml create mode 100644 aws_gke_oidc_config/CHANGELOG.md create mode 100644 aws_gke_oidc_config/README.md create mode 100644 aws_gke_oidc_config/examples/main.tf create mode 100644 aws_gke_oidc_config/main.tf create mode 100644 aws_gke_oidc_config/variables.tf create mode 100644 aws_gke_oidc_config/versions.tf create mode 100644 aws_gke_oidc_role/.terraform-docs.yml create mode 100644 aws_gke_oidc_role/CHANGELOG.md create mode 100644 aws_gke_oidc_role/README.md create mode 100644 aws_gke_oidc_role/examples/role_and_config/main.tf create mode 100644 aws_gke_oidc_role/examples/role_and_config/providers.tf create mode 100644 aws_gke_oidc_role/examples/role_with_policy/main.tf create mode 100644 aws_gke_oidc_role/examples/role_with_policy/providers.tf create mode 100644 aws_gke_oidc_role/main.tf create mode 100644 aws_gke_oidc_role/outputs.tf create mode 100644 aws_gke_oidc_role/variables.tf create mode 100644 aws_gke_oidc_role/versions.tf diff --git a/aws_gke_oidc_config/.terraform-docs.yml b/aws_gke_oidc_config/.terraform-docs.yml new file mode 100644 index 00000000..0727059d --- /dev/null +++ b/aws_gke_oidc_config/.terraform-docs.yml @@ -0,0 +1,12 @@ +content: |- + {{ .Header }} + + ## Example + + ```hcl + {{ include "examples/main.tf" }} + ``` + + {{ .Inputs }} + + {{ .Outputs }} diff --git a/aws_gke_oidc_config/CHANGELOG.md b/aws_gke_oidc_config/CHANGELOG.md new file mode 100644 index 00000000..79cad37d --- /dev/null +++ b/aws_gke_oidc_config/CHANGELOG.md @@ -0,0 +1,6 @@ +## 0.1.0 +* PR [#239](https://github.com/mozilla/terraform-modules/pull/239) - feat: add aws_gke_oidc_config and aws_gke_oidc_role modules +``` +add aws_gke_oidc_config and aws_gke_oidc_role modules +``` + diff --git a/aws_gke_oidc_config/README.md b/aws_gke_oidc_config/README.md new file mode 100644 index 00000000..245e4f7d --- /dev/null +++ b/aws_gke_oidc_config/README.md @@ -0,0 +1,36 @@ + +# AWS-GKE OIDC Config +This module will create an AWS OIDC config that creates a trust relationship between a GKE cluster & AWS account. + +Once this module has been invoked for a given account + GKE cluster, the `aws_gke_oidc_role` module can be used +to create any number of roles to be used by GKE workloads. + +See the `aws_gke_oidc_role` for complete usage instructions + +## Example + +```hcl +/* + * Creates an OIDC trust relationship between the global-platform-admin-mgmt cluster & the authenticated AWS account. + */ + +module "oidc_config" { + source = "../." + gcp_region = "us-west1" + gcp_project_id = "moz-fx-platform-mgmt-global" + gke_cluster_name = "global-platform-admin-mgmt" +} +``` + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [gcp\_project\_id](#input\_gcp\_project\_id) | ID of the GKE cluster's project | `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 | + +## Outputs + +No outputs. + \ No newline at end of file diff --git a/aws_gke_oidc_config/examples/main.tf b/aws_gke_oidc_config/examples/main.tf new file mode 100644 index 00000000..5297c14c --- /dev/null +++ b/aws_gke_oidc_config/examples/main.tf @@ -0,0 +1,10 @@ +/* + * Creates an OIDC trust relationship between the global-platform-admin-mgmt cluster & the authenticated AWS account. + */ + +module "oidc_config" { + source = "../." + gcp_region = "us-west1" + gcp_project_id = "moz-fx-platform-mgmt-global" + gke_cluster_name = "global-platform-admin-mgmt" +} diff --git a/aws_gke_oidc_config/main.tf b/aws_gke_oidc_config/main.tf new file mode 100644 index 00000000..41d69e1f --- /dev/null +++ b/aws_gke_oidc_config/main.tf @@ -0,0 +1,25 @@ +/* + * # AWS-GKE OIDC Config + * This module will create an AWS OIDC config that creates a trust relationship between a GKE cluster & AWS account. + * + * Once this module has been invoked for a given account + GKE cluster, the `aws_gke_oidc_role` module can be used + * to create any number of roles to be used by GKE workloads. + * + * See the `aws_gke_oidc_role` for complete usage instructions +*/ + +resource "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}" + + client_id_list = [ + "sts.amazonaws.com" + ] + + thumbprint_list = [ + data.tls_certificate.gke_oidc.certificates.0.sha1_fingerprint + ] +} + +data "tls_certificate" "gke_oidc" { + url = "https://container.googleapis.com/v1/projects/${var.gcp_project_id}/locations/${var.gcp_region}/clusters/${var.gke_cluster_name}" +} diff --git a/aws_gke_oidc_config/variables.tf b/aws_gke_oidc_config/variables.tf new file mode 100644 index 00000000..0a24bd16 --- /dev/null +++ b/aws_gke_oidc_config/variables.tf @@ -0,0 +1,16 @@ +### Required + +variable "gcp_region" { + description = "GKE cluster's GCP region" + type = string +} + +variable "gcp_project_id" { + description = "ID of the GKE cluster's project" + type = string +} + +variable "gke_cluster_name" { + description = "GKE cluster name" + type = string +} diff --git a/aws_gke_oidc_config/versions.tf b/aws_gke_oidc_config/versions.tf new file mode 100644 index 00000000..36a9084e --- /dev/null +++ b/aws_gke_oidc_config/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.37" + } + } + required_version = "~> 1.0" +} diff --git a/aws_gke_oidc_role/.terraform-docs.yml b/aws_gke_oidc_role/.terraform-docs.yml new file mode 100644 index 00000000..8ae8a91f --- /dev/null +++ b/aws_gke_oidc_role/.terraform-docs.yml @@ -0,0 +1,16 @@ +content: |- + {{ .Header }} + + ## Example + + ```hcl + {{ include "examples/role_and_config/main.tf" }} + ``` + + ```hcl + {{ include "examples/role_with_policy/main.tf" }} + ``` + + {{ .Inputs }} + + {{ .Outputs }} diff --git a/aws_gke_oidc_role/CHANGELOG.md b/aws_gke_oidc_role/CHANGELOG.md new file mode 100644 index 00000000..79cad37d --- /dev/null +++ b/aws_gke_oidc_role/CHANGELOG.md @@ -0,0 +1,6 @@ +## 0.1.0 +* PR [#239](https://github.com/mozilla/terraform-modules/pull/239) - feat: add aws_gke_oidc_config and aws_gke_oidc_role modules +``` +add aws_gke_oidc_config and aws_gke_oidc_role modules +``` + diff --git a/aws_gke_oidc_role/README.md b/aws_gke_oidc_role/README.md new file mode 100644 index 00000000..7fc25aeb --- /dev/null +++ b/aws_gke_oidc_role/README.md @@ -0,0 +1,128 @@ + +# AWS-GKE OIDC Role +This module will create an AWS role that will allow a specified GKE service account to assume it. + +Requires that `../aws_gke_oidc_config` has been applied for a given AWS account + GKE cluster combination +if you get an error about the `aws_iam_openid_connect_provider` data source being missing, apply that module. + +After creating these resources, add the following environment variables, volumes, and volume mounts to your pod definition: +* env: +``` +- name: AWS_REGION + value: +- name: AWS_ROLE_ARN + value: +- name: AWS_WEB_IDENTITY_TOKEN_FILE + value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token +- name: AWS_STS_REGIONAL_ENDPOINTS + value: regional +``` +* volumes: +``` +- name: aws-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + audience: sts.amazonaws.com + expirationSeconds: 86400 + path: token +``` +* volumeMounts: +``` +- mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount/ + name: aws-token +``` + +## Example + +```hcl +/* +* Example of creating both an OIDC config & role to utilize it +*/ + +module "oidc_config" { + source = "../../../aws_gke_oidc_config/" + gcp_region = "us-west1" + gcp_project_id = "moz-fx-platform-mgmt-global" + gke_cluster_name = "global-platform-admin-mgmt" +} + +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 = [] +} +``` + +```hcl +/* +* Example of creating just the role. The module will infer the OIDC url from vars. +* Attaches an inline ec2 policy & managed AWS ViewOnly policy. +* Resulting role will be assumable by the "foo" service account in the "bar" namespace of the "baz" cluster +*/ + +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" + iam_policy_arns = [aws_iam_policy.example_policy.arn, data.aws_iam_policy.view_only.arn] +} + +resource "aws_iam_policy" "example_policy" { + name = "example_policy" + path = "/" + description = "My example policy" + + # Terraform's "jsonencode" function converts a + # Terraform expression result to valid JSON syntax. + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "ec2:Describe*", + ] + Effect = "Allow" + Resource = "*" + }, + ] + }) +} + +data "aws_iam_policy" "view_only" { + arn = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess" +} +``` + +## Inputs + +| 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 | +| [iam\_policy\_arns](#input\_iam\_policy\_arns) | One or more policy arns to attach to created AWS role | `list(string)` | n/a | yes | +| [role\_name](#input\_role\_name) | Name to give the AWS role | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| [role\_arn](#output\_role\_arn) | ARN for the GKE-AWS connector role | + \ No newline at end of file diff --git a/aws_gke_oidc_role/examples/role_and_config/main.tf b/aws_gke_oidc_role/examples/role_and_config/main.tf new file mode 100644 index 00000000..1361d165 --- /dev/null +++ b/aws_gke_oidc_role/examples/role_and_config/main.tf @@ -0,0 +1,23 @@ +/* +* Example of creating both an OIDC config & role to utilize it +*/ + +module "oidc_config" { + source = "../../../aws_gke_oidc_config/" + gcp_region = "us-west1" + gcp_project_id = "moz-fx-platform-mgmt-global" + gke_cluster_name = "global-platform-admin-mgmt" +} + +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 = [] +} diff --git a/aws_gke_oidc_role/examples/role_and_config/providers.tf b/aws_gke_oidc_role/examples/role_and_config/providers.tf new file mode 100644 index 00000000..b2c3630a --- /dev/null +++ b/aws_gke_oidc_role/examples/role_and_config/providers.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +# Configure the AWS Provider +provider "aws" { + region = "us-west-2" +} diff --git a/aws_gke_oidc_role/examples/role_with_policy/main.tf b/aws_gke_oidc_role/examples/role_with_policy/main.tf new file mode 100644 index 00000000..b8388452 --- /dev/null +++ b/aws_gke_oidc_role/examples/role_with_policy/main.tf @@ -0,0 +1,42 @@ +/* +* Example of creating just the role. The module will infer the OIDC url from vars. +* Attaches an inline ec2 policy & managed AWS ViewOnly policy. +* Resulting role will be assumable by the "foo" service account in the "bar" namespace of the "baz" cluster +*/ + +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" + iam_policy_arns = [aws_iam_policy.example_policy.arn, data.aws_iam_policy.view_only.arn] +} + +resource "aws_iam_policy" "example_policy" { + name = "example_policy" + path = "/" + description = "My example policy" + + # Terraform's "jsonencode" function converts a + # Terraform expression result to valid JSON syntax. + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "ec2:Describe*", + ] + Effect = "Allow" + Resource = "*" + }, + ] + }) +} + +data "aws_iam_policy" "view_only" { + arn = "arn:aws:iam::aws:policy/job-function/ViewOnlyAccess" +} diff --git a/aws_gke_oidc_role/examples/role_with_policy/providers.tf b/aws_gke_oidc_role/examples/role_with_policy/providers.tf new file mode 100644 index 00000000..b2c3630a --- /dev/null +++ b/aws_gke_oidc_role/examples/role_with_policy/providers.tf @@ -0,0 +1,13 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 5.0" + } + } +} + +# Configure the AWS Provider +provider "aws" { + region = "us-west-2" +} diff --git a/aws_gke_oidc_role/main.tf b/aws_gke_oidc_role/main.tf new file mode 100644 index 00000000..f2a5f296 --- /dev/null +++ b/aws_gke_oidc_role/main.tf @@ -0,0 +1,51 @@ +/* + * # AWS-GKE OIDC Role + * This module will create an AWS role that will allow a specified GKE service account to assume it. + * + * Requires that `../aws_gke_oidc_config` has been applied for a given AWS account + GKE cluster combination + * if you get an error about the `aws_iam_openid_connect_provider` data source being missing, apply that module. + * + * After creating these resources, add the following environment variables, volumes, and volume mounts to your pod definition: + * * env: + * ``` + * - name: AWS_REGION + * value: + * - name: AWS_ROLE_ARN + * value: + * - name: AWS_WEB_IDENTITY_TOKEN_FILE + * value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token + * - name: AWS_STS_REGIONAL_ENDPOINTS + * value: regional + * ``` + * * volumes: + * ``` + * - name: aws-token + * projected: + * defaultMode: 420 + * sources: + * - serviceAccountToken: + * audience: sts.amazonaws.com + * expirationSeconds: 86400 + * path: token + * ``` + * * volumeMounts: + * ``` + * - mountPath: /var/run/secrets/eks.amazonaws.com/serviceaccount/ + * name: aws-token + * ``` +*/ + +module "iam_assumable_role_for_oidc" { + source = "terraform-aws-modules/iam/aws//modules/iam-assumable-role-with-oidc" + version = "~> v5.9" + create_role = true + role_name = var.role_name + role_description = "Role for ${var.gke_cluster_name}/${var.gke_namespace}/${var.gke_service_account} to assume" + provider_url = replace(data.aws_iam_openid_connect_provider.gke_oidc.url, "https://", "") + role_policy_arns = var.iam_policy_arns + oidc_fully_qualified_subjects = ["system:serviceaccount:${var.gke_namespace}:${var.gke_service_account}"] +} + +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}" +} diff --git a/aws_gke_oidc_role/outputs.tf b/aws_gke_oidc_role/outputs.tf new file mode 100644 index 00000000..da87ea5a --- /dev/null +++ b/aws_gke_oidc_role/outputs.tf @@ -0,0 +1,4 @@ +output "role_arn" { + description = "ARN for the GKE-AWS connector role" + value = module.iam_assumable_role_for_oidc.iam_role_name +} diff --git a/aws_gke_oidc_role/variables.tf b/aws_gke_oidc_role/variables.tf new file mode 100644 index 00000000..3c58917b --- /dev/null +++ b/aws_gke_oidc_role/variables.tf @@ -0,0 +1,41 @@ +### Required + +variable "iam_policy_arns" { + description = "One or more policy arns to attach to created AWS role" + type = list(string) +} + +variable "role_name" { + description = "Name to give the AWS role" + type = string +} + +variable "aws_region" { + description = "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 +} diff --git a/aws_gke_oidc_role/versions.tf b/aws_gke_oidc_role/versions.tf new file mode 100644 index 00000000..36a9084e --- /dev/null +++ b/aws_gke_oidc_role/versions.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.37" + } + } + required_version = "~> 1.0" +}