IaC with GitHub Actions for Google Cloud Platform

Irem Ertürk
4 min readApr 4, 2022

--

Let’s start with a short introduction to IaC and GitHub Actions. IaC (Infrastructure as Code) is the practice of managing and provisioning hardware resources by using the advantages of declarative language. Terraform is a software tool that is created by HashiCorp to ease applying IaC concepts. On the other side, GitHub Actions is a CI/CD(Continuous Integration & Continuous Delivery) tool offered by GitHub to create automated workflows to deploy applications (for us destroy and provision resources) without the need for any manual interaction.

In this blog post, how to automate resource provisioning in Google Cloud Platform by using Terraform and GitHub actions will be covered. On the other hand, the rest of the blog does not include any explanation of Terraform and GitHub Actions basics. If you are unfamiliar with them please check their official websites to kick start.

Even though we are trying to automate the GCP resource creation process, we still need to create the first couple of resources manually. I know it sounds contradicting the idea of what we are achieving but in the end with that initial step, we will be able to hundreds or more resources seamlessly.

Prerequisite Steps

  1. Create an account GCP account with Google Email
  2. Create GCP Project in GCP Console (note the unique project id)
  3. Create GCP Service Account and grant Owner role
  4. Download service-account-key (.json) for authentication
  5. Enable Cloud Resource Manager API for the project
  6. Create GCS bucket with name *project_terraform_state* to store & version terraform-state files. (suggested to enable object versioning)

After the prerequisite steps, we have a GCP project and associated service account with Owner access rights.

To be able to automate resource creation and deletion in GCP, we need to authenticate the Github Actions. To establish authentication, we will use the google-github-actions/auth. This action support two authentication mechanism.

  1. Traditional Authentication via a Google Cloud Service Account Key JSON
  2. Authentication via Workload Identity Federation

Between these two approaches, the traditional authentication approach is easier to configure whereas the workload identity federation approach ensures a more secure authentication mechanism. You can find the advantages of keyless authentication via workload identity federation here.

Now let's take a look at which steps are needed to set up these two authentication mechanisms in GitHub Actions.

Authenticate with Service Account Access Key

We need to copy the content of service-account-keys (.json) that we have downloaded in prerequisite step 3 and create a GitHub Secret named GCP_SA_KEY for the project.

Image 1: Templated Service Account Key

Voila! when we have a secret in place we are almost done and the only thing is to create a workflow with the GCP authentication step.

Complete IaC destroy Resources workflow

If we look at the steps within the workflow one by one, GCP authentication is happening in step: Auth GCP Service Account by specifying the credentials_json parameter as the secret that we have created. Following that we are able to set up Terraform and run terraform methods (in the given example terraform destroy) without the need to re-specify the authentication key.

Authenticate with Workload Identity Federation

The keyless authentication approach requires the creation of additional resources in Google Cloud. Hereby you can find the required commands that you can need to run on your terminal. (Please ensure you have installed gcloud CLI before following the steps below)

  • Login in gcloud CLI
export GOOGLE_APPLICATION_CREDENTIALS="<path/to/your/service-account-authkeys>.json"
gcloud auth application-default login
  • Prepare Constant Variables
# Pre-defined Values (already created prerequsite resources)
export PROJECT_ID=<project-id>
export SERVICE_ACCOUNT=<service-account-name>
# Constant Values
export WORKLOAD_IDENTITY_POOL_NAME=cicd-pool
export WORKLOAD_IDENTITY_PROVIDER_NAME=cicd-provider
export REPO=<gitHubUsername/gitHubProjectRepositor>
  • Create Workload Identity Pool
gcloud iam workload-identity-pools create "${WORKLOAD_IDENTITY_POOL_NAME}" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="GitHub Actions Pool"
  • Find the Workload Identity Pool Id
export workload_identity_pool_id=gcloud iam workload-identity-pools describe "${WORKLOAD_IDENTITY_POOL_NAME}" \
--project="${project_id}" \
--location="global" \
--format="value(name)"
  • Create Workload Identity Provider
gcloud iam workload-identity-pools providers create-oidc "${WORKLOAD_IDENTITY_PROVIDER_NAME}" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="${WORKLOAD_IDENTITY_POOL_NAME}" \
--display-name="CICD provider" \
--attribute-mapping= "google.subject=assertion.sub,attribute.actor=assertion.actor,attribute.repository=assertion.repository" \
--issuer-uri="https://token.actions.githubusercontent.com"
  • Associate service account and Workload Identity Pool
gcloud iam service-accounts add-iam-policy-binding "${service_account}@${PROJECT_ID}.iam.gserviceaccount.com" \
--project="${PROJECT_ID}" \
--role="roles/iam.workloadIdentityUser" \
--member= "principalSet://iam.googleapis.com/${workload_identity_pool_id}/attribute.repository/${REPO}"

If you have encountered any issues while running these resources, I have created an automation script to ease the creation of resources. If you prefer to create the resource with the predefined code snipped, you need to run the following commands in your terminal and that’s it!

./go create_workload_identity_pool <project-id>
./go create_workload_identity_provider <project-id>
./go associate_service_account_2_workload_identity_pool <project_id> <service_account_name> <workload_identity_pool_id>

When we successfully followed the steps above, we are ready to set up our workflow and authenticate it with the workload identity pool as below.

If you check the details in Auth GCP Service Account step, we do not need to specify the credentials_json argument anymore, rather we are providing workload_identity_provider and service_account arguments. Also please pay attention to the permissions block and the id-token should have the write access.

If you are still encountering any issues after following these steps, I highly recommend reading the troubleshooting section within the original documentation of google-github-actions/auth.

.

--

--