Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add improved terraform and bicep workflows #59

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .github/workflows/IAC-bicep-unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: 'Bicep Unit Tests'

# Uncomment the trigger conditions below to enable this workflow
# on:
# push:

# Set the default working directory to point at the bicep folder
defaults:
run:
working-directory: IAC/bicep

env:
LOCATION: "eastus"

# Special permissions required for OIDC authentication
permissions:
id-token: write
contents: read

jobs:
bicep-unit-tests:
name: 'Bicep Unit Tests'
runs-on: ubuntu-latest
# Bicep What-if / Validate functions also check if your role has permisisons to create the resources
# The account here actually needs to have read/write permisisons.
environment: production

steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2

# Authenticate to Az CLI using OIDC
- name: 'Az CLI login'
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

# Checks that all Bicep configuration files adhere to a canonical format
- name: Bicep Lint
uses: Azure/cli@v1
with:
inlineScript: az bicep build --file main.bicep

# Validate whether a template is valid at subscription scope
- name: Bicep Validate
uses: Azure/cli@v1
with:
inlineScript: |
az deployment sub validate \
--name validate-${{ github.run_id }} \
--template-file main.bicep \
--location $LOCATION
142 changes: 142 additions & 0 deletions .github/workflows/IAC-bicep-whatif-deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
name: 'Bicep Whatif / Deploy'

# Uncomment the trigger conditions below to enable this workflow
# on:
# push:
# branches:
# - main
# pull_request:
# branches:
# - main

# Set the default working directory to point at the bicep folder
defaults:
run:
working-directory: IAC/bicep

# Special permissions required for OIDC authentication
permissions:
id-token: write
contents: read
pull-requests: write

env:
LOCATION: "eastus"

jobs:
bicep-whatif:
name: 'Bicep Whatif'
runs-on: ubuntu-latest
environment: production

steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2

# Authenticate to Az CLI using OIDC
- name: 'Az CLI login'
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

# Checks that all Bicep configuration files adhere to a canonical format
- name: Bicep Lint
uses: Azure/cli@v1
with:
inlineScript: az bicep build --file main.bicep

# Validate whether a template is valid at subscription scope
- name: Bicep Validate
uses: Azure/cli@v1
with:
inlineScript: |
az deployment sub validate \
--name validate-${{ github.run_id }} \
--template-file main.bicep \
--location $LOCATION

# Preview changes
- name: "What-If"
uses: Azure/cli@v1
with:
inlineScript: |
az deployment sub what-if \
--name whatif-${{ github.run_id }} \
--template-file main.bicep \
--location $LOCATION > whatif

# Create string output of Whatif
- name: Create String Output
id: whatif-string
run: |
WHATIF=$(cat whatif)
echo "## Whatif Output" >> whatif.string
echo "<details><summary>Click to expand</summary>" >> whatif.string
echo "" >> whatif.string
echo '```' >> whatif.string
echo "$WHATIF" >> whatif.string
echo '```' >> whatif.string
echo "</details>" >> whatif.string

SUMMARY=$(cat whatif.string)
SUMMARY="${SUMMARY//'%'/'%25'}"
SUMMARY="${SUMMARY//$'\n'/'%0A'}"
SUMMARY="${SUMMARY//$'\r'/'%0D'}"

echo "::set-output name=summary::$SUMMARY"

# Publish What-If output as a task summary
- name: Publish Whatif to Task Summary
run: |
cat whatif.string >> $GITHUB_STEP_SUMMARY

# If this is a PR post the changes
- name: Push Whatif Output to PR
if: github.ref != 'refs/heads/main'
uses: actions/github-script@v2
env:
SUMMARY: "${{ steps.whatif-string.outputs.summary }}"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const body = `${process.env.SUMMARY}`;
github.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
})

bicep-deploy:
name: 'Bicep Deploy'
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
environment: production-approval
needs: [bicep-whatif]

steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2

# Authenticate to Az CLI using OIDC
- name: 'Az CLI login'
uses: azure/login@v1
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

# Deploy
- name: "Bicep Deployment"
uses: Azure/cli@v1
with:
inlineScript: |
az deployment sub create \
--name deploy-${{ github.run_id }} \
--template-file main.bicep \
--location $LOCATION

121 changes: 121 additions & 0 deletions .github/workflows/IAC-terraform-drift-detect
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
name: 'Terraform Drift Dectection'

# Uncomment the trigger conditions below to enable this workflow
# on:
# schedule:
# # runs nightly at 4:23 am UTC
# - cron: '23 4 * * *'

# Set the default working directory to point at the terraform folder
defaults:
run:
working-directory: IAC/terraform

#Special permissions required for OIDC authentication
permissions:
id-token: write
contents: read
issues: write

# These environment variables are used by the terraform azure provider to setup OIDD authenticate.
env:
ARM_CLIENT_ID: "${{ secrets.AZURE_CLIENT_ID }}"
ARM_SUBSCRIPTION_ID: "${{ secrets.AZURE_SUBSCRIPTION_ID }}"
ARM_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}"

jobs:
terraform-plan:
name: 'Terraform Plan'
runs-on: ubuntu-latest
environment: production-readonly
env:
# This is needed since we are running terraform with read-only permissions
ARM_SKIP_PROVIDER_REGISTRATION: true
outputs:
tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }}

steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2

# Install the latest version of the Terraform CLI
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
terraform_wrapper: false

# Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc.
- name: Terraform Init
run: terraform init

# Generates an execution plan for Terraform
# An exit code of 0 indicated no changes, 1 a terraform failure, 2 there are pending changes.
- name: Terraform Plan
id: tf-plan
run: |
export exitcode=0
terraform plan -detailed-exitcode -no-color -out tfplan || export exitcode=$?

echo "::set-output name=exitcode::$exitcode"

if [ $exitcode -eq 1 ]; then
echo Terraform Plan Failed!
exit 1
else
exit 0
fi

# Save plan to artifacts
- name: Publish Terraform Plan
uses: actions/upload-artifact@v2
with:
name: tfplan
path: tfplan

# Create string output of Terraform Plan
- name: Create String Output
id: tf-plan-string
run: |
TERRAFORM_PLAN=$(terraform show -no-color tfplan)
echo "## Terraform Plan Output" >> tf.string
echo "<details><summary>Click to expand</summary>" >> tf.string
echo "" >> tf.string
echo '```terraform' >> tf.string
echo "$TERRAFORM_PLAN" >> tf.string
echo '```' >> tf.string
echo "</details>" >> tf.string

SUMMARY=$(cat tf.string)
SUMMARY="${SUMMARY//'%'/'%25'}"
SUMMARY="${SUMMARY//$'\n'/'%0A'}"
SUMMARY="${SUMMARY//$'\r'/'%0D'}"

echo "::set-output name=summary::$SUMMARY"

# Publish Terraform Plan as task summary
- name: Publish Terraform Plan to Task Summary
run: |
cat tf.string >> $GITHUB_STEP_SUMMARY

# If changes are detected, create a new issue
- name: Publish Drift Report
if: steps.tf-plan.outputs.exitcode == 2
uses: actions/github-script@v2
env:
SUMMARY: "${{ steps.tf-plan-string.outputs.summary }}"
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const body = `${process.env.SUMMARY}`;
github.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: "Terraform Configuration Drift Detected",
body: body
})

# Mark the workflow as failed if drift detected
- name: Error on Failure
if: steps.tf-plan.outputs.exitcode == 2
run: exit 1
Loading