Terraform Plan JSON
Import Terraform plan JSON output to analyze firewall rules across AWS, Azure, and GCP providers in a single file. netbobr scans planned_values for security group and firewall resources, extracting flows from each provider's native field format.
Export command
Generate and convert a Terraform plan to JSON:
# Generate a plan file
terraform plan -out=tfplan
# Convert to JSON
terraform show -json tfplan > plan.jsonterraform show -json requires Terraform 0.12 or later. The output must be the JSON plan format, not the human-readable plan text.
Supported resource types
| Resource Type | Provider | Description |
|---|---|---|
aws_security_group_rule | AWS | Individual security group rule |
aws_security_group | AWS | Security group with inline ingress/egress blocks |
aws_vpc_security_group_ingress_rule | AWS | Single inbound rule (AWS provider v5 style) |
aws_vpc_security_group_egress_rule | AWS | Single outbound rule (AWS provider v5 style) |
azurerm_network_security_rule | Azure | Network security group rule |
azurerm_network_security_group | Azure | Network security group with inline security_rule blocks |
google_compute_firewall | GCP | Compute firewall rule |
Minimal example
{
"planned_values": {
"root_module": {
"resources": [
{
"type": "aws_security_group_rule",
"name": "allow-https",
"address": "module.security.aws_security_group_rule.allow-https",
"values": {
"type": "ingress",
"protocol": "tcp",
"from_port": 443,
"to_port": 443,
"cidr_blocks": ["10.0.0.0/8"],
"security_group_id": "sg-0123456789"
}
}
]
}
}
}Parser behavior
- Scans the
planned_values.root_module.resourcesarray, including nestedchild_modulesrecursively. - Each supported resource type uses its own extraction logic matching the native cloud format:
- AWS SG rules:
type(ingress/egress),protocol,from_port,to_port,cidr_blocks - AWS SG inline:
ingressandegressblocks with the same field structure - AWS VPC rules (
aws_vpc_security_group_ingress_rule/_egress_rule):ip_protocol,from_port,to_port,cidr_ipv4. For ICMP,from_portis the ICMP type. - All AWS resources behave like the native AWS parser:
0-65535becomes1-65535, protocol-1is ANY, unsupported protocols are skipped with a warning, and the group's member instances are the0.0.0.0/0placeholder, reported in one summary warning per file. - AWS peers that are not IPv4 CIDRs are skipped with a warning:
source_security_group_id, inlinesecurity_groups,referenced_security_group_id,self = true,ipv6_cidr_blocks/cidr_ipv6, andprefix_list_ids/prefix_list_id. Example:Security group reference sg-abc123 in TF resource aws_security_group_rule.db cannot be resolved to CIDR -- skipped. - AWS rules with no peer at all (the value is unknown at plan time) are analysed with
0.0.0.0/0and a warning such asTF aws_security_group_rule.db: source address is not set -- substituted 0.0.0.0/0. - Azure NSG rules (
azurerm_network_security_rule, and each inlinesecurity_ruleof anazurerm_network_security_group): the same rules as the native Azure NSG parser.- Singular and plural fields are combined and expanded:
source_address_prefix(es),destination_address_prefix(es),destination_port_range(s). - Source maps to source and destination to destination in both directions: outbound rules are not swapped.
*andInternetmean0.0.0.0/0. Other service tags (VirtualNetwork,Storage.WestEurope, ...) andsource/destination_application_security_group_idsare replaced by the0.0.0.0/0placeholder, with a warning such asTF azurerm_network_security_rule.vnet: source service tag "VirtualNetwork" cannot be resolved to CIDR -- substituted 0.0.0.0/0. A rule whose two sides are both unresolvable is skipped.- An address or port that is unknown at plan time is absent from
planned_values. It is substituted (0.0.0.0/0, or1-65535for ports) with a warning such assource address is not set -- substituted 0.0.0.0/0. accessis case-insensitive. Deny rules are not evaluated and are counted in one summary warning per file.Esp/Ahrules are skipped with a warning.- Inline rules are reported per rule:
ruleNameis the rulename,ruleIdis<NSG address>/<name>.
- Singular and plural fields are combined and expanded:
- GCP firewall rules: the same behaviour as the native GCP parser:
source_tags,source_service_accounts,target_tagsandtarget_service_accountsare substituted with0.0.0.0/0and warned;source_ranges = []is treated like an absent attribute;denyblocks are counted in one "deny rules were not evaluated" warning per file;disabled = truerules are skipped with a warning; the target instances of rules without target tags are reported in one summary warning per file.
- AWS SG rules:
- A plan that produces no flows (for example only deny rules or only security group references) reports that there are no allowed flows to analyse, with the warnings.
Limitations
| Limitation | Detail |
|---|---|
| Security group references | Rules referencing other SGs by ID instead of CIDR blocks (or self = true) generate a warning and no flow. |
| Data sources | Only planned_values resources are scanned. Data source lookups and remote state references are not resolved. |
| Azure inline + standalone rules | Terraform does not allow inline security_rule blocks and azurerm_network_security_rule resources on the same NSG. If a plan still has both, both are imported, so the same traffic may be counted twice. Azure rule priority and default rules are not modelled. |
| Computed values | Fields marked as (known after apply) are missing or null in planned_values. Unknown AWS and Azure addresses are analysed as 0.0.0.0/0 and unknown ports as 1-65535, with a warning. A missing GCP source_ranges or destination_ranges cannot be told apart from an unset one, so it gets the GCP default 0.0.0.0/0 without a source/destination warning. |
Accuracy
Accuracy measured against a 400-rule CSV baseline (360 Tier 1 + 40 Tier 2).
| Metric | Value |
|---|---|
| CLI match rate | 97.0% (388/400) -- highest of all formats |
| Browser match rate | 97.0% (388/400) |
| Tier 1 accuracy | 100.0% (348/348) |
| Tier 2 accuracy | 100.0% (40/40) |
| Field accuracy | 100% (risk score, risk level, verdict) |
Terraform Plan achieves the highest match rate because it covers all three cloud providers with fully resolved values, including Azure NSG rules that can express both specific source and destination CIDRs (Tier 2).
Troubleshooting
"No flows parsed"
Verify the file is terraform show -json output, not terraform plan text output. The JSON file must contain a planned_values key at the top level.
"Missing resources"
Check if resources are defined in child modules. netbobr recursively scans child_modules within planned_values.root_module, so nested modules are supported.
"Security group reference warning"
Rules that reference other security groups by ID (e.g., source_security_group_id: "sg-abc123") instead of CIDR blocks generate a warning. These rules cannot produce flows because the SG members are unknown.
"Unsupported resource type"
Only the resource types listed above are scanned. Other firewall-related resources (e.g., aws_network_acl_rule, aws_networkfirewall_rule_group) are not currently supported.
CLI usage:
npx @netbobr/cli analyze plan.json --cloud-format tf-planBrowser: Drag and drop the .json file onto the import area. Terraform Plan format is auto-detected by the presence of planned_values.