Skip to content

Commit cf3273d

Browse files
authored
fix: Enhance WI module usability with existing KSA (#557)
1 parent 0bcf3ca commit cf3273d

File tree

5 files changed

+111
-10
lines changed

5 files changed

+111
-10
lines changed

examples/workload_identity/main.tf

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ module "gke" {
5353
]
5454
}
5555

56+
# example without existing KSA
5657
module "workload_identity" {
5758
source = "../../modules/workload-identity"
5859
project_id = var.project_id
@@ -61,5 +62,27 @@ module "workload_identity" {
6162
use_existing_k8s_sa = false
6263
}
6364

65+
66+
# example with existing KSA
67+
resource "kubernetes_service_account" "test" {
68+
metadata {
69+
name = "foo-ksa"
70+
}
71+
secret {
72+
name = "bar"
73+
}
74+
}
75+
76+
module "workload_identity_existing_ksa" {
77+
source = "../../modules/workload-identity"
78+
project_id = var.project_id
79+
name = "existing-${module.gke.name}"
80+
cluster_name = module.gke.name
81+
location = module.gke.location
82+
namespace = "default"
83+
use_existing_k8s_sa = true
84+
k8s_sa_name = kubernetes_service_account.test.metadata.0.name
85+
}
86+
6487
data "google_client_config" "default" {
6588
}

modules/workload-identity/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ resource "kubernetes_service_account" "preexisting" {
5151
metadata {
5252
name = "preexisting-sa"
5353
namespace = "prod"
54-
annotations = {
55-
"iam.gke.io/gcp-service-account" = "preexisting-sa@${var.project_id}.iam.gserviceaccount.com"
56-
}
5754
}
5855
}
5956

@@ -71,7 +68,9 @@ module "my-app-workload-identity" {
7168

7269
| Name | Description | Type | Default | Required |
7370
|------|-------------|:----:|:-----:|:-----:|
71+
| cluster\_name | Cluster name. Required if using existing KSA. | string | `""` | no |
7472
| k8s\_sa\_name | Name for the existing Kubernetes service account | string | `"null"` | no |
73+
| location | Cluster location (region if regional cluster, zone if zonal cluster). Required if using existing KSA. | string | `""` | no |
7574
| name | Name for both service accounts | string | n/a | yes |
7675
| namespace | Namespace for k8s service account | string | `"default"` | no |
7776
| project\_id | GCP project ID | string | n/a | yes |

modules/workload-identity/main.tf

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,23 @@ locals {
1919
gcp_sa_email = google_service_account.cluster_service_account.email
2020

2121
# This will cause terraform to block returning outputs until the service account is created
22-
k8s_given_name = var.k8s_sa_name != null ? var.k8s_sa_name : var.name
23-
output_k8s_name = var.use_existing_k8s_sa ? local.k8s_given_name : kubernetes_service_account.main[0].metadata[0].name
24-
output_k8s_namespace = var.use_existing_k8s_sa ? var.namespace : kubernetes_service_account.main[0].metadata[0].namespace
22+
k8s_given_name = var.k8s_sa_name != null ? var.k8s_sa_name : var.name
23+
output_k8s_name = var.use_existing_k8s_sa ? local.k8s_given_name : kubernetes_service_account.main[0].metadata[0].name
24+
output_k8s_namespace = var.use_existing_k8s_sa ? var.namespace : kubernetes_service_account.main[0].metadata[0].namespace
25+
token = var.use_existing_k8s_sa ? data.google_client_config.default.0.access_token : ""
26+
cluster_ca_certificate = var.use_existing_k8s_sa ? data.google_container_cluster.primary.0.master_auth.0.cluster_ca_certificate : ""
27+
cluster_endpoint = var.use_existing_k8s_sa ? "https://${data.google_container_cluster.primary.0.endpoint}" : ""
28+
}
29+
30+
data "google_container_cluster" "primary" {
31+
count = var.use_existing_k8s_sa ? 1 : 0
32+
name = var.cluster_name
33+
project = var.project_id
34+
location = var.location
35+
}
36+
37+
data "google_client_config" "default" {
38+
count = var.use_existing_k8s_sa ? 1 : 0
2539
}
2640

2741
resource "google_service_account" "cluster_service_account" {
@@ -51,11 +65,11 @@ module "annotate-sa" {
5165
enabled = var.use_existing_k8s_sa
5266
skip_download = true
5367

54-
create_cmd_entrypoint = "kubectl"
55-
create_cmd_body = "annotate sa -n ${local.output_k8s_namespace} ${local.k8s_given_name} iam.gke.io/gcp-service-account=${local.gcp_sa_email}"
68+
create_cmd_entrypoint = "${path.module}/scripts/kubectl_wrapper.sh"
69+
create_cmd_body = "${local.cluster_endpoint} ${local.token} ${local.cluster_ca_certificate} kubectl annotate --overwrite sa -n ${local.output_k8s_namespace} ${local.k8s_given_name} iam.gke.io/gcp-service-account=${local.gcp_sa_email}"
5670

57-
destroy_cmd_entrypoint = "kubectl"
58-
destroy_cmd_body = "annotate sa -n ${local.output_k8s_namespace} ${local.k8s_given_name} iam.gke.io/gcp-service-account-"
71+
destroy_cmd_entrypoint = "${path.module}/scripts/kubectl_wrapper.sh"
72+
destroy_cmd_body = "${local.cluster_endpoint} ${local.token} ${local.cluster_ca_certificate} kubectl annotate sa -n ${local.output_k8s_namespace} ${local.k8s_given_name} iam.gke.io/gcp-service-account-"
5973
}
6074

6175
resource "google_service_account_iam_member" "main" {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/bin/bash
2+
# Copyright 2018 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
17+
set -e
18+
19+
if [ "$#" -lt 3 ]; then
20+
>&2 echo "Not all expected arguments set."
21+
exit 1
22+
fi
23+
24+
HOST=$1
25+
TOKEN=$2
26+
CA_CERTIFICATE=$3
27+
28+
shift 3
29+
30+
RANDOM_ID="${RANDOM}_${RANDOM}"
31+
export TMPDIR="/tmp/kubectl_wrapper_${RANDOM_ID}"
32+
33+
function cleanup {
34+
rm -rf "${TMPDIR}"
35+
}
36+
trap cleanup EXIT
37+
38+
mkdir "${TMPDIR}"
39+
40+
export KUBECONFIG="${TMPDIR}/config"
41+
42+
# shellcheck disable=SC1117
43+
base64 --help | grep "\--decode" && B64_ARG="--decode" || B64_ARG="-d"
44+
echo "${CA_CERTIFICATE}" | base64 ${B64_ARG} > "${TMPDIR}/ca_certificate"
45+
46+
kubectl config set-cluster kubectl-wrapper --server="${HOST}" --certificate-authority="${TMPDIR}/ca_certificate" --embed-certs=true 1>/dev/null
47+
rm -f "${TMPDIR}/ca_certificate"
48+
kubectl config set-context kubectl-wrapper --cluster=kubectl-wrapper --user=kubectl-wrapper --namespace=default 1>/dev/null
49+
kubectl config set-credentials kubectl-wrapper --token="${TOKEN}" 1>/dev/null
50+
kubectl config use-context kubectl-wrapper 1>/dev/null
51+
kubectl version 1>/dev/null
52+
53+
"$@"

modules/workload-identity/variables.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@ variable "name" {
1919
type = string
2020
}
2121

22+
variable "cluster_name" {
23+
description = "Cluster name. Required if using existing KSA."
24+
type = string
25+
default = ""
26+
}
27+
28+
variable "location" {
29+
description = "Cluster location (region if regional cluster, zone if zonal cluster). Required if using existing KSA."
30+
type = string
31+
default = ""
32+
}
33+
2234
variable "k8s_sa_name" {
2335
description = "Name for the existing Kubernetes service account"
2436
type = string

0 commit comments

Comments
 (0)