Skip to content
LinkState
Go back

Policy intent drift hides between render and enforcement

Introduction to Access Policy Comparison

Understanding Intended Access Policy

Intended access policy is the declarative expression of who or what may communicate with whom, under which conditions, and with what protocol/port constraints. It is typically authored in a high‑level language (e.g., YAML, JSON, or a domain‑specific DSL) that is independent of any particular device syntax. The intent captures:

Because the intent is abstract, it must be rendered into device‑specific configuration (ACLs, firewall rules, security group entries) before it can be enforced. The correctness of the enforcement hinges on the fidelity of each transformation step.

Rendered ACL Lines and Merged Device Config

Rendered ACL lines are the low‑level statements produced by a policy engine after it has translated the intent into the syntax of a target device (e.g., Cisco IOS access‑list, Juniper firewall filter, Linux iptables/nftables, or AWS security group JSON). Each line contains:

  1. Sequence number – determines evaluation order.
  2. Match criteria – source/destination IP, port, protocol, optionally DSCP, VLAN, or interface.
  3. Actionpermit/deny (or accept/drop).
  4. Optional modifiers – logging, rate‑limit, or count.

Merged device config is the final set of configuration lines that exist on the device after the rendered ACL has been combined with any pre‑existing configuration (e.g., legacy rules, interface‑specific overrides, or static NAT). Merging may involve:

If the merge operation is not deterministic or if the device’s parser interprets overlapping ranges differently, the applied state (what the device actually evaluates) can diverge from the rendered state (what the policy engine emitted).

Access Policy Drafting by AI Assistants

Overview of AI‑Driven Segmentation Changes

AI assistants that propose segmentation changes typically operate in a loop:

  1. Ingest current policy repository, topology data, and observed flow telemetry.
  2. Generate a candidate diff (add, modify, delete rules) that satisfies a stated goal (e.g., “allow api‑svc to talk to db‑svc on TCP 3306”).
  3. Score the candidate using a learned model that estimates risk, blast‑radius, and compliance with organizational guardrails.
  4. Emit a proposed change set in the same declarative format used by the policy‑as‑code pipeline.

Because the model is trained on historical configs, it may reproduce patterns that are syntactically correct but semantically misaligned with the current intent (e.g., using a stale subnet, mis‑typing a protocol number, or omitting an implicit deny). The assistant’s output looks plausible in a code review, yet the rendered ACL may enforce a different boundary.

Review Process for Drafted Segmentation Changes

A robust review combines static analysis and policy‑path tracing:

If any step yields a mismatch between the reviewer’s expectation and the simulated outcome, the change is rejected or revised before merging.

Comparison of Intended and Rendered Policies

Identifying Discrepancies in ACL Lines

Discrepancies appear when the rendered ACL lines do not faithfully implement the intended rule set. Common patterns:

SymptomLikely CauseDetection Method
Missing deny for a subnet that should be blockedRendering engine omitted implicit deny or collapsed overlapping rangesCompare intent‑derived deny list vs. rendered ACL; look for gaps in coverage.
Extra permit for a service port not in intentAI assistant inserted a rule with an overly broad port range (e.g., tcp any any 1024-65535)Parse rendered ACL, extract port ranges, intersect with intent‑specified services.
Sequence number shift causing a rule to be evaluated after a conflicting denyMerge operation used insert at wrong index or device renumbered ACL on reloadRender ACL with explicit sequence numbers; compare to device show access‑list output.
Use of deprecated protocol number (e.g., ip vs tcp)Rendering engine defaulted to ip when protocol unspecifiedVerify each line’s protocol field against intent.

A practical technique is to normalize both intent and rendered ACL into a common representation (e.g., a list of 5‑tuples: <src_ip/src_mask>,<dst_ip/dst_mask>,<proto>,<src_port>,<dst_port>,<action>) and then compute set differences.

Analyzing Merged Device Config for Inconsistencies

Even if the rendered ACL is correct, the merged config may introduce inconsistencies:

To detect these, extract the effective ACL from the device (show access‑list <name> or show firewall) and compare it to the rendered ACL after applying the same merge logic that the device uses (often documented in the vendor’s configuration guide). Any divergence points to a merge‑layer issue.

Tools and Techniques for Policy Comparison

ToolPrimary UseExample Command
batfishIntent‑to‑render validation, header space analysisbatfish analyze --questions HeaderSpace --inputs intent.yaml --snapshot ./configs
cisco‑acl‑parser (Python)Normalize Cisco ACL lines to 5‑tuplespython -m acl_parser --input rendered.acl --output normalized.json
nftables‑jsonConvert nftables rule set to JSON for diffingnft list ruleset > current.json
git diff --no-indexQuick textual diff of rendered vs. merged configgit diff --no-index rendered.acl merged.cfg
opa (Open Policy Agent)Evaluate custom policy (e.g., “no rule may permit 0.0.0.0/0”)opa eval --data policy.rego --input rendered.json "data.allow"
tcpdump / flowmonObserve actual packets to validate enforcementtcpdump -i eth0 -nn src 10.0.1.5 and dst 10.0.2.10

A typical CI job might run:

# .gitlab-ci.yml snippet
validate_policy:
  script:
    - batfish snapshot set ./intents ./rendered
    - batfish question run HeaderSpace --snapshot ./intents
    - python compare_acls.py --intent intent.yaml --rendered rendered.acl --device merged.cfg

Troubleshooting Wrong Boundary Enforcement

Common Causes of Enforcement Errors

  1. Incorrect selector expansion – AI generated src: 10.0.0.0/8 when intent was src: 10.0.1.0/24.
  2. Implicit deny omission – rendering engine assumes a permissive default and does not add the final deny any any.
  3. Sequence number collision – two rules get the same number; the device keeps only the last one loaded.
  4. NAT or proxy interference – traffic is translated before ACL evaluation, causing the ACL to see post‑NAT addresses.
  5. Policy drift – a legacy rule not captured in the intent repository remains in the merged config and overrides the new intent.
  6. Vendor‑specific quirks – e.g., Cisco ACLs evaluate established keyword only for TCP; mis‑specifying it for UDP results in no match.

Step‑by‑Step Troubleshooting Guide

  1. State the observed symptom – e.g., “Host A (10.0.1.5) cannot reach Host B (10.0.2.20) on TCP 443.”
  2. Capture the flow – use a mirror or flow export to confirm the packet’s 5‑tuple as seen by the device.
  3. Retrieve the applied ACLshow access‑list <name> or equivalent.
  4. Trace the policy path:
    • Identify the first ACL line that matches the

Share this post on:

Previous Post
Canarying MTU fixes without creating new loss
Next Post
Drift timelines from config and telemetry