diff options
author | Franck Cuny <franck@fcuny.net> | 2022-08-10 17:39:53 -0700 |
---|---|---|
committer | Franck Cuny <franck@fcuny.net> | 2022-08-10 17:42:22 -0700 |
commit | 318dfa47f1866a50aa64426b220e27ed26ee444a (patch) | |
tree | f4f0d5bdcda041d97cefb94c40842d578d68f1a8 /ops | |
parent | ref(ops/buildkite): use service account impersonation for GCP (diff) | |
download | world-318dfa47f1866a50aa64426b220e27ed26ee444a.tar.gz |
feat(ops/tf): script to create GCP service accounts and set roles
Since I'm using terraform for a few things, I want to store the state in a GCP bucket. This script takes care of creating the bucket, creating the service account for terraform, setting the roles, and enabling impersonation. The script is (or at least is intended) to be idempotent. If a new project is created, running will update only what is needed. Change-Id: Ie92703be6d17749dc76dabcf9e73e7b274e8d2ac Reviewed-on: https://cl.fcuny.net/c/world/+/711 Reviewed-by: Franck Cuny <franck@fcuny.net> Tested-by: CI
Diffstat (limited to 'ops')
-rwxr-xr-x | ops/tf-gcs-init/tf-gcs-init.sh | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/ops/tf-gcs-init/tf-gcs-init.sh b/ops/tf-gcs-init/tf-gcs-init.sh new file mode 100755 index 0000000..f675381 --- /dev/null +++ b/ops/tf-gcs-init/tf-gcs-init.sh @@ -0,0 +1,113 @@ +#!/usr/bin/env bash + +# This script creates a bucket in GCS that will be used to store +# terraform state. It also creates a service account 'terraform' to +# perform the actions. It ensures the admin of the account can +# impersonate the 'terraform' service account, so we don't need to +# generate keys. The roles for the SA are also set. + +# TODO: +# gcloud projects add-iam-policy-binding fcuny-backups --member="serviceAccount:terraform@fcuny-homelab.iam.gserviceaccount.com" --role="roles/viewer" +# gcloud projects add-iam-policy-binding fcuny-backups +# --member="serviceAccount:terraform@fcuny-homelab.iam.gserviceaccount.com" +# --role="roles/owner" +# I need to perform some actions on all the projects, not just the +# first one, need to expand the script for that part. + +set -u +set -e +set -o pipefail + +# I'm the admin of the project +GCP_ADMIN_ACCOUNT="franck.cuny@gmail.com" + +# this is the main project that is used for "core" infra +GCP_PROJECT="fcuny-homelab" +GCP_PROJECTS="$(gcloud projects list --format 'value(projectId)')" +GCS_LOCATION="us-west1" +GCS_BUCKET_NAME="world-tf-state" +GCP_SERVICE_ACCOUNT_NAME="terraform" +GCP_SERVICE_ACCOUNT="${GCP_SERVICE_ACCOUNT_NAME}@${GCP_PROJECT}.iam.gserviceaccount.com" +GCP_SERVICE_ACCOUNT_ROLES=( + "roles/editor" + "roles/owner" +) + +function bucket:exist() { + if gsutil ls gs://${1} &>/dev/null; then + true + else + false + fi +} + +function bucket() { + if ! bucket:exist "${GCS_BUCKET_NAME}"; then + echo "creating GCS bucket $GCS_BUCKET_NAME ..." + ( + set -x + gsutil mb -p ${GCP_PROJECT} -l ${GCS_LOCATION} gs://${GCS_BUCKET_NAME} + gsutil versioning set on gs://${GCS_BUCKET_NAME} + ) + else + echo "GCS bucket $GCS_BUCKET_NAME already created" + fi +} + +function service_account:exist() { + if gcloud iam service-accounts describe "${1}" &>/dev/null; then + true + else + false + fi +} + +function service_account() { + if ! service_account:exist "${GCP_SERVICE_ACCOUNT}"; then + echo "creating service account ..." + ( + set -x + gcloud iam service-accounts create "${GCP_SERVICE_ACCOUNT_NAME}" --display-name="Terraform Service Account" + ) + else + echo "service account already created" + fi +} + +function service_account:has_role() { + [[ $(gcloud projects get-iam-policy ${1} --flatten=bindings --filter="bindings.members=serviceAccount:${2} AND bindings.role=$3" 2>/dev/null | wc -l) -ne 0 ]] +} + +function service_account:admins_token_creator() { + [[ $(gcloud --project=${1} iam service-accounts get-iam-policy ${GCP_SERVICE_ACCOUNT} --flatten=bindings --filter="bindings.members=user:${GCP_ADMIN_ACCOUNT} AND bindings.role=roles/iam.serviceAccountTokenCreator" 2>/dev/null | wc -l) -ne 0 ]] +} + +function roles() { + for project in $GCP_PROJECTS; do + for role in "${GCP_SERVICE_ACCOUNT_ROLES[@]}"; do + if ! service_account:has_role "${project}" "${GCP_SERVICE_ACCOUNT}" "${role}" ; then + echo "granting ${role##*/} role to service account for project ${project} ..." + ( + set -x + gcloud projects add-iam-policy-binding "${project}" --member="serviceAccount:${GCP_SERVICE_ACCOUNT}" --role="${role}" + ) 1>/dev/null + else + echo "service account already has ${role##*/} role for project ${project}" + fi + done + + if ! service_account:admins_token_creator "${project}" ; then + echo "adding AccountTokenCreator role to admin account for project ${project} ..." + ( + set -x + gcloud --project="${project}" iam service-accounts add-iam-policy-binding "${GCP_SERVICE_ACCOUNT}" --member user:${GCP_ADMIN_ACCOUNT} --role="roles/iam.serviceAccountTokenCreator" + ) 1>/dev/null + else + echo "admin account has already AccountTokenCreator role for project ${project}" + fi + done +} + +bucket +service_account +roles |