Files
hermes-skills/skills/devops/infrastructure-automation/references/mikrotik-security-hardening.md
T

6.7 KiB

MikroTik Router Security Hardening

A repeatable security audit and hardening procedure for RouterOS 7.x routers. Run when onboarding a new router or performing a periodic security review.

Audit checklist

1. IP Services — Restrict listening addresses

Check current state: /ip/service/print

Default state exposes SSH (22), API (8728), Winbox (8291), and API-SSL (8729) to 0.0.0.0/0 (any IP). Tighten each:

/ip/service/set ssh address=10.1.0.0/24,10.1.1.0/24,192.168.88.0/24,10.77.0.0/24
/ip/service/set api address=10.1.0.0/24,10.1.1.0/24
/ip/service/set winbox address=<subnets-needed>  # Keep open if user needs Winbox from anywhere
/ip/service/disable api-ssl

CRITICAL: Include 10.77.0.0/24 in SSH's allowed-address list when WireGuard tunnel is used for remote management. If you forget, you will lock yourself out and need WinBox access to recover.

RECOVERY from lockout: SSH to the router fails with "Connection closed by remote host". The fix via WinBox terminal: /ip/service/set ssh address=10.77.0.0/24. Always include this in the set command the first time.

2. Firewall — Remove duplicate rules

RouterOS config accumulates duplicate rules over time (especially WG tunnel rules). Audit:

/ip/firewall/filter/print detail

Look for:

  • Multiple rules with identical comments and action
  • Rules that are redundant (e.g., same port/protocol accepted more than once)
  • Orphaned rules with no action (missing action=accept/drop)

Remove duplicates by matching the comment text and removing all but one:

/ip/firewall/filter/remove [find where comment="allow WG tunnel (ITPP)"]
/ip/firewall/filter/remove [find where comment="allow ITPP tunnel"]

Then re-count: /ip/firewall/filter/print count. A clean home router has ~26 rules.

3. L2TP/IPsec — Disable weak authentication methods

Check current: /interface/l2tp-server/server/print

Default enables PAP, CHAP, MSCHAP1, MSCHAP2. PAP sends passwords in cleartext. MSCHAP1 is weak. Keep only CHAP + MSCHAP2:

/interface/l2tp-server/server/set authentication=chap,mschap2

4. Remove obsolete PPP secrets

When WireGuard replaces L2TP for remote management, the shonuff user's PPP secret is obsolete. Remove it:

/ppp/secret/remove [find where name=shonuff]

Leave gadmin (the user's primary VPN account) intact.

5. Stale user accounts

Check: /user/print

Remove any users that haven't logged in recently or belong to decommissioned services (e.g., a Remote Winbox SSTP user from a defunct third-party service):

/user/remove [find where name=<stale-username>]

Also check for orphaned SSTP/L2TP client interfaces: /interface/sstp-client/print — disable or remove interfaces pointing to dead services.

7. SMTP Configuration for Scheduled Emails

If the router sends scheduled email backups (logs, config, backup files), these settings are specific to this netcup KVM infrastructure:

  • Port: 2525 (NOT 465). Port 465 times out from netcup infrastructure. Only 2525 works.
  • TLS: starttls (NOT yes). Port 465 uses SSL/TLS; port 2525 uses STARTTLS.
  • DNS servers: Must be set explicitly. AT&T DHCP leases don't resolve mail.germainebrown.com. Set to internal AdGuard:
    /ip/dns/set servers=10.1.1.14,10.1.1.10
    

Apply settings:

/tool/e-mail/set port=2525 tls=starttls password="<current-password>"

Diagnostic chain for SMTP failures:

  1. DNS resolve failed → check /ip/dns/set servers= — AT&T gateway can't resolve MXroute
  2. timeout occured → missing established/related input rule (see §8). Also check if the port in use is actually open from the server's IP — try nc -zv mail.germainebrown.com 2525 from the management box.
  3. AUTH failed → check password in /tool/e-mail/print against current mail provider creds. The mail password may have been changed since the router was configured.
  4. succeeded → test with /tool/e-mail/send to="test@domain" subject="test" body="test"

Check status: /tool/e-mail/print — look for last-status: succeeded.

Known quirk: When changing SMTP settings or password on RouterOS, the previous error entries in the log buffer (e-mail,error) persist — the new test may have succeeded even though old errors are still visible. Always check last-status on /tool/e-mail/print rather than scroll-back logs.

Also fix the scheduler scripts: the filenames created by /log print file=<name> and /export file=<name> auto-append extensions (.txt / .rsc). Ensure the email file= parameter matches what's actually created:

Scheduler creates Email attaches Match?
logs.txt home-rtr-logs.txt Fix: use same filename on both sides
export.rsc home-rtr-config.rsc Fix: use same filename on both sides

8. Firewall INPUT chain — Add established/related rule

RouterOS forwards typically have connection-state=established,related but the INPUT chain may lack it. Without this rule, outgoing connections initiated by the router itself (SMTP, DNS) have their return traffic blocked by WAN-DROP.

Symptom: SMTP shows timeout occurred or DNS shows DNS resolve failed even though DNS servers are correct and ports are open.

Add at position 1 (before WAN-DROP):

/ip/firewall/filter/add chain=input action=accept connection-state=established,related place-before=1 comment="Allow established/related input"

Verify with: /ip/firewall/filter/print count where chain=input

L2TP server IPSec secret

The L2TP server's IPsec PSK (ipsec-secret) is in cleartext in the config. Ensure it:

  • Is a strong random string (12+ characters)
  • Is stored in the password manager / recovery bundle
  • Is NOT shared across routers (unique per router)

Common failure: WireGuard public key mismatch

This is the most common cause of "tunnel configured correctly but 0 B received". The router's config export (/export show-sensitive) includes the WireGuard private key, but RouterOS may have regenerated it since that export was saved. The public key in the export is now stale.

Diagnosis: Server wg show shows TX counts increasing but RX stays at 0, even though the router pingable on WAN IP and UDP port is accessible.

Fix: Read the router's ACTUAL public key directly:

/interface/wireguard/print detail where name=wg-itpp

Compare public-key= from that output with the server's wg show peer public key. If mismatched:

  1. Update the server's /etc/wireguard/wg0.conf [Peer] section with the correct public key
  2. Restart wg-quick@wg0
  3. Verify handshake appears within seconds

Prevention: Never trust public-key= from a config export file. Always verify against the live router's interface. The export captures the key at export time; it can go stale if the router regenerates its WG keys during a config reset or manual rekey.