Sửa lỗi Terraform 'Output refers to sensitive value' Khi Xuất Secret

intermediate🏗️ Terraform2026-04-02| Terraform 0.14+, mọi hệ điều hành (Linux, macOS, Windows), mọi nhà cung cấp cloud

Error Message

Error: Output refers to sensitive value; use 'sensitive = true' to allow this output
#terraform#output#sensitive#bảo mật

Lỗi Gặp Phải

Bạn viết một output block tham chiếu đến một attribute nhạy cảm — mật khẩu database, API key, hoặc secret được tạo ra — và terraform plan hoặc terraform apply dừng lại ngay với thông báo:

Error: Output refers to sensitive value

  on outputs.tf line 3, in output "db_password":
   3:   value = aws_db_instance.main.password

To allow this, the output must be marked with sensitive = true.
To expose the value, set the "sensitive" argument.

Terraform phát hiện bạn sắp đưa một secret ra ngoài qua output block. Nó sẽ không tiếp tục cho đến khi bạn quyết định rõ ràng cách xử lý.

Nguyên Nhân

Terraform 0.14 đã bổ sung tính năng tự động theo dõi độ nhạy cảm. Các provider đánh dấu một số attribute là sensitive trong schema của họ — aws_db_instance.password, random_password.result, và các attribute tương tự. Cờ nhạy cảm này lan truyền qua cấu hình của bạn như một nhãn tag.

Khi một giá trị nhạy cảm đến output block, Terraform yêu cầu bạn xác nhận tường minh. Bạn phải đánh dấu output là sensitive, hoặc chủ động biến đổi/che giấu giá trị đó. Không thể bỏ qua.

Các nguồn phổ biến gây ra lỗi này:

  • aws_db_instance.*.password
  • random_password.*.result
  • aws_secretsmanager_secret_version.*.secret_string
  • azurerm_key_vault_secret.*.value
  • Bất kỳ variable nào được khai báo với sensitive = true

Cách Sửa 1 — Đánh Dấu Output Là Sensitive (Phổ Biến Nhất)

Module khác cần giá trị này? Pipeline CI/CD đọc từ state? Thêm sensitive = true vào output block:

# outputs.tf
output "db_password" {
  value     = aws_db_instance.main.password
  sensitive = true
}

Terraform vẫn ghi giá trị vào state. Nó chỉ hiển thị (sensitive value) trên terminal thay vì secret thực tế. Pipeline của bạn vẫn có thể đọc được:

terraform output -raw db_password

Lệnh này in giá trị thô ra stdout — hữu ích khi cần đưa secret vào script mà không hiển thị chúng trong output của Terraform.

Cách Sửa 2 — Không Export Secret Ra Ngoài

Thực ra, giải pháp bền vững nhất là ngừng export secret từ Terraform hoàn toàn. Thay vào đó, output ARN hoặc đường dẫn, và để service sử dụng tự fetch secret khi chạy.

# Output tham chiếu, không phải secret
output "db_secret_arn" {
  value = aws_secretsmanager_secret.db.arn
}

# Ứng dụng của bạn lấy secret lúc runtime bằng ARN
# Không có gì nhạy cảm chảy qua Terraform output

Cách này giữ secret khỏi CI log, Terraform output, và bất kỳ nơi nào con người có thể vô tình đọc được. Với môi trường production, đây là cách tiếp cận đáng hướng tới.

Cách Sửa 3 — Dùng nonsensitive() Để Bỏ Đánh Dấu Nhạy Cảm

Đôi khi bạn thực sự cần giá trị plaintext trong output — môi trường dev tạm thời, giá trị đã công khai, hoặc migration mà bạn đã chấp nhận đánh đổi. Hàm nonsensitive() loại bỏ cờ nhạy cảm:

# outputs.tf — chỉ dùng khi bạn thực sự muốn lộ giá trị
output "db_password" {
  value = nonsensitive(aws_db_instance.main.password)
}

Không có hộp thoại xác nhận. Terraform tin tưởng bạn. Giá trị hiển thị dưới dạng plaintext trên terminal và được lưu không che giấu trong state — đó chính xác là lý do bạn nên dùng hàm này một cách thận trọng.

Trước khi dùng nonsensitive(), hãy tự hỏi: state file này có được lưu trong S3 bucket mà năm kỹ sư có quyền truy cập không? Giá trị này có thể xuất hiện trong CI log không? Nếu câu trả lời là có, hãy cân nhắc lại.

Cách Sửa 4 — Biến Nhạy Cảm Được Truyền Vào Output

Khi độ nhạy cảm xuất phát từ một input variable bạn khai báo với sensitive = true, quy tắc tương tự áp dụng. Đánh dấu output là sensitive để tuân theo:

# variables.tf
variable "api_key" {
  type      = string
  sensitive = true
}

# outputs.tf
output "configured_api_key" {
  value     = var.api_key
  sensitive = true   # bắt buộc — nguồn là sensitive
}

Cách Sửa 5 — Giá Trị Nhạy Cảm Trong Kiểu Phức Hợp

Đôi khi secret nằm bên trong một map hoặc object cùng với các trường không nhạy cảm. Có hai lựa chọn.

Đánh dấu toàn bộ output là sensitive:

output "db_config" {
  value = {
    host     = aws_db_instance.main.address
    port     = aws_db_instance.main.port
    password = aws_db_instance.main.password
  }
  sensitive = true
}

Hoặc tách ra — giữ các trường không nhạy cảm trong output riêng và bỏ qua password:

output "db_connection_info" {
  value = {
    host = aws_db_instance.main.address
    port = aws_db_instance.main.port
    # bỏ password — consumer tự lấy từ Secrets Manager
  }
}

Cách thứ hai gọn hơn khi caller chỉ cần thông tin kết nối, không cần credentials.

Kiểm Tra Kết Quả

Chạy terraform plan — không có lỗi nghĩa là đã sửa xong. Sau đó apply:

terraform apply

Một sensitive output hiển thị trong kết quả apply như sau:

Outputs:

db_password = <sensitive>

Để xác nhận giá trị đã được lưu và có thể truy cập khi cần:

# Liệt kê tất cả output (sensitive hiển thị là "<sensitive>")
terraform output

# Đọc một sensitive output cụ thể — in giá trị thô ra stdout
terraform output -raw db_password

# Đọc tất cả dưới dạng JSON (bao gồm cả giá trị sensitive)
terraform output -json

Trong CI pipeline, lấy giá trị như sau:

DB_PASS=$(terraform output -raw db_password)
# $DB_PASS có thể dùng trong script mà không xuất hiện trong log của Terraform

Giá Trị Nhạy Cảm Trong Remote State

Đọc output từ config khác qua terraform_remote_state? Độ nhạy cảm được truyền theo giá trị qua ranh giới state:

data "terraform_remote_state" "db" {
  backend = "s3"
  config = {
    bucket = "my-tfstate"
    key    = "db/terraform.tfstate"
    region = "us-east-1"
  }
}

# Vẫn được coi là sensitive trong config này — không cần đánh dấu lại
locals {
  db_pass = data.terraform_remote_state.db.outputs.db_password
}

Không cần chú thích lại. Terraform tự động theo dõi.

Hướng Dẫn Quyết Định Nhanh

  • Module hoặc pipeline khác cần giá trị thực?sensitive = true
  • Service sử dụng có thể tự fetch secret? → output ARN hoặc đường dẫn, bỏ qua secret
  • Môi trường non-prod, tạm thời, hoặc giá trị đã công khai?nonsensitive(), cân nhắc kỹ trước khi dùng
  • Object chứa cả trường sensitive và non-sensitive? → tách thành hai output hoặc đánh dấu toàn bộ block là sensitive

Related Error Notes