# 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.
