Real tfplan2md output from actual Terraform plans. See what your reports will look like.
tfplan2md includes built-in templates for different use cases. Choose the right level of detail for your workflow.
Compact overview showing only action counts and resource type breakdown. Perfect for notifications where the full report isn't needed.
Terraform Version: 1.14.0
Generated: 2025-12-20T14:30:00Z
| Action | Count | Resource Types |
|---|---|---|
| β Add | 12 | 1 azurerm_firewall_network_rule_collection 1 azurerm_key_vault 1 azurerm_key_vault_secret 2 azurerm_log_analytics_workspace 1 azurerm_resource_group 2 azurerm_role_assignment 1 azurerm_storage_account 1 azurerm_subnet 2 azurerm_virtual_network |
| π Change | 6 | 1 azurerm_firewall_network_rule_collection 1 azurerm_key_vault 1 azurerm_key_vault_secret 2 azurerm_storage_account 1 azurerm_virtual_network |
| β»οΈ Replace | 2 | 1 azurerm_network_security_group 1 azurerm_subnet |
| β Destroy | 3 | 1 azurerm_role_assignment 1 azurerm_storage_account 1 azurerm_virtual_network |
| Total | 23 |
# Terraform Plan Summary
**Terraform Version:** 1.14.0
**Generated:** 2025-12-20T14:30:00Z
## Summary
| Action | Count | Resource Types |
|--------|-------|----------------|
| β Add | 12 | 1 azurerm_firewall_network_rule_collection<br/>1 azurerm_key_vault<br/>1 azurerm_key_vault_secret<br/>2 azurerm_log_analytics_workspace<br/>1 azurerm_resource_group<br/>2 azurerm_role_assignment<br/>1 azurerm_storage_account<br/>1 azurerm_subnet<br/>2 azurerm_virtual_network |
| π Change | 6 | 1 azurerm_firewall_network_rule_collection<br/>1 azurerm_key_vault<br/>1 azurerm_key_vault_secret<br/>2 azurerm_storage_account<br/>1 azurerm_virtual_network |
| β»οΈ Replace | 2 | 1 azurerm_network_security_group<br/>1 azurerm_subnet |
| β Destroy | 3 | 1 azurerm_role_assignment<br/>1 azurerm_storage_account<br/>1 azurerm_virtual_network |
| **Total** | **23** | |
Full report with summary, resource changes, and attribute details. Shows exactly what will change.
Terraform Version: 1.14.0
| Action | Count | Resource Types |
|---|---|---|
| β Add | 12 | ... |
| π Change | 6 | ... |
| Total | 23 |
core β π rg-tfplan2md-demo π eastus| Attribute | Value |
|---|---|
| location | π eastus |
| name | π rg-tfplan2md-demo |
π·οΈ Tags: environment: demo owner: tfplan2md
data β π sttfplan2mddata in π rg-tfplan2md-demo π eastus | 2π§ account_replication_type, tags.cost_center| Attribute | Before | After |
|---|---|---|
| account_replication_type | LRS |
GRS |
| tags.cost_center | - | 1234 |
# Terraform Plan Report
**Terraform Version:** 1.14.0
## Summary
| Action | Count | Resource Types |
|--------|-------|----------------|
| β Add | 12 | ... |
| π Change | 6 | ... |
| **Total** | **23** | |
## Resource Changes
### π¦ Module: root
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px">
<summary>β azurerm_resource_group <b><code>core</code></b> β <code>π rg-tfplan2md-demo</code> <code>π eastus</code></summary>
<br/>
| Attribute | Value |
|-----------|-------|
| location | `π eastus` |
| name | `π rg-tfplan2md-demo` |
**π·οΈ Tags:** `environment: demo` `owner: tfplan2md`
</details>
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px">
<summary>π azurerm_storage_account <b><code>data</code></b> β <code>π sttfplan2mddata</code> in <code>π rg-tfplan2md-demo</code> <code>π eastus</code> | 2π§ account_replication_type, tags.cost_center</summary>
<br/>
| Attribute | Before | After |
|-----------|--------|-------|
| account_replication_type | `LRS` | `GRS` |
| tags.cost_center | - | `1234` |
</details>
See how tfplan2md transforms complex Terraform changes into readable reports.
Array index changes are replaced with a semantic diff showing which rules were added, modified, or removed.
network_rules β π demo-network-rules in π rg-firewall-demo | 9π§ priority, rule[0].destination_addresses[0], rule[0].destination_ports[0], +6 moreCollection: demo-network-rules | Priority: 150 | Action: β
Allow
| Change | Rule Name | Protocols | Source Addresses | Destination Addresses | Destination Ports | Description |
|---|---|---|---|---|---|---|
| β | allow-dns |
π TCP, π¨ UDP |
π 10.1.0.0/24 |
π 168.63.129.16 |
π 53 |
|
| π | allow-http |
π TCP | - π 10.1.0.0/24 |
- π 0.0.0.0/0 |
π 80 | |
| β | allow-ssh-old |
π TCP |
π 10.0.0.0/16 |
π 10.1.0.0/24 |
π 22 |
|
| βΊοΈ | allow-https |
π TCP |
π 10.1.0.0/24 |
π 0.0.0.0/0 |
π 443 |
<details open style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>π azurerm_firewall_network_rule_collection <b><code>network_rules</code></b> β <code>π demo-network-rules</code> in <code>π rg-firewall-demo</code> | 9π§ priority, rule[0].destination_addresses[0], rule[0].destination_ports[0], +6 more</summary>
<br>
### π azurerm_firewall_network_rule_collection.network_rules
**Collection:** `demo-network-rules` | **Priority:** `150` | **Action:** `β
Allow`
#### Rule Changes
| Change | Rule Name | Protocols | Source Addresses | Destination Addresses | Destination Ports | Description |
| -------- | ----------- | ----------- | ------------------ | ---------------------- | ------------------- | ------------- |
| β | `allow-dns` | `π TCP`, `π¨ UDP` | `π 10.1.0.0/24` | `π 168.63.129.16` | `π 53` | `` |
| π | `allow-http` | π TCP | <code style="display:block; white-space:normal; padding:0; margin:0;"><span style="background-color: #fff5f5; border-left: 3px solid #d73a49; color: #24292e; display: inline-block; padding-left: 8px; margin-left: 0;">- π 10.<span style="background-color: #ffc0c0; color: #24292e;">1</span>.0.0/<span style="background-color: #ffc0c0; color: #24292e;">24</span></span><br><span style="background-color: #f0fff4; border-left: 3px solid #28a745; color: #24292e; display: inline-block; padding-left: 8px; margin-left: 0;">+ π 10.<span style="background-color: #acf2bd; color: #24292e;">0</span>.0.0/<span style="background-color: #acf2bd; color: #24292e;">8</span></span></code> | <code style="display:block; white-space:normal; padding:0; margin:0;"><span style="background-color: #fff5f5; border-left: 3px solid #d73a49; color: #24292e; display: inline-block; padding-left: 8px; margin-left: 0;">- <span style="background-color: #ffc0c0; color: #24292e;">π 0.0.0.0/0</span></span><br><span style="background-color: #f0fff4; border-left: 3px solid #28a745; color: #24292e; display: inline-block; padding-left: 8px; margin-left: 0;">+ <span style="background-color: #acf2bd; color: #24292e;">β³οΈ</span></span></code> | π 80 | |
| β | `allow-ssh-old` | `π TCP` | `π 10.0.0.0/16` | `π 10.1.0.0/24` | `π 22` | `` |
| βΊοΈ | `allow-https` | `π TCP` | `π 10.1.0.0/24` | `π 0.0.0.0/0` | `π 443` | `` |
</details>
Resources are automatically organized by Terraform module for better readability in multi-module configurations.
core β π rg-tfplan2md-demo π eastus| Attribute | Value |
|---|---|
| location | π eastus |
| name | π rg-tfplan2md-demo |
π·οΈ Tags: environment: demo owner: tfplan2md
logs β π sttfplan2mdlogs in π rg-tfplan2md-demo π eastus| Attribute | Value |
|---|---|
| account_replication_type | LRS |
| account_tier | Standard |
| allow_blob_public_access | β false |
| location | π eastus |
| min_tls_version | TLS1_2 |
| name | π sttfplan2mdlogs |
| resource_group_name | π rg-tfplan2md-demo |
π·οΈ Tags: cost_center: ops environment: demo
module.networkhub β π vnet-hub in π rg-tfplan2md-demo π eastus π 10.0.0.0/16| Attribute | Value |
|---|---|
| address_space[0] | π 10.0.0.0/16 |
| location | π eastus |
| name | π vnet-hub |
| resource_group_name | π rg-tfplan2md-demo |
π·οΈ Tags: environment: demo
module.securityrg_reader β π€ Jane Doe (User) β π‘οΈ Reader on rg-tfplan2md-demo| Attribute | Value |
|---|---|
| scope | π rg-tfplan2md-demo in subscription 12345678-1234-1234-1234-123456789012 |
| role_definition_id | π‘οΈ Reader (acdd72a7-3385-48ef-bd42-f606fba81ae7) |
| principal_id | π€ Jane Doe (User) [00000000-0000-0000-0000-000000000001] |
| principal_type | π€ User |
| role_definition_name | π‘οΈ Reader |
module.network.module.monitoringnetwork β π law-network-monitoring in π rg-tfplan2md-demo π eastus| Attribute | Value |
|---|---|
| location | π eastus |
| name | π law-network-monitoring |
| resource_group_name | π rg-tfplan2md-demo |
| retention_in_days | 30 |
| sku | PerGB2018 |
π·οΈ Tags: environment: demo module: monitoring
## Resource Changes
### π¦ Module: root
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>β azurerm_resource_group <b><code>core</code></b> β <code>π rg-tfplan2md-demo</code> <code>π eastus</code></summary>
<br>
| Attribute | Value |
| ----------- | ------- |
| location | `π eastus` |
| name | `π rg-tfplan2md-demo` |
**π·οΈ Tags:** `environment: demo` `owner: tfplan2md`
</details>
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>β azurerm_storage_account <b><code>logs</code></b> β <code>π sttfplan2mdlogs</code> in <code>π rg-tfplan2md-demo</code> <code>π eastus</code></summary>
<br>
| Attribute | Value |
| ----------- | ------- |
| account_replication_type | `LRS` |
| account_tier | `Standard` |
| allow_blob_public_access | `β false` |
| location | `π eastus` |
| min_tls_version | `TLS1_2` |
| name | `π sttfplan2mdlogs` |
| resource_group_name | `π rg-tfplan2md-demo` |
**π·οΈ Tags:** `cost_center: ops` `environment: demo`
</details>
---
### π¦ Module: `module.network`
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>β azurerm_virtual_network <b><code>hub</code></b> β <code>π vnet-hub</code> in <code>π rg-tfplan2md-demo</code> <code>π eastus</code> <code>π 10.0.0.0/16</code></summary>
<br>
| Attribute | Value |
| ----------- | ------- |
| address_space[0] | `π 10.0.0.0/16` |
| location | `π eastus` |
| name | `π vnet-hub` |
| resource_group_name | `π rg-tfplan2md-demo` |
**π·οΈ Tags:** `environment: demo`
</details>
---
### π¦ Module: `module.security`
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>β azurerm_role_assignment <b><code>rg_reader</code></b> β <code>π€ Jane Doe (User)</code> β <code>π‘οΈ Reader</code> on <code>rg-tfplan2md-demo</code></summary>
<br>
| Attribute | Value |
| ----------- | ------- |
| scope | `π rg-tfplan2md-demo` in subscription `12345678-1234-1234-1234-123456789012` |
| role_definition_id | `π‘οΈ Reader` (`acdd72a7-3385-48ef-bd42-f606fba81ae7`) |
| principal_id | `π€ Jane Doe (User)` [`00000000-0000-0000-0000-000000000001`] |
| principal_type | `π€ User` |
| role_definition_name | `π‘οΈ Reader` |
</details>
---
### π¦ Module: `module.network.module.monitoring`
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>β azurerm_log_analytics_workspace <b><code>network</code></b> β <code>π law-network-monitoring</code> in <code>π rg-tfplan2md-demo</code> <code>π eastus</code></summary>
<br>
| Attribute | Value |
| ----------- | ------- |
| location | `π eastus` |
| name | `π law-network-monitoring` |
| resource_group_name | `π rg-tfplan2md-demo` |
| retention_in_days | `30` |
| sku | `PerGB2018` |
**π·οΈ Tags:** `environment: demo` `module: monitoring`
</details>
Role assignments show human-readable names with principal mapping instead of cryptic GUIDs.
rg_reader β π€ Jane Doe (User) β π‘οΈ Reader on rg-tfplan2md-demo| Attribute | Value |
|---|---|
| scope | π rg-tfplan2md-demo in subscription 12345678-1234-1234-1234-123456789012 |
| role_definition_id | π‘οΈ Reader (acdd72a7-3385-48ef-bd42-f606fba81ae7) |
| principal_id | π€ Jane Doe (User) [00000000-0000-0000-0000-000000000001] |
| principal_type | π€ User |
| role_definition_name | π‘οΈ Reader |
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>β azurerm_role_assignment <b><code>rg_reader</code></b> β <code>π€ Jane Doe (User)</code> β <code>π‘οΈ Reader</code> on <code>rg-tfplan2md-demo</code></summary>
<br>
| Attribute | Value |
| ----------- | ------- |
| scope | `π rg-tfplan2md-demo` in subscription `12345678-1234-1234-1234-123456789012` |
| role_definition_id | `π‘οΈ Reader` (`acdd72a7-3385-48ef-bd42-f606fba81ae7`) |
| principal_id | `π€ Jane Doe (User)` [`00000000-0000-0000-0000-000000000001`] |
| principal_type | `π€ User` |
| role_definition_name | `π‘οΈ Reader` |
</details>
{
"users": {
"12345678-1234-1234-1234-123456789012": "jane.doe@contoso.com",
"87654321-4321-4321-4321-210987654321": "john.smith@contoso.com"
},
"groups": {
"abcdef12-3456-7890-abcd-ef1234567890": "Platform Team"
},
"servicePrincipals": {
"fedcba98-7654-3210-fedc-ba9876543210": "terraform-spn"
}
}
Sensitive values are automatically masked by default to prevent accidental exposure in PRs.
db_password β π db-password| Attribute | Value |
|---|---|
| content_type | password |
| key_vault_id | Key Vault kv-tfplan2md in resource group rg-tfplan2md-demo of subscription 12345678-1234-1234-1234-123456789012 |
| name | π db-password |
| value | (sensitive) |
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>β azurerm_key_vault_secret <b><code>db_password</code></b> β <code>π db-password</code></summary>
<br>
| Attribute | Value |
| ----------- | ------- |
| content_type | `password` |
| key_vault_id | Key Vault `kv-tfplan2md` in resource group `rg-tfplan2md-demo` of subscription `12345678-1234-1234-1234-123456789012` |
| name | `π db-password` |
| value | `(sensitive)` |
</details>
db_password β π db-password| Attribute | Value |
|---|---|
| content_type | password |
| key_vault_id | Key Vault kv-tfplan2md in resource group rg-tfplan2md-demo of subscription 12345678-1234-1234-1234-123456789012 |
| name | π db-password |
| value | super-secret-value |
<details style="margin-bottom:12px; border:1px solid rgb(var(--palette-neutral-10, 153, 153, 153)); padding:12px;">
<summary>β azurerm_key_vault_secret <b><code>db_password</code></b> β <code>π db-password</code></summary>
<br>
| Attribute | Value |
| ----------- | ------- |
| content_type | `password` |
| key_vault_id | Key Vault `kv-tfplan2md` in resource group `rg-tfplan2md-demo` of subscription `12345678-1234-1234-1234-123456789012` |
| name | `π db-password` |
| value | `super-secret-value` |
</details>
Complete example projects showing tfplan2md in action.
A handcrafted Terraform plan demonstrating all tfplan2md features: firewall rules, NSG rules, role assignments, module grouping, and more.
Real Terraform configuration creating Azure DevOps projects, repositories, variable groups, and pipelines. Generate your own plans and test tfplan2md.
Run the comprehensive demo using Docker or build from source.
# Default report with principal mapping
docker run --rm oocx/tfplan2md \
/examples/comprehensive-demo/plan.json \
--principals /examples/comprehensive-demo/demo-principals.json
# Summary report
docker run --rm oocx/tfplan2md \
/examples/comprehensive-demo/plan.json \
--template summary
# Show sensitive values
docker run --rm oocx/tfplan2md \
/examples/comprehensive-demo/plan.json \
--principals /examples/comprehensive-demo/demo-principals.json \
--show-sensitive
git clone https://github.com/oocx/tfplan2md.git
cd tfplan2md
# Default report
dotnet run --project src/Oocx.TfPlan2Md/Oocx.TfPlan2Md.csproj -- \
examples/comprehensive-demo/plan.json \
--principals examples/comprehensive-demo/demo-principals.json
# Summary report
dotnet run --project src/Oocx.TfPlan2Md/Oocx.TfPlan2Md.csproj -- \
examples/comprehensive-demo/plan.json \
--template summary