Skip to content

v4.9.0-2

Pre-release
Pre-release
Compare
Choose a tag to compare
@github-actions github-actions released this 26 Jan 13:51
· 466 commits to main since this release
v4.9.0-2
56dfca4

v4.8.0...v4.9.0-2

Changes from v4.9.0-1

56dfca4 fix(mask): Change the default separator from ; to ,

Features

#1083 #1115 support masking secrets

You can mask secrets in outputs of terraform.
This feature prevents the leak of secrets.

The following outputs are masked.

Caution

Even if you maske secrets using this feature, secrets are still stored in Terraform States.
Please see also Sensitive Data in State.

You can use environment variables TFCMT_MASKS and TFCMT_MASKS_SEPARATOR.

  • TFCMT_MASKS: A list of masks. Masks are joined by TFCMT_MASKS_SEPARATOR
  • TFCMT_MASKS_SEPARATOR: A separator of masks. The default value is ,

The format of each mask is ${type}:${value}.
${type} must be either env or regexp.
If ${type} is env, ${value} is a masked environment variable name.
If ${type} is regexp, ${value} is a masked regular expression.

e.g. Mask GitHub access tokens and the environment variable DATADOG_API_KEY.

export TFCMT_MASKS="env:GITHUB_TOKEN,env:DATADOG_API_KEY,regexp:ghp_[^ ]+"
tfcmt plan -- terraform plan

e.g. Change the separator to /.

export TFCMT_MASKS_SEPARATOR=/
export TFCMT_MASKS="env:GITHUB_TOKEN/env:DATADOG_API_KEY/regexp:ghp_[^ ]+"

All matching strings are replaced with ***.
Replacements are done in order of TFCMT_MASKS, so the result depends on the order of TFCMT_MASKS.
For example, if TFCMT_MASKS is regexp:foo,regexp:foo.*, regexp:foo.* has no meaning because all foo are replaced with *** before replacing foo.* with *** so foo.* doesn't match with anything.

Example

This example creates a resource google_cloudbuild_trigger.
This resource has a GitHub Access token as a field substitutions._GH_TOKEN.

main.tf

resource "google_cloudbuild_trigger" "filename_trigger" {
  location = "us-central1"

  trigger_template {
    branch_name = "main"
    repo_name   = "my-repo"
  }

  substitutions = {
    _GH_TOKEN = var.gh_token # Secret
  }

  filename = "cloudbuild.yaml"
}

variable "gh_token" {
  type        = string
  description = "GitHub Access token"
}

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "5.13.0"
    }
  }
}

If you run terraform plan without masking, the secret would be leaked.
To prevent the leak, let's mask the secret.

export TFCMT_MASKS=env:TF_VAR_gh_token # Mask the environment variable TF_VAR_gh_token

Please see _GH_TOKEN in the output of tfcmt plan and the pull request comment.
You can confirm _GH_TOKEN is masked as *** properly.

$ tfcmt plan -- terraform plan
tfcmt plan -- terraform plan

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # google_cloudbuild_trigger.filename_trigger will be created
  + resource "google_cloudbuild_trigger" "filename_trigger" {
      + create_time   = (known after apply)
      + filename      = "cloudbuild.yaml"
      + id            = (known after apply)
      + location      = "us-central1"
      + name          = (known after apply)
      + project       = "hello"
      + substitutions = {
          + "_GH_TOKEN" = "***"
        }
      + trigger_id    = (known after apply)

      + trigger_template {
          + branch_name = "main"
          + project_id  = (known after apply)
          + repo_name   = "my-repo"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't
guarantee to take exactly these actions if you run "terraform apply" now.

image