FW rules validation

Good evening,

Background:
My current homelab / network is an unifi setup, which works good. We have bought a new house for which we get the keys in a few weeks, hopefully. We will not move in straight away, need to re-decorate, new carpets etc, so I thought this would be a great opportunity to upgrade my network with Mikrotik gear.

Goal:
I plan to get the RB5009UPr+S+IN router, CRS312-4C+8XG-RM switch, CRS354-48G-4S+2Q+RM switch and 2x cAP ax AP's. I have not made up my mind on the hardware, 100%. I thought that I might do some research before I get the hardware, so I have created these firewall rules.

Would someone, take a look and see if they are ok? too strict? too weak? in the right order? a waste of time? comments good or bad, always welcome.

# MikroTik Firewall Rules for Multi-VLAN Environment
# ====================================================

# VLAN Configuration Summary:
# VLAN 10 (Trusted): 10.0.10.0/24 - Full internet + IoT/Camera access + limited MGMT
# VLAN 20 (Guest): 10.0.20.0/24 - Internet only with bandwidth limits
# VLAN 30 (IoT): 10.0.30.0/24 - Internet only
# VLAN 40 (Camera): 10.0.40.0/24 - Internet only
# VLAN 50 (MGMT): 10.0.50.0/24 - Full access to all VLANs
# VLAN 67 (VPN): 172.20.67.0/24 - VPN tunnel traffic only
# VLAN 69 (DMZ): 10.0.69.0/29 - Web hosting, Internet access

# ====================================================
# ADDRESS LISTS
# ====================================================

/ip firewall address-list
add address=10.0.10.0/24 list=VLAN10_Trusted
add address=10.0.20.0/24 list=VLAN20_Guest
add address=10.0.30.0/24 list=VLAN30_IoT
add address=10.0.40.0/24 list=VLAN40_Camera
add address=10.0.50.0/24 list=VLAN50_MGMT
add address=172.20.67.0/24 list=VLAN67_VPN
add address=10.0.69.0/29 list=VLAN69_DMZ

# Specific media servers in MGMT VLAN
add address=10.0.50.10 list=Plex_Server
add address=10.0.50.20 list=Jellyfin_Server
add address=10.0.50.30 list=Overseerr_Server

# DMZ webserver
add address=10.0.69.2 list=DMZ_Webserver

# All internal networks
add address=10.0.10.0/24 list=Internal_Networks
add address=10.0.20.0/24 list=Internal_Networks
add address=10.0.30.0/24 list=Internal_Networks
add address=10.0.40.0/24 list=Internal_Networks
add address=10.0.50.0/24 list=Internal_Networks
add address=172.20.67.0/24 list=Internal_Networks
add address=10.0.69.0/29 list=Internal_Networks

# ====================================================
# BANDWIDTH QUEUE FOR GUEST VLAN
# ====================================================

/queue simple
add name="Guest_VLAN_Limit" target=10.0.20.0/24 max-limit=5M/20M burst-limit=6M/25M burst-threshold=4M/16M burst-time=30s/30s

# ====================================================
# FIREWALL FILTER RULES - INPUT CHAIN
# ====================================================

/ip firewall filter

# --- ANTI-LOCKOUT RULE (MUST BE FIRST) ---
add chain=input action=accept in-interface=eth5 protocol=tcp dst-port=22,80,443,8291 comment="Anti-Lockout: Allow management access on eth5" place-before=0

# Accept established/related connections
add chain=input action=accept connection-state=established,related,untracked comment="Accept established/related/untracked"

# Drop invalid connections
add chain=input action=drop connection-state=invalid comment="Drop invalid connections"

# Allow ICMP from all internal VLANs
add chain=input action=accept protocol=icmp src-address-list=Internal_Networks comment="Allow ICMP from all VLANs"

# Allow DNS queries to router from all VLANs
add chain=input action=accept protocol=udp dst-port=53 src-address-list=Internal_Networks comment="Allow DNS from all VLANs"
add chain=input action=accept protocol=tcp dst-port=53 src-address-list=Internal_Networks comment="Allow DNS TCP from all VLANs"

# Allow DHCP requests from all VLANs
add chain=input action=accept protocol=udp dst-port=67 src-address-list=Internal_Networks comment="Allow DHCP from all VLANs"

# Allow full management from MGMT VLAN
add chain=input action=accept src-address-list=VLAN50_MGMT comment="Allow all from MGMT VLAN"

# Drop all other input
add chain=input action=drop comment="Drop all other input"

# ====================================================
# FIREWALL FILTER RULES - FORWARD CHAIN
# ====================================================

# Accept established/related connections
add chain=forward action=accept connection-state=established,related,untracked comment="Accept established/related/untracked"

# Drop invalid connections
add chain=forward action=drop connection-state=invalid comment="Drop invalid connections"

# --- VLAN 50 MGMT - Full Access to Everything ---
add chain=forward action=accept src-address-list=VLAN50_MGMT comment="MGMT VLAN: Full access to all VLANs"

# --- VLAN 69 DMZ Rules ---
# Allow DMZ to Internet
add chain=forward action=accept src-address-list=VLAN69_DMZ dst-address-list=!Internal_Networks comment="DMZ: Allow Internet access"

# Allow MGMT to DMZ
add chain=forward action=accept src-address-list=VLAN50_MGMT dst-address-list=VLAN69_DMZ comment="DMZ: Allow MGMT access"

# Allow inbound HTTP/HTTPS to DMZ webserver (from Internet)
add chain=forward action=accept dst-address=10.0.69.2 protocol=tcp dst-port=80,443 in-interface-list=WAN comment="DMZ: Allow HTTP/HTTPS to webserver"

# Block DMZ from accessing internal VLANs
add chain=forward action=drop src-address-list=VLAN69_DMZ dst-address-list=Internal_Networks comment="DMZ: Block access to internal VLANs"

# --- VLAN 10 TRUSTED Rules ---
# Allow Trusted to IoT VLAN
add chain=forward action=accept src-address-list=VLAN10_Trusted dst-address-list=VLAN30_IoT comment="Trusted: Allow access to IoT VLAN"

# Allow Trusted to Camera VLAN
add chain=forward action=accept src-address-list=VLAN10_Trusted dst-address-list=VLAN40_Camera comment="Trusted: Allow access to Camera VLAN"

# Allow Trusted to specific media servers in MGMT VLAN
add chain=forward action=accept src-address-list=VLAN10_Trusted dst-address=10.0.50.10 protocol=tcp dst-port=32400 comment="Trusted: Allow Plex access"
add chain=forward action=accept src-address-list=VLAN10_Trusted dst-address=10.0.50.20 protocol=tcp dst-port=8097 comment="Trusted: Allow Jellyfin access"
add chain=forward action=accept src-address-list=VLAN10_Trusted dst-address=10.0.50.30 protocol=tcp dst-port=5055 comment="Trusted: Allow Overseerr access"

# Block Trusted from other MGMT VLAN resources
add chain=forward action=drop src-address-list=VLAN10_Trusted dst-address-list=VLAN50_MGMT comment="Trusted: Block other MGMT VLAN access"

# Allow Trusted to Internet
add chain=forward action=accept src-address-list=VLAN10_Trusted dst-address-list=!Internal_Networks comment="Trusted: Allow Internet access"

# Block Trusted from other internal VLANs
add chain=forward action=drop src-address-list=VLAN10_Trusted dst-address-list=Internal_Networks comment="Trusted: Block other VLAN access"

# --- VLAN 20 GUEST Rules ---
# Allow Guest to Internet only
add chain=forward action=accept src-address-list=VLAN20_Guest dst-address-list=!Internal_Networks comment="Guest: Allow Internet only"

# Block Guest from all internal VLANs
add chain=forward action=drop src-address-list=VLAN20_Guest dst-address-list=Internal_Networks comment="Guest: Block all VLAN access"

# --- VLAN 30 IoT Rules ---
# Allow IoT to Internet only
add chain=forward action=accept src-address-list=VLAN30_IoT dst-address-list=!Internal_Networks comment="IoT: Allow Internet only"

# Block IoT from all internal VLANs
add chain=forward action=drop src-address-list=VLAN30_IoT dst-address-list=Internal_Networks comment="IoT: Block all VLAN access"

# --- VLAN 40 Camera Rules ---
# Allow Camera to Internet only
add chain=forward action=accept src-address-list=VLAN40_Camera dst-address-list=!Internal_Networks comment="Camera: Allow Internet only"

# Block Camera from all internal VLANs
add chain=forward action=drop src-address-list=VLAN40_Camera dst-address-list=Internal_Networks comment="Camera: Block all VLAN access"

# --- VLAN 67 VPN Rules ---
# Block VPN VLAN from accessing any other internal VLANs
add chain=forward action=drop src-address-list=VLAN67_VPN dst-address-list=Internal_Networks comment="VPN: Block all VLAN access"

# VPN traffic should go through VPN tunnel (handled by routing/marking)
add chain=forward action=accept src-address-list=VLAN67_VPN comment="VPN: Allow VPN tunnel traffic"

# --- Final Drop Rule ---
add chain=forward action=drop comment="Drop all other forward traffic"

# ====================================================
# NAT RULES
# ====================================================

/ip firewall nat

# Port forward for DMZ webserver (HTTP/HTTPS)
add chain=dstnat action=dst-nat dst-port=80 protocol=tcp to-addresses=10.0.69.2 to-ports=80 in-interface-list=WAN comment="DMZ: Port forward HTTP to webserver"
add chain=dstnat action=dst-nat dst-port=443 protocol=tcp to-addresses=10.0.69.2 to-ports=443 in-interface-list=WAN comment="DMZ: Port forward HTTPS to webserver"

# Masquerade for Internet access (exclude VPN VLAN)
add chain=srcnat action=masquerade out-interface-list=WAN src-address-list=!VLAN67_VPN comment="NAT for Internet access (exclude VPN VLAN)"

# Masquerade for VPN VLAN through VPN interface
add chain=srcnat action=masquerade out-interface=<your-vpn-interface> src-address-list=VLAN67_VPN comment="NAT for VPN VLAN through VPN tunnel"

# ====================================================
# MANGLE RULES FOR VPN ROUTING
# ====================================================

/ip firewall mangle

# Mark connections from VPN VLAN
add chain=prerouting action=mark-connection new-connection-mark=vpn_conn passthrough=yes src-address-list=VLAN67_VPN comment="Mark VPN VLAN connections"

# Mark routing for VPN VLAN traffic
add chain=prerouting action=mark-routing new-routing-mark=vpn_route passthrough=no connection-mark=vpn_conn comment="Mark VPN VLAN routing"

Thanks efw

Hi,

changed the category of topic.

please post configuration here to save jumping back%forth to github

I'm not looking at actual config (it's not easy to look at some other person's code to reverse-engineer the thought process), just a general remark: always try to make firewall rules as strict as it gets ... if they are too strict, then something won't work and it will stand out. In the reverse case (rules not strict enough) nothing will stand out ... until sonebody/something will exploit the vulnerabilities (and tgen it will be too late).

And a bit less general remark: blocking ICMP on WAN interface(s) in chain=input doesn't actually improve security (because blocking ICMP is "security through obscurity" and that doesn't really work), but can cause some issues (e.g. blocking PMTUD which can lead to sporadic connectivity/performance issues).

Hi,

I prefer an approch per zone...and create, in forward lot of jump to chain depending needed traffic. I think it's more easier to follow and audit/manage over time ; i also do the same for the ipv6 filters.

In theory, you can't rename an address list WITHOUT manually change all rules using it... it's not a fortinet and not an object. So be care when naming them !

Don't block ICMP, learn it's role, you'll understand.
Also a good way is to order your rules by chain and by usage, forward is 90% used after input/output. A good order is forward, input, forward, customs...

With rb5009, don't let cpu frequency to auto if using cpu processed feature (wireguard, ipsec, eoip, vxlan, etc...)

ex of my personnal forward chain :

/ip firewall filter
add action=fasttrack-connection chain=forward comment="special dummy rule to enable fasttrack connections" connection-state=established,related hw-offload=yes
add action=accept chain=forward comment="established/related connections" connection-state=established,related
add action=drop chain=forward comment="drop invalid connections" connection-state=invalid
add action=accept chain=forward comment=icmp protocol=icmp

add action=jump chain=forward comment="common to internet" dst-address-list=!net_wan jump-target=common_to_internet out-interface-list=wan

add action=jump chain=forward comment="intra admin" dst-address-list=net_admin jump-target=intra_admin src-address-list=net_admin
add action=jump chain=forward comment="intra lan" dst-address-list=net_lan jump-target=intra_lan src-address-list=net_lan
add action=jump chain=forward comment="intra server" dst-address-list=net_server jump-target=intra_server src-address-list=net_server

add action=jump chain=forward comment="admin to guest" dst-address-list=net_guest jump-target=admin_to_guest src-address-list=net_admin
add action=jump chain=forward comment="admin to internet" dst-address-list=!net_wan jump-target=admin_to_internet out-interface-list=wan src-address-list=net_admin
add action=jump chain=forward comment="admin to lan" dst-address-list=net_lan jump-target=admin_to_lan src-address-list=net_admin
add action=jump chain=forward comment="admin to server" dst-address-list=net_server jump-target=admin_to_server src-address-list=net_admin
add action=jump chain=forward comment="admin to wan" dst-address-list=net_wan jump-target=admin_to_wan src-address-list=net_admin

add action=jump chain=forward comment="guest to admin" dst-address-list=net_admin jump-target=guest_to_admin src-address-list=net_guest
add action=jump chain=forward comment="guest to internet" dst-address-list=!net_wan jump-target=guest_to_internet out-interface-list=wan src-address-list=net_guest
add action=jump chain=forward comment="guest to lan" dst-address-list=net_lan jump-target=guest_to_lan src-address-list=net_guest
add action=jump chain=forward comment="guest to server" dst-address-list=net_server jump-target=guest_to_server src-address-list=net_guest
add action=jump chain=forward comment="guest to wan" dst-address-list=net_wan jump-target=guest_to_wan src-address-list=net_guest

add action=jump chain=forward comment="internet to server" dst-address-list=net_server in-interface-list=wan jump-target=internet_to_server

add action=jump chain=forward comment="lan to admin" dst-address-list=net_admin jump-target=lan_to_admin src-address-list=net_lan
add action=jump chain=forward comment="lan to guest" dst-address-list=net_guest jump-target=lan_to_guest src-address-list=net_lan
add action=jump chain=forward comment="lan to internet" dst-address-list=!net_wan jump-target=lan_to_internet out-interface-list=wan src-address-list=net_lan
add action=jump chain=forward comment="lan to server" dst-address-list=net_server jump-target=lan_to_server src-address-list=net_lan
add action=jump chain=forward comment="lan to wan" dst-address-list=net_wan jump-target=lan_to_wan src-address-list=net_lan

add action=jump chain=forward comment="router to server" dst-address-list=net_server jump-target=router_to_server src-address-list=gw_interco70a
add action=jump chain=forward comment="router to server" disabled=yes dst-address-list=net_server jump-target=router_to_server src-address-list=gw_lan

add action=jump chain=forward comment="server to admin" dst-address-list=net_admin jump-target=server_to_admin src-address-list=net_server
add action=jump chain=forward comment="server to guest" dst-address-list=net_guest jump-target=server_to_guest src-address-list=net_server
add action=jump chain=forward comment="server to internet" dst-address-list=!net_wan jump-target=server_to_internet out-interface-list=wan src-address-list=net_server
add action=jump chain=forward comment="server to lan" dst-address-list=net_lan jump-target=server_to_lan src-address-list=net_server
add action=jump chain=forward comment="server to wan" dst-address-list=net_wan jump-target=server_to_wan src-address-list=net_server

add action=jump chain=forward comment="wan to admin" dst-address-list=net_admin jump-target=wan_to_admin src-address-list=net_wan
add action=jump chain=forward comment="wan to guest" dst-address-list=net_guest jump-target=wan_to_guest src-address-list=net_wan
add action=jump chain=forward comment="wan to lan" dst-address-list=net_lan jump-target=wan_to_lan src-address-list=net_wan
add action=jump chain=forward comment="wan to server" dst-address-list=net_server jump-target=wan_to_server src-address-list=net_wan

add action=accept chain=forward comment="accept all" disabled=yes log=yes log-prefix=DEBUG_FORWARD
add action=drop chain=forward comment="drop all" log-prefix=DEBUG_FORWARD



Hey bud,

Thats great, very helpful, I will take some to re-work the rules into zone based

1 Like

For a beginner a default firewall rules from Mikrotik are more than enough so maybe start with that and learn what each rule does. Also I can recommend you youtube channels from TheNetworkBerg, TheNetworkTrip, official Mikrotik YouTube channel and also Mikrotik Indonesia channel with English subtitles. They have great content on firewall topic.

Also one important notice: Don't leave your router WITHOUT FIREWALL RULES and CONNECTED TO THE INTERNET.

Here is my set of FW rules:

/ip firewall filter
add action=accept chain=input comment=\
    "defconf: accept established,related,untracked" connection-state=\
    established,related,untracked
add action=drop chain=input comment="defconf: drop invalid" connection-state=\
    invalid
add action=accept chain=input comment="defconf: accept ICMP" protocol=icmp
add action=accept chain=input comment=Winbox dst-port=XXXX in-interface-list=\
    MGMT protocol=tcp
add action=accept chain=input comment=SNMP dst-port=XXXX \
    in-interface-list=MGMT protocol=udp
add action=accept chain=input comment=\
    "defconf: accept to local loopback (for CAPsMAN)" dst-address=127.0.0.1
add action=accept chain=input comment=EoIP protocol=gre src-address=X.X.X.X
add action=accept chain=input comment=DNS_UDP dst-port=53 in-interface-list=\
    LAN protocol=udp
add action=accept chain=input comment=DNS_TCP dst-port=53 in-interface-list=\
    LAN protocol=tcp
add action=drop chain=input comment="Drop all else"
add action=accept chain=forward comment="defconf: accept in ipsec policy" \
    ipsec-policy=in,ipsec
add action=accept chain=forward comment="defconf: accept out ipsec policy" \
    ipsec-policy=out,ipsec
add action=fasttrack-connection chain=forward comment="defconf: fasttrack" \
    connection-state=established,related hw-offload=yes
add action=accept chain=forward comment=\
    "defconf: accept established,related, untracked" connection-state=\
    established,related,untracked
add action=drop chain=forward comment="defconf: drop invalid" \
    connection-state=invalid
add action=accept chain=forward comment="Internet pristup" in-interface-list=\
    LAN out-interface-list=WAN
add action=accept chain=forward comment="VPN pristup" dst-address=\
    X.X.X.X/29 in-interface=wireguard1
add action=drop chain=forward comment="Odbaci sve ostalo"

I allow what I want and drop everything else. You will see it’s a mix of default rules and my rules needed for my specific application.