VyOSLIII · Security HardeningSecurity
Router hardening checklist — configuration review, OOB management, audit log
What you'll learn
- Walk the production router hardening checklist for a VyOS 1.5 LTS router
- Verify every peer has authentication, every interface has a description, every CoPP rule is in place
- Establish an out-of-band management path (serial console, IPMI, dedicated VLAN)
- Configure the audit log to record configuration changes, authentication attempts, and system events
Prerequisites
Verified against VyOS 1.5.x LTS (circinus) · VyOS 1.4.x (sagitta) — legacy · FRRouting 10.x (VyOS 1.5) · Linux kernel 6.6 LTS (VyOS 1.5 base) · strongSwan 5.9.x (IPsec) · WireGuard 1.0.x (kernel module + userspace tooling)
A router’s security is the sum of every choice the operator has made since the last install. A configuration that started secure (no default credentials, CoPP in place, every peer has authentication) drifts over time: a new BGP peer is added without authentication, a CoPP rule is removed for a debugging session and never put back, a default user is left enabled. The hardening checklist is the operator’s discipline to catch the drift.
The production hardening checklist has three sections:
- Configuration review — verify every security control is still in place. This is a manual review of the running configuration, not an automated scan.
- Out-of-band management — establish a path to the router that does not depend on the production network. The OOB path is what the operator uses when the production network is down or compromised.
- Audit log — record every configuration change, authentication attempt, and system event. The audit log is the operator’s defence against the post- incident review question “what happened?”.
This lesson walks the checklist, explains the rationale for each item, and shows the production commands to verify the control.
The configuration review
The configuration review is a manual walk of the running configuration. The operator checks every security control against the checklist:
# Every BGP peer, then the peers that carry a key
show configuration commands | match "protocols bgp neighbor"
show configuration commands | match "protocols bgp neighbor .* password"
# OSPF authentication is per-interface on 1.5
show configuration commands | match "protocols ospf interface"
show configuration commands | match "protocols ospf .* authentication"
# Control-plane rate limiting lives in the input chain
show configuration commands | match "firewall ipv4 input filter"
show configuration commands | match "firewall ipv4 input filter .* limit"
# SSH and the local accounts
show configuration commands | match "service ssh"
show configuration commands | match "system login"
# The firewall as a whole, and the base hooks specifically
show configuration commands | match "firewall"
show configuration commands | match "firewall ipv4 (input|forward|output) filter"
The output of these commands is the operator’s evidence.
show configuration commands flattens the running
configuration into one set command per line, and match
is a regular expression against that flat text — so the
two-line pattern above is deliberate. The first line
enumerates the objects, the second enumerates the objects
that carry the control, and the review is the
subtraction. Nine neighbours and six passwords is a
finding; you do not get that finding from either line on
its own.
flowchart TB
R["Running configuration"] --> C1{"Every BGP peer<br/>carries a password?"}
C1 -->|no| F1["FAIL: peer without TCP-MD5"]
C1 -->|yes| C2{"Every OSPF interface<br/>authenticated?"}
C2 -->|no| F2["FAIL: unauthenticated adjacency"]
C2 -->|yes| C3{"Input chain rate-limits<br/>the control protocols?"}
C3 -->|no| F3["FAIL: no control-plane limit"]
C3 -->|yes| C4{"SSH hardened?"}
C4 -->|no| F4["FAIL: harden SSH"]
C4 -->|yes| C5{"Base hooks default-drop,<br/>named sets jumped to?"}
C5 -->|no| F5["FAIL: filter absent or inert"]
C5 -->|yes| PASS["Controls present<br/>- now read them"]
The diagram shows the review sequence. Each check is a branch: a missing control is a failure that the operator must remediate. A configuration that passes all checks is ready for the audit log review.
Checklist item 1: every BGP peer has authentication
show configuration commands | match "protocols bgp neighbor" | match "remote-as"
show configuration commands | match "protocols bgp neighbor" | match "password"
show configuration commands | match "protocols bgp neighbor" | match "ttl-security"
The first line is the peer inventory — one remote-as
line per configured neighbour. The second is the peers
that carry TCP-MD5. The third is the peers that carry
GTSM. Any neighbour present in the first list and absent
from the second is the finding.
On VyOS 1.5 the peer stanza sits directly under
protocols bgp, not under the ASN:
set protocols bgp system-as 64512
set protocols bgp neighbor 10.0.0.5 remote-as 64513
set protocols bgp neighbor 10.0.0.5 password COORDINATE-OUT-OF-BAND
set protocols bgp neighbor 10.0.0.5 ttl-security hops 1
The local ASN moved to system-as in VyOS 1.4 and the
neighbours moved out from under it. A checklist written
against protocols bgp 64512 neighbor ... matches nothing
on a 1.5 router — and an empty result from a review
command reads exactly like a missing control, which is the
worst way for a checklist to fail.
A typical BGP configuration has 5-50 neighbours; the
review can be done by hand in 10-15 minutes. For a
larger deployment, show configuration commands is
line-oriented text, so the subtraction is a comm or an
awk away — but keep the output of both lists in the
change ticket, not just the verdict.
Checklist item 2: every OSPF interface has authentication
show configuration commands | match "protocols ospf interface"
show configuration commands | match "protocols ospf" | match "authentication"
show configuration commands | match "protocols ospf interface" | match "passive"
For every OSPF interface, the operator verifies that authentication is configured. On VyOS 1.5 the per-interface OSPF settings live under the protocol, not under the interface:
set protocols ospf interface eth1 authentication md5 key-id 1 md5-key COORDINATE-OUT-OF-BAND
The third grep is the one operators forget. An interface
that faces a customer or a user VLAN and is not
passive is running OSPF at anyone who plugs in, and
authentication limits the damage rather than removing it:
a passive interface still advertises the prefix and never
forms an adjacency, which is the control you actually
wanted. Read the two lists together — an interface that is
neither authenticated nor passive is the finding.
Checklist item 3: the control plane is rate-limited
show configuration commands | match "firewall ipv4 input filter"
show configuration commands | match "firewall ipv4 input filter" | match "limit"
show configuration commands | match "firewall ipv6 input filter" | match "limit"
The mechanism is a limit rate and limit burst on the
rule that accepts each class, so the accept keeps working
at the legitimate rate and the excess falls through to
whatever follows:
set firewall group address-group BGP-PEERS address '10.0.0.5'
set firewall group address-group BGP-PEERS address '10.0.0.9'
set firewall ipv4 input filter default-action 'drop'
set firewall ipv4 input filter rule 20 action 'accept'
set firewall ipv4 input filter rule 20 description 'SSH from management, rate limited'
set firewall ipv4 input filter rule 20 protocol 'tcp'
set firewall ipv4 input filter rule 20 destination port '22'
set firewall ipv4 input filter rule 20 source address '10.99.0.0/24'
set firewall ipv4 input filter rule 20 state 'new'
set firewall ipv4 input filter rule 20 limit rate '4/minute'
set firewall ipv4 input filter rule 20 limit burst '8'
set firewall ipv4 input filter rule 30 action 'accept'
set firewall ipv4 input filter rule 30 description 'BGP from configured peers only'
set firewall ipv4 input filter rule 30 protocol 'tcp'
set firewall ipv4 input filter rule 30 destination port '179'
set firewall ipv4 input filter rule 30 source group address-group BGP-PEERS
set firewall ipv4 input filter rule 40 action 'accept'
set firewall ipv4 input filter rule 40 description 'ICMP to the router, rate limited'
set firewall ipv4 input filter rule 40 protocol 'icmp'
set firewall ipv4 input filter rule 40 limit rate '10/second'
set firewall ipv4 input filter rule 40 limit burst '20'
Two of those rules are rate limited and one is not, and
that is the judgement the checklist is really reviewing.
limit on the SSH rule bounds a password-guessing rate
without bounding an established session, because state new restricts the rule to the handshake. limit on ICMP
bounds a flood. Putting a limit on BGP would be a
mistake: the legitimate rate of a full-table
convergence is not something you can guess, and the
consequence of guessing low is that you drop your own
routing. BGP is protected by who, not by how fast —
a source address group holding exactly the configured
peers, which is the narrowest control available and the
one to verify.
Checklist item 4: SSH is hardened
show configuration commands | match "service ssh"
show configuration commands | match "system login user"
show configuration commands | match "system login user" | match "public-keys"
The controls the 1.5 service ssh tree actually exposes,
and what each one is for:
set service ssh port '2222'
set service ssh listen-address '10.99.0.1'
set service ssh password-authentication 'disable'
set service ssh root-login 'disable'
set service ssh ciphers ['chacha20-poly1305@openssh.com', 'aes256-gcm@openssh.com']
set service ssh key-exchange ['curve25519-sha256', 'diffie-hellman-group18-sha512']
set service ssh mac ['hmac-sha2-512-etm@openssh.com', 'hmac-sha2-256-etm@openssh.com']
The review reads the third grep against the second: every
account in system login user that has no public-keys
entry is an account that cannot log in once
password-authentication is disable, which is either the
control working or a lockout waiting to happen, and the
checklist is the place to find out which.
Checklist item 5: the firewall is in place and reachable
show configuration commands | match "firewall ipv4 input filter default-action"
show configuration commands | match "firewall ipv4 forward filter default-action"
show configuration commands | match "firewall ipv4 name"
show configuration commands | match "jump-target"
show firewall ipv4 input filter
The operator verifies at least:
default-action 'drop'on the base hooks.input filteris traffic to the router,forward filteris traffic through it,output filteris traffic the router originates. A default ofaccepton either of the first two makes every rule below it advisory.- An
established/relatedrule near the top of each chain. On 1.5 these are separate values ofstate(state established,state related), not anenableleaf under astatenode — the 1.3 form does not commit. - A rule for each routing protocol you actually run,
scoped by source where the peers are static. BGP is TCP
179 in the input chain; OSPF is
protocol ospf; both are addressed to the router, so neither belongs inforward. - A rule for management, scoped to the management prefix as in item 3.
The fourth grep is the one that catches the failure this
item exists for. A firewall ipv4 name <SET> rule set is
inert on its own: nothing in it is evaluated until a base
hook contains a rule with action jump and a
jump-target naming it. A router can carry a beautifully
written 40-rule set that has never seen a packet, and the
configuration review will show it as present. show firewall ipv4 input filter closes that gap by printing the
live counters — a chain where every counter is zero is
either a very quiet router or a chain nothing reaches.
Out-of-band management
The OOB management path is what the operator uses when the production network is down or compromised. Three mechanisms are typical:
- Serial console — a physical serial port on the router that connects to a terminal server. The terminal server is on a separate physical network (often a different ISP) and is reachable when the production network is down.
- IPMI / iLO / iDRAC — a dedicated out-of-band management interface on the server (not a router feature, but applicable to virtualised routers). The IPMI interface is on a separate physical network.
- Dedicated management VLAN — a separate VLAN carried over a separate physical path to the router. The management VLAN carries SSH and HTTPS only.
flowchart LR
OP["Operator<br/>workstation"] -->|"terminal server"| OOB["OOB network"]
OOB -->|"serial / IPMI"| R["Router"]
OP -->|"SSH"| PROD["Production network"]
PROD --> R
The diagram shows the two paths: the production path through SSH over the production network, and the OOB path through the terminal server. The OOB path is the operator’s lifeline when the production network is down.
# A dedicated management interface, in its own VRF
set vrf name mgmt table '100'
set interfaces ethernet eth1 address '10.99.0.1/24'
set interfaces ethernet eth1 description 'OOB management'
set interfaces ethernet eth1 vrf 'mgmt'
# Run the SSH daemon inside that VRF
set service ssh vrf 'mgmt'
set service ssh password-authentication 'disable'
# One named account per human, with a key
set system login user netops full-name 'NetOps on-call'
set system login user netops authentication public-keys oncall@jump type 'ssh-ed25519'
set system login user netops authentication public-keys oncall@jump key 'AAAAC3NzaC1lZDI1NTE5AAAAIExampleKeyMaterialGoesHere'
The management interface is on a separate network (10.99.0.0/24) with its own routing table, so a route leaked or injected in the default table cannot pull management traffic onto the production path.
The account carries a key rather than a password, which is
what makes password-authentication 'disable' survivable.
Where a password is unavoidable, the node is
set system login user netops authentication plaintext-password 'value'.
VyOS hashes it during commit and the running
configuration afterwards shows encrypted-password with a
$6$ hash, so the cleartext exists only in your terminal
scrollback — which is its own reason to prefer the key.
The audit log
The audit log is the operator’s defence against the post-incident question “what happened?”. The log records every configuration change, every authentication attempt, and every system event:
The audit trail has two halves on VyOS, and a checklist that only reviews one of them has a hole in it.
Events go to syslog. The router ships them to a collector on the OOB network:
set system syslog host '10.99.0.100' facility all level 'info'
set system syslog console facility all level 'warning'
facility all level 'info' on the remote is the volume you
want off the box. level 'warning' on the console is
deliberate and not a typo: an info-level console floods
the serial line with routine chatter, and the serial line
is the one path you will be reading during the incident
when everything else has failed. Part XLVIII covers the
syslog tree, including the TCP and TLS transports, in
detail.
Configuration does not go to syslog. VyOS keeps a commit archive on the box and can ship a copy of every committed configuration off it:
set system config-management commit-revisions '100'
set system config-management commit-archive location 'scp://archive@10.99.0.100:/srv/router-configs'
Every successful commit writes a revision locally and
pushes a copy to that location. This is the half that
answers “what changed”, because it is the only half that
contains the configuration itself.
The audit trail therefore captures:
- Configuration changes — the commit archive holds one
full configuration per commit;
show system commitlists the revisions with the user and the timestamp, andcompare <revA> <revB>produces the diff between any two of them. The diff is computed on demand from the stored revisions, not recorded at commit time. - Authentication attempts — every SSH login attempt is logged by the daemon with the source address, the username, and the outcome, and reaches the collector through syslog.
- System events — daemon restarts, interface transitions, routing protocol state changes, also through syslog.
Both destinations sit on the OOB network, so both survive a compromise of the production path.
Failure modes
Checklist not run
The operator does not run the checklist. The configuration drifts over time: a new BGP peer is added without authentication, a CoPP rule is removed for debugging. Six months later, an attacker compromises the new peer and uses the missing authentication to inject routes.
Diagnostic: the checklist is a manual review; the absence of a review is the failure.
Fix: schedule the checklist review on a recurring calendar event (quarterly is typical). The review is a manual walk of the checklist items with the operator verifying each control.
OOB network down
The OOB network has its own ISP and its own switches. The ISP goes down; the terminal server is unreachable. The operator has no path to the router except the production network.
Diagnostic: the operator cannot SSH to the terminal server. The terminal server’s status page is offline.
Fix: the OOB network is a single point of failure. Defensive idiom: dual-ISP OOB network with automatic failover, or a cellular modem as a tertiary path.
Audit trail never leaves the box
The operator configures logging and the commit archive and stops there. Both are files on the router’s disk, and an attacker with configuration access owns both.
Diagnostic: show configuration commands | match "system syslog host"
returns nothing, and so does
show configuration commands | match "commit-archive". Two
empty results, two halves of the audit trail that exist
only where the incident can reach them.
Fix: a remote syslog host and a commit-archive location,
both on the OOB network. Note that these are two separate
findings with two separate fixes — configuring the syslog
host and calling the item done leaves the configuration
history unprotected, which is the half that answers the
question you will actually be asked.
Default credentials left in place
The operator installs VyOS and does not change the
default vyos user password. An attacker scans the
Internet for VyOS routers with the default password;
the operator’s router is found.
Diagnostic: show configuration commands | match "system login user".
An account whose only authentication line is an
encrypted-password is a password account; whether that
password is the installer default is not something the
configuration can tell you, which is why this item is a
rotation rather than a check.
Fix: give the account a key
(system login user <name> authentication public-keys),
set service ssh password-authentication 'disable' once
the key is proven from a second session, and rotate the
password anyway so the console path is not the default
either. Where a RADIUS or TACACS+ backend exists
(system login radius / system login tacacs), the local
account becomes the break-glass credential — keep exactly
one, document where its password is held, and
set system login user <name> disable the rest rather than
deleting them, so the removal is visible in the commit
archive.
Rollback
A hardening change is reversible through the standard VyOS mechanisms:
rollback Nreverts to stored revision N. On 1.5 this loads the revision into the candidate configuration and commits it, so it is a change like any other — and it reverts everything, not just the item you regret.delete service ssh listen-address <ip>andcommitto remove a listen-address restriction.delete system syslog host <ip>andcommitto remove a remote syslog destination.delete system login user <user> disablere-enables a suspended account;delete system login user <user>removes it outright.commit-confirm 5before any of the firewall or SSH items, every time. Each of them can end the session you are typing into, and the OOB path exists precisely because that happens.
The VyOS commit validator checks syntax and internal
consistency. It has no opinion about whether a BGP peer has
a password or whether the input chain defaults to drop, so
nothing about a clean commit says the controls survived
the change. That gap is the whole reason this checklist is
a human walk on a calendar.
Production discipline
Cross-course references
LIII-VyOS-Security(this part) covers the authentication, CoPP, and prefix-filtering mechanisms that the checklist reviews.XLVII-VyOS-MgmtHardeningcovers the management-plane hardening (SSH, login users, PKI) in detail.XLVIII-VyOS-LoggingSyslogcovers the logging and remote syslog configuration in detail.vyos-xxiv-04-bgp-authenticationcovers whypasswordis the mechanism the BGP tree exposes and TCP-AO is not.vyos-iv-05-post-install-hardeningcovers the first-boot version of these controls on a router that has just been installed.- The CIS Benchmarks for VyOS provide a community-driven hardening checklist that complements this lesson.
Quiz
Knowledge check · 4 questions
Q1. What is the operator's defence against the post-incident question "what changed?"?
Q2. A router hardening checklist is best run as an automated scan that fires once at install time.
Q3. R1 is a production edge router. The operator runs the hardening checklist and finds that BGP neighbour 10.0.0.5 (added by a colleague two months ago) does not have authentication configured. The colleague's commit message in the audit log says "added BGP peer for new upstream". What is the security impact and what is the fix?
R1 has a BGP neighbour 10.0.0.5 that does not have authentication. The neighbour was added two months ago. The colleague's commit message is the only evidence of the addition.
Q4. R1's audit log is shipped to a remote syslog server on the production network. The production network is compromised: an attacker has gained access to the management plane and can read the syslog traffic. The operator wants to ensure the audit log is preserved even when the production network is compromised. What is the fix?
R1's remote syslog is on the production network. An attacker who has compromised the production network can read the syslog traffic and may be able to manipulate it. The operator wants the audit log to be on a network the attacker cannot reach.
Passing score: 75%. Answers are checked in this browser.