Skip to main content
RunBook Academy

OPNsenseXIV · VLANs and SegmentationInter-VLAN routing and east-west filtering

East-west firewalling — VLAN-to-VLAN rules and least privilege

Advanced⏱ ~16 minpfctltcpdumpalias

What you'll learn

  • Write VLAN-to-VLAN firewall rules that enforce least privilege
  • Enumerate the service dependencies between VLANs
  • Apply the source-group, destination-group, and port-group patterns to inter-VLAN rules
  • Audit an inter-VLAN rule set for over-permissiveness

Prerequisites

Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14

Not yet marked complete on this device.

East-west traffic is the traffic that crosses between VLANs inside the firewall. It is the dominant traffic class in most production estates — far more than north-south traffic (LAN to Internet, Internet to LAN via port forwarding). East-west is also the traffic class where segmentation fails when it fails: a flat VLAN where any host can talk to any other host is not segmented, regardless of how many VLANs the operator has created.

This lesson covers how to write VLAN-to-VLAN rules that enforce least privilege, how to enumerate the service dependencies that justify each rule, and how to keep the rule set auditable over time.

Why east-west rules are different from north-south rules

North-south rules (LAN ↔ Internet, Internet ↔ DMZ) are coarse: permit or block categories of traffic. The Internet does not need to reach internal VLANs; the LAN needs to reach most of the Internet; the DMZ needs to be reachable from the Internet but not from the LAN.

East-west rules are fine-grained: which service on VLAN 20 needs to be reachable from which host on VLAN 10. The granularity is the same granularity the application has — and applications have a long tail of dependencies (databases, caches, message queues, identity providers, monitoring agents).

The discipline of east-west firewalling is to enumerate those dependencies and write a rule for each one. The operator who writes “any to any” between VLANs has not done the work.

The service-dependency enumeration

Before writing an east-west rule, the operator must answer: what service on the destination VLAN does the source VLAN actually need?

The answer comes from the application’s network requirements:

  • A user VLAN needs DNS (UDP 53 to the DNS server) and probably NTP (UDP 123 to the NTP server).
  • A user VLAN typically does not need direct database access. The application uses the database via a server in a server VLAN.
  • A server VLAN that runs a web application needs database access (TCP 3306 for MySQL, TCP 5432 for PostgreSQL) to the database server VLAN.
  • A server VLAN that runs an internal API needs the API to be reachable from the user VLAN (TCP 443 to the API server).
  • A management VLAN needs to reach the firewall IP for GUI/SSH, but no other VLAN needs to reach the management VLAN.

The list is per-application. The operator who writes the list once and shares it with the application team has the foundation for an auditable rule set.

A worked example: the user VLAN (10) needs to reach the web application (HTTPS) on the servers VLAN (20), and the web application needs to reach the database (TCP 5432) on the database VLAN (30).

Source VLANSourceDestination VLANDestinationPortReason
Users (10)192.0.2.0/24Servers (20)203.0.113.50443Web application access
Users (10)192.0.2.0/24DNS (20)203.0.113.1053DNS resolution
Servers (20)203.0.113.50Database (30)198.51.100.205432Web app to PostgreSQL
Servers (20)203.0.113.50DNS (20)203.0.113.1053Web app DNS

Each rule has a reason. The audit answer to “why does this rule exist?” is in the table.

The rule pattern

For each service dependency, write one rule on the source VLAN. The rule has:

  • Action: pass.
  • Source: the source subnet or specific host.
  • Destination: the specific destination IP (or alias).
  • Destination port: the specific port (or alias).
  • Description: the reason. Owner, ticket, review date.

The discipline: avoid “any” in any field. A rule with destination “any” is a permit-all to the destination subnet. A rule with port “any” is a permit-all on every port. The narrower the rule, the smaller the blast radius if the rule is wrong.

Read-only / Safeinter-vlan ruleset
$ pfctl -s rules | grep -E 'igb1_vlan10|igb1_vlan20' | head -10
@10 pass in quick on igb1_vlan10 inet proto tcp from 192.0.2.0/24 to 203.0.113.50 port = https
[ Permit users to web application on servers VLAN. Owner: NetOps. Ticket NET-2401. Reviewed 2026-08-01. ]
@11 pass in quick on igb1_vlan10 inet proto tcp from 192.0.2.0/24 to 203.0.113.10 port = 53
[ Permit users to DNS server. Owner: NetOps. Ticket NET-2402. Reviewed 2026-08-01. ]
@50 pass in quick on igb1_vlan20 inet proto tcp from 203.0.113.50 to 198.51.100.20 port = 5432
[ Permit web app to PostgreSQL database. Owner: AppTeam. Ticket APP-1102. Reviewed 2026-08-01. ]
@99 block drop in quick on igb1_vlan10 inet from any to any
[ Default deny on VLAN 10. Catches all traffic not explicitly permitted above. ]

Illustrative output

The four rules shown implement the worked example. Each rule has a description; the default deny is the safety net.

Aliases for source groups, destination groups, port groups

Aliases are how OPNsense rulesets stay readable. The operator who writes “192.0.2.0/24 to 203.0.113.50 port = https” is fine; the operator who writes the same thing ten times for ten different sources creates maintenance debt.

Common alias patterns for east-west rules:

  • vlan10_hosts: an alias of specific hosts on VLAN 10 that need a particular service.
  • db_servers: an alias of database server IPs across VLANs.
  • web_app_ports: an alias of TCP ports 80, 443, 8443 used by a web application.
  • monitoring_agents: an alias of monitoring agent IPs that need to reach services across VLANs.

Aliases are referenced in rules by name. When a host is added to an alias, every rule that uses the alias picks up the new host without a rule change.

Auditing an east-west ruleset

Three audit questions to ask of an existing inter-VLAN ruleset.

Audit 1: Is there a rule with “any” anywhere?

A rule with source any, destination any, or port any is almost certainly over-permissive. The exception is the default-deny rule at the bottom of the rule set, which is intentionally broad.

pfctl -s rules | grep -E 'from any to any|to any port = any|from any to .* port = any'

Any rule that matches is a candidate for narrowing.

Audit 2: Is the rule description up to date?

A rule without a description, or with a description that does not match the rule’s actual behaviour, is an audit finding. The operator reviewing the rule cannot tell what it is for.

The fix: every rule has a description; every description references an owner, a ticket, and a review date.

Audit 3: Is there a rule that is no longer needed?

Rules outlive the services that justified them. A server is decommissioned; the rule that permitted traffic to the server stays. A service is moved to a new VLAN; the rule that permitted traffic to the old VLAN IP stays.

The fix: quarterly review of every inter-VLAN rule. Remove rules that no longer correspond to a live service dependency.

Read-only / Safeaudit any-rules
$ pfctl -s rules | grep -E 'any' | head -5
12  pass in quick on igb1_vlan10 inet proto tcp from 192.0.2.0/24 to any port = https
47  pass in quick on igb1_vlan20 inet proto tcp from any to 198.51.100.20 port = 5432
89  pass in quick on igb1_vlan10 inet from any to any
104 block drop in quick on igb1_vlan10 inet from any to any

Illustrative output

The audit output distinguishes between the rules that intentionally use “any” (the default deny) and the rules that use “any” but should not (the over-permissive pass rules).

The “permit a group” anti-pattern

A common anti-pattern: the operator creates an alias called trusted_vlans that contains every VLAN the operator considers safe, and writes a single rule “permit trusted_vlans to any”. The rule is wide; the alias name is aspirational.

The blast radius of a misconfigured trusted-vlans alias is enormous. A host compromised on any “trusted” VLAN can reach any other VLAN. The segmentation is cosmetic.

The discipline: do not alias VLANs together. Each VLAN gets its own rule set, even if the rule sets look similar. The cost of duplicating rule sets is small; the cost of an over-permissive trusted-vlans alias is large.

A worked inter-VLAN ruleset

The minimal viable inter-VLAN ruleset for a three-VLAN estate (users, servers, database):

VLAN 10 (Users) rules

OrderActionSourceDestinationPortDescription
1passvlan10_subnetdns_server53Permit DNS to internal resolver
2passvlan10_subnetweb_app443Permit web application
3blockanyanyanyDefault deny

VLAN 20 (Servers) rules

OrderActionSourceDestinationPortDescription
1passdns_serverany53Permit DNS server outbound (recursive resolution)
2passweb_apppostgres_db5432Permit web app to PostgreSQL
3passmonitoring_agentanyanyPermit monitoring agent to all servers
4blockanyanyanyDefault deny

VLAN 30 (Database) rules

OrderActionSourceDestinationPortDescription
1passweb_apppostgres_db5432Permit web app database queries
2passmonitoring_agentpostgres_db5432Permit monitoring queries to database
3blockanyanyanyDefault deny

The three rule sets implement the dependencies between the VLANs. Each rule has a description. The default deny at the bottom of each rule set is the safety net.

Summary

  • East-west firewalling is fine-grained. The granularity is the application’s network requirements.
  • Every inter-VLAN rule has a reason. Enumerate the service dependencies before writing the rule.
  • The default deny is the foundation. Every VLAN is born isolated; rules enable what is needed.
  • Audit the ruleset for “any” usage, missing descriptions, and unused rules.
  • Avoid the “permit trusted VLANs” anti-pattern. Each VLAN gets its own rule set.

Knowledge check · 4 questions

  1. Q1. You inherit an inter-VLAN ruleset with a rule "permit any to any" between VLAN 10 and VLAN 20. The rule description says "allow all east-west traffic". What is the most appropriate first action?

  2. Q2. OPNsense evaluates inter-VLAN rules on both the source VLAN interface and the destination VLAN interface for the same packet.

  3. Q3. Which of the following are valid audit questions for an inter-VLAN ruleset? Select all that apply.

  4. Q4. You add a new VLAN 40 (storage). The application team tells you the storage array at 198.51.100.100 needs to be reachable from the database server at 198.51.100.20 on TCP 2049 (NFS). You write a single rule on VLAN 30 permitting 198.51.100.20 to 198.51.100.100 port 2049. What is the most appropriate additional step?

Passing score: 75%. Answers are checked in this browser.