Terraform Fundamentals - Outputs
Learn how to use Terraform outputs to display deployment details like public IPs, DNS names, and credentials.
Now that we’ve developed variable-driven Terraform configurations, it’s time to discuss outputs. We have already worked with outputs in earlier posts but lets go a little deeper in this post.
Outputs allows us to extract and reuse the results of our infrastructure builds. Whether we’re setting up infrastructure for internal teams or preparing an environment for red team operations, Terraform outputs help us capture essential details like IP addresses, DNS names, ARNs, or even entire data blocks, making them accessible after deployment is complete.
Follow my journey of 100 Days of Red Team on WhatsApp, Telegram or Discord.
Terraform outputs are defined using the output block. Typically, we place these in a separate outputs.tf
file to maintain organization within our configuration.
Here’s the basic structure of an output
block:
output "name" {
value = <expression>
description = "What this output represents"
sensitive = true|false
}
name
: This is the key used to reference the output.value
: The expression to output—usually referencing a resource attribute.description
: (Optional) A human-readable explanation of the output.sensitive
: (Optional) Prevents Terraform from displaying the output in the CLI/logs.
Following are examples of output blocks we have used in our examples so far:
Hello World Project
output "public_ip" {
description = "Public IP of the EC2 instance"
value = aws_instance.hello.public_ip
}
Hello World S3 Project
output "website_url" {
value = aws_s3_bucket.website_bucket.website_endpoint
}
Outputs are particularly useful when we need to reference a value in external tools, such as scripts or CI pipelines, or simply want to display something valuable in the terminal once provisioning is finished. For example, after creating an EC2 instance, we can output its public IP, eliminating the need to sift through the AWS console or manually query the state file.
Additionally, outputs can be utilized by other Terraform configurations through remote state or modules, facilitating cross-project sharing. This is especially beneficial when we divide infrastructure into layers—imagine one configuration builds the network while another uses those outputs to launch compute resources within it.
Terraform supports various output types, including strings, lists, and maps. We can also manage visibility using the sensitive = true
flag, which conceals values from the terminal and logs. This is crucial when handling secrets, passwords, or private keys. However, it’s important to remember that even with sensitive = true
flag, these values still reside in the state file, so we should always treat terraform.tfstate
as sensitive and store it securely.
Let’s explore a simple yet relevant example. Suppose we’re deploying a security group along with a compute resource, such as a lightweight EC2 or Lightsail instance. We can output the instance’s public IP, SSH username, and resource ID. If this is part of a red team operation, we might also output dynamic values like the S3 pre-signed URL of a payload bucket or the DNS name of a redirector. Automatically displaying or piping these values into automation scripts saves time and minimizes errors.
For red team operators, outputs are not merely about convenience; they play a crucial role in integrating operational pipelines. Outputs can directly feed into scripts that initiate post-deployment tasks: configuring C2 listeners, generating payloads using the deployed IP, or sending Slack/webhook alerts to operators with a summary of what’s live. Moreover, they help us avoid manual copy/paste errors.
For instance, if we deploy a phishing infrastructure module that outputs a domain, email service endpoint, and load balancer DNS, we can directly pipe those into tools that create email campaigns or dynamic redirect rules. However, caution is essential: outputting sensitive values like private keys, C2 URLs, or login credentials can pose risks if those outputs are logged or exposed. In a red team context, this concern extends beyond security; it reflects operational discipline. Marking outputs as sensitive = true
is a good practice, but it should not replace the need to keep state files secure and access-controlled.
Best practices for outputs
✅ Use outputs to capture critical information your team or automation needs post-deploy.
✅ Use
description
for all outputs—makes your code easier to understand and maintain.✅ Mark sensitive data (
private keys
, credentials, secrets) withsensitive = true
to avoid leaking them in logs or CLI output.✅ Avoid hardcoding secrets as outputs unless absolutely necessary.
✅ Keep outputs organized in a separate
outputs.tf
file for better structure.✅ In red team operations, pipe outputs into automation tools or store them securely for later use.
🚫 Don’t rely on
sensitive = true
as a security boundary—secure your state file, especially when it contains sensitive data.
TL;DR
- Terraform outputs let us extract useful values—like IPs, resource IDs, or connection commands—from our deployments.
- Outputs are defined using the output {} block.
- Store outputs in the outputs.tf file for better organization.
- Use the flag sensitive = true for displaying sensitive values such as secrets, tokens, passwords etc. However, it should not be treated as a security boundary.
Follow my journey of 100 Days of Red Team on WhatsApp, Telegram or Discord.