Security Hardening¶
Security Checklist¶
Before putting a switch into production, verify:
- All unused ports shutdown
- Port security enabled on access ports
- SSH only (no Telnet)
- BPDU Guard on access ports
- DHCP Snooping enabled
- Dynamic ARP Inspection enabled
- Storm control configured
- ACLs for VLAN isolation
- Logging to syslog server
- Spanning tree priority set (intentional primary)
- Backup power verified
- Cabling labeled and tested
Each item is covered in the same order below.
All command blocks on this page are Cisco IOS, entered from global configuration mode (conf t) unless noted — see Cisco IOS CLI.
Disable Unused Ports¶
Reduce attack surface. Create a dedicated "blackhole" VLAN first — on many IOS versions, assigning a port to a VLAN that doesn't yet exist in the VLAN database will fail or behave inconsistently:
vlan 999
name UNUSED
interface range Gi0/1 - 10
shutdown
switchport access vlan 999
Port Security¶
Prevent MAC table flooding attacks:
interface range Gi0/1 - 47
switchport mode access
switchport port-security
switchport port-security maximum 2
switchport port-security violation shutdown
Passwords & Privilege Levels¶
A switch has several independent passwords, and confusing them is the usual cause of "I'm logged in but can't do anything":
| Credential | Controls | Set with |
|---|---|---|
| Line password (console/vty) | Access to that line, with no username | line con 0 → password <pw> + login |
| Local user | Username-based login, used by login local and SSH |
username admin secret <pw> |
| Enable secret | Privileged EXEC (SW01#) — separate from whatever got you a session |
enable secret <pw> |
Cisco IOS — global configuration mode (conf t):
! Local account for SSH/vty login
username admin secret <password>
! Privileged mode — a DIFFERENT password from the account above
enable secret <different-password>
! Obscure any remaining type-7 passwords in the config
service password-encryption
enable secret vs enable password¶
Always enable secret. The older enable password stores the value as type 7, a reversible Cisco-proprietary encoding that any online decoder reverses in seconds — it is obfuscation, not encryption. enable secret stores a hash instead. If both are configured, enable secret takes effect and the enable password line just sits in the config leaking a recoverable password — remove it with no enable password.
service password-encryption only applies type-7 encoding to other plaintext passwords in the config (line passwords, and so on). It raises the bar against someone reading a show run over your shoulder and nothing more. It is not a substitute for using secret forms.
Platform note: on Catalyst switches running IOS 15.2 and earlier — including the 2960 and 3560-CX families —
enable secretproduces a type 5 (MD5) hash, and that's the strongest available. The stronger type 8 (PBKDF2-SHA256) and type 9 (scrypt) hashes, and theenable algorithm-typecommand that selects them, were introduced in IOS 15.3(3)M and do not exist on these platforms. Check withenable algorithm-type ?before assuming.
Privilege Levels¶
IOS has privilege levels 0–15. A fresh login lands at level 1 (user EXEC, SW01>); enable raises you to level 15 (privileged EXEC, SW01#). Intermediate levels can be built for role-based access, assigning specific commands to a level.
The practical shortcut — give the account level 15 directly, and SSH drops you straight into privileged mode with no enable step:
username admin privilege 15 secret <password>
Convenient for a single-admin network, and it sidesteps the trap where SSH works but enable doesn't. The trade-off is that it removes the second gate: anyone who obtains that one password has full control immediately, and there's no separate enable secret standing in the way. Keep the two-step model where more than one person has access.
SSH Management Only¶
Secure remote access, restrict to management VLAN. For the full walkthrough of turning SSH on from a console-only switch — including connecting from a modern client, which older IOS makes awkward — see Enable SSH on a Cisco Switch.
hostname SW1
ip domain-name example.lan
username admin secret <strong-password>
crypto key generate rsa modulus 2048
ip ssh version 2
line vty 0 4
transport input ssh
login local
access-list 1 permit 10.0.99.0 0.0.0.255
line vty 0 4
access-class 1 in
Verify you can SSH in (
show ip ssh, test login) before closing your console session.
AAA (Authentication, Authorization, Accounting)¶
The login local model above is per-line authentication — fine for a few switches with local accounts. AAA is IOS's framework for doing this centrally: authentication (who are you), authorization (what may you do — privilege level, which commands), accounting (what did you do — session/command logs to a server). It's enabled with aaa new-model, which replaces the per-line model with method lists — e.g. "try the TACACS+ server, fall back to local accounts if unreachable."
When it's worth it: many devices and many admins — one central account database (typically TACACS+ for network gear), instant revocation, per-command audit trails. On a small network, AAA pointing at local accounts is mostly ceremony — with one exception: some features require it regardless, notably the SCP server (ip scp server enable silently fails every transfer without AAA authorization configured).
The minimal local-accounts form those features need:
Cisco IOS — global configuration mode (conf t):
aaa new-model
aaa authentication login default local
aaa authorization exec default local
Caution:
aaa new-modeltakes effect immediately and changes how every vty line authenticates. Keep your console session open and verify a fresh SSH login works before disconnecting — a method list pointing at an unreachable server with no local fallback locks out everything but the console.
BPDU Guard¶
Prevent rogue switches on access ports (see Spanning Tree Protocol Fundamentals for what a BPDU actually is and why an access port sending one is a red flag):
interface range Gi0/1 - 47
spanning-tree bpduguard enable
spanning-tree portfast
Never on uplinks: Do not apply port security, PortFast, or BPDU Guard to uplink/trunk ports (Gi0/48 in these examples — the same port trusted for DHCP snooping and DAI below). Port security's MAC limit and BPDU Guard will errdisable an uplink, cutting the switch off from the network.
DHCP Snooping¶
Block rogue DHCP servers (see DHCP Fundamentals for the Discover/Offer/Request/Ack process this is protecting):
ip dhcp snooping
ip dhcp snooping vlan 10,20,30
interface Gi0/48
ip dhcp snooping trust
Dynamic ARP Inspection¶
Prevent ARP spoofing attacks:
ip arp inspection vlan 10,20,30
ip arp inspection validate src-mac dst-mac ip
interface Gi0/48
ip arp inspection trust
Dependency: DAI validates ARP packets against the DHCP snooping binding table, so DHCP Snooping must be enabled first (as shown above) for dynamic validation to work. Without it, DAI has no bindings to check against and will drop legitimate ARP traffic on untrusted ports.
Caution: Statically addressed devices (lighting consoles, Dante/sACN nodes) never send DHCP requests, so they have no snooping binding — DAI will drop all their ARP traffic and silently cut them off. Permit each one explicitly with an ARP ACL:
arp access-list STATIC_DEVICES
permit ip host 10.0.10.50 mac host aaaa.bbbb.cccc
! Apply the ACL on the VLANs where the static devices live
ip arp inspection filter STATIC_DEVICES vlan 10
Storm Control¶
Prevent broadcast storms from misbehaving devices:
interface range Gi0/1 - 48
storm-control broadcast level 10
storm-control multicast level 10
storm-control action trap
Caution: Storm control drops multicast above the rising threshold regardless of the
actionsetting — on VLANs carrying multicast traffic (Dante, sACN) this can silently kill it. See Dante & sACN on the Network before applyingstorm-control multicastto those VLANs.Platform note: the
levelvalue's accepted format varies by switch model — many Catalyst platforms expect a decimal percentage (level 10.00) and reject a bare integer, while others accept either. Some platforms uselevel pps <low> <high>instead of a percentage. Checkstorm-control ?on your specific hardware before applying.
Access Control Lists¶
Enforce VLAN isolation policies (ACLs can also filter by TCP/UDP port for more granular rules than IP-only):
ip access-list extended GUEST_POLICY
deny ip 10.0.20.0 0.0.0.255 10.0.10.0 0.0.0.255
permit ip any any
interface Vlan20
ip access-group GUEST_POLICY in
Logging & Alerts¶
Monitor for attacks and violations:
logging 10.0.99.5
logging source-interface Vlan99
logging trap informational
snmp-server community <read-only-string> RO
snmp-server host 10.0.99.5 version 2c <read-only-string>
snmp-server enable traps
Replace
<read-only-string>with a real, non-default SNMP community string — never leave it aspublic.
Spanning Tree Priority¶
Don't leave root bridge election to chance (lowest MAC address wins by default) — deliberately set an intentional, known primary so the topology is predictable. See Spanning Tree Protocol Fundamentals for how root election works:
! On the intended primary switch:
spanning-tree vlan 10 root primary
! On the designated backup switch:
spanning-tree vlan 10 root secondary
What a Fleet Audit Actually Finds¶
Tally from auditing four in-service Catalyst access switches (3560-CX ×2, 9200CX, 3850) against this page, 2026-08-24. The point: the per-port hardening was universally right, and every finding was a global setting that drifted per-switch because it was set by hand.
Consistently right on all four:
- Rapid-PVST +
extend system-id, BPDU guard witherrdisable recovery - SSH v2 only on the VTYs, per-port storm-control/portfast/
power inline neveron user ports - Trunks with a dedicated unused native VLAN
Found drifting on at least one switch:
| Finding | Fix |
|---|---|
No enable secret + unprotected line con 0 — walk-up full access |
enable secret + login local on con 0 |
ip http server / secure-server left on |
no ip http server / no ip http secure-server |
no service password-encryption |
service password-encryption |
| VLANs only in vlan.dat (VTP server) — a config restore onto a wiped switch leaves trunks pointing at nothing | vtp mode transparent, VLANs in the config |
| Smart Call Home phoning the vendor | no service call-home (IOS-XE) |
No NTP, no timezone, no logging buffered |
ntp server …, clock timezone, logging buffered 16384 |
| One switch with no config backup at all | back it up before touching anything else |
The cure is a generated day-0 baseline applied at commission time rather than hand-set globals: one file carrying every line above plus a deliberate STP priority per role (24576 core / 61440 access — see Spanning Tree Priority), applied with configure replace so a redeploy is also a reset.
Physical & Operational Checks¶
Not everything on the checklist is a CLI command — verify these before go-live too:
- Backup power — confirm the switch is on UPS/generator-backed power, and that the UPS itself has been load-tested recently, not just plugged in
- Cabling labeled and tested — every run identified at both ends and verified for link speed/duplex, so a future fault doesn't turn into a physical cable hunt
Verify It Took¶
Applying the commands is not proof the features are running — several of the failure modes above are silent. Spot-check each one before go-live:
Cisco IOS — privileged EXEC:
show port-security
show ip dhcp snooping binding
show ip arp inspection vlan 10
show storm-control
show spanning-tree root
show ip ssh