gruntwork-io / terragrunt

Terragrunt is a flexible orchestration tool that allows Infrastructure as Code written in OpenTofu/Terraform to scale.
https://terragrunt.gruntwork.io/
MIT License
8.01k stars 971 forks source link

Can't pass sensitive output from a module to another one as a (sensitive) variable #2552

Open tailaiw opened 1 year ago

tailaiw commented 1 year ago

I have a module database which outputs the database password as a sensitive output

# terraform/database/outputs.tf
output "password" {
  value     = aws_db_instance.db.password
  sensitive = true
}

I have a module app that depends on the database module and wanted to take the database password as a sensitive variable

# terragrunt/_env/app.hcl
dependency "database" {
  config_path = find_in_parent_folders("database")
}

inputs = {
  db_ password = dependency.database.outputs.password
}
# terraform/app/variables.tf
variable "db_password" {
  type      = string
  sensitive = true
}

When I terragrunt apply the app module, I got the error complaining Unsupported attribute; This object does not have an attribute named "password".. I understand the sensitive=true in the database module's output makes the output not included in the output file. Does the app module take the dependent variable from the output file or the dependent module's state file?

denis256 commented 1 year ago

Hi, reading of sensitive data is supported, maybe that find_in_parent_folders("database") find a different directory with different files

I have a simplified example in https://github.com/denis256/terragrunt-tests/tree/master/sensitive-output-2552

├── README.md
├── app
│   ├── main.tf
│   └── terragrunt.hcl
└── dependency
    ├── main.tf
    └── terragrunt.hcl
# dependency/main.tf 
output "password" {
  value = "potato"
  sensitive = true
}

# app/terragrunt.hcl 
dependency "d1" {
  config_path = "../dependency"
}

inputs = {
  content = dependency.d1.outputs.password
}

# app/main.tf 
variable "content" {}
resource "local_file" "file" {
  content     = var.content
  filename = "${path.module}/file.txt"
}
$ cd app
# since it is first run, I apply on dependency too
$ terragrunt run-all apply
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
$ cat file.txt
potato
tailaiw commented 1 year ago

@denis256 thank you so much for the example! You're right that reading sensitive output works. I look into this again and realize the problem in my case is that my AWS RDS database was not setup with explicit password but auto-generated with AWS secret manager, so aws_rds_instance.db.password is (effectively) null. So to solve my problem, I need to pass the secret manager id and retrieve the password in the app, instead of relying on the sensitive output/input of terraform.

What is still confusing me is that, when I do something like the following, I can see from the state file that terraform does output this variable password which has a null value.

output "password" {
  value     = null
  sensitive = true
}

But when my value is aws_db_instance.db.password which is a sensitive null (see below), terraform skips including it in the output. No sure if this is expected behavior of terraform but it is somehow misleading.

> aws_db_instance.db.password
(sensitive value)
> nonsensitive(aws_db_instance.db.password)
tostring(null)
denis256 commented 1 year ago

Hm, can be used data / aws_secretsmanager_secret_version to read password?

data "aws_secretsmanager_secret_version" "password" {
  secret_id = data.aws_secretsmanager_secret.password
}
data.aws_secretsmanager_secret_version.password