Guide: deny-others rules
The deny-others rule is one of Invariant's most powerful tools for enforcing network segmentation and Zero Trust principles. It allows you to define a broad scope of traffic that should be denied by default, with specific, explicitly permitted exceptions. This guide will walk you through understanding, writing, and troubleshooting deny-others rules.
The core purpose of a deny-others rule is to implement a "default deny" posture for a defined segment of your network. You specify what traffic should be allowed, and Invariant verifies that all other traffic within a defined scope is indeed blocked.
Key Components:
- Target Network (
ingress-networkoregress-network): Defines the primary network segment the rule applies to. Foringress-deny-others, this is the destination network. Foregress-deny-others, this is the source network. - Scope of Denial (
withinclause - Optional): Narrows down the type of traffic that the "deny by default" logic applies to. If omitted, it applies to all traffic targeting (for ingress) or originating from (for egress) the network. - Explicit Permissions (
deny-all-except.flowsclause - Required): A list of specific traffic flows that are permitted within the defined scope.
High-Level Evaluation Logic:
Invariant evaluates a deny-others rule by performing an exhaustive search:
- Identify Target Network: Resolves the
ingress-networkoregress-networkto specific IP spaces. - Identify Scope of Denial: Resolves the traffic characteristics defined in the
withinclause (e.g., specific protocols, ports, source/destination IPs). Ifwithinis not present, the scope is all traffic. - Identify Explicitly Permitted Flows: Resolves the flows listed in
deny-all-except.flows. - Search for Violations: Invariant searches for any traffic flow that:
- Matches the Target Network.
- Falls within the Scope of Denial (matches the
withinclause). - Is NOT part of the Explicitly Permitted Flows (does not match any flow in
deny-all-except.flows). - AND can be successfully delivered through the network (i.e., passes all routing and firewall configurations).
- Violation: If such a flow is found, the
deny-othersrule is violated because traffic that should have been denied (as it wasn't explicitly permitted) was allowed.
Use Cases:
- Securing sensitive zones (e.g., PCI CDE, databases) by allowing only minimal necessary access.
- Implementing Zero Trust network segmentation by defining what traffic is allowed and denying everything else.
- Gradually migrating to a Zero Trust model by using
enforce: falseto discover existing allowed traffic (see Build a Zero Trust deployment backlog).
Writing deny-others Rules
Let's construct an ingress-deny-others rule to control SSH access to a DATACENTER network.
Defining the Target Network
First, specify the network segment this rule protects. For an ingress rule, this is the destination.
access-policy:
- name: datacenter-ssh-control
ingress-network: DATACENTER # DATACENTER is a named network, e.g., 10.1.0.0/16
# ...
Defining the Scope of Denial (within clause)
The within clause defines the broader category of traffic you intend to control with this rule. All traffic matching within will be denied unless explicitly allowed by deny-all-except.
- Purpose: To narrow down what traffic is subject to the "deny by default" part of the rule.
- Common Scenarios:
- Scoping by protocol:
within: [{protocol: tcp}](controls all TCP traffic toDATACENTER). - Scoping by protocol and port:
within: [{protocol: tcp, destination-port: SSH}](controls all SSH traffic toDATACENTER). - Scoping by source and protocol:
within: [{source-address: RFC1918, protocol: tcp}](controls all internal TCP traffic toDATACENTER).
- Scoping by protocol:
- Note: If
withinis omitted, the scope is all traffic to/from the target network. This is very broad and usually desired only ifdeny-all-exceptis also very comprehensive.
For our SSH example, we want to control all TCP traffic destined for the SSH port on our DATACENTER network:
# ...
rules:
- type: ingress-deny-others
comment: Only MGMT_SERVER can SSH into DATACENTER
within:
- protocol: tcp
destination-port: SSH # Assumes SSH is defined as tcp/22
# ...
Defining Explicit Permissions (deny-all-except.flows clause)
This clause lists the specific flows that are allowed, creating exceptions to the denial defined by ingress-network and within.
- Structure: A list of flow definitions. Each flow can specify
source-address,destination-address(though usually redundant for ingress rules ifingress-networkis specific),destination-port,source-port, andprotocol.
We want to allow SSH only from MGMT_SERVER:
# ...
deny-all-except:
flows:
- comment: Allow SSH from MGMT_SERVER to DATACENTER
source-address: MGMT_SERVER # e.g., 192.168.1.10/32
protocol: tcp
destination-port: SSH
Complete Example Rule
access-policy:
- name: datacenter-ssh-control
comment: Controls SSH access into the DATACENTER network
owner: security-[email protected]
ingress-network: DATACENTER
rules:
- type: ingress-deny-others
comment: Only MGMT_SERVER can SSH into DATACENTER
within:
- protocol: tcp
destination-port: SSH
deny-all-except:
flows:
- comment: Allow SSH from MGMT_SERVER to DATACENTER
source-address: MGMT_SERVER
protocol: tcp
destination-port: SSH
This rule states: "For any TCP traffic going to the SSH port on any host in DATACENTER, deny it, unless it is TCP traffic from MGMT_SERVER to the SSH port."
Best Practices
- Start Broad, Permit Specific: It's often easier to define a broader
withinscope (e.g., all TCP traffic to a sensitive zone) and then list the few necessary permitted flows indeny-all-except. - Use
enforce: false: When creating newdeny-othersrules or migrating to a Zero Trust model, start withenforce: false. This allows Invariant to report "violations" (i.e., traffic that is currently allowed but would be denied by this rule if enforced) without failing your CI/CD pipeline. Use thepolicy_violations_unenforcedreport to build a backlog of flows to explicitly allow or block. - Be Precise: Ensure your network and service definitions (
def/directory) are accurate. A typo in an IP address or service name indeny-all-exceptcan lead to unintended denials.
Understanding Violations and policy_details
When a deny-others rule is violated, it means Invariant found a traffic flow that:
- Matched the
ingress-network(oregress-network). - Matched the
withinclause (if specified). - Did not match any flow in
deny-all-except.flows. - Was successfully deliverable through the network.
Violations are reported in policy_violations (for enforced rules) or policy_violations_unenforced. The policy_details report provides the crucial context.
Key fields in policy_details for a deny-others violation:
ok: false: Indicates a rule violation.flow_str: A human-readable summary of the specific example flow that violated the rule. This is the traffic that was permitted but should have been denied according to the rule's logic.- Example:
tcp src_ip=10.5.5.5 dst_ip=10.1.0.50 dst_port=22
- Example:
start: The entry point of the violating flow into the network model (e.g.,@enter(edge-router[GigabitEthernet0/1])).traces: A list of one or more detailed paths (virtual traceroutes) the violating flow took through the network.
Interpreting Traceroutes (traces section)
The traces section is vital for understanding why a violating flow was permitted. Each trace represents a possible path:
- Structure: A list of
hops. Eachhopobject contains:node: The hostname of the device.steps: A list of actions/evaluations the packet underwent on that node.
- Key
stepsto analyze:RECEIVED(interface): Packet arrival on an interface.PERMITTED(filter='filter_name', filterType='INGRESS_FILTER'|'EGRESS_FILTER'): Packet was allowed by the specified ACL or firewall filter.FORWARDED(..., routes=[...], resolvedNextHopIp='...'): Routing decision made. Shows the route(s) used and the resolved next-hop IP.ACCEPTED(interface): Packet delivered to the destination IP on the final node, via the specified local interface.
By examining the traces, you can pinpoint which ACL allowed the unintended traffic or if routing misconfigurations led the traffic to bypass an intended security control.
Example Scenario:
If your deny-others rule for DATACENTER (denying all TCP except from MGMT_SERVER) is violated by a flow from USER_SUBNET to DATACENTER_SERVER_A on TCP/8080, the traceroute might show:
- Packet from
USER_SUBNETarrives atdist-switch-1. dist-switch-1has an ACLVLAN_INBOUND_ACLthatPERMITTEDthe flow (perhaps it has anpermit ip any anyrule).dist-switch-1FORWARDEDthe packet towardsDATACENTER_SERVER_A.- Packet
ACCEPTEDbyDATACENTER_SERVER_A.
This trace tells you that VLAN_INBOUND_ACL on dist-switch-1 needs to be tightened.
Understanding policy_logs
The policy_logs report provides a summary for every rule Invariant processed, including deny-others rules.
Key fields for deny-others rules in policy_logs:
ok: The overall pass (true) or fail (false) status of the rule.skipped:trueif the rule could not be evaluated due to syntax errors, unresolvable network/service names, or other issues.errorswill contain details.errors: A list of error messages if the rule wasskippedor encountered problems during evaluation.violations: The number of unique example flows found that violate the rule. For a passingdeny-othersrule, this will be 0.checks: The number of distinct search queries or checks Invariant performed to validate this rule. For adeny-othersrule, this typically involves Invariant constructing a query to find any flow that (matches target network AND matcheswithinAND does NOT matchdeny-all-except.flows) and IS deliverable.check_log: (Accessible via JSON output) Provides a detailed list of the underlying checks. Fordeny-others, this would show the parameters of the reachability search Invariant performed.
How policy_logs helps:
- Confirmation: Verifies that your rule was understood and processed by Invariant.
- Scope of Test: The
checkscount gives an idea of the comprehensiveness of Invariant's validation for that rule. - Debugging Skipped Rules: If a rule is
skipped, theerrorsfield is the first place to look for why.
Common Pitfalls and Troubleshooting
- Overly Broad
within: Ifwithinis too general (e.g., justprotocol: tcp) anddeny-all-exceptis not exhaustive, you might inadvertently block legitimate traffic that wasn't considered. - Overly Narrow
within: Ifwithinis too specific, the "deny by default" part of the rule might not cover traffic you intended to block. For example,within: [{protocol: tcp, destination-port: HTTP}]will only control HTTP; other TCP traffic to the target network won't be affected by this specificdeny-othersrule. - Typos in
deny-all-except: A misspelled service name or incorrect IP indeny-all-except.flowsmeans that flow won't be correctly exempted, potentially leading to it being flagged as a violation (if it's deliverable) or actually blocked if the rule is enforced. - Router Interface IPs: If your
ingress-networkdefines a subnet (e.g.,10.1.1.0/24), and a router interface (e.g., SVI for that VLAN) has an IP within that subnet (e.g.,10.1.1.1), traffic to that router interface IP might be evaluated. If your ACLs are on the router interface itself, you might want to usedestination-excludeiningress-networkto exclude the router's own IPs from the target definition if the intent is to protect hosts behind the router. - Interaction of
source-addressinwithin:- Policy:
ingress-network: DATACENTER_A - Rule:
within: [{source-address: CORP_SUBNET_B}] - This means the rule's scope of denial applies to traffic from
CORP_SUBNET_Bdestined toDATACENTER_A. Only flows fromCORP_SUBNET_BtoDATACENTER_Awill be denied unless listed indeny-all-except.
- Policy:
By understanding these components and how Invariant reports on them, you can effectively use deny-others rules to build and maintain a robust, verifiable network security posture.