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

add verify prod and refactor terraform check/deploy #197

Merged
merged 2 commits into from
May 17, 2024
Merged
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
216 changes: 216 additions & 0 deletions .github/workflows/.terraform.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Copyright 2024 Chainguard, Inc.
# SPDX-License-Identifier: Apache-2.0

name: Reusable Terraform Workflow

on:
workflow_call:
inputs:
workload_identity_provider:
type: string
required: true
description: "Workload identity provider for GCP Workload Federation."
service_account:
type: string
required: true
description: "GCP Service Account to impersonate."
checkout_sha:
required: false
type: string
description: 'Commit SHA to run at.'
working_directory:
required: true
type: string
description: 'Location for the terraform.'
project_id:
required: false
type: string
description: 'GCP project ID.'
octo-sts-identity:
required: false
default: ''
type: string
description: 'The Octo STS identity name'

jobs:
terraform:
name: Terraform
runs-on: 'ubuntu-latest'
permissions:
contents: read # clone the repository contents
id-token: write # federates with GCP

env:
SHA: ${{ inputs.checkout_sha || github.sha }}
PROJECT_ID: ${{ inputs.project_id }}
TF_PLAN_BIN: 'plan.tmp'
TF_PLAN_OUT: 'plan.out'

defaults:
run:
working-directory: "${{ inputs.working_directory }}"

steps:
- uses: step-security/harden-runner@63c24ba6bd7ba022e95695ff85de572c04a18142 # v2.7.0
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
with:
ref: ${{ env.SHA }}

- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version-file: './go.mod'
check-latest: true

- name: Authenticate to Google Cloud
uses: 'google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c' # v2.1.2
id: auth
with:
token_format: 'access_token'
project_id: '${{ inputs.project_id }}'
workload_identity_provider: '${{ inputs.workload_identity_provider }}'
service_account: '${{ inputs.service_account }}'

- name: 'Set up Cloud SDK'
uses: google-github-actions/setup-gcloud@98ddc00a17442e89a24bbf282954a3b65ce6d200 # v2.1.0

- uses: 'docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20' # v2
with:
username: 'oauth2accesstoken'
password: '${{ steps.auth.outputs.access_token }}'
registry: 'gcr.io'

- name: Setup terraform
uses: 'hashicorp/setup-terraform@a1502cd9e758c50496cc9ac5308c4843bcd56d36' # v3.0.0
with:
terraform_version: 1.6

- name: Terraform fmt
id: fmt
run: terraform fmt -check -recursive

- name: Terraform init
id: init
run: terraform init -reconfigure

- name: Terraform Validate
id: validate
run: terraform validate -no-color

- name: Terraform Plan
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know of anything that we can run over this to check for injection vulnerabilities?

Skimming, the only one that stood out is inputs.working_directory, and that's a reach, but would be good to sanity check things

id: plan
continue-on-error: true
shell: bash
run: |
set +e

terraform plan -input=false -lock=false -detailed-exitcode -no-color -out=${{ env.TF_PLAN_BIN }}
exitcode=$?
case "$exitcode" in
0)
# 0 = Succeeded with empty diff (no changes)
echo "Succeeded with empty diff (no changes)"
echo "TF_PLAN_OUTCOME=same" >> "$GITHUB_OUTPUT"
;;
1)
# 1 = Error
echo "Error"
echo "TF_PLAN_OUTCOME=error" >> "$GITHUB_OUTPUT"
exit 1
;;
2)
# 2 = Succeeded with non-empty diff (changes present)
echo "Succeeded with non-empty diff (changes present)"
echo "TF_PLAN_OUTCOME=diff" >> "$GITHUB_OUTPUT"
;;
*)
echo "unknown error"
echo "TF_PLAN_OUTCOME=unknown" >> "$GITHUB_OUTPUT"
exit 1
;;
esac
terraform show -no-color ${{ env.TF_PLAN_BIN }} > "${GITHUB_WORKSPACE}"/${{ env.TF_PLAN_OUT }}
exit 0

- uses: octo-sts/action@6177b4481c00308b3839969c3eca88c96a91775f # v1.0.0
if: github.event_name == 'pull_request_target'
id: octo-sts
with:
scope: ${{ github.repository }}
identity: ${{ inputs.octo-sts-identity }}

- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
if: github.event_name == 'pull_request_target'
with:
github-token: ${{ steps.octo-sts.outputs.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 checks for "${{ inputs.working_directory }}"')
})

// adapted from: https://github.com/actions/github-script/issues/266#issuecomment-1159681385
const run_url = process.env.GITHUB_SERVER_URL + '/' + process.env.GITHUB_REPOSITORY + '/actions/runs/' + process.env.GITHUB_RUN_ID
const run_link = '<a href="' + run_url + '">Actions</a>.'
const fs = require('fs')
const plan_file = fs.readFileSync('${{ env.TF_PLAN_OUT }}', 'utf8')
const plan = plan_file.length > 64000 ? plan_file.toString().substring(0, 64000) + " ..." : plan_file
const truncated_message = plan_file.length > 64000 ? "Output is too long and was truncated. You can read full Plan in " + run_link + "<br /><br />" : ""

// 2. Prepare format of the comment
const output = `Terraform checks for "${{ inputs.working_directory }}"
#### 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
${plan}
\`\`\`

</details>
${truncated_message}

*Pusher: @${{ github.actor }}, Action: \`${{ github.event_name }}\`, Working Directory: \`${{ inputs.working_directory }}\`, 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
})
}

- name: Terraform Plan Status
if: ${{ steps.plan.outputs.TF_PLAN_OUTCOME == 'error' || steps.plan.outputs.TF_PLAN_OUTCOME == 'unknown' }}
run: exit 1

- name: Terraform Apply
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
run: terraform apply -auto-approve -input=false "${{ env.TF_PLAN_BIN }}"
68 changes: 22 additions & 46 deletions .github/workflows/deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ on:
- "main"
workflow_dispatch:

concurrency: deploy
concurrency:
group: deploy
cancel-in-progress: false

jobs:
deploy:
Expand All @@ -20,48 +22,22 @@ jobs:
id-token: write # federates with GCP

steps:
- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v3
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
with:
go-version-file: './go.mod'
check-latest: true

- uses: google-github-actions/auth@55bd3a7c6e2ae7cf1877fd1ccb9d54c0503c457c # v2.1.2
id: auth
with:
token_format: 'access_token'
project_id: 'octo-sts'
workload_identity_provider: 'projects/96355665038/locations/global/workloadIdentityPools/github-pool/providers/github-provider'
service_account: '[email protected]'

- uses: 'docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20' # v2
with:
username: 'oauth2accesstoken'
password: '${{ steps.auth.outputs.access_token }}'
registry: 'gcr.io'

# Attempt to deploy the terraform configuration
- uses: hashicorp/setup-terraform@651471c36a6092792c552e8b1bef71e592b462d8 # v2.0.0
with:
terraform_version: 1.6

- working-directory: ./iac
run: |
terraform init

terraform plan

terraform apply -auto-approve

- uses: rtCamp/action-slack-notify@4e5fb42d249be6a45a298f3c9543b111b02f7907 # v2.3.0
if: ${{ failure() }}
env:
SLACK_ICON: http://github.com/chainguard-dev.png?size=48
SLACK_USERNAME: guardian
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: 'octo-sts-alerts' # Use a channel
SLACK_COLOR: '#8E1600'
MSG_MINIMAL: 'true'
SLACK_TITLE: Deploying OctoSTS to Cloud Run failed
SLACK_MESSAGE: |
For detailed logs: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
- uses: ./.github/workflows/.terraform.yaml
with:
project_id: 'octo-sts'
workload_identity_provider: 'projects/96355665038/locations/global/workloadIdentityPools/github-pool/providers/github-provider'
service_account: '[email protected]'
working_directory: ./iac

- uses: rtCamp/action-slack-notify@4e5fb42d249be6a45a298f3c9543b111b02f7907 # v2.3.0
if: ${{ failure() }}
env:
SLACK_ICON: http://github.com/chainguard-dev.png?size=48
SLACK_USERNAME: guardian
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
SLACK_CHANNEL: 'octo-sts-alerts' # Use a channel
SLACK_COLOR: '#8E1600'
MSG_MINIMAL: 'true'
SLACK_TITLE: Deploying OctoSTS to Cloud Run failed
SLACK_MESSAGE: |
For detailed logs: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
32 changes: 32 additions & 0 deletions .github/workflows/verify-prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2024 Chainguard, Inc.
# SPDX-License-Identifier: Apache-2.0

name: Verify prod Octo-sts

on:
pull_request_target:
branches:
- 'main'
mattmoor marked this conversation as resolved.
Show resolved Hide resolved
types:
- labeled

concurrency:
group: deploy
cancel-in-progress: false

jobs:
verify-prod-octo-sts:
if: contains(github.event.pull_request.labels.*.name, 'ok-to-test')

permissions:
contents: read # clone the repository contents
id-token: write # federates with GCP

uses: ./.github/workflows/.terraform.yaml
with:
project_id: 'octo-sts'
workload_identity_provider: 'projects/96355665038/locations/global/workloadIdentityPools/github-pool/providers/github-provider'
service_account: '[email protected]'
working_directory: ./iac
octo-sts-identity: verify-prod
checkout_sha: ${{ github.event.pull_request.head.sha }}