GitHub Action: atmos-terraform-apply
This Github Action is used to run Terraform apply for a single, Atmos-supported component with a saved planfile in S3 and DynamoDB.
Introduction
This Github Action is used to run Terraform apply for a single, Atmos-supported component with a saved planfile in S3 and DynamoDB.
Before running this action, first create and store a planfile with the companion action, github-action-atmos-terraform-plan.
For more, see Atmos GitHub Action Integrations
Usage
Prerequisites
This GitHub Action requires AWS access for two different purposes. This action will attempt to first pull a Terraform planfile from a S3 Bucket with metadata in a DynamoDB table with one role.
Then the action will run terraform apply against that component with another role. We recommend configuring
OpenID Connect with AWS
to allow GitHub to assume roles in AWS and then deploying both a Terraform Apply role and a Terraform State role.
For Cloud Posse documentation on setting up GitHub OIDC, see our github-oidc-provider component.
In order to retrieve Terraform Plan Files (not to be confused with Terraform State files, e.g. tfstate), we configure an S3 Bucket to store plan files and a DynamoDB table to track plan metadata. Both need to be deployed before running
this action. For more on setting up those components, see the gitops component. This action will then use the github-action-terraform-plan-storage action to update these resources.
Config
Please note! This GitHub Action only works with atmos >= 1.186.0.
If you are using atmos >= 1.158.0, < 1.186.0 please use v4 version of this action.
If you are using atmos >= 1.99.0, < 1.158.0 please use v3 version of this action.
If you are using atmos >= 1.63.0, < 1.99.0 please use v2 version of this action.
If you are using atmos < 1.63.0 please use v1 version of this action.
The action expects the atmos configuration file atmos.yaml to be present in the repository.
The action supports AWS and Azure to store Terraform plan files.
You can read more about plan storage in the cloudposse/github-action-terraform-plan-storage documentation.
Depends of cloud provider the following fields should be set in the atmos.yaml:
AWS
The config should have the following structure:
integrations:
github:
gitops:
opentofu-version: 1.7.3
terraform-version: 1.5.2
infracost-enabled: false
artifact-storage:
region: us-east-2
bucket: cptest-core-ue2-auto-gitops
table: cptest-core-ue2-auto-gitops-plan-storage
role: arn:aws:iam::xxxxxxxxxxxx:role/cptest-core-ue2-auto-gitops-gha
role:
plan: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops
# Set `apply` empty if you don't want to assume IAM role before terraform apply
apply: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops
matrix:
sort-by: .stack_slug
group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-")
Azure
The config should have the following structure:
integrations:
github:
gitops:
opentofu-version: 1.7.3
terraform-version: 1.5.2
infracost-enabled: false
artifact-storage:
plan-repository-type: azureblob
blob-account-name: tfplans
blob-container-name: plans
metadata-repository-type: cosmos
cosmos-container-name: terraform-plan-storage
cosmos-database-name: terraform-plan-storage
cosmos-endpoint: "https://my-cosmo-account.documents.azure.com:443/"
# We remove the `role` section as it is AWS specific
matrix:
sort-by: .stack_slug
group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-")
Stack level configuration
Wherever it is possible to specify integration.github.gitops on stack level
it is required to define default values in atmos.yaml
It is possible to override integration settings on a stack level by defining settings.integrations.
components:
terraform:
foobar:
settings:
integrations:
github:
gitops:
artifact-storage:
bucket: cptest-plat-ue2-auto-gitops
table: cptest-plat-ue2-auto-gitops-plan-storage
role: arn:aws:iam::xxxxxxxxxxxx:role/cptest-plat-ue2-auto-gitops-gha
role:
# Set `plan` empty if you don't want to assume IAM role before terraform plan
plan: arn:aws:iam::yyyyyyyyyyyy:role/cptest-plat-gbl-identity-gitops
apply: arn:aws:iam::yyyyyyyyyyyy:role/cptest-plat-gbl-identity-gitops
Support OpenTofu
This action supports OpenTofu.
Please note! OpenTofu supported by Atmos >= 1.73.0.
For details read
To enable OpenTofu add the following settings to atmos.yaml
- Set the
opentofu-versionin theatmos.yamlto the desired version - Set
components.terraform.commandtotofu
Example
components:
terraform:
command: tofu
...
integrations:
github:
gitops:
opentofu-version: 1.7.3
...
Workflow example
In this example, the action is triggered when certain events occur, such as a manual workflow dispatch or the opening, synchronization, or reopening of a pull request, specifically on the main branch. It specifies specific permissions related to assuming roles in AWS. Within the "apply" job, the "component" and "stack" are hardcoded (foobar and plat-ue2-sandbox). In practice, these are usually derived from another action.
We recommend combining this action with the affected-stacks GitHub Action inside a matrix to plan all affected stacks in parallel.
name: "atmos-terraform-apply"
on:
workflow_dispatch:
pull_request:
types:
- closed
branches:
- main
# These permissions are required for GitHub to assume roles in AWS
permissions:
id-token: write
contents: read
jobs:
apply:
runs-on: ubuntu-latest
steps:
- name: Terraform Apply
uses: cloudposse/github-action-atmos-terraform-apply@v5
with:
component: "foobar"
stack: "plat-ue2-sandbox"
atmos-config-path: ./rootfs/usr/local/etc/atmos/
Migrating from v4 to v5
The notable changes in v5 are:
v5works only withatmos >= 1.186.0v5usesatmos terraform plan-diffto ensure changes to be applied are consistent with the stored (approved by the user) planfile.
Migrating from v3 to v4
The notable changes in v4 are:
v4works only withatmos >= 1.158.0v4supports atnostemplatesandfunctions
Migrating from v2 to v3
The notable changes in v3 are:
v3works only withatmos >= 1.99.0v3support azure plan and metadata storagev3supports stack level integration gitops settingsv3allow to skip internal checkout withskip-checkoutinput
The only required migration step is updating atmos version to >= 1.99.0
Migrating from v1 to v2
The notable changes in v2 are:
v2works only withatmos >= 1.63.0v2dropsinstall-terraforminput because terraform is not required for affected stacks callv2dropsatmos-gitops-config-pathinput and the./.github/config/atmos-gitops.yamlconfig file. Now you have to use GitHub Actions environment variables to specify the location of theatmos.yaml.
The following configuration fields now moved to GitHub action inputs with the same names
| name |
|---|
atmos-version |
atmos-config-path |
The following configuration fields moved to the atmos.yaml configuration file.
| name | YAML path in atmos.yaml |
|---|---|
aws-region | integrations.github.gitops.artifact-storage.region |
terraform-state-bucket | integrations.github.gitops.artifact-storage.bucket |
terraform-state-table | integrations.github.gitops.artifact-storage.table |
terraform-state-role | integrations.github.gitops.artifact-storage.role |
terraform-plan-role | integrations.github.gitops.role.plan |
terraform-apply-role | integrations.github.gitops.role.apply |
terraform-version | integrations.github.gitops.terraform-version |
enable-infracost | integrations.github.gitops.infracost-enabled |
sort-by | integrations.github.gitops.matrix.sort-by |
group-by | integrations.github.gitops.matrix.group-by |
For example, to migrate from v1 to v2, you should have something similar to the following in your atmos.yaml:
./.github/config/atmos.yaml
# ... your existing configuration
integrations:
github:
gitops:
terraform-version: 1.5.2
infracost-enabled: false
artifact-storage:
region: us-east-2
bucket: cptest-core-ue2-auto-gitops
table: cptest-core-ue2-auto-gitops-plan-storage
role: arn:aws:iam::xxxxxxxxxxxx:role/cptest-core-ue2-auto-gitops-gha
role:
plan: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops
apply: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops
matrix:
sort-by: .stack_slug
group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-")
.github/workflows/main.yaml
- name: Plan Atmos Component
uses: cloudposse/github-action-atmos-terraform-apply@v2
with:
component: "foobar"
stack: "plat-ue2-sandbox"
atmos-config-path: ./rootfs/usr/local/etc/atmos/
atmos-version: 1.63.0
This corresponds to the v1 configuration (deprecated) below.
The v1 configuration file ./.github/config/atmos-gitops.yaml looked like this:
atmos-version: 1.45.3
atmos-config-path: ./rootfs/usr/local/etc/atmos/
terraform-state-bucket: cptest-core-ue2-auto-gitops
terraform-state-table: cptest-core-ue2-auto-gitops
terraform-state-role: arn:aws:iam::xxxxxxxxxxxx:role/cptest-core-ue2-auto-gitops-gha
terraform-plan-role: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops
terraform-apply-role: arn:aws:iam::yyyyyyyyyyyy:role/cptest-core-gbl-identity-gitops
terraform-version: 1.5.2
aws-region: us-east-2
enable-infracost: false
sort-by: .stack_slug
group-by: .stack_slug | split("-") | [.[0], .[2]] | join("-")
And the v1 GitHub Action Workflow looked like this.
.github/workflows/main.yaml
- name: Plan Atmos Component
uses: cloudposse/github-action-atmos-terraform-apply@v1
with:
component: "foobar"
stack: "plat-ue2-sandbox"
atmos-gitops-config-path: ./.github/config/atmos-gitops.yaml
Migrating from v0 to v1
v1drops thecomponent-pathvariable and instead fetches if directly from theatmos.yamlfile automatically. Simply remove thecomponent-pathargument from your invocations of thecloudposse/github-action-atmos-terraform-applyaction.v1moves most of theinputsto the Atmos GitOps config path./.github/config/atmos-gitops.yaml. Simply create this file, transfer your settings to it, then remove the corresponding arguments from your invocations of thecloudposse/github-action-atmos-terraform-applyaction.
| name |
|---|
atmos-version |
atmos-config-path |
terraform-state-bucket |
terraform-state-table |
terraform-state-role |
terraform-plan-role |
terraform-apply-role |
terraform-version |
aws-region |
enable-infracost |
If you want the same behavior in v1 as in v0 you should create config ./.github/config/atmos-gitops.yaml with the same variables as in v0 inputs.
- name: Terraform apply
uses: cloudposse/github-action-atmos-terraform-apply@v1
with:
atmos-gitops-config-path: ./.github/config/atmos-gitops.yaml
component: "foobar"
stack: "plat-ue2-sandbox"
Which would produce the same behavior as in v0, doing this:
- name: Terraform apply
uses: cloudposse/github-action-atmos-terraform-apply@v0
with:
component: "foobar"
stack: "plat-ue2-sandbox"
component-path: "components/terraform/s3-bucket"
terraform-apply-role: "arn:aws:iam::111111111111:role/acme-core-gbl-identity-gitops"
terraform-state-bucket: "acme-core-ue2-auto-gitops"
terraform-state-role: "arn:aws:iam::999999999999:role/acme-core-ue2-auto-gitops-gha"
terraform-state-table: "acme-core-ue2-auto-gitops"
aws-region: "us-east-2"
Inputs
| Name | Description | Default | Required |
|---|---|---|---|
| atmos-config-path | The path to the atmos.yaml file | N/A | true |
| atmos-version | The version of atmos to install | >= 1.186.0 | false |
| branding-logo-image | Branding logo image url | https://cloudposse.com/logo-300x69.svg | false |
| branding-logo-url | Branding logo url | https://cloudposse.com/ | false |
| component | The name of the component to apply. | N/A | true |
| debug | Enable action debug mode. Default: 'false' | false | false |
| infracost-api-key | Infracost API key | N/A | false |
| plan-storage | Enable plan storage. Default: 'true'. Set to 'false' to disable plan storage. | true | false |
| sha | Commit SHA to apply. Default: github.sha | ${{ github.event.pull_request.head.sha }} | true |
| skip-checkout | Disable actions/checkout. Useful for when the checkout happens in a previous step and file are modified outside of git through other actions | false | false |
| stack | The stack name for the given component. | N/A | true |
| token | Used to pull node distributions for Atmos from Cloud Posse's GitHub repository. Since there's a default, this is typically not supplied by the user. When running this action on github.com, the default value is sufficient. When running on GHES, you can pass a personal access token for github.com if you are experiencing rate limiting. | ${{ github.server_url == 'https://github.com' && github.token || '' }} | false |
Outputs
| Name | Description |
|---|---|
| status | Apply Status. Either 'succeeded' or 'failed' |