-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Antti Kivimäki <[email protected]>
- Loading branch information
Showing
10 changed files
with
493 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Terraform Bootstrap Example recipe | ||
|
||
This recipe demonstrates how to bootstrap Terraform state management in Azure. | ||
The goal is to have separate state storage for a number of different | ||
environments, all on Azure, and to manage the state storage itself using | ||
Terraform. This is a common pattern in IaC projects. | ||
|
||
The recipe is mainly intended to be used together with GitHub Actions, but that | ||
functionality is optional and managed by a user setting that is set when | ||
executing the recipe. If GitHub Actions is used, pipeline files are generated | ||
such that IaC changes flow through a format check, validate, plan and apply | ||
pipeline. | ||
|
||
## Prerequisites | ||
|
||
Pre-creating resources is optional, but permissions management is easier if you | ||
do. The following resources are required: | ||
|
||
1. A subscription | ||
2. (OPTIONAL) As many resource groups as you want to have environments (e.g. dev, | ||
qa, prod). These resource groups should be empty, but they don't have to be. | ||
3. A service principal with contributor access to the resource groups, and a | ||
client secret for the SP. | ||
|
||
### Generating a service principal | ||
|
||
1. Go to Azure Portal and the Entra ID blade and add an Enterprise Application. | ||
It does not matter what the redirect URL is. Everything can be left at default. | ||
An App Registration should also be generated in your chosen tenant. | ||
2. For each resource group, go to the IAM blade and add the application as a | ||
contributor. | ||
3. Go to the Certificates & secrets blade for the Service Principal and add a | ||
client secret. Copy the secret value. | ||
|
||
## Usage | ||
|
||
Authenticate to Azure: | ||
|
||
```shell | ||
az login | ||
``` | ||
|
||
You can use either your own account (if you have the necessary permissions on | ||
the target subscription) of the Service Principal generated earlier. | ||
|
||
Run the following commands: | ||
|
||
```shell | ||
cd terraform && task init | ||
``` | ||
|
||
If you chose to generate a CI/CD pipeline, the init task will prompt for the | ||
subscription ID, tenant ID, client ID and client secret for each of the | ||
environments. Use the values for the Service Principal generated earlier. | ||
These values will be stored as secrets in GitHub. | ||
|
||
If you used the Service Principal credentials when running `task init`, you are | ||
done. If not, you need to also assign the "Storage Blob Data Contributor" role | ||
to the Service Principal on the storage accounts created by the recipe. You can | ||
do this in the Azure Portal in IAM blades of the resource groups. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
apiVersion: v1 | ||
name: terraform-bootstrap | ||
version: v0.0.1 | ||
description: Set up Terraform basics like state file bootstrapping | ||
initHelp: Install Task from https://taskfile.dev and run `task init` in the 'terraform' subdirectory of the project directory to set up terraform. | ||
vars: | ||
- name: ENVIRONMENTS | ||
description: Comma-separated list of environments to create, e.g. "dev, qa, prod" | ||
columns: [NAME, RESOURCE_GROUP_NAME] | ||
|
||
- name: SERVICE_NAME | ||
description: Service name | ||
|
||
- name: CREATE_RESOURCE_GROUPS | ||
confirm: true | ||
|
||
- name: RESOURCE_GROUP_LOCATION | ||
if: CREATE_RESOURCE_GROUPS == true | ||
options: | ||
- "North Europe" | ||
- "West Europe" | ||
# ... | ||
|
||
- name: CREATE_GITHUB_ACTIONS_PIPELINE | ||
confirm: true |
52 changes: 52 additions & 0 deletions
52
examples/terraform-bootstrap/templates/.github/workflows/terraform-apply.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{{- if .Variables.CREATE_GITHUB_ACTIONS_PIPELINE }} | ||
name: Terraform Apply | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
ENVIRONMENT: | ||
required: true | ||
type: string | ||
TERRAFORM_VERSION: | ||
required: true | ||
type: string | ||
secrets: | ||
ARM_SUBSCRIPTION_ID: | ||
required: true | ||
ARM_TENANT_ID: | ||
required: true | ||
ARM_CLIENT_ID: | ||
required: true | ||
ARM_CLIENT_SECRET: | ||
required: true | ||
|
||
env: | ||
TF_IN_AUTOMATION: "true" | ||
|
||
jobs: | ||
plan: | ||
runs-on: ubuntu-latest | ||
environment: {{ "${{ inputs.ENVIRONMENT }}" }} | ||
env: | ||
ARM_CLIENT_ID: {{ "${{ secrets.ARM_CLIENT_ID }}" }} | ||
ARM_CLIENT_SECRET: {{ "${{ secrets.ARM_CLIENT_SECRET }}" }} | ||
ARM_SUBSCRIPTION_ID: {{ "${{ secrets.ARM_SUBSCRIPTION_ID }}" }} | ||
ARM_TENANT_ID: {{ "${{ secrets.ARM_TENANT_ID }}" }} | ||
steps: | ||
- name: Setup Terraform | ||
uses: hashicorp/setup-terraform@v2 | ||
with: | ||
terraform_version: {{ "${{ inputs.TERRAFORM_VERSION }}" }} | ||
|
||
- name: Download the plan | ||
uses: actions/download-artifact@v2 | ||
with: | ||
name: terraform-plan-{{ "${{ inputs.ENVIRONMENT }}" }} | ||
|
||
- name: Restore run permissions | ||
run: chmod -R +x .terraform | ||
|
||
- name: Terraform Apply | ||
id: apply | ||
run: terraform apply -input=false -no-color terraform.tfplan | ||
{{- end }} |
93 changes: 93 additions & 0 deletions
93
examples/terraform-bootstrap/templates/.github/workflows/terraform-plan.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
{{- if .Variables.CREATE_GITHUB_ACTIONS_PIPELINE }} | ||
name: Terraform Plan | ||
|
||
on: | ||
workflow_call: | ||
inputs: | ||
ENVIRONMENT: | ||
required: true | ||
type: string | ||
TERRAFORM_VERSION: | ||
required: true | ||
type: string | ||
TERRAFORM_BACKEND_STORAGE_NAME: | ||
required: true | ||
type: string | ||
RESOURCE_GROUP_NAME: | ||
required: true | ||
type: string | ||
secrets: | ||
ARM_SUBSCRIPTION_ID: | ||
required: true | ||
ARM_TENANT_ID: | ||
required: true | ||
ARM_CLIENT_ID: | ||
required: true | ||
ARM_CLIENT_SECRET: | ||
required: true | ||
|
||
env: | ||
TF_IN_AUTOMATION: "true" | ||
|
||
jobs: | ||
plan: | ||
runs-on: ubuntu-latest | ||
env: | ||
ARM_CLIENT_ID: {{ "${{ secrets.ARM_CLIENT_ID }}" }} | ||
ARM_CLIENT_SECRET: {{ "${{ secrets.ARM_CLIENT_SECRET }}" }} | ||
ARM_SUBSCRIPTION_ID: {{ "${{ secrets.ARM_SUBSCRIPTION_ID }}" }} | ||
ARM_TENANT_ID: {{ "${{ secrets.ARM_TENANT_ID }}" }} | ||
steps: | ||
- name: Check out repository code | ||
uses: actions/checkout@v2 | ||
|
||
- name: Setup Terraform | ||
uses: hashicorp/setup-terraform@v2 | ||
with: | ||
terraform_version: {{ "${{ inputs.TERRAFORM_VERSION }}" }} | ||
|
||
- name: Terraform Format | ||
id: fmt | ||
run: terraform fmt -check | ||
working-directory: ./terraform | ||
|
||
- name: Terraform Init | ||
id: init | ||
run: >- | ||
terraform init | ||
-backend-config="resource_group_name={{ "${{ inputs.RESOURCE_GROUP_NAME }}" }}" | ||
-backend-config="storage_account_name={{ "${{ inputs.TERRAFORM_BACKEND_STORAGE_NAME }}" }}" | ||
-backend-config="container_name=tfstate" | ||
-backend-config="key=tfstate_" | ||
working-directory: ./terraform | ||
|
||
- name: Terraform Workspace | ||
id: workspace | ||
run: terraform workspace select {{ "${{ inputs.ENVIRONMENT }}" }} | ||
working-directory: ./terraform | ||
|
||
- name: Terraform Validate | ||
id: validate | ||
run: terraform validate -no-color | ||
working-directory: ./terraform | ||
|
||
- name: Terraform Plan | ||
id: plan | ||
run: terraform plan -out=terraform.tfplan -no-color | ||
working-directory: ./terraform | ||
continue-on-error: true | ||
env: | ||
TF_VAR_resource_group_name: {{ "${{ inputs.RESOURCE_GROUP_NAME }}" }} | ||
|
||
- name: Terraform Plan Status | ||
if: steps.plan.outcome == 'failure' | ||
run: exit 1 | ||
|
||
- name: Archive Terraform plan | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
name: terraform-plan-{{ "${{ inputs.ENVIRONMENT }}" }} | ||
path: ./terraform | ||
retention-days: 7 | ||
{{- end }} |
43 changes: 43 additions & 0 deletions
43
examples/terraform-bootstrap/templates/.github/workflows/terraform.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
{{- if .Variables.CREATE_GITHUB_ACTIONS_PIPELINE -}} | ||
name: Terraform CI/CD | ||
on: | ||
push: | ||
branches: | ||
- main | ||
paths: | ||
- "terraform/**" | ||
- ".github/workflows/terraform*.yml" | ||
|
||
jobs: | ||
{{- range $i, $env := .Variables.ENVIRONMENTS }} | ||
{{- if (gt $i 0) }} | ||
{{/* Add empty line if not the first job */ -}} | ||
{{ end }} | ||
build-{{ $env.NAME }}: | ||
name: Build for {{ $env.NAME | upper }} | ||
uses: ./.github/workflows/terraform-plan.yml | ||
with: | ||
ENVIRONMENT: {{ $env.NAME }} | ||
TERRAFORM_VERSION: {{ "${{ vars.TERRAFORM_VERSION }}" }} | ||
TERRAFORM_BACKEND_STORAGE_NAME: {{ template "storage_account_name_prefix" $ }}{{ template "resource_tag" $ }}{{ $env.NAME }} | ||
RESOURCE_GROUP_NAME: {{ $env.RESOURCE_GROUP_NAME }} | ||
secrets: | ||
ARM_CLIENT_ID: {{ printf "${{ secrets.ARM_CLIENT_ID_%s }}" ($env.NAME | upper) }} | ||
ARM_CLIENT_SECRET: {{ printf "${{ secrets.ARM_CLIENT_SECRET_%s }}" ($env.NAME | upper) }} | ||
ARM_SUBSCRIPTION_ID: {{ printf "${{ secrets.ARM_SUBSCRIPTION_ID_%s }}" ($env.NAME | upper) }} | ||
ARM_TENANT_ID: {{ printf "${{ secrets.ARM_TENANT_ID_%s }}" ($env.NAME | upper) }} | ||
|
||
deploy-{{ $env.NAME }}: | ||
name: Deploy to {{ $env.NAME | upper }} | ||
needs: build-{{ $env.NAME }} | ||
uses: ./.github/workflows/terraform-apply.yml | ||
with: | ||
ENVIRONMENT: {{ $env.NAME }} | ||
TERRAFORM_VERSION: {{ "${{ vars.TERRAFORM_VERSION }}"}} | ||
secrets: | ||
ARM_CLIENT_ID: {{ printf "${{ secrets.ARM_CLIENT_ID_%s }}" ($env.NAME | upper) }} | ||
ARM_CLIENT_SECRET: {{ printf "${{ secrets.ARM_CLIENT_SECRET_%s }}" ($env.NAME | upper) }} | ||
ARM_SUBSCRIPTION_ID: {{ printf "${{ secrets.ARM_SUBSCRIPTION_ID_%s }}" ($env.NAME | upper) }} | ||
ARM_TENANT_ID: {{ printf "${{ secrets.ARM_TENANT_ID_%s }}" ($env.NAME | upper) }} | ||
{{- end }} | ||
{{- end -}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.terraform | ||
terraform.tfstate.d |
Oops, something went wrong.