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-network
oregress-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 (
within
clause - 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.flows
clause - 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-network
oregress-network
to specific IP spaces. - Identify Scope of Denial: Resolves the traffic characteristics defined in the
within
clause (e.g., specific protocols, ports, source/destination IPs). Ifwithin
is 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
within
clause). - 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-others
rule 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: false
to 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
within
is omitted, the scope is all traffic to/from the target network. This is very broad and usually desired only ifdeny-all-except
is 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-network
is 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
within
scope (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-others
rules 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_unenforced
report 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-except
can 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
within
clause (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
. Eachhop
object contains:node
: The hostname of the device.steps
: A list of actions/evaluations the packet underwent on that node.
- Key
steps
to 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_SUBNET
arrives atdist-switch-1
. dist-switch-1
has an ACLVLAN_INBOUND_ACL
thatPERMITTED
the flow (perhaps it has anpermit ip any any
rule).dist-switch-1
FORWARDED
the packet towardsDATACENTER_SERVER_A
.- Packet
ACCEPTED
byDATACENTER_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
:true
if the rule could not be evaluated due to syntax errors, unresolvable network/service names, or other issues.errors
will contain details.errors
: A list of error messages if the rule wasskipped
or encountered problems during evaluation.violations
: The number of unique example flows found that violate the rule. For a passingdeny-others
rule, this will be 0.checks
: The number of distinct search queries or checks Invariant performed to validate this rule. For adeny-others
rule, this typically involves Invariant constructing a query to find any flow that (matches target network AND matcheswithin
AND 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
checks
count gives an idea of the comprehensiveness of Invariant's validation for that rule. - Debugging Skipped Rules: If a rule is
skipped
, theerrors
field is the first place to look for why.
Common Pitfalls and Troubleshooting
- Overly Broad
within
: Ifwithin
is too general (e.g., justprotocol: tcp
) anddeny-all-except
is not exhaustive, you might inadvertently block legitimate traffic that wasn't considered. - Overly Narrow
within
: Ifwithin
is 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-others
rule. - Typos in
deny-all-except
: A misspelled service name or incorrect IP indeny-all-except.flows
means 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-network
defines 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-exclude
iningress-network
to exclude the router's own IPs from the target definition if the intent is to protect hosts behind the router. - Interaction of
source-address
inwithin
:- 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_B
destined toDATACENTER_A
. Only flows fromCORP_SUBNET_B
toDATACENTER_A
will 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.