-
Notifications
You must be signed in to change notification settings - Fork 5
/
cluster_workload_identity.sh
executable file
·140 lines (113 loc) · 5.42 KB
/
cluster_workload_identity.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#!/bin/bash
if [[ $# -ne 1 ]]; then
echo "usage: script <create|destroy|shell>"
exit 1
fi
# TODO: ensure the following variable match your environment, especially
# the zone, project, bucket, and network.
ZONE=europe-west4-a
PROJECT=workload-identity-playground-123456
BUCKET=gke-workload-identity-playground-bucket
NETWORK=production-network # usually "default"
CLUSTER=storage-consumer
DEPLOYMENT_NAME=example-gke-workload-identity
# GSA is the service account that the *pods* will use to access Google Cloud Platform.
# We use unique names since recreating service accounts with the same name as a previously
# deleted one create chaos. Therefore, upon creation, randomise a new name and store in a file.
# Upon destruction, delete the same file. Alternatively, you can opt-in to skip this part and use
# static names, see below.
STATE_FILENAME=.random_suffix
if [[ -f "$STATE_FILENAME" ]]; then
SUFFIX=$(cat "$STATE_FILENAME")
else
# generate random lowercase alphanumeric string of 6 chars.
SUFFIX=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 6 | head -n 1)
echo "No current state was found, randomized new suffix of ${SUFFIX}"
echo "$SUFFIX" > "${STATE_FILENAME}"
fi
GSA="storage-consumer-gsa-${SUFFIX}"
# To use static names, just use below.
# GSA=storage-consumer-gsa
# Kubernetes service account and namespace. Don't need to be suffixed.
# If you modify the namespace, you also need to change the deployment.
KSA=storage-consumer-ksa
K8S_NAMESPACE=storage-consumer-ns
# We create a very restricted service account to run cluster nodes.
RUNNER_GSA=gke-runner-acc
RUNNER_GSA_FULL="${RUNNER_GSA}@${PROJECT}.iam.gserviceaccount.com"
GSA_FULL="${GSA}@${PROJECT}.iam.gserviceaccount.com"
if [[ "$1" == "create" ]]; then
# Create restricted service account to run cluster nodes under.
gcloud iam service-accounts create "${RUNNER_GSA}" --display-name="${RUNNER_GSA}"
gcloud projects add-iam-policy-binding ${PROJECT} \
--member "serviceAccount:${RUNNER_GSA_FULL}" \
--role roles/logging.logWriter
gcloud projects add-iam-policy-binding ${PROJECT} \
--member "serviceAccount:${RUNNER_GSA_FULL}" \
--role roles/monitoring.metricWriter
gcloud projects add-iam-policy-binding ${PROJECT} \
--member "serviceAccount:${RUNNER_GSA_FULL}" \
--role roles/monitoring.viewer
# Create cluster with workload identity support, using restricted runner account.
gcloud beta container clusters create "${CLUSTER}" \
--enable-ip-alias \
--enable-autoupgrade \
--zone="$ZONE" \
--network="${NETWORK}" \
--metadata disable-legacy-endpoints=true \
--identity-namespace="$PROJECT".svc.id.goog \
--service-account="${RUNNER_GSA_FULL}"
# create service account that the pod should use
gcloud iam service-accounts create "$GSA" --display-name="${GSA}"
# give it admin permissions to this storage bucket only
gsutil iam ch "serviceAccount:${GSA_FULL}:roles/storage.objectAdmin" "gs://${BUCKET}"
# get credentials to cluster
gcloud container clusters get-credentials "${CLUSTER}" --zone="$ZONE"
# create k8s namespace
kubectl create namespace "$K8S_NAMESPACE"
# create k8s service account in namespace
kubectl create serviceaccount --namespace "$K8S_NAMESPACE" "$KSA"
# Allow the Kubernetes service account to use the Google service account by creating an Cloud IAM policy
# binding between the two. This binding allows the Kubernetes Service account to act as the Google service account.
gcloud iam service-accounts add-iam-policy-binding \
--role roles/iam.workloadIdentityUser \
--member "serviceAccount:${PROJECT}.svc.id.goog[${K8S_NAMESPACE}/${KSA}]" \
"${GSA_FULL}"
kubectl annotate serviceaccount \
--namespace "${K8S_NAMESPACE}" \
"${KSA}" \
"iam.gke.io/gcp-service-account=${GSA_FULL}"
# launch some node js test on cluster.
sleep 5
kubectl apply -f deployment.yaml
kubectl apply -f loadbalancer.yaml
# try to print external ip of load balancer, but will most likely give "<pending>"
kubectl get services --namespace "${K8S_NAMESPACE}"
echo "if the above gives <pending> try again later using:"
echo "kubectl get services --namespace ${K8S_NAMESPACE}"
fi
if [[ "$1" == "shell" ]]; then
# attach to pod and see what permissions we got using the default account.
# sleep 10
kubectl run --rm -it \
"${CLUSTER}" \
--generator=run-pod/v1 \
--image google/cloud-sdk:slim \
--serviceaccount "${KSA}" \
--namespace "${K8S_NAMESPACE}"
fi
if [[ "$1" == "destroy" ]]; then
# to delete cluster when done
gcloud container clusters delete storage-consumer --zone="$ZONE"
# delete service account, and its assigned roles.
gcloud iam service-accounts remove-iam-policy-binding --role roles/iam.workloadIdentityUser --member "serviceAccount:${PROJECT}.svc.id.goog[${K8S_NAMESPACE}/${KSA}]" "${GSA_FULL}"
gsutil iam ch -d "serviceAccount:${GSA_FULL}" "gs://${BUCKET}"
gcloud iam service-accounts delete "${GSA_FULL}"
# deleting runner, and its assigned roles.
gcloud projects remove-iam-policy-binding ${PROJECT} --member "serviceAccount:${RUNNER_GSA_FULL}" --role roles/logging.logWriter
gcloud projects remove-iam-policy-binding ${PROJECT} --member "serviceAccount:${RUNNER_GSA_FULL}" --role roles/monitoring.metricWriter
gcloud projects remove-iam-policy-binding ${PROJECT} --member "serviceAccount:${RUNNER_GSA_FULL}" --role roles/monitoring.viewer
gcloud iam service-accounts delete "${RUNNER_GSA_FULL}"
# remove state file.
rm "${STATE_FILENAME}"
fi