logo generated with https://www.freepik.com/ai/images

Image generated with https://www.freepik.com/ai/images

TerraApprove

TerraApprove is a tool that can be integrated in a CI/CD pipeline and can be used to reduce the risk of applying a Terraform plan that can cause undesired changes. All the resources that require special attention (e.g. stateful resources) can be tagged with a decorator. TerraApprove will then check if the plan contains any of these resources and will produce an output that can be used to decide if the plan can be applied with -auto-approve or if manual approval is required.

:warning: It’s up to the user to implement the necessary logic to ask the user for approval.

A GitHub Action is also provided to simplify the integration in a GitHub workflow. See here for more details.

Usage

  1. You need a Terraform code base and the relative Terraform plan. The Terraform plan must be in JSON format.

    cd examples/simple
    terraform init
    terraform plan -out=tfplan
    terraform show -json tfplan > tfplan.json
    
  2. Run the application specifying the path to the Terraform codebase & plan.

    terraapprove ./examples/simple ./examples/simple/tfplan.json
    
  3. Inspect the exit code to know if the plan can be applied with -auto-approve or if a manual approval is required.

Operating modes

The application supports two operating modes:

  • Standard mode, this is the default mode.
  • Safe to apply mode, can be enabled using the flag --reverse.

Standard mode

In this mode, all the resources are considered safe to apply by default except the ones that are tagged with RequireApproval or are specified in the global rules.

Safe to apply mode

In this mode, all the resources are considered unsafe by default to apply except the ones that are tagged with SafeToApply or are specified in the global rules.

RequireApproval decorator

The RequireApproval decorator can be used to mark a resource that requires manual approval. The decorator can be used as follows:

# RequireApproval()
resource "aws_instance" "example" {
  ...
}

:memo: The decorator must be placed between the previous resource (the line following the closing bracket } ) and the declaration of resource that must be protected. The decorator can be used on any resource type or modules (expect for data).

Decorator arguments

The decorator accepts arguments to customize the behavior. The arguments are specified as a JSON object. The following arguments are supported:

Argument Description If not set
matchActions A list of actions that must be matched for the decorator to be applied. The possible values are CREATE, UPDATE_IN_PLACE, DELETE. All actions require approval

Example:

# RequireApproval({ matchActions: ["CREATE"]})
resource "aws_instance" "example" {
  ...
}

How to handle approval for deleted resources

Deleted resources might not be part of the code base, hence we need another way to protect them. These resources can be protected specifying the fully qualified address in a file named .terraapprove.yaml. The file must be placed in the root folder of the codebase.

requireApproval:
  - fullyQualifiedAddress: "null_resource.do_nothing_2"
    actions: ["DELETE"]

SafeToApply decorator

The SafeToApply decorator can be used to mark a resource that is safe to apply. If the resource is found in the plan, the application will not consider it as a resource that requires approval. If the plan contains only resources that are safe to apply, the application will exit with code 0. This might be useful if the code base contains resource that changes often and even if they are misconfigured do not produce any harm.

The decorator can be used as follows:

# SafeToApply()
resource "aws_instance" "example" {
  ...
}

Decorator arguments

The decorator accepts arguments to customize the behavior. The arguments are specified as a JSON object. The following arguments are supported:

Argument Description If not set
matchActions A list of actions that must be matched for the decorator to be applied. The possible values are CREATE, UPDATE_IN_PLACE, DELETE. All actions are safe to apply

Example:

# SafeToApply({ matchActions: ["CREATE"]})
resource "aws_instance" "example" {
  ...
}

Global rules

The application supports global rules that affect all the resources in the code base without the need to mark all the resources with a decorator. The rules must be added to the .terraapprove.yaml file in the root folder of the codebase.

The supported rules are:

  • matching a list of actions
  • matching a list of provider types

A set of predefined configurations is available here. The description of the predefined configurations is available here.

Matching actions in standard mode

When using the standard mode, the requireApproval.allResource.actions parameter can be used to specify the list of actions that always require approval. If in the plan there is at least one resource that specify on the action listed in the parameter, the application will exit with code 1 indicating that an approval is required.

.terraapprove.yaml

global:
  requireApproval:
    allResources:
      actions: # Supported values are "CREATE", "UPDATE_IN_PLACE", "DELETE"
        - "DELETE"

Matching actions in safe to apply mode

When using the safe to apply mode, the safeToApply.allResource.actions parameter can be used to specify the list of actions that are always safe to apply. If in the plan there are only resources that specify the action listed in the parameter, the application will exit with code 0 indicating that the plan can be applied with -auto-approve.

.terraapprove.yaml

global:
  safeToApply:
    allResources:
      actions: # Supported values are "CREATE", "UPDATE_IN_PLACE", "DELETE"
        - "CREATE"

Matchers in standard mode

When using the standard mode, the requireApproval.allResources.matchers parameter can be used to specify matching rules to identify resources impacted in the plan. If a resource is matched, the tool the application will exit with code 1 indicating that an approval is required. The matcher accepts a providerType and optionally a list of actions. If the list of actions is not specified, all the actions are matched automatically.

.terraapprove.yaml

global:
  requireApproval:
    allResources:
      matchers:
        - providerType: "google_storage_bucket"
          actions: ["DELETE"]

Matchers in safe to apply mode

When using the safe to apply mode, the safeToApply.allResources.matchers parameter can be used to specify matching rules to identify resources impacted in the plan. If in the plan there are only resources that have been matched (including resources matched via decorators), the application will exit with code 0 indicating that an approval is not required.

.terraapprove.yaml

global:
  safeToApply:
    allResources:
      matchers:
        - providerType: "google_storage_bucket"
          actions: ["CREATE"]

Alternatives

This is a list of alternative tools (definitely more mature than TerraApprove) that can be used to achieve the same (or similar) results:

  • https://www.openpolicyagent.org/docs/latest/terraform/
  • https://www.runatlantis.io/