Setting up a Creator
resource within the Cloud
Quick Links
Setting Up a Terraform Creator
Required
Precheck
export ORG_ID=""
export BILLING_ACCOUNT_ID=""
export _ADMIN=${USER}-terraform-ops-admin
export _CREDS=~/.config/gcloud/${USER}=terraform-ops-admin.json
# pre-installation required for billing components
gcloud components update
gcloud components install beta
....
gcloud beta billing accounts list
### ------------------ OUTPUT --------------------------
# ACCOUNT_ID NAME OPEN MASTER_ACCOUNT_ID
# 0153E3-9593A6-BE6675 My Billing Account True
Find Organizations
$ gcloud organizations list
....
### ------------------ OUTPUT --------------------------
# DISPLAY_NAME ID DIRECTORY_CUSTOMER_ID
# eblusolutions.com 109748593075 C02c779sc
Create Admin Project
# if admin project is NOT already created...
$ gcloud projects create ${_ADMIN} \
--organization ${ORG_ID} \
--set-as-default
....
$ gcloud beta billing projects link ${_ADMIN} \
--billing-account ${BILLING_ACCOUNT_ID}
Create the service account for admin project
$ gcloud iam service-accounts create ${TF_ADMIN_SA_NAME} \
--display-name "Terraform creator account"
$ gcloud iam service-accounts keys create ${_CREDS} \
--iam-account terraform@${_ADMIN}.iam.gserviceaccount.com
Grant the SA permissions to VIEW Admin Project and manage Cloud Storage
$ gcloud projects add-iam-policy-binding ${_ADMIN} \
--member serviceAccount:${TF_ADMIN_SA_NAME}@${_ADMIN}.iam.gserviceaccount.com \
--role roles/viewer
Enable APIs for Terraform to function
gcloud services enable cloudresourcemanager.googleapis.com,
gcloud services enable cloudbilling.googleapis.com,
gcloud services enable iam.googleapis.com,
gcloud services enable compute.googleapis.com,
gcloud services enable serviceusage.googleapis.com
Add Organization/Folder Permissions
$ gcloud organizations add-iam-policy-binding ${ORG_ID} \
--member serviceAccount:${TF_ADMIN_SA_NAME}@${_ADMIN}.iam.gserviceaccount.com \
--role roles/billing.user
Remote State
Create a remote backend bucket in Google Cloud Storage for a backend.tf
to manage terraform.tfstate
$ gsutil mb -p ${_ADMIN} gs://${_ADMIN}
cat > backend.tf << EOF
terraform {
backend "gcs" {
bucket = "${_ADMIN}"
prefix = "creator/state"
}
}
EOF
Enable versioning of the remote bucket:
$ gsutil versioning set on gs://${_ADMIN}
Azure
BUILDER
Steps to build the necessary resource to invoke a
terraform creator
# Requirements # - Terraform installed on the builder machine or container env # - Azure CLI installed on the builder machine or container env # # Variables # - ARM_SUBSCRIPTION_ID # - ARM_TENANT_ID # - STORAGE_ACCOUNT_NAME # - RESOURCE_GROUP # - STORAGE_ACCOUNT_CONTAINER_NAME set -o ########################################## # AUTH ########################################## # Uncomment if tenant is NOT known or utilizing <self> credentials # az login -t $ARM_TENANT_ID # az account set --subscription ee91ab82-b559-49b4-bfb4-3780cdf9a068 ########################################## # !! WARNING !! ########################################## # Note: some data cannot be deleted by law, e.g. hippa, phi, financial data needed for tax audits etc etc. # Because of the severity and legal consequences of losing such data, # it is a common cloud practice to apply management locks on a resource to prevent it from being deleted. # -- # We will NOT grant the DELETE permissions because of the following: # Automation is powerful!! # With great power comes great responsibility, # which we don’t want to grant a headless (and therefore brainless) build agent. # It’s important to understand that git (even with signed commits) gives technical traceability, # but at eBlu that might not satisfy requirements for legal audit-ability. ########################################## # RESOURCE CREATION ########################################## # If new resource is necessary # creating the resource Group # az group create -n $RESOURE_GROUP_NAME -l eastus2 ########################################## # STORAGE: # FROM HERE THIS CAN BE EXECUTED DIRECTLY IF THE RESOURCE IS CONSTRUCTED AND LINKED TO BILLING ########################################## #creating the storage account az storage account create -n analyticsopsstate0921 -g eblusolutions-analytics-ops -l eastus2 --kind StorageV2 --sku Standard_LRS --https-only true --allow-blob-public-access false #creating a tfstate container az storage container create -n tfstate --account-name analyticsopsstate0921 ########################################## # KEYVAULT CREATION & CONFIG ########################################## #creating the KeyVault az keyvault create -n analytics-ops-kv -g eblusolutions-analytics-ops -l eastus2 #Creating a SAS Token for the storage account, storing in KeyVault az storage container generate-sas --account-name analyticsopsstate0921 --expiry 2022-01-01 --name tfstate --permissions dlrw -o json | xargs az keyvault secret set --vault-name analytics-ops-kv --name tfSASToken --value ########################################## # SPN CREATION & CONFIG ########################################## #creating a Service Principal for AKS and Azure DevOps #requires elevation az ad sp create-for-rbac -n eblusolutions-analytics-ops --role "Contributor" #creating an ssh key if you don't already have one ssh-keygen -f ~/.ssh/id_rsa_terraform #store the public key in Azure KeyVault az keyvault secret set --vault-name analytics-ops-kv --name AnalyticsLinuxSSHPubGen -f ~/.ssh/id_rsa_terraform.pub > /dev/null #store the service principal id in Azure KeyVault az keyvault secret set --vault-name analytics-ops-kv --name spn-id --value <SPD-ID> >/dev/null #store the service principal secret in Azure KeyVault az keyvault secret set --vault-name analytics-ops-kv --name spn-secret --value <SPD-SECRET> > /dev/null ########################################## # BACKEND INIT ########################################## # init tf backend terraform init -backend-config="resource_group_name=eblusolutions-analytics-ops" -backend-config="storage_account_name=analyticsopsstate0921" -backend-config="container_name=tfstate"
# known
export BASE_RESOURCE_PREFIX=eblusolutions_analytics_ops
export ARM_TENANT_ID=3bf257a8-abbc-4bc6-915e-4c612569749c
export ARM_SUBSCRIPTION_ID=ee91ab82-b559-49b4-bfb4-3780cdf9a068
export STORAGE_ACCOUNT_NAME=analytics-ops-state
export RESOURCE_GROUP_NAME="eblusolutions-analytics-ops"
export STORAGE_ACCOUNT_CONTAINER_NAME=$BASE_RESOURCE_PREFIX
# 'name' property in the output is deprecated and will be removed in the future. Use 'appId' instead.
# {
# "appId": "xxxxxxx-xxxx-xxx-xxxx-xxxxxxxxxxxxx",
# "displayName": "eblusolutions-analytics-ops",
# "name": "xxxxxxxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxxxx",
# "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
# "tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx"
# }