Skip to content

10.8 Terraform Outputs

Overview

Terraform outputs expose important information about the created infrastructure. This configuration provides three key outputs: resource group name, public IP address, and VM password.

Output Definitions

All outputs are defined in outputs.tf:

output "resource_group_name" {
  value = azurerm_resource_group.example.name
}

output "public_ip_address" {
  value = "http://${azurerm_public_ip.example.ip_address}"
}

output "vm_password" {
  value     = azurerm_linux_virtual_machine.example[0].admin_password
  sensitive = true
}

Output Details

1. resource_group_name

output "resource_group_name" {
  value = azurerm_resource_group.example.name
}

Purpose: Displays the randomly generated resource group name

Example Output:

resource_group_name = "rg-happy-dolphin"

Why Useful: - Need the exact name for Azure CLI commands - Reference in other Terraform configurations - Documentation and tracking

Usage:

# Get the value
terraform output resource_group_name

# Use in Azure CLI
RG_NAME=$(terraform output -raw resource_group_name)
az resource list --resource-group $RG_NAME

2. public_ip_address

output "public_ip_address" {
  value = "http://${azurerm_public_ip.example.ip_address}"
}

Purpose: Provides the HTTP URL to access the load-balanced web application

Example Output:

public_ip_address = "http://20.121.45.67"

Why Useful: - Immediate access to the deployed application - Testing and verification - Sharing with team members

Usage:

# Get the URL
terraform output public_ip_address

# Open in browser (Linux)
xdg-open $(terraform output -raw public_ip_address)

# Test with curl
curl $(terraform output -raw public_ip_address)

String Interpolation:

"http://${azurerm_public_ip.example.ip_address}"
- Automatically prepends http:// to the IP address - Makes it a clickable URL in terminal output - Ready to paste into browser

3. vm_password

output "vm_password" {
  value     = azurerm_linux_virtual_machine.example[0].admin_password
  sensitive = true
}

Purpose: Displays the admin password for VM access

Example Output:

vm_password = <sensitive>

Why Sensitive: - sensitive = true prevents password from showing in normal output - Protects credentials in logs and console output - Must explicitly request to view

Accessing Sensitive Outputs:

# Shows <sensitive>
terraform output vm_password

# Shows actual password
terraform output -raw vm_password

# Save to variable
VM_PASSWORD=$(terraform output -raw vm_password)
echo $VM_PASSWORD

Array Index [0]:

azurerm_linux_virtual_machine.example[0].admin_password
- References the first VM (index 0) - Both VMs have the same password - Could output both: example[0] and example[1]

Viewing Outputs

After Apply

Outputs are automatically displayed after terraform apply:

$ terraform apply

Apply complete! Resources: 15 added, 0 changed, 0 destroyed.

Outputs:

public_ip_address = "http://20.121.45.67"
resource_group_name = "rg-golden-panther"
vm_password = <sensitive>

View All Outputs

terraform output

Output:

public_ip_address = "http://20.121.45.67"
resource_group_name = "rg-golden-panther"
vm_password = <sensitive>

View Specific Output

# With formatting
terraform output public_ip_address

# Raw value (no quotes)
terraform output -raw public_ip_address

View Sensitive Output

# Shows <sensitive>
terraform output vm_password

# Shows actual value
terraform output -raw vm_password

JSON Format

terraform output -json

Output:

{
  "public_ip_address": {
    "sensitive": false,
    "type": "string",
    "value": "http://20.121.45.67"
  },
  "resource_group_name": {
    "sensitive": false,
    "type": "string",
    "value": "rg-golden-panther"
  },
  "vm_password": {
    "sensitive": true,
    "type": "string",
    "value": "Abc123!@#XyzDef456"
  }
}

Using Outputs in Scripts

Bash Script Example

#!/bin/bash

# Get outputs
RG_NAME=$(terraform output -raw resource_group_name)
PUBLIC_IP=$(terraform output -raw public_ip_address)
VM_PASSWORD=$(terraform output -raw vm_password)

# Use in commands
echo "Resource Group: $RG_NAME"
echo "Testing endpoint: $PUBLIC_IP"

# Test the application
for i in {1..5}; do
  echo "Request $i:"
  curl $PUBLIC_IP
  echo ""
done

# List resources
az resource list --resource-group $RG_NAME --output table

PowerShell Script Example

# Get outputs
$rgName = terraform output -raw resource_group_name
$publicIp = terraform output -raw public_ip_address
$vmPassword = terraform output -raw vm_password

# Use in commands
Write-Host "Resource Group: $rgName"
Write-Host "Public IP: $publicIp"

# Test the application
1..5 | ForEach-Object {
    Write-Host "Request $_:"
    Invoke-WebRequest -Uri $publicIp
}

Advanced Output Configurations

Multiple VM Passwords

Output passwords for all VMs:

output "vm_passwords" {
  value = {
    for idx, vm in azurerm_linux_virtual_machine.example :
    vm.name => vm.admin_password
  }
  sensitive = true
}

Output:

vm_passwords = {
  "test-vm0" = "password1"
  "test-vm1" = "password2"
}

VM Private IPs

output "vm_private_ips" {
  value = [
    for nic in azurerm_network_interface.example :
    nic.private_ip_address
  ]
}

Output:

vm_private_ips = [
  "10.0.1.4",
  "10.0.1.5"
]

Complete Infrastructure Summary

output "infrastructure_summary" {
  value = {
    resource_group = azurerm_resource_group.example.name
    location       = azurerm_resource_group.example.location
    vnet_name      = azurerm_virtual_network.example.name
    vnet_cidr      = azurerm_virtual_network.example.address_space[0]
    subnet_name    = azurerm_subnet.example.name
    subnet_cidr    = azurerm_subnet.example.address_prefixes[0]
    lb_name        = azurerm_lb.example.name
    public_ip      = azurerm_public_ip.example.ip_address
    vm_count       = length(azurerm_linux_virtual_machine.example)
    vm_names       = [for vm in azurerm_linux_virtual_machine.example : vm.name]
  }
}

Output:

infrastructure_summary = {
  resource_group = "rg-golden-panther"
  location       = "eastus"
  vnet_name      = "test-vnet"
  vnet_cidr      = "10.0.0.0/16"
  subnet_name    = "test-subnet"
  subnet_cidr    = "10.0.1.0/24"
  lb_name        = "test-lb"
  public_ip      = "20.121.45.67"
  vm_count       = 2
  vm_names       = ["test-vm0", "test-vm1"]
}

Connection Information

output "connection_info" {
  value = {
    web_url      = "http://${azurerm_public_ip.example.ip_address}"
    username     = azurerm_linux_virtual_machine.example[0].admin_username
    vm_names     = [for vm in azurerm_linux_virtual_machine.example : vm.name]
    instructions = "Access the web application at the web_url. VMs are behind a load balancer and not directly accessible."
  }
}

Load Balancer Details

output "load_balancer_info" {
  value = {
    name                = azurerm_lb.example.name
    frontend_ip         = azurerm_public_ip.example.ip_address
    backend_pool_name   = azurerm_lb_backend_address_pool.example.name
    health_probe_port   = azurerm_lb_probe.example.port
    lb_rule_frontend    = azurerm_lb_rule.example_rule.frontend_port
    lb_rule_backend     = azurerm_lb_rule.example_rule.backend_port
  }
}

Output Descriptions

Add descriptions to outputs:

output "resource_group_name" {
  value       = azurerm_resource_group.example.name
  description = "The name of the resource group containing all infrastructure resources"
}

output "public_ip_address" {
  value       = "http://${azurerm_public_ip.example.ip_address}"
  description = "The public URL to access the load-balanced web application"
}

output "vm_password" {
  value       = azurerm_linux_virtual_machine.example[0].admin_password
  sensitive   = true
  description = "The admin password for VM access (use 'terraform output -raw vm_password' to view)"
}

Using Outputs in Other Modules

Root Module

module "infrastructure" {
  source = "./modules/vnet-vm-lb"

  resource_group_location = "eastus"
  virtual_machine_size    = "Standard_B2s"
}

output "app_url" {
  value = module.infrastructure.public_ip_address
}

output "resource_group" {
  value = module.infrastructure.resource_group_name
}

Chaining Modules

module "network" {
  source = "./modules/network"
}

module "compute" {
  source    = "./modules/compute"
  subnet_id = module.network.subnet_id
}

output "application_url" {
  value = module.compute.public_ip_address
}

Saving Outputs to File

JSON File

terraform output -json > outputs.json

Specific Output to File

terraform output -raw public_ip_address > public_ip.txt
terraform output -raw vm_password > .secrets/vm_password.txt

Environment File

cat > .env <<EOF
RESOURCE_GROUP=$(terraform output -raw resource_group_name)
PUBLIC_IP=$(terraform output -raw public_ip_address)
VM_PASSWORD=$(terraform output -raw vm_password)
EOF

Output Best Practices

  1. Provide Useful Information: Output what users need to access/manage resources
  2. Use Descriptions: Explain what each output represents
  3. Mark Sensitive Data: Use sensitive = true for passwords, keys
  4. Format for Usability: Add http:// prefix, format URLs
  5. Group Related Data: Use objects for related outputs
  6. Document Usage: Explain how to use sensitive outputs
  7. Avoid Over-Outputting: Only output necessary information

Common Use Cases

Testing After Deployment

#!/bin/bash
echo "Testing deployment..."

URL=$(terraform output -raw public_ip_address)

for i in {1..10}; do
  echo "Request $i:"
  curl -s $URL
  echo ""
  sleep 1
done

Automated Documentation

#!/bin/bash
cat > DEPLOYMENT.md <<EOF
# Deployment Information

## Resource Group
$(terraform output -raw resource_group_name)

## Application URL
$(terraform output -raw public_ip_address)

## Access Instructions
1. Open browser to: $(terraform output -raw public_ip_address)
2. You should see "Hello World from test-vm0" or "test-vm1"

## Admin Credentials
- Username: azureadmin
- Password: (stored in secrets manager)

## Deployed: $(date)
EOF

Integration with CI/CD

# GitHub Actions example
- name: Deploy Infrastructure
  run: terraform apply -auto-approve

- name: Get Public IP
  id: outputs
  run: |
    echo "public_ip=$(terraform output -raw public_ip_address)" >> $GITHUB_OUTPUT

- name: Test Deployment
  run: |
    curl ${{ steps.outputs.outputs.public_ip }}

Troubleshooting

Output Not Available

Error: "The output variable requested could not be found"

Solution: Ensure terraform apply has completed successfully

Sensitive Output Not Showing

Issue: Output shows <sensitive>

Solution: Use -raw flag:

terraform output -raw vm_password

Output Shows Old Value

Issue: Output doesn't reflect recent changes

Solution: Run terraform refresh or terraform apply

Next Steps

Proceed to 10.9-Deployment-Guide.md for step-by-step instructions on deploying this infrastructure.