Terraform's sensitive flag is metadata that controls how values are displayed; it is not encryption. Output to the CLI is masked, but the most important fact to remember is that the value is still stored in state.
The Associate exam loves to test masking behavior, what lives in state, and when to reach for outputs vs. functions. In practice, terraform output -json, verbose logs, and CI handling are where teams most often slip up.
Setting sensitive = true on a variable or output masks the value in human-facing terraform plan/apply and terraform output. This is a display control to reduce exposure; it does not encrypt or remove the value.
The key point is that the value is persisted in Terraform state. Local state is kept as plaintext-ish JSON, and remote backends do not encrypt at the application layer either (they rely on backend-side encryption and access control).
Where sensitive values flow and where they get masked
# terraform output (human-facing) → shown masked
# terraform output -json → value is included, but with "sensitive": true flagBasic definition: marking variables and outputs as sensitive
variable "db_password" {
type = string
sensitive = true
}
# Mark the output as sensitive too
output "db_password_masked" {
value = var.db_password
sensitive = true
}
# Interactive prompts do not echo the value, and plan/apply mask itTerraform tangles together the variable/output sensitive attribute, the sensitive()/nonsensitive() functions, and the Sensitive attribute on the provider-side schema. Combining them correctly depending on the goal is what matters.
In particular, when you want to treat a value built up inside an expression (such as a local or template result) as sensitive, tag it explicitly with the sensitive() function. Only strip the flag with nonsensitive() when you genuinely intend to expose the value via an output.
| Feature | Primary purpose | CLI display / output | Stored in state |
|---|---|---|---|
| variable sensitive | Mask input values | Hides value on plan/apply; no echo on prompt | Value is stored |
| output sensitive | Mask output values | Shown masked by terraform output | Value is stored |
| sensitive()/nonsensitive() | Tag or untag an expression as sensitive | Affects human-facing display (mask or expose) | Value is stored |
| Provider-side Sensitive attribute | Schema-level secrecy | Suppresses appearance in plan diffs and logs | Value is stored |
Example: using the functions appropriately
locals {
raw = "user"
secret = sensitive("p@ssw0rd")
combined = "${local.raw}:${local.secret}" # combined inherits sensitive
published = nonsensitive(local.secret) # explicitly exposed (use sparingly)
}
output "combined_masked" {
value = local.combined
sensitive = true
}
# Only use nonsensitive() when exposure is genuinely required
output "published_plain" {
value = local.published
sensitive = false
}Human-facing terraform plan/apply and terraform output mask sensitive values. terraform console shows (sensitive value) by default and keeps the value hidden until you explicitly expose it with nonsensitive().
terraform output -json is designed for automation: it includes the actual value in the JSON while adding a "sensitive": true flag. Take extra care when piping the result into other tools.
CLI example (comments describe expected behavior)
# terraform console
> var.db_password
(sensitive value)
> nonsensitive(var.db_password)
"p@ssw0rd"
# terraform output
$ terraform output db_password_masked
sensitive
# terraform output -json (for automation; handle with care)
$ terraform output -json | jq '.db_password_masked'
{
"sensitive": true,
"type": "string",
"value": "p@ssw0rd" # value is included as expected; must be protected
}Terraform keeps each resource's final attribute values in state. Even sensitive values stay in state. Protect local state with file permissions, and for team use rely on a remote backend with proper encryption and access controls.
Backends such as S3, GCS, and Azure Storage support server-side encryption and KMS integration. Combine that with tight IAM, audit logs, and versioning or legal-hold features to limit the blast radius if something does leak.
S3 backend example (encryption and access control as baseline)
terraform {
backend "s3" {
bucket = "my-tf-state-bucket"
key = "env/prod/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true # enable SSE
kms_key_id = "arn:aws:kms:ap-northeast-1:123456789012:key/xxxx"
dynamodb_table = "tf-state-lock" # locking recommended
}
}
# Reference: state retains values like this (conceptual)
# {
# "resources": [
# {
# "type": "example_resource",
# "instances": [
# { "attributes": { "password": "p@ssw0rd" } }
# ]
# }
# ]
# }In CI, pass variables through TF_VAR_ environment variables or the CI's built-in secrets feature, and keep tfvars files out of the repository. Be especially careful with terraform output -json: mask values and restrict access so they do not leak through logs or artifacts.
Verbose logs (TF_LOG=DEBUG/TRACE) can accidentally include sensitive values. Enable them only temporarily, restrict the destination, and dispose of the output promptly.
GitHub Actions example (secrets and masking)
jobs:
plan:
runs-on: ubuntu-latest
env:
TF_VAR_db_password: ${{ secrets.DB_PASSWORD }}
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform init -input=false
- run: terraform plan -input=false -no-color
# If automation needs the value, take care: -json may include it; restrict the destination
- run: |
terraform output -json \
| jq -r '.db_password_masked.value' \
| awk '{print "::add-mask::" $0}' # mask before using it
Expressions that include a sensitive value generally propagate the sensitive flag. To avoid unintended exposure, mark outputs as sensitive and avoid reaching for nonsensitive(). Only fall back to nonsensitive() when the downstream consumer truly needs the plaintext.
Also, assigning a sensitive value to a non-sensitive output produces an error. That is an intentional safety net against implicit leaks.
Examples: blocking accidental exposure and intentionally exposing a value
# NG: assigning a sensitive value to a non-sensitive output (errors at plan time)
# output "leak" {
# value = var.db_password # var is sensitive=true
# sensitive = false
# }
# OK: keep it masked on output
output "db_password_safe" {
value = var.db_password
sensitive = true
}
# Explicit exposure (only when truly required)
output "db_password_plain" {
value = nonsensitive(var.db_password)
sensitive = false
}Associate
問題 1
Which statement correctly describes what happens when a Terraform variable is marked sensitive = true?
正解: A
sensitive controls display masking, not encryption. Human-facing CLI output is masked, but the value is stored in state, and encryption and access control are the backend's responsibility. There is no guarantee that the value is omitted from -json output or that providers will never log it either.
If I mark a variable sensitive, will it never appear in CI logs?
Human-facing Terraform output is masked, but values can still leak through -json output, third-party tool logs, or verbose logs (TF_LOG). In CI, combine a secrets store, masking rules, and restricted artifact publishing to keep values protected.
How do I remove a past password that is still recorded in state?
Fully erasing history is hard, so the standard answer is to rotate the credential. Drop any unneeded outputs and, if necessary, run terraform state rm to remove the resource from state and recreate it. Cleaning up versioned history on a remote backend depends on backend features such as deletion or legal-hold release.
Should I use the sensitive() function or the variable sensitive attribute?
Use the variable sensitive attribute for inputs, and the sensitive() function for computed or composed values (locals, template results, etc.). Only strip the flag with nonsensitive() when you explicitly need to expose the value through an output.
Practice with certification-focused question sets
無料で問題を解いてみるNicheeLab Editorial Team
NicheeLab editorial team focused on data engineering and cloud certification learning. Content is structured around practical study needs and official exam domains.
HCL Syntax: Terraform's Configuration Language (2026)
HCL2 fundamentals for Terraform — blocks, attributes, expres...
Terraform Authoring & Operations Pro: Complete Guide (2026)
Tactics for the Terraform Pro exam — module authoring, works...
Terraform Providers: Plugin Management Fundamentals (2026)
Provider mechanics — required_providers, versions, mirrors, ...
Terraform Resource Blocks: Declarative Infra Units (2026)
Resource block fundamentals — addresses, references, common ...
Terraform Data Sources: Read-Only External Data (2026)
Data source basics — declaration, refresh behavior, dependen...