mirror of
https://github.com/nmasur/dotfiles
synced 2024-12-26 16:24:52 +00:00
281 lines
9.7 KiB
YAML
281 lines
9.7 KiB
YAML
name: 'Terraform'
|
|
env:
|
|
|
|
AWS_ACCOUNT_NUMBER: ''
|
|
AWS_PLAN_ROLE_NAME: github_actions_plan
|
|
AWS_APPLY_ROLE_NAME: github_actions_admin
|
|
|
|
# Always required. Used for authenticating to AWS, but can also act as your
|
|
# default region if you don't want to specify in the provider configuration.
|
|
AWS_REGION: us-east-1
|
|
|
|
# You must change these to fit your project.
|
|
TF_VAR_project: change-me
|
|
TF_VAR_label: change-me
|
|
TF_VAR_owner: Your Name Here
|
|
|
|
# If storing Terraform in a subdirectory, specify it here.
|
|
TERRAFORM_DIRECTORY: .
|
|
|
|
# Pinned versions of tools to use.
|
|
# Check for new releases:
|
|
# - https://github.com/hashicorp/terraform/releases
|
|
# - https://github.com/fugue/regula/releases
|
|
# - https://github.com/terraform-linters/tflint/releases
|
|
TERRAFORM_VERSION: 1.2.6
|
|
REGULA_VERSION: 2.9.0
|
|
TFLINT_VERSION: 0.39.1
|
|
|
|
# Terraform configuration options
|
|
TERRAFORM_PARALLELISM: 10
|
|
|
|
# These variables are passed to Terraform based on GitHub information.
|
|
TF_VAR_repo: ${{ github.repository }}
|
|
|
|
# This workflow is triggered in the following ways.
|
|
on:
|
|
|
|
# Any push or merge to these branches.
|
|
push:
|
|
branches:
|
|
- dev
|
|
- prod
|
|
|
|
# Any pull request targeting these branches (plan only).
|
|
pull_request:
|
|
branches:
|
|
- dev
|
|
- prod
|
|
|
|
|
|
# Any manual trigger on these branches.
|
|
workflow_dispatch:
|
|
branches:
|
|
- dev
|
|
- prod
|
|
|
|
# -------------------------------------------------------------------
|
|
# The rest of this workflow can operate without adjustments. Edit the
|
|
# below content at your own risk!
|
|
# -------------------------------------------------------------------
|
|
|
|
# Used to connect to AWS IAM
|
|
permissions:
|
|
id-token: write
|
|
contents: read
|
|
pull-requests: write
|
|
|
|
# Only run one workflow at a time for each Terraform state. This prevents
|
|
# lockfile conflicts, especially during PR vs push.
|
|
concurrency: terraform-${{ github.base_ref || github.ref }}
|
|
|
|
jobs:
|
|
terraform:
|
|
|
|
name: 'Terraform'
|
|
|
|
# Change this if you need to run your deployment on-prem.
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
|
|
# Downloads the current repo code to the runner.
|
|
- name: Checkout Repo Code
|
|
uses: actions/checkout@v3
|
|
|
|
# Enable access to KVM, required to build an image
|
|
- name: Enable KVM group perms
|
|
run: |
|
|
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
|
sudo udevadm control --reload-rules
|
|
sudo udevadm trigger --name-match=kvm
|
|
|
|
# Login to AWS
|
|
- name: AWS Assume Role
|
|
uses: aws-actions/configure-aws-credentials@v1.6.1
|
|
with:
|
|
role-to-assume: ${{ env.AWS_ROLE_ARN }}
|
|
aws-region: ${{ env.AWS_REGION }}
|
|
|
|
# Install Nix
|
|
- name: Install Nix
|
|
uses: cachix/install-nix-action@v17
|
|
with:
|
|
extra_nix_config: |
|
|
substituters = s3://insert-cache-bucket https://cache.nixos.org/
|
|
trusted-public-keys = insert-cache-bucket:M6PsZjHXcLvbQyPUBLICKEYGVoNwI84g1FBQzouRU= cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=
|
|
|
|
# Build the image
|
|
- name: Build Image
|
|
run: nix build .#aws
|
|
|
|
# Copy the image to S3
|
|
- name: Upload Image to Cache
|
|
env:
|
|
NIX_CACHE_PRIVATE_KEY: ${{ secrets.NIX_CACHE_PRIVATE_KEY }}
|
|
run: |
|
|
echo "$NIX_CACHE_PRIVATE_KEY" > cache.key
|
|
nix store sign --key-file cache.key $(readlink result)
|
|
nix copy --to s3://t2-aws-nixos-test $(readlink result)
|
|
rm cache.key
|
|
|
|
# Exports all GitHub Secrets as environment variables prefixed by
|
|
# "TF_VAR_", which exposes them to Terraform. The name of each GitHub
|
|
# Secret must match its Terraform variable name exactly.
|
|
- name: Export Secrets to Terraform Variables
|
|
env:
|
|
ALL_SECRETS: ${{ toJson(secrets) }}
|
|
run: |
|
|
echo "$ALL_SECRETS" \
|
|
| jq "to_entries | .[] | \"TF_VAR_\" + ( .key | ascii_downcase ) + \"=\" + .value" \
|
|
| tr -d \" >> $GITHUB_ENV
|
|
|
|
# Installs the Terraform binary and some other accessory functions.
|
|
- name: Setup Terraform
|
|
uses: hashicorp/setup-terraform@v2
|
|
with:
|
|
terraform_version: ${{ env.TERRAFORM_VERSION }}
|
|
|
|
# Checks whether Terraform is formatted properly. If this fails, you
|
|
# should install the pre-commit hook.
|
|
- name: Check Formatting
|
|
run: |
|
|
terraform fmt -no-color -check -diff -recursive
|
|
|
|
# Downloads a Terraform code lint test.
|
|
- uses: terraform-linters/setup-tflint@v1
|
|
name: Setup TFLint
|
|
with:
|
|
tflint_version: v${{ env.TFLINT_VERSION }}
|
|
|
|
# Sets up linting with this codebase.
|
|
- name: Init TFLint
|
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
|
run: tflint --init
|
|
|
|
# Lints the current code.
|
|
- name: Run TFLint
|
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
|
run: |
|
|
tflint -f compact
|
|
find ./modules/* -type d -maxdepth 0 | xargs -I __ tflint -f compact --disable-rule=terraform_required_providers --disable-rule=terraform_required_version __
|
|
|
|
# Connects to remote state backend and download providers.
|
|
- name: Terraform Init
|
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
|
run: |
|
|
terraform init \
|
|
-backend-config="role_arn=${{ env.AWS_STATE_ROLE_ARN }}" \
|
|
-backend-config="region=us-east-1" \
|
|
-backend-config="workspace_key_prefix=accounts/${{ env.AWS_ACCOUNT_NUMBER }}/${{ github.repository }}" \
|
|
-backend-config="key=state.tfstate" \
|
|
-backend-config="dynamodb_table=global-tf-state-lock"
|
|
|
|
# Set the Terraform Workspace to the current branch name.
|
|
- name: Set Terraform Workspace
|
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
|
shell: bash
|
|
run: |
|
|
export WORKSPACE=${{ github.base_ref || github.ref_name }}
|
|
terraform workspace select ${WORKSPACE} || terraform workspace new $WORKSPACE
|
|
echo "TF_WORKSPACE=$(echo ${WORKSPACE} | sed 's/\//_/g')" >> $GITHUB_ENV
|
|
|
|
# Checks differences between current code and infrastructure state.
|
|
- name: Terraform Plan
|
|
id: plan
|
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
|
run: |
|
|
terraform plan \
|
|
-input=false \
|
|
-no-color \
|
|
-out=tfplan \
|
|
-parallelism=${TERRAFORM_PARALLELISM} \
|
|
-var-file=variables-${TF_WORKSPACE}.tfvars
|
|
|
|
# Gets the results of the plan for pull requests.
|
|
- name: Terraform Show Plan
|
|
id: show
|
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
|
run: terraform show -no-color tfplan
|
|
|
|
# Adds the results of the plan to the pull request.
|
|
- name: Comment Plan
|
|
uses: actions/github-script@v6
|
|
if: github.event_name == 'pull_request'
|
|
env:
|
|
STDOUT: "```terraform\n${{ steps.show.outputs.stdout }}```"
|
|
with:
|
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
script: |
|
|
// 1. Retrieve existing bot comments for the PR
|
|
const { data: comments } = await github.rest.issues.listComments({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: context.issue.number,
|
|
})
|
|
const botComment = comments.find(comment => {
|
|
return comment.user.type === 'Bot' && comment.body.includes('Terraform Format and Style')
|
|
})
|
|
|
|
// 2. Prepare format of the comment
|
|
const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
|
|
#### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
|
|
#### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
|
|
<details><summary>Validation Output</summary>
|
|
|
|
\`\`\`\n
|
|
${{ steps.validate.outputs.stdout }}
|
|
\`\`\`
|
|
|
|
</details>
|
|
|
|
#### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
|
|
|
|
<details><summary>Show Plan</summary>
|
|
|
|
\`\`\`\n
|
|
${process.env.PLAN}
|
|
\`\`\`
|
|
|
|
</details>
|
|
|
|
*Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Working Directory: \`${{ env.tf_actions_working_dir }}\`, Workflow: \`${{ github.workflow }}\`*`;
|
|
|
|
// 3. If we have a comment, update it, otherwise create a new one
|
|
if (botComment) {
|
|
github.rest.issues.updateComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
comment_id: botComment.id,
|
|
body: output
|
|
})
|
|
} else {
|
|
github.rest.issues.createComment({
|
|
issue_number: context.issue.number,
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
body: output
|
|
})
|
|
}
|
|
|
|
# Downloads Regula and checks whether the plan meets compliance requirements.
|
|
- name: Regula Compliance Check
|
|
shell: bash
|
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
|
run: |
|
|
REGULA_URL="https://github.com/fugue/regula/releases/download/v${REGULA_VERSION}/regula_${REGULA_VERSION}_Linux_x86_64.tar.gz"
|
|
curl -sL "$REGULA_URL" -o regula.tar.gz
|
|
tar xzf regula.tar.gz
|
|
terraform show -json tfplan | ./regula run
|
|
|
|
# Deploys infrastructure or changes to infrastructure.
|
|
- name: Terraform Apply
|
|
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
|
run: |
|
|
terraform apply \
|
|
-auto-approve \
|
|
-input=false \
|
|
-parallelism=${TERRAFORM_PARALLELISM} \
|
|
tfplan
|