-
Notifications
You must be signed in to change notification settings - Fork 0
ci: terraform composite action — plan/apply/destroy + scaleway lifecycle #36
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
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
8e82946
ci(actions): refactor terraform workflows into a reusable composite a…
84a3327
ci: reusable terraform workflow with first-class secret handling
78453d9
ci: drop the reusable-workflow wrapper, use the composite action dire…
6ba8d23
ci: drop the -lock=false escape hatch from the terraform action
236590a
t
7ee2ac9
fix(00-remote_state): set role_name in the tfvars to tf-state-access
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 |
|---|---|---|
| @@ -1,33 +1,92 @@ | ||
| name: Terraform (workspace-driven) | ||
| name: Terraform | ||
| description: > | ||
| Run terraform for a root. The workspace and its variables come from the root's | ||
| workspace/<name>.tfvars: the filename is the terraform workspace, the contents | ||
| are its variables. Keeps workspace selection declarative and version-controlled | ||
| (not a local, gitignored .terraform/environment). | ||
| Run Terraform for a workspace-driven root: set up Terraform, mint an Infisical | ||
| OIDC token, assume an AWS role via OIDC (for remote state access) and retrieve Scaleway Machine Identity credentials, then init → workspace select → | ||
| plan/apply/destroy. The repository must already be checked out. | ||
|
|
||
| This action takes NO secret inputs. Provider credentials are read from the | ||
| calling job's environment (set them there — the reusable terraform.yml workflow | ||
| does, sourcing SCW_ACCESS_KEY/SCW_SECRET_KEY from its `secrets:` block): | ||
| - SCW_ACCESS_KEY / SCW_SECRET_KEY (Scaleway API key) | ||
| - SCW_DEFAULT_ORGANIZATION_ID / _PROJECT_ID | ||
| - INFISICAL_MACHINE_IDENTITY_ID (for the minted INFISICAL_AUTH_JWT) | ||
|
|
||
| inputs: | ||
| root: | ||
| description: Path to the terraform root (passed to -chdir). | ||
| description: Path to the Terraform root (passed to -chdir). | ||
| required: true | ||
| tfvars-file: | ||
| description: > | ||
| Filename of the .tfvars under env/ (e.g. 02-cluster-staging.tfvars). | ||
| Workspace name is derived by stripping the .tfvars extension. | ||
| required: true | ||
| apply: | ||
| description: 'When "true", apply; otherwise plan.' | ||
| command: | ||
| description: 'Terraform command to run: plan | apply | destroy.' | ||
| required: false | ||
| default: plan | ||
| aws-role-arn: | ||
| description: ARN of the IAM role to assume via OIDC (Terraform-state R/W). | ||
| required: true | ||
| aws-region: | ||
| description: AWS region for the assumed role. | ||
| required: false | ||
| default: eu-west-3 | ||
| infisical-oidc-audience: | ||
| description: > | ||
| OIDC audience for the Infisical machine identity. When set (the default), | ||
| mint a GitHub OIDC JWT into INFISICAL_AUTH_JWT. Set to "" to skip it for | ||
| roots that don't read Infisical. | ||
| required: false | ||
| default: "false" | ||
| default: https://github.com/IntegratedDynamic | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - shell: bash | ||
| - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 | ||
| with: | ||
| # Keep in sync with mise.toml [tools] terraform version. | ||
| terraform_version: "1.14" | ||
|
|
||
| # Keyless Infisical auth: mint a GitHub OIDC JWT into INFISICAL_AUTH_JWT (the | ||
| # provider's default token env var). The audience must match the identity's | ||
| # boundAudiences. getIDToken masks the value automatically. | ||
| - name: Mint Infisical OIDC token | ||
| if: inputs.infisical-oidc-audience != '' | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| AUDIENCE: ${{ inputs.infisical-oidc-audience }} | ||
| with: | ||
| script: | | ||
| const jwt = await core.getIDToken(process.env.AUDIENCE) | ||
| core.exportVariable('INFISICAL_AUTH_JWT', jwt) | ||
|
|
||
| - name: Assume AWS role via OIDC | ||
| uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 | ||
| with: | ||
| role-to-assume: ${{ inputs.aws-role-arn }} | ||
| aws-region: ${{ inputs.aws-region }} | ||
|
|
||
| - name: Terraform ${{ inputs.command }} | ||
| shell: bash | ||
| env: | ||
| ROOT: ${{ inputs.root }} | ||
| APPLY: ${{ inputs.apply }} | ||
| TFVARS: ${{ inputs.tfvars-file }} | ||
| COMMAND: ${{ inputs.command }} | ||
| # SCW_* and INFISICAL_MACHINE_IDENTITY_ID are inherited from the job env. | ||
| run: | | ||
| set -euo pipefail | ||
| ws="$(basename "$ROOT"/workspace/*.tfvars .tfvars)" | ||
| ws="${TFVARS%.tfvars}" | ||
| terraform -chdir="$ROOT" init -input=false | ||
| terraform -chdir="$ROOT" workspace select -or-create "$ws" | ||
| if [ "$APPLY" = "true" ]; then | ||
| terraform -chdir="$ROOT" apply -auto-approve -input=false -var-file="workspace/$ws.tfvars" | ||
| # apply may target a brand-new env whose workspace doesn't exist yet; | ||
| # read paths (plan/destroy) select an existing one. | ||
| if [ "$COMMAND" = "apply" ]; then | ||
| terraform -chdir="$ROOT" workspace select -or-create "$ws" | ||
| else | ||
| terraform -chdir="$ROOT" plan -input=false -var-file="workspace/$ws.tfvars" | ||
| terraform -chdir="$ROOT" workspace select "$ws" | ||
| fi | ||
| case "$COMMAND" in | ||
| plan) terraform -chdir="$ROOT" plan -input=false -var-file="env/${TFVARS}" ;; | ||
| apply) terraform -chdir="$ROOT" apply -input=false -auto-approve -var-file="env/${TFVARS}" ;; | ||
| destroy) terraform -chdir="$ROOT" destroy -input=false -auto-approve -var-file="env/${TFVARS}" ;; | ||
| *) echo "::error::unknown command '$COMMAND' (expected plan|apply|destroy)"; exit 1 ;; | ||
| esac | ||
This file contains hidden or 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 |
|---|---|---|
| @@ -1,75 +1,57 @@ | ||
| name: Apply Terraform Backend Role | ||
|
|
||
| # Terraform GitOps for the 00-remote_state/1-iam/ root: the org-wide S3 state | ||
| # access role is created/synchronised from remote. Plans on PR, applies on push | ||
| # to main. Credentials come from the identity/00-ci-trust CI role assumed via | ||
| # OIDC — no static AWS keys. | ||
| # Terraform GitOps for the 00-remote_state/1-iam/ root: the org-wide state-access | ||
| # role is created/synchronised from remote via the .github/actions/terraform | ||
| # composite action. Plans on PR, applies on push to main. Credentials come from | ||
| # the identity/00-ci-trust CI role assumed via OIDC — no static AWS keys. | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - '00-remote_state/1-iam/**' | ||
| - '.github/actions/terraform/**' | ||
| - '.github/workflows/iam_terraform-backend-role.yml' | ||
| pull_request: | ||
| paths: | ||
| - '00-remote_state/1-iam/**' | ||
| - '.github/actions/terraform/**' | ||
| - '.github/workflows/iam_terraform-backend-role.yml' | ||
|
|
||
| concurrency: | ||
| group: tf-backend-role-${{ github.ref }} | ||
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| terraform: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 15 | ||
| permissions: | ||
| id-token: write # mint the OIDC token exchanged for temporary AWS creds | ||
| contents: read | ||
| steps: | ||
| # Fail fast and clearly if creds aren't set, instead of letting the | ||
| # tooling emit a confusing assume-role error. | ||
| - name: Assert credentials are present | ||
| - name: Assert state role ARN is present | ||
| env: | ||
| ROLE_ARN: ${{ vars.AWS_GITHUB_ACTIONS_ROLE_ARN }} | ||
| run: | | ||
| if [ -z "$ROLE_ARN" ]; then | ||
| echo "::error::vars.AWS_GITHUB_ACTIONS_ROLE_ARN is not set. Set it to the github-actions-terraform role ARN (provisioned by identity/00-ci-trust/)." | ||
| echo "::error::vars.AWS_GITHUB_ACTIONS_ROLE_ARN is not set (provisioned by identity/00-ci-trust/)." | ||
| exit 1 | ||
| fi | ||
|
|
||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| with: | ||
| persist-credentials: false | ||
| fetch-depth: 1 | ||
|
|
||
| - uses: hashicorp/setup-terraform@b9cd54a3c349d3f38e8881555d616ced269862dd # v3.1.2 | ||
| with: | ||
| # Keep in sync with mise.toml [tools] terraform version. | ||
| terraform_version: "1.14" | ||
|
|
||
| - name: Assume the CI role via OIDC | ||
| uses: aws-actions/configure-aws-credentials@7474bc4690e29a8392af63c5b98e7449536d5c3a # v4.3.1 | ||
| - uses: ./.github/actions/terraform | ||
| with: | ||
| role-to-assume: ${{ vars.AWS_GITHUB_ACTIONS_ROLE_ARN }} | ||
| aws-region: eu-west-3 | ||
|
|
||
| - name: Terraform plan | ||
| if: github.event_name == 'pull_request' | ||
| env: | ||
| TF_CHDIR: "00-remote_state/1-iam" | ||
| TF_ENVIRONMENT: "00-remote-state-iam.tfvars" | ||
| run: | | ||
| set -euo pipefail | ||
| terraform -chdir="${TF_CHDIR}" init -input=false | ||
| terraform -chdir="${TF_CHDIR}" workspace select "${TF_ENVIRONMENT%.*}" | ||
| terraform -chdir="${TF_CHDIR}" plan -input=false -var-file="env/${TF_ENVIRONMENT}" | ||
|
|
||
| - name: Terraform apply | ||
| if: github.event_name == 'push' | ||
| env: | ||
| TF_CHDIR: "00-remote_state/1-iam" | ||
| TF_ENVIRONMENT: "00-remote-state-iam.tfvars" | ||
| run: | | ||
| set -euo pipefail | ||
| terraform -chdir="${TF_CHDIR}" init -input=false | ||
| terraform -chdir="${TF_CHDIR}" workspace select "${TF_ENVIRONMENT%.*}" | ||
| terraform -chdir="${TF_CHDIR}" apply -auto-approve -input=false -var-file="env/${TF_ENVIRONMENT}" | ||
| root: 00-remote_state/1-iam | ||
| tfvars-file: 00-remote-state-iam.tfvars | ||
| aws-role-arn: ${{ vars.AWS_GITHUB_ACTIONS_ROLE_ARN }} | ||
| command: ${{ github.event_name == 'push' && 'apply' || 'plan' }} | ||
| # This root touches neither Infisical nor Scaleway — skip the OIDC mint. | ||
| infisical-oidc-audience: "" |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.