Hey there, I am writing my bootstrap file for creating the initial bucket for the Terraform states.
I am interested to know what good practices and configurations would look like for my bucket.
Here is my script so far, please read the comments between code:
BUCKET_NAME=gs://acmec-testing-1
PROJECT=acmec
gsutil mb \
# Is Bucket Policy Only this a good idea?
-b on \
-c standard \
-l us-east1 \
-p $PROJECT \
$BUCKET_NAME
# What are good practices around labeling this?
gsutil label set ./labels.json $BUCKET_NAME
# What are your lifecycle configuration if any?
gsutil lifecycle set ./lifecycle.json $BUCKET_NAME
# What permissions should I give to the account used for terraform apply in CI?
gsutil defacl ch -u john.doe@example.com:READ $BUCKET_NAME
# Do I need this?
gsutil versioning set on $BUCKET_NAME
I am new into these DevOps stuff so I am worried to make mistakes that would cost me to leak sensitive information.
Thanks in advance.
❯ gsutil rm -r gs://acmec-testing-1
Removing gs://acmec-testing-1/terraform.tfstate#1583025424297405...
AccessDeniedException: 403 Object 'shp-testing-3/terraform.tfstate' is subject to bucket's retention policy and cannot be deleted, overwritten or archived until 2021-02-28T23:17:04.297256878-08:100:
Basically don’t use any retention policy for terraform stuff, instead use versioning.
Alright, after reading what other people are doing I came up with the following solution.
# Use "gcloud organizations list" to find the organization ID.
ORG_ID=""
# Use "gcloud beta billing accounts list" to find the billing account ID.
BILLING_ACCOUNT=""
PROJECT_ID="terraform-project"
BUCKET_NAME="gs://terraform-bucket"
create_terraform_project() {
org_id=$1
project_id=$2
billing_account=$3
gcloud projects create ${project_id} \
--name Terraform \
--set-as-default \
--organization ${org_id}
gcloud beta billing projects link ${project_id} \
--billing-account ${billing_account}
}
create_terraform_service_account() {
project_id=$1
account_name=terraform
creds=./.tmp/credentials.json
service_account=${account_name}@${project_id}.iam.gserviceaccount.com
gcloud iam service-accounts create ${account_name} \
--display-name "Terraform Admin Account" \
--project ${project_id}
gcloud iam service-accounts keys create ${creds} \
--iam-account ${service_account} \
--project ${project_id}
}
add_service_account_project_permissions() {
project_id=$1
account_name=terraform
service_account=${account_name}@${project_id}.iam.gserviceaccount.com
gcloud projects add-iam-policy-binding ${project_id} \
--member serviceAccount:${service_account} \
--role roles/viewer
gcloud projects add-iam-policy-binding ${project_id} \
--member serviceAccount:${service_account} \
--role roles/storage.admin
}
add_service_account_org_permissions() {
org_id=$1
project_id=$2
account_name=terraform
service_account=${account_name}@${project_id}.iam.gserviceaccount.com
gcloud organizations add-iam-policy-binding ${org_id} \
--member serviceAccount:${service_account} \
--role roles/resourcemanager.projectCreator
gcloud organizations add-iam-policy-binding ${org_id} \
--member serviceAccount:${service_account} \
--role roles/billing.user
}
create_bucket() {
project_id=$1
bucket_name=$2
gsutil mb \
-b on \
-c standard \
-l us-east1 \
-p ${project_id} \
${bucket_name}
gsutil label set ./labels.json ${bucket_name}
gsutil lifecycle set ./lifecycle.json ${bucket_name}
gsutil versioning set on ${bucket_name}
}
create_terraform_project $ORG_ID $PROJECT_ID $BILLING_ACCOUNT
create_terraform_service_account $PROJECT_ID
add_service_account_project_permissions $PROJECT_ID
add_service_account_org_permissions $ORG_ID $PROJECT_ID
create_bucket $PROJECT_ID $BUCKET_NAME
I ended up disabling lifecycle, at the end of the day the price for keeping those copies are too small for worth the hassle in the future.