Catalyst 3850: console access from a Linux jumphost and config backups
In short. Plug a USB serial adapter into the stack console and leave it there. Add the operator account to
dialoutso no sudo is needed, and open it withscreen /dev/ttyUSB0 9600. Back up with an expect script that logs in over SSH, runsshow running-config, and writes a file the repository tracks. The break-glass path is mesh VPN to the jumphost, then serial, and the jumphost's own uplink must be yours.
I want a console on my Catalyst stack without walking to the rack, and my config in git
A switch whose management SVI is unreachable is a switch you cannot fix remotely, unless something is already plugged into its console. And a configuration that lives only on the switch is one power-supply failure from being reconstructed from memory. The jumphost solves both. The reasons the configuration is pushed from the repository rather than typed, and why the console is the only out-of-band path, are in the decision post at the end.
What you need
- A WS-C3850-12X48U stack on IOS-XE 16.12. The stack has one active console: the master's. Cable the adapter to member 1, which has priority 15 and is master unless something has gone wrong.
- A Linux jumphost in the rack with a spare USB port, reachable over the mesh VPN. In the examples it is a small box on VLAN 1 with the address
10.1.1.20. - A USB to RJ45 console adapter with a chipset Linux knows out of the box. FTDI and Prolific both appear as
/dev/ttyUSB0. The 3850 also has a mini-USB console port; a plain USB cable to that works too and appears as/dev/ttyACM0. screenorminicom,expect,git, and a credential for the switch held in the secrets store and exposed to the script as an environment variable at run time, never written to disk.
flowchart LR
OP["Operator laptop"] -- "mesh VPN" --> JH["Jumphost 10.1.1.20<br/>operator in dialout"]
JH -- "SSH, normal path" --> SW["sw-a.site.example<br/>management SVI VLAN 1"]
JH -- "USB serial, break-glass" --> CON["Stack console port<br/>member 1"]
JH -- "expect + git" --> REPO["Repository<br/>switch/sw-a.site.example.cfg"]Steps
-
Plug in the adapter and find the device.
dmesg | tailshows the kernel attaching it;ls -l /dev/ttyUSB*shows it owned by root with groupdialout. -
Put the operator account in
dialoutso the console never needs sudo. Log out and in again for the group to apply.
sudo usermod -aG dialout operator
id operator
- Open the console. The 3850 defaults to 9600 baud, 8 data bits, no parity, one stop bit, no flow control.
screengets that right with just the speed:
screen /dev/ttyUSB0 9600
Press Enter once to wake the prompt. To leave, Ctrl-a then k, and answer yes; detaching with Ctrl-a d keeps the session and blocks the next person. With minicom use minicom -D /dev/ttyUSB0 -b 9600 and turn hardware flow control off in its settings, or the terminal appears dead.
- Write the backup script. It connects over SSH in the normal case, disables paging, captures the running configuration, and strips the lines that change on every save so the diff in git is only real change. The password comes from the environment.
#!/usr/bin/expect -f
# backup-switch.exp <host> <user> <outfile>; password in SWITCH_PASSWORD
set timeout 60
set host [lindex $argv 0]
set user [lindex $argv 1]
set out [lindex $argv 2]
set pass $env(SWITCH_PASSWORD)
spawn ssh -o StrictHostKeyChecking=accept-new $user@$host
expect "assword:"
send "$pass\r"
expect "#"
send "terminal length 0\r"
expect "#"
log_file -noappend $out
send "show running-config\r"
expect "end\r"
expect "#"
log_file
send "exit\r"
expect eof
Run it from a wrapper that resolves the secret, then cleans the capture:
export SWITCH_PASSWORD="$(secret-get switch/sw-a.site.example)"
./backup-switch.exp sw-a.site.example ops switch/sw-a.site.example.cfg
unset SWITCH_PASSWORD
sed -i -e '/^! Last configuration change/d' -e '/^! NVRAM config last updated/d' -e '/^ntp clock-period/d' switch/sw-a.site.example.cfg
secret-get stands for whatever your secrets store's CLI is. The point is that the value exists only in the environment of one process.
-
Commit it.
git difffirst; if the only change is a line you forgot to strip, add it to thesed. The commit message says what changed on the switch and why, which is the audit trail you will want later. -
Pushing configuration is the same script in reverse:
configure terminal, send the lines from a file in the repository,end,write memory, then run the backup again and confirm the diff is empty. Hand edits on the console are allowed when the SSH path is down, and are copied back by running step 4 the same day. -
The break-glass path. When the management SVI is unreachable, connect to the mesh VPN, SSH to the jumphost, and open
screen. Nothing in that chain depends on the switch's configuration being right, which is the whole value of it.
Verify it worked
Open the console and confirm the prompt is the site's FQDN; if it is not, you are on the wrong serial cable or in the wrong rack. Run the backup script and confirm the file starts with Building configuration... and ends with end. Run it twice in a row and confirm git diff is empty between the two runs. Then, from somewhere other than the rack, connect through the mesh VPN and open the console: if that works from your kitchen it will work at three in the morning.
Gotchas
terminal length 0is per session. Without it the capture stalls on--More--and the script times out with a half-written file.log_filecaptures everything from that point, including the echo of the command you sent. Thesedstep handles the volatile lines; a first line ofshow running-configin the file is harmless but you can strip it too.- Do not store the host key check as
no.accept-newtrusts the key on the first connection and refuses a changed one, which is the behaviour you want from a script that handles credentials. - A USB adapter re-enumerates after a jumphost reboot and can come back as
/dev/ttyUSB1if a second adapter exists. A udev rule keyed on the adapter's serial number gives it a stable name like/dev/console-sw-a. - Management egress over a data centre's guest WiFi. One jumphost had that as its only uplink, because it was there and it worked. Someone rotated the WiFi password and the jumphost, the console on it, and the switch behind it were unreachable for ten days. The jumphost's own uplink is yours, on your VLAN, through your firewall, or it is not a jumphost.
FAQ
Why SSH for the backup rather than serial? Serial is 9600 baud. A full running configuration takes a minute or more to scroll, and the serial line is the break-glass path, so the script should not be sitting on it. Serial is for when SSH is gone.
Why expect rather than a proper network automation tool?
A single expect script has no dependencies beyond expect itself and runs on any jumphost, including one being rebuilt from nothing. For two switches per site it is the right size. A larger estate would justify more.
Can the backup be scheduled? Yes, and it should be: a daily run that commits only when the diff is non-empty catches hand edits that never got copied back. The scheduled run needs the secret from the store at run time, the same way the manual one does.