Skip to content

Commit

Permalink
feat(terraform): configure partial backend (#267)
Browse files Browse the repository at this point in the history
* chore: get Terraform backend config from JSON file

Fixes #266

* feat(terraform): configure partial backend

* refactor
  • Loading branch information
hknutsen authored Oct 12, 2023
1 parent fc8f101 commit e4d564b
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 18 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/terraform.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ on:
required: false
default: ~1.5.0

backend_config:
description: The path of a configuration file containing the remaining arguments for a partial backend configuration.
type: string
required: false
default: ""
# Ref: https://developer.hashicorp.com/terraform/language/settings/backends/configuration#partial-configuration

artifact_name:
description: The name of the artifact to upload.
type: string
Expand Down Expand Up @@ -62,6 +69,8 @@ env:
# Makes output more consistent and less confusing in workflows where users don't directly execute Terraform commands.
TF_IN_AUTOMATION: true

TF_CLI_ARGS_init: -backend-config=${{ github.workspace }}/${{ inputs.backend_config }}

# Configure OIDC authentication to Azure using environment variables.
# Required by the AzureRM backend and provider.
ARM_USE_OIDC: true
Expand Down
1 change: 1 addition & 0 deletions docs/usage-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
environment: development
working_directory: terraform
terraform_version: "1.5.0"
backend_config: config/tfbackend/dev.azurerm.tfbackend.json
secrets:
AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
Expand Down
33 changes: 26 additions & 7 deletions scripts/terraform-backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,32 @@ This directory contains a script `terraform-backend.sh` that will create an Azur

It accepts the following arguments:

1. The name of the storage account to create.
1. The name of the Azure resource group to create the storage account in.
1. The Azure region to create the storage account in.
1. The path of the JSON file containing the Terraform backend configuration.

## Prerequisites

- [Install Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) (latest version as of writing: `2.49.0`).
- [Install jq](https://stedolan.github.io/jq/download/) (latest version as of writing: `1.6`) - to create lifecycle management policy.
- [Install Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) (latest version as of writing: `2.49.0`) - to create Azure resource group, storage account and container
- [Install jq](https://stedolan.github.io/jq/download/) (latest version as of writing: `1.6`) - to parse JSON config file
- Azure role `Owner` at the subscription scope.

## Configuration specification

Example configuration:

```json
{
"resource_group_name": "tfstate",
"storage_account_name": "tfstate32417",
"container_name": "tfstate",
"use_azuread_auth": true
}
```

> **Note**
>
> `.use_azuread_auth` should be `true`.
## Usage

1. Login to Azure:
Expand All @@ -22,22 +38,25 @@ It accepts the following arguments:
az login
```

1. Set active subscription:
1. Set Azure subscription:

```console
az account set -s <SUBSCRIPTION_NAME_OR_ID>
```

1. Configure resource group name, storage account name and container name in a file `*.azurerm.tfbackend.json`,
e.g. `dev.azurerm.tfbackend.json`.

1. Run the script:

```console
./terraform-backend.sh <STORAGE_ACCOUNT_NAME> <RESOURCE_GROUP_NAME> <LOCATION>
./terraform-backend.sh <LOCATION> <CONFIG_FILE>
```

For example:

```console
./terraform-backend.sh tfstate$RANDOM tfstate northeurope
./terraform-backend.sh northeurope dev.azurerm.tfbackend.json
```

1. Configure OIDC to authenticate from GitHub Actions to the Terraform backend using the [OIDC script](../oidc/README.md).
Expand Down
75 changes: 64 additions & 11 deletions scripts/terraform-backend/terraform-backend.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,57 @@

set -eu

readonly STORAGE_ACCOUNT_NAME=${1:?"STORAGE_ACCOUNT_NAME is unset or null"}
readonly RESOURCE_GROUP_NAME=${2:?"RESOURCE_GROUP_NAME is unset or null"}
readonly LOCATION=${3:?"LOCATION is unset or null"}
readonly CONTAINER_NAME="tfstate"
LOCATION=${1:?"LOCATION is unset or null"}
CONFIG_FILE=${2:?"CONFIG_FILE is unset or null"}

################################################################################
# Verify target Azure subscription
################################################################################

SUBSCRIPTION_NAME=$(az account show --query name --output tsv)

read -r -p "Create Terraform backend in Azure \
subscription '$SUBSCRIPTION_NAME'? (y/N) " response

case $response in
[yY][eE][sS]|[yY])
;;
*)
exit 0
;;
esac

################################################################################
# Read Terraform backend configuration
################################################################################

if [[ -f "$CONFIG_FILE" ]]
then
echo "Using config file '$CONFIG_FILE'."
else
echo "Config file '$CONFIG_FILE' does not exist."
exit 1
fi

CONFIG=$(cat "$CONFIG_FILE")

RESOURCE_GROUP_NAME=$(echo "$CONFIG" | jq -r .resource_group_name)
STORAGE_ACCOUNT_NAME=$(echo "$CONFIG" | jq -r .storage_account_name)
CONTAINER_NAME=$(echo "$CONFIG" | jq -r .container_name)

################################################################################
# Create Azure resource group
################################################################################

az group create \
--name "${RESOURCE_GROUP_NAME}" \
--location "${LOCATION}" \
--output none

################################################################################
# Create Azure Storage account
################################################################################

storage_account_id="$(az storage account create \
--name "${STORAGE_ACCOUNT_NAME}" \
--resource-group "${RESOURCE_GROUP_NAME}" \
Expand All @@ -27,6 +68,8 @@ storage_account_id="$(az storage account create \
--query id \
--output tsv)"

echo "Storage account ID: $storage_account_id"

az storage account blob-service-properties update \
--account-name "${STORAGE_ACCOUNT_NAME}" \
--resource-group "${RESOURCE_GROUP_NAME}" \
Expand All @@ -44,16 +87,24 @@ az security atp storage update \
--is-enabled true \
--output none

################################################################################
# Create Azure Storage container
################################################################################

az storage container create \
--name "${CONTAINER_NAME}" \
--account-name "${STORAGE_ACCOUNT_NAME}" \
--auth-mode login \
--output none

management_policy=$(jq --null-input '{
################################################################################
# Create Azure Storage lifecycle policy
################################################################################

management_policy=$(echo "$CONFIG" | jq '{
rules: [
{
name: "delete-old-versions",
name: "Delete old tfstate versions",
enabled: true,
type: "Lifecycle",
definition: {
Expand All @@ -67,6 +118,9 @@ management_policy=$(jq --null-input '{
filters: {
blobTypes: [
"blockBlob"
],
prefixMatch: [
.container_name
]
}
}
Expand All @@ -80,14 +134,13 @@ az storage account management-policy create \
--policy "${management_policy}" \
--output none

################################################################################
# Create Azure resource lock
################################################################################

az resource lock create \
--name 'Terraform' \
--lock-type CanNotDelete \
--resource "${storage_account_id}" \
--notes "Prevent deletion of Terraform backend" \
--output none

echo "resource_group_name = \"${RESOURCE_GROUP_NAME}\"
storage_account_name = \"${STORAGE_ACCOUNT_NAME}\"
container_name = \"${CONTAINER_NAME}\"
use_azuread_auth = true"

0 comments on commit e4d564b

Please sign in to comment.