Locking down management
R1 now routes correctly, but anyone who can reach it can talk to it. Out of the box, this VyOS build doesn't run SSH at all, yet BGP's TCP port 179 answers connections from any address, including your LAN and the whole internet. (BGP itself rejects strangers, but only after the TCP handshake, so the port is still a target.) Before a router goes into production, lock down how it's managed.
A management address
Give the router one address that exists only for management, and bind every management service to it. A loopback is ideal: it's always up, it doesn't belong to any one link, and its purpose is obvious. Here R1 gets 198.51.100.254/32, from the unused half of the /24. (It's more specific than the blackhole, so it still works.)
In a bigger network, management usually lives on a separate out-of-band network or in its own Virtual Routing and Forwarding (VRF) instance, so you can still reach the router when the production network is broken. The idea is the same: one known address per router, and services listen nowhere else.
SSH: keys only, on that address
listen-addressbinds SSH to the management loopback. Connections to any other address on the router are refused outright.- Log in with SSH keys. Load your public key into the user account, check that key login works, then disable password authentication. Doing it in one commit, as here, is fine, but only if the key is right. On a remote router, use
commit-confirm(see the checklist) so a mistake rolls itself back. - A pre-login banner states that access is restricted. It doesn't stop anyone, but it makes the terms of access explicit, which can matter if you ever need to take action against an intruder.
- In production, give each person their own user with their own key, rather than sharing the
vyosaccount.
An input firewall
Binding SSH to the loopback doesn't hide it: the loopback is inside our announced /24, so the whole internet can route to it. The lab proves it: before the firewall, the upstream could open a connection to SSH.
VyOS's firewall ipv4 input filter applies to traffic addressed to the router itself. It doesn't affect traffic passing through. A minimal policy:
- Accept replies to connections the router opened (
established,related), and dropinvalidpackets. - Accept anything from the router to itself (
lo). - Accept ICMP, so ping and path MTU discovery keep working.
- Accept SSH only from the management networks, and BGP only from configured neighbors.
- Drop everything else.
Firewall groups keep the rules readable, and mean that adding a BGP neighbor or a management subnet is a one-line change. Remember to add each new BGP neighbor to BGP-PEERS, or its session will never come up.
This lab only filters IPv4. If your interfaces have IPv6 addresses, write the same policy under firewall ipv6 input filter, because the IPv4 rules don't apply to IPv6 at all.
Also worth doing
- NTP: VyOS ships with
time1–3.vyos.netas NTP servers. Point it at your own or your provider's, so logs from every device line up. - Remote syslog, so you still have the logs if the router dies or is compromised.
- SNMP or streaming telemetry for monitoring, bound to the management address and limited to your monitoring hosts, like SSH.
set interfaces loopback lo address '198.51.100.254/32'
set system login banner pre-login 'Authorised access only. All activity is logged.'
set system login user vyos authentication public-keys admin@host key 'AAAAC3NzaC1lZDI1NTE5AAAAICr2rfW95lj3ygmOijRVlMJmROyeBWv+unBUvXjxfL6Y'
set system login user vyos authentication public-keys admin@host type 'ssh-ed25519'
set service ssh listen-address '198.51.100.254'
set service ssh disable-password-authentication- Line 1: The management loopback. A /32 inside our aggregate, so it's reachable from anywhere we route to.
- Line 2: Shown before the password or key exchange completes.
- Lines 3–4: The admin's public key (from
ssh-keygenon the management host; the private key never leaves it). - Line 5: SSH listens on the management address only.
- Line 6: Keys only. Commit this only once you know the key works, or use commit-confirm.
set firewall group network-group MGMT-NETS network '198.51.100.0/25'
set firewall group address-group BGP-PEERS address '203.0.113.0'
set firewall group address-group BGP-PEERS address '192.0.2.1'
set firewall ipv4 input filter default-action 'drop'
set firewall ipv4 input filter rule 10 action 'accept'
set firewall ipv4 input filter rule 10 state 'established'
set firewall ipv4 input filter rule 10 state 'related'
set firewall ipv4 input filter rule 20 action 'drop'
set firewall ipv4 input filter rule 20 state 'invalid'
set firewall ipv4 input filter rule 30 action 'accept'
set firewall ipv4 input filter rule 30 inbound-interface name 'lo'
set firewall ipv4 input filter rule 40 action 'accept'
set firewall ipv4 input filter rule 40 protocol 'icmp'
set firewall ipv4 input filter rule 50 action 'accept'
set firewall ipv4 input filter rule 50 protocol 'tcp'
set firewall ipv4 input filter rule 50 destination port '22'
set firewall ipv4 input filter rule 50 source group network-group 'MGMT-NETS'
set firewall ipv4 input filter rule 60 action 'accept'
set firewall ipv4 input filter rule 60 protocol 'tcp'
set firewall ipv4 input filter rule 60 destination port '179'
set firewall ipv4 input filter rule 60 source group address-group 'BGP-PEERS'- Lines 1–3: Groups: who may manage the router, and who may speak BGP to it.
- Line 4: Anything not explicitly allowed, to the router itself, is dropped.
- Lines 5–9: Replies to connections R1 opened (including BGP sessions it initiated), and junk that matches no connection.
- Lines 10–11: The router talking to itself.
- Lines 12–13: ICMP, so ping and path MTU discovery work.
- Lines 14–17: SSH from the management networks only.
- Lines 18–21: BGP from configured neighbors only.
root@host:~# ssh vyos@198.51.100.254 uname -n
Authorised access only. All activity is logged.
R1
root@host:~# ssh vyos@198.51.100.1 uname -n
ssh: connect to host 198.51.100.1 port 22: Connection refused
root@host:~# ssh -o PubkeyAuthentication=no vyos@198.51.100.254 uname -n
Authorised access only. All activity is logged.
vyos@198.51.100.254: Permission denied (publickey).
root@host:~# nc -zv -w3 198.51.100.1 179
nc: connect to 198.51.100.1 port 179 (tcp) timed out: Operation now in progress- Lines 1–3: Key login to the management address works, after the banner.
- Lines 4–5: Nothing listens on the LAN address, so the router refuses the connection.
- Lines 6–8: Without a key, the server only offers
publickey: no password prompt to brute-force. - Lines 9–10: The LAN host isn't a BGP neighbor, so TCP 179 is silently dropped.
# Before the input firewall (management stage only)
upstream:/# nc -zv -w3 198.51.100.254 22
198.51.100.254 (198.51.100.254:22) open
upstream:/# nc -zv -w3 203.0.113.1 179
203.0.113.1 (203.0.113.1:179) open
# After the input firewall
upstream:/# nc -zv -w3 198.51.100.254 22
nc: 198.51.100.254 (198.51.100.254:22): Operation timed out
upstream:/# nc -zv -w3 203.0.113.1 179
203.0.113.1 (203.0.113.1:179) open- Lines 2–3: Before the firewall, the upstream (standing in for the internet) could reach SSH on the management address.
- Lines 7–8: After: dropped, so the connection times out.
- Lines 9–10: BGP from a configured neighbor still gets through.
vyos@R1:~$ show ip bgp summary
IPv4 Unicast Summary:
BGP router identifier 198.51.100.1, local AS number 64500 VRF default vrf-id 0
BGP table version 12
RIB entries 5, using 800 bytes of memory
Peers 2, using 60 KiB of memory
Neighbor V AS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc
192.0.2.1 4 64511 8 7 12 0 0 00:03:20 1 1 IX route server 1
203.0.113.0 4 64496 9 7 12 0 0 00:03:39 2 1 UPSTREAM transit
Total number of neighbors 2
vyos@R1:~$ show firewall ipv4 input filter
Ruleset Information
---------------------------------
ipv4 Firewall "input filter"
Rule Action Protocol Packets Bytes Conditions
------- -------- ---------- --------- ------- -------------------------------------------
10 accept all 29 5864 ct state { established, related } accept
20 drop all 0 0 ct state invalid
30 accept all 2 144 iifname "lo" accept
40 accept icmp 0 0 meta l4proto icmp accept
50 accept tcp 1 60 tcp dport 22 ip saddr @N_MGMT-NETS accept
60 accept tcp 1 60 tcp dport 179 ip saddr @A_BGP-PEERS accept
default drop all 6 360 comment "INP-filter default-action "- Lines 10–11: Both sessions stayed up through the firewall commit.
- Line 22: Most traffic is matched here: the established BGP sessions.
- Line 26: The host's SSH connection…
- Line 27: …and the upstream's test connection to port 179.
- Line 28: Everything else, including the upstream's SSH attempt and the host's port 179 test.
Check your understanding
SSH is bound to 198.51.100.254. Why is an input firewall still needed?
- It isn't; binding hides SSH from the internet
- Because the management address is routable from the internet, so binding alone doesn't restrict who can connect
- To stop traffic passing through R1 to the LAN
- Because SSH keys don't work without a firewall