diff --git a/.github/workflows/terraform-pipeline.yml b/.github/workflows/terraform-pipeline.yml new file mode 100644 index 0000000..c39b7e6 --- /dev/null +++ b/.github/workflows/terraform-pipeline.yml @@ -0,0 +1,141 @@ +name: Terraform pipeline + +on: + workflow_dispatch: + push: + paths: + - 'terraform/**' + branches: + - main + +permissions: + id-token: write + contents: read + +env: + ARM_ACCESS_KEY: ${{ secrets.ARM_ACCESS_KEY }} + ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + +jobs: + plan: + runs-on: ubuntu-latest + defaults: + run: + working-directory: ./terraform + name: Plan + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Azure login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Setup terraform + uses: hashicorp/setup-terraform@v3 + + - name: Terraform format check + continue-on-error: true + id: fmt + run: terraform fmt -check + + - name: Terraform init + id: init + run: terraform init + + - name: Terraform validate + id: validate + run: terraform validate -no-color + + - name: Terraform plan + id: plan + run: terraform plan -no-color -out terraform-plan + + - uses: WcAServices/markdown-template-action@v1 + continue-on-error: true + with: + # These will be injected into the below template, in addition to GitHub's standard + # variables. You can perform string operations here as well. + variables: >- + FMT_OUTCOME="${{ steps.fmt.outcome }}" + INIT_OUTCOME="${{ steps.init.outcome }}" + VALIDATE_OUTCOME="${{ steps.validate.outcome }}" + VALIDATE_OUTPUT="${{ steps.validate.outputs.stdout }}" + PLAN_OUTCOME="${{ steps.plan.outcome }}" + PLAN_OUTPUT="${{ steps.plan.outputs.stdout }}" + + template: | + #### Terraform Format and Style 🖌`$FMT_OUTCOME` + + #### Terraform Initialization ⚙️`$INIT_OUTCOME` + + #### Terraform Validation 🤖`$VALIDATE_OUTCOME` + +
+ Validation Output + + ``` + $VALIDATE_OUTPUT + ``` + +
+ + #### Terraform Plan 📖`$PLAN_OUTCOME` + +
+ + Show Plan + + ```terraform + $PLAN_OUTPUT + ``` + +
+ + *Actor: @$GITHUB_ACTOR, Action: `$GITHUB_EVENT_NAME`* + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: plan + path: ./terraform + + apply: + runs-on: ubuntu-latest + environment: staging + needs: plan + name: Apply + defaults: + run: + working-directory: ./terraform + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Azure login + uses: azure/login@v2 + with: + client-id: ${{ secrets.AZURE_CLIENT_ID }} + tenant-id: ${{ secrets.AZURE_TENANT_ID }} + subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + - name: Setup terraform + uses: hashicorp/setup-terraform@v3 + + - name: Terraform init + run: terraform init + + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: plan + path: ./terraform + + - name: Terraform apply + run: terraform apply -auto-approve terraform-plan + diff --git a/docs/terraform-pipeline.md b/docs/terraform-pipeline.md new file mode 100644 index 0000000..e312870 --- /dev/null +++ b/docs/terraform-pipeline.md @@ -0,0 +1,61 @@ +# How to setup and use the terraform pipeline + +## Intro + +This document explains how to use the workflow located at `.github/workflows/terraform-pipeline.yml`. You might want to use this workflow to provision the [`kubecraft`](https://github.com/mischavandenburg/kubecraft) community project on your own infrastructure on Azure. + +## Pre-requisites + +To follow along, you will need: + +- A fork of [`mischavandenburg/kubecraft`](https://github.com/mischavandenburg/kubecraft) on your Github account. +- An Azure account with an active subscription. + +## Azure setup + +Before executing the pipeline on your Github account, we need to configure the remote backend (`azurerm` provider on Azure Blob Storage) and obtain the details for OIDC authentication. + +### Service Principal and Federated Identity + +Follow these documents in order for a complete walk-through to setup a service principal with a federated identity for OIDC authentication from Github actions: + +- [Create a service principal](https://learn.microsoft.com/en-us/entra/identity-platform/howto-create-service-principal-portal) +- [Configure a federated identity](https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation-create-trust?pivots=identity-wif-apps-methods-azp#github-actions) + +**Note:** You will need to create credentials valid for a `push` to the `main` branch, and for the `staging` environment. + +### Remote backend configuration + +For the remote backend configuration, we will need to configure a resource group, storage account, and container on Azure Blob Storage. You can use the following script to provision these resources: + +```bash +#!/bin/bash + +RESOURCE_GROUP_NAME=tfstate +STORAGE_ACCOUNT_NAME=tfstate$RANDOM +CONTAINER_NAME=tfstate + +# Create resource group +az group create --name $RESOURCE_GROUP_NAME --location eastus + +# Create storage account +az storage account create --resource-group $RESOURCE_GROUP_NAME --name $STORAGE_ACCOUNT_NAME --sku Standard_LRS --encryption-services blob + +# Create blob container +az storage container create --name $CONTAINER_NAME --account-name $STORAGE_ACCOUNT_NAME + +ACCOUNT_KEY=$(az storage account keys list --resource-group tfstate --account-name $STORAGE_ACCOUNT_NAME --query '[0].value' -o tsv) +``` + +Now, take note of your `$STORAGE_ACCOUNT_NAME`. You will need to specify its value under the `storage_account_name` property of the `backend` configuration on `terraform/providers`. + +Also, copy your `ACCOUNT_KEY` and store it on Github Actions secrets under a secret named `ARM_ACCESS_KEY`. + +### Github environment + +The Terraform pipeline leverages environment protection rules to enable manual approvals for the `terraform apply` command. In order to use this workflow, you will need to create a `staging` environment from your repository settings page (on your own fork). You don't need to add any environment protection rules if you don't want to, but if you do, simply check the "require approvals" checkbox and add yourself as a required reviewer. + +### Push and Test + +Once you've created the secrets on Github Actions for OIDC authentication, adjusted the backend provider configuration to your own Azure storage account, and created the `staging` environment on your repository, commit your changes and push the code to your `main` branch. This will trigger the pipeline automatically. Alternatively, you can navigate to `https://github.com/your-username/kubecraft/actions`, select the Terraform pipeline workflow on the left hand side menu, and use the "Run workflow" button to manually trigger the workflow execution. + diff --git a/terraform/providers.tf b/terraform/providers.tf index 1aa000e..2277e2a 100644 --- a/terraform/providers.tf +++ b/terraform/providers.tf @@ -15,8 +15,21 @@ terraform { version = "~>3.0" } } + + backend "azurerm" { + resource_group_name = "tfstate" + # TODO: use your own storage_account_name + storage_account_name = "tfstate1028" + container_name = "tfstate" + key = "terraform.tfstate" + } } provider "azurerm" { features {} } + +provider "azapi" { + use_oidc = true +} +