diff options
Diffstat (limited to 'ops/tf-gcs-init')
-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 |