Skip to content

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.json

terraform 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 TypeProviderDescription
aws_security_group_ruleAWSIndividual security group rule
aws_security_groupAWSSecurity group with inline ingress/egress blocks
aws_vpc_security_group_ingress_ruleAWSSingle inbound rule (AWS provider v5 style)
aws_vpc_security_group_egress_ruleAWSSingle outbound rule (AWS provider v5 style)
azurerm_network_security_ruleAzureNetwork security group rule
azurerm_network_security_groupAzureNetwork security group with inline security_rule blocks
google_compute_firewallGCPCompute 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.resources array, including nested child_modules recursively.
  • 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: ingress and egress blocks 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_port is the ICMP type.
    • All AWS resources behave like the native AWS parser: 0-65535 becomes 1-65535, protocol -1 is ANY, unsupported protocols are skipped with a warning, and the group's member instances are the 0.0.0.0/0 placeholder, reported in one summary warning per file.
    • AWS peers that are not IPv4 CIDRs are skipped with a warning: source_security_group_id, inline security_groups, referenced_security_group_id, self = true, ipv6_cidr_blocks / cidr_ipv6, and prefix_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/0 and a warning such as TF 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 inline security_rule of an azurerm_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.
      • * and Internet mean 0.0.0.0/0. Other service tags (VirtualNetwork, Storage.WestEurope, ...) and source/destination_application_security_group_ids are replaced by the 0.0.0.0/0 placeholder, with a warning such as TF 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, or 1-65535 for ports) with a warning such as source address is not set -- substituted 0.0.0.0/0.
      • access is case-insensitive. Deny rules are not evaluated and are counted in one summary warning per file. Esp/Ah rules are skipped with a warning.
      • Inline rules are reported per rule: ruleName is the rule name, ruleId is <NSG address>/<name>.
    • GCP firewall rules: the same behaviour as the native GCP parser: source_tags, source_service_accounts, target_tags and target_service_accounts are substituted with 0.0.0.0/0 and warned; source_ranges = [] is treated like an absent attribute; deny blocks are counted in one "deny rules were not evaluated" warning per file; disabled = true rules are skipped with a warning; the target instances of rules without target tags are reported in one summary warning per file.
  • 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

LimitationDetail
Security group referencesRules referencing other SGs by ID instead of CIDR blocks (or self = true) generate a warning and no flow.
Data sourcesOnly planned_values resources are scanned. Data source lookups and remote state references are not resolved.
Azure inline + standalone rulesTerraform 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 valuesFields 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).

MetricValue
CLI match rate97.0% (388/400) -- highest of all formats
Browser match rate97.0% (388/400)
Tier 1 accuracy100.0% (348/348)
Tier 2 accuracy100.0% (40/40)
Field accuracy100% (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-plan

Browser: Drag and drop the .json file onto the import area. Terraform Plan format is auto-detected by the presence of planned_values.