about summary refs log tree commit diff
path: root/ops/tf-gcs-init/tf-gcs-init.sh
blob: 95d4d7e7aba8a4b8e462545ae4135d148bbd170c (plain) (blame)
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
#!/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.

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