Outputs, Sensitive Masking & Remote State Data Sources
Expose endpoint URLs, security group IDs, and connection strings to consumers.
Mark outputs as sensitive to prevent terminal log leakage and CI/CD exposure.
Read attributes across isolated stacks with the 'terraform_remote_state' data source.
The Big Idea
Just as functions return values, Terraform modules return Outputs. Outputs serve two primary purposes: exposing helpful endpoints to human engineers after an apply (such as a load balancer DNS name), and serving as public interface contracts for parent modules and external stacks.
When an output contains sensitive data (like an RDS master password or an IAM secret access key), Terraform enforces strict protection. If an output is derived from any sensitive resource attribute, Terraform will fail the build unless you explicitly declare sensitive = true.
For large organizations, monolithic state files are a major anti-pattern. Instead, you decouple infrastructure into independent tiers (e.g. Core Network, Database Tier, Kubernetes Compute). Using the terraform_remote_state data source, the compute tier can safely read the VPC ID and Subnet IDs from the network tier's state file without shared mutation risks.
Jargon Buster: Plain-English Translations
- Output Value: A named return value exported by a Terraform configuration or module.
- Sensitive Attribute: A flag that instructs Terraform to redact values from human-facing CLI logs, displaying '
' instead. - Decoupled Stacks: Splitting infrastructure into independently deployed state files to minimize blast radius and deployment lock contention.
- Data Source: A read-only block used to fetch information from external cloud providers or other Terraform state files.
Declaring Outputs & Consuming Cross-Stack Remote State
# In Stack 1 (Networking): outputs.tf
output "vpc_id" {
value = aws_vpc.core.id
description = "The physical ID of the production VPC"
}
output "database_password" {
value = random_password.master.result
description = "Master database password"
sensitive = true # Redacts secret from terminal logs
}
# -------------------------------------------------------------
# In Stack 2 (Compute / ECS): main.tf
# Read Stack 1's outputs without sharing state mutation locks
data "terraform_remote_state" "network" {
backend = "s3"
config = {
bucket = "enterprise-production-terraform-state-2026"
key = "core/production/vpc.tfstate"
region = "us-east-1"
}
}
# Use the read-only output in compute resources
resource "aws_security_group" "web_app" {
name = "web-application-firewall"
vpc_id = data.terraform_remote_state.network.outputs.vpc_id
description = "Web firewall inside network-tier VPC"
}
Beginner Traps & Gotchas
1. Thinking 'sensitive = true' encrypts the value in the state file
The Gotcha: Believing that sensitive outputs are encrypted in terraform.tfstate.
The Fix: 'sensitive = true' only redacts values from CLI terminal outputs and plan diffs. The secret is still stored in raw plaintext in the state file.
2. Creating tight coupling with circular remote state references
The Gotcha: Stack A reading from Stack B while Stack B reads from Stack A.
The Fix: Design strict hierarchical layers: Foundation (Network) -> Data (Databases) -> Application (Compute). Dependencies must only flow downward.