Skip to content

Cisco IOS / IOS-XE

This page covers administrative access — engineers logging in to the CLI — on Cisco IOS and IOS-XE. It is the device-side counterpart to TACACS+ and RADIUS.

For endpoint access control (802.1X and MAB) on the same platforms, see Build an 802.1X lab, which walks the switch side end to end. The NAC section below only records what differs between software trains.

PlatformSoftwareWhat was verified
Cisco IOSv (vios_l2)15.2TACACS+ login, enable, command authorization and accounting at levels 0/1/15; RADIUS administrative login with exec authorization and accounting
Cisco IOL (X86_64BI_LINUX_L2)17.12.1 (Dublin)TACACS+ login, enable, command authorization and accounting at levels 0/1/15

Both are virtual platforms. The AAA configuration below is not platform-specific — it is the same on Catalyst, ISR and Nexus-adjacent IOS-XE gear — but output formats differ slightly between trains, and those differences are called out where they matter.

The good news for anyone running a mixed estate: the TACACS+ device-administration configuration is identical on 15.x and 17.x. The named tacacs server block replaced the legacy tacacs-server host global on 15.x already, so one template covers both.

This is the standard shape: Taranac authenticates the login, decides the privilege level, authorizes every command, and records everything.

aaa new-model
!
! ── The server and its group ────────────────────────────────────
tacacs server TARANAC-1
address ipv4 10.0.0.20
key <TACACS_SECRET>
timeout 30
!
aaa group server tacacs+ TARANAC
server name TARANAC-1
!
! ── Authentication ──────────────────────────────────────────────
aaa authentication login default group TARANAC local
aaa authentication login CONSOLE local
aaa authentication enable default group TARANAC enable
!
! ── Authorization ───────────────────────────────────────────────
aaa authorization config-commands
aaa authorization exec default group TARANAC local
aaa authorization commands 0 default group TARANAC local
aaa authorization commands 1 default group TARANAC local
aaa authorization commands 15 default group TARANAC local
!
! ── Accounting ──────────────────────────────────────────────────
aaa accounting exec default start-stop group TARANAC
aaa accounting commands 0 default start-stop group TARANAC
aaa accounting commands 1 default start-stop group TARANAC
aaa accounting commands 15 default start-stop group TARANAC
!
! ── Source the packets from the registered address ──────────────
ip tacacs source-interface Vlan1
!
line con 0
login authentication CONSOLE
line vty 0 4
login authentication default
transport input ssh

Save it — write memory. A switch that reloads with half of this missing fails in ways that look nothing like a missing configuration.

This is the single most misunderstood part of Cisco AAA, and it fails silently in the permissive direction, which is the worst way for a security control to fail.

aaa authorization commands and aaa accounting commands take one privilege level per line. There is no all keyword, no range, and no wildcard. IOS will not warn you about levels you did not list — it simply never sends those commands to Taranac.

Levels 0, 1 and 15 cover the stock IOS command set and are what the example configures:

LevelWhat lives there
0enable, disable, exit, help, logout — five commands, easy to forget, and enable is not a command you want unaudited
1User EXEC — the read-only show commands an operator has by default
15Privileged EXEC and configuration mode — everything else

If you use custom privilege levels, you must add a line for each one. Any deployment that has run privilege exec level 7 … to build a tiered operator role needs aaa authorization commands 7 and aaa accounting commands 7 as well. Otherwise the tier you carefully built is the one tier nobody is checking. The rule is simply: every privilege level in use on the device needs both lines.

aaa authorization config-commands is the related trap one level up. Without it, commands typed in configuration mode are not sent for authorization even when aaa authorization commands 15 is present — exec-mode commands are checked, config-mode commands sail through. Since configuration mode is where the damage happens, the line belongs in every deployment that authorizes commands at all.

Every line in the block above routes authentication to a server that can become unreachable. Two safeguards make that survivable, and both are in the example:

  • The local fallback keyword. group TARANAC local tries Taranac first and falls back to the local user database only when the server does not answer. It does not fall back when Taranac answers with a reject — a denied login stays denied, which is what you want. This requires a local account to actually exist: keep a username … privilege 15 secret … on the device.
  • A separate console method list. aaa authentication login CONSOLE local bound to line con 0 keeps the console on local authentication permanently. When the network is down and the TACACS+ server is unreachable, the console is how you get in. A device whose console also points at default can lock you out completely.

Similarly, aaa authentication enable default group TARANAC enable ends in the enable keyword, falling back to the locally configured enable secret.

ip tacacs source-interface Vlan1 pins the source address of TACACS+ packets to that interface’s IP. That address is what Taranac matches against the registered device.

Leave it out and IOS picks the egress interface closest to the server, which is usually right — until a routing change, a second uplink or an SVI renumbering makes it wrong. The failure is unhelpful: Taranac sees a request from an unregistered client and drops it without logging a policy decision, so the device reports a timeout and falls back to local while Taranac’s logs show nothing at all. Pin it explicitly.

The same applies to RADIUS via ip radius source-interface.

The example sets timeout 30, not the familiar 5 seconds. That is deliberate.

When a user is enrolled in push MFA, Taranac holds the AAA exchange open while it sends a push to their phone and waits for them to approve it. The device must stay willing to wait for a human. At timeout 5 the switch gives up long before anyone can reach into a pocket, and the login fails over to the local database — which looks exactly like a server outage.

The effective approval window is the smaller of the device timeout and Taranac’s own server-side cap. Raising one side alone changes nothing; if you want to give admins more time to tap “approve”, raise both together.

For TACACS+ this is clean — the TCP connection simply stays open for the duration. See the RADIUS section for why the UDP case behaves differently.

show tacacs is the first stop. The output differs between trains, and 17.x is considerably more useful:

SW#show tacacs
Tacacs+ Server - public :
Server name: TARANAC-1
Server address: 10.0.0.20
Server port: 49
Socket opens: 875
Socket closes: 875
Socket aborts: 0
Socket errors: 0
Socket Timeouts: 0
Failed Connect Attempts: 0
Total Packets Sent: 938
Total Packets Recv: 938

Health has to be inferred from the counters. Socket opens matching Socket closes with zeros across aborts, errors and timeouts is a healthy server. Any movement in Socket Timeouts or Failed Connect Attempts means reachability trouble — wrong address, wrong port, or a firewall in the path.

Then confirm the whole chain end to end:

  • test aaa group TARANAC <user> <password> legacy — authenticates without risking your session, and tells you whether the secret and policy are right.
  • Log in from a second session and run something your policy should deny. A denial arriving from Taranac is the only real proof that command authorization is live; a successful login proves only authentication.
  • Check the accounting records in Taranac. Commands appearing under the right user, with the right privilege level, confirms the accounting lines took effect — and is how you catch a missing privilege level before an auditor does.

Some estates standardise on RADIUS for administrative login. IOS supports it, with real limitations. Note the named method list (VTY) rather than default — it keeps the console untouched, which serves the same rescue purpose as the CONSOLE list above.

aaa new-model
!
radius server TARANAC-1
address ipv4 10.0.0.20 auth-port 1812 acct-port 1813
timeout 30
retransmit 1
key <RADIUS_SECRET>
!
aaa group server radius TARANAC-R
server name TARANAC-1
!
aaa authentication login VTY group TARANAC-R local
aaa authorization exec VTY group TARANAC-R local
aaa accounting exec VTY start-stop group TARANAC-R
!
ip radius source-interface Vlan1
radius-server attribute 6 on-for-login-auth
radius-server attribute 8 include-in-access-req
radius-server attribute 25 access-request include
!
line con 0
! no AAA here — local console rescue
line vty 0 4
login authentication VTY
authorization exec VTY
accounting exec VTY
transport input ssh

Taranac returns the privilege level as a Cisco AV-pair, shell:priv-lvl=15, rendered from a RADIUS profile — see RADIUS profiles. aaa authorization exec is what makes the device apply it; without that line the user authenticates and lands at privilege 1 regardless of what the profile said.

The three radius-server attribute lines are worth keeping. They make the switch include Service-Type on login authentication, Framed-IP-Address, and the Class attribute in accounting — the last one is what lets Taranac correlate an accounting record back to the session that produced it.

Push MFA over RADIUS deserves one note. RADIUS is UDP, so the instinct is to raise retransmit to widen the approval window. It does not work that way: the push budget is capped on the server side, and retransmits arriving during the wait are deduplicated and answered from cache — they neither extend the window nor trigger a second push. Raise timeout on the device and the corresponding server-side cap together; leave retransmit low.

Verify with show aaa servers, which reports RADIUS only — TACACS+ never appears there, which is why a TACACS-only device returns nothing at all:

SW#show aaa servers
RADIUS: id 1, priority 1, host 10.0.0.20, auth-port 1812, acct-port 1813
State: current UP, duration 674590s, previous duration 0s
Dead: total time 0s, count 0
Authen: request 3, timeouts 0, failover 0, retransmission 0
Response: accept 3, reject 0, challenge 0
Response: unexpected 0, server error 0, incorrect 0, time 131ms
Account: request 5, timeouts 0, failover 0, retransmission 0
Request: start 3, interim 0, stop 2
Response: start 3, interim 0, stop 2

State: current UP with Dead: count 0 is what healthy looks like. The challenge counter is the one to watch when MFA is in play — a non-zero value means Access-Challenge exchanges are happening, which is the multi-step authentication working as intended.

The switch-side 802.1X and MAB configuration for Cisco IOS is covered step by step in Build an 802.1X lab — global plumbing, the NAC server group on ports 1814/1815, the CoA listener, and the access-port template with authentication open as monitor mode. It is not repeated here.

What belongs on this page is the part that changed between software trains. IOS 15’s authentication port commands and IOS-XE’s session manager are different generations of the same feature, and the verification commands are not interchangeable:

TaskIOS 15.xIOS-XE 17.x
List sessionsshow authentication sessionsshow access-session
One port in detailshow authentication sessions interface Gi1/1 detailsshow access-session interface Gi1/1 details
Port configuration styleauthentication commands on the interfaceIBNS 2.0 — policy-map type control subscriber

On 17.x, show authentication sessions is rejected outright as an invalid command rather than deprecated with a hint, which sends people looking for a configuration fault that does not exist. If a session list command errors out, try the other spelling before assuming the port is broken.

Both trains accept the same Taranac-side authorization results, since those arrive as RADIUS attributes rather than CLI. What Taranac sends for a Cisco device:

Profile settingAttributes sent
VLANTunnel-Type = VLAN, Tunnel-Medium-Type = IEEE-802, Tunnel-Private-Group-ID = <vlan>
Named ACLFilter-Id = <name> — the ACL must already exist on the switch
Downloadable ACLCisco-AVPair = ip:inacl#<line>, one per rule
URL redirectCisco-AVPair = url-redirect=<url> and url-redirect-acl=<acl>
Session timeoutSession-Timeout, Termination-Action = RADIUS-Request

And what it sends for CoA — reauthenticate, bounce the port, or shut the port — all as Cisco-AVPair = subscriber:command=….

SymptomLikely cause
Login hangs, then succeeds with local credentialsServer unreachable. Check Socket Timeouts / Failed Connect Attempts in show tacacs, or State in show aaa servers.
Login rejected, and Taranac logs show nothingThe request never arrived as a known client — source address does not match the registered device (ip tacacs source-interface), or the secret does not match. Unknown clients are dropped without a policy decision.
Login works, user lands at privilege 1Missing aaa authorization exec, or the matched policy rule returns no profile.
Push MFA always deniesDevice timeout too low. Raise it to 30 s and match the server-side cap.
Commands run that policy should denyNo aaa authorization commands line for that privilege level, or aaa authorization config-commands missing for config mode.
Commands missing from the audit trailNo aaa accounting commands line for that privilege level.
Locked out after applying AAANo CONSOLE method list, or no local account for the local fallback. Recover via console or password recovery.
show authentication sessions is invalidIOS-XE 17.x — use show access-session.
show aaa servers returns nothingExpected on a TACACS-only device. Use show tacacs.