Note
GitHub Action to plan and apply OpenTofu/Terraform (TF) via pull request (PR) automation.
Overview: Highlights · Usage · Parameters · Security · Changelog · License
Screenshot of PR comment example with multiple command arguments.
Configure OpenTofu/Terraform to run multiple commands automatically via PR trigger events.
- Both Hashicorp
terraform
and OpenTofutofu
CLIs are supported, with the latter offering an open-source and backwards-compatible drop-in replacement for the former. - Prerequisite commands like
init
are run automatically, along with user-configurable options for workspace, var-file, backend-config, and more. - Multiple TF commands can be run in parallel across different workspaces, directories, or files with matrix strategy.
Retrieve TF plan file for apply, cache TF module plugins, and dynamically substitute input variables.
- Store TF plan file as a repository artifact for later reference or for use in subsequent TF
apply
ordestroy
commands. - Use ".terraform.lock.hcl" file (which should be included in version control) to cache TF plugins and associated dependencies for faster subsequent workflow runs.
Best suited for DevOps and Platform engineers wanting to empower their teams to self-service scalably.
- Each PR and associated workflow run holds a complete log of infrastructure changes for ease of collaborative debugging as well as audit compliance.
- Removes the overhead of needing to maintain dedicated TF runners, containers or VMs like Atlantis.
on:
pull_request:
push:
branches: [main]
jobs:
tf:
runs-on: ubuntu-latest
permissions:
actions: read # Required to download repository artifact.
checks: write # Required to add status summary.
contents: read # Required to checkout repository.
pull-requests: write # Required to add PR comment and label.
steps:
- uses: actions/checkout@v4
- uses: opentofu/setup-opentofu@v1
- uses: devsectop/tf-via-pr@v11
with:
arg_chdir: sample/directory/path
arg_command: ${{ github.event_name == 'push' && 'apply' || 'plan' }}
arg_lock: ${{ github.event_name == 'push' && 'true' || 'false' }}
arg_var_file: env/dev.tfvars
arg_workspace: development
Tip
- Pin your workflow version to a specific release tag or SHA to harden your CI/CD pipeline security against supply chain attacks.
- Environment variables can be passed in for cloud provider authentication (e.g., aws-actions/configure-aws-credentials action can be used for short-lived credentials).
The following functional workflow examples demonstrate common use-cases, while a comprehensive list of inputs is documented below.
- Trigger on
pull_request
(plan) andpush
(apply) events with Terraform and AWS authentication. - Trigger on
pull_request
(plan) andmerge_group
(apply) events with OpenTofu in matrix strategy. - Trigger on
pull_request
(plan or apply) event with tenv to avoid TF wrapper on self-hosted runners.
Before the workflow uploads the TF plan file as an artifact, it can be encrypted with a passphrase to prevent exposure of sensitive data using encrypt_passphrase
input with a secret (e.g., ${{ secrets.KEY }}
). This is done with OpenSSL's symmetric stream counter mode encryption with salt and pbkdf2.
In order to locally decrypt the TF plan file, use the following command (noting the whitespace prefix to prevent recording the command in shell history):
openssl enc -aes-256-ctr -pbkdf2 -salt -in <tfplan> -out <tfplan.decrypted> -pass pass:<passphrase> -d
Name | Description |
---|---|
cache_plugins Default: false |
Boolean flag to cache TF plugins for faster workflow runs (requires .terraform.lock.hcl file). |
comment_pr Default: true |
Boolean flag to add PR comment of TF command output. |
encrypt_passphrase Example: ${{ secrets.KEY }} |
String passphrase to encrypt the TF plan file. |
fmt_enable Default: true |
Boolean flag to enable TF fmt command and display diff of changes. |
label_pr Default: true |
Boolean flag to add PR label of TF command to run. |
outline_enable Default: true |
Boolean flag to add an outline diff of TF plan file. |
tf_tool Default: terraform |
String name of the TF tool to use and override default assumption from wrapper environment variable. |
tf_version Example: ~> 1.8.0 |
String version constraint of the TF tool to install and use. |
update_comment Default: false |
Boolean flag to update existing PR comment instead of creating a new comment and deleting the old one. |
validate_enable Default: false |
Boolean flag to enable TF validate command check. |
Name | Description |
---|---|
arg_auto_approve |
Boolean flag to toggle skipping of interactive approval of plan before applying. |
arg_backend |
Boolean flag to toggle TF backend initialization. |
arg_backend_config |
Comma-separated string list of file path(s) to the backend configuration. |
arg_backup |
Boolean flag to toggle backup of the existing state file before modifying. |
arg_chdir |
String path to the working directory where the TF command should be run. |
arg_check |
Boolean flag to toggle checking of file formatting with appropriate exit code. |
arg_cloud |
Boolean flag to toggle TF backend initialization. |
arg_command Default: plan |
String name of the TF command to run (either 'plan' or 'apply'). |
arg_compact_warnings |
Boolean flag to toggle compact output for warnings. |
arg_concise |
Boolean flag to toggle skipping of refresh log lines. |
arg_destroy |
Boolean flag to toggle destruction of all managed objects. |
arg_detailed_exitcode |
String to set the detailed exit code mode. |
arg_diff Default: true |
Boolean flag to toggle display diff of formatting changes. |
arg_force_copy |
Boolean flag to toggle suppression of prompts about copying state data. |
arg_from_module |
String path to copy contents from the given module source into the target directory. |
arg_generate_config_out |
String path to write the generated configuration. |
arg_get |
Boolean flag to toggle downloading of modules for the configuration. |
arg_ignore_remote_version |
Boolean flag to toggle checking if the local and remote TF versions use compatible state representations. |
arg_json |
Boolean flag to toggle JSON output format. |
arg_list Default: false |
Boolean flag to toggle listing of files whose formatting differs. |
arg_lock |
Boolean flag to toggle state locking during state operations. |
arg_lock_timeout |
String duration to retry a state lock. |
arg_lockfile |
String to set dependency lockfile mode. |
arg_migrate_state |
Boolean flag to toggle reconfiguration of the backend, attempting to migrate any existing state. |
arg_no_tests |
Boolean flag to toggle validation of test files. |
arg_or_create |
Boolean flag to toggle workspace creation if it doesn't exist. |
arg_out Default: tfplan |
String path to write the generated plan. |
arg_parallelism |
String number to limit the number of concurrent operations. |
arg_plugin_dir |
Comma-separated string list of directory path(s) containing plugin binaries. |
arg_reconfigure |
Boolean flag to toggle reconfiguration of the backend, ignoring any saved configuration. |
arg_recursive Default: true |
Boolean flag to toggle recursive processing of directories. |
arg_refresh |
Boolean flag to skip checking of external changes to remote objects. |
arg_refresh_only |
Boolean flag to toggle checking of remote objects still match the current configuration without proposing any actions to undo external changes. |
arg_replace |
Comma-separated string list of resource addresses to replace. |
arg_state |
String path to read and save state. |
arg_state_out |
String path to write state. |
arg_target |
Comma-separated string list of resource addresses to target. |
arg_test_directory |
String path to the test directory. |
arg_upgrade |
Boolean flag to toggle upgrading the latest module and provider versions allowed within configured constraints. |
arg_var |
Comma-separated string list of variables to set in the format 'key=value'. |
arg_var_file |
Comma-separated string list of file path(s) to the variable configuration. |
arg_workspace |
String name of the workspace to select or create. |
arg_write Default: false |
Boolean flag to toggle writing of formatted files. |
Name | Description |
---|---|
check_id |
String output of the workflow check run ID. |
comment_id |
String output of the PR comment ID. |
fmt_result |
String output of the TF fmt command. |
header |
String output of the TF command input. |
identifier |
String output of the TF run's unique identifier. |
last_result |
String output of the last TF command. |
outline |
String outline of the TF plan. |
summary |
String summary of the last TF command. |
Integrating security in your CI/CD pipeline is critical to practicing DevSecOps. This action aims to be secure by default, and it should be complemented with your own review to ensure it meets your (organization's) security requirements.
- Action dependencies are maintained by GitHub and pinned to a specific SHA: actions/cache, actions/github-script and actions/upload-artifact.
- Restrict changes to certain environments with deployment protection rules so that approval is required before changes to the infrastructure can be applied.
- Ease of integration with OpenID Connect by passing short-lived credentials as environment variables to the workflow.
- All notable changes to this project are documented in human-friendly releases.
- The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Tip
All forms of contribution are very welcome and deeply appreciated for fostering open-source projects.
- Please create a PR to contribute changes you'd like to see.
- Please raise an issue to discuss proposed changes or report unexpected behavior.
- Please open a discussion to share ideas about where you'd like to see this project go.
- Please consider becoming a stargazer if you find this project useful.
This project includes a GitHub Codespaces container for a tailored TF development environment, complete with tools and runtimes to lower the barrier to entry for contributors.
- This project is licensed under the permissive Apache License 2.0.
- All works herein are my own, shared of my own volition, and contributors.
- Copyright 2022-2024 Rishav Dhar — All wrongs reserved.