TACACS+ for Cisco IOS XE with ISE 3.5: Command Sets, Shell Profiles and a Shared Secret Fault

I set up ISE 3.5 as the TACACS+ server for an IOS XE router: a network admin with full access and a help desk user who can run show commands but not show running-config or enter config mode. Then I broke the shared secret and watched the local fallback take over. Real Live Logs for every case.

Lab diagram: ops-01 connects by SSH to core-rtr5 Eth0/0, which sends TACACS+ on TCP 49 to ise35 for authentication, per-command authorization and accounting. A shared secret mismatch marks th

RADIUS decides who gets on the network. TACACS+ decides what an engineer is allowed to type once they're on a router. With Cisco ISE, that means a Device Admin policy set, a shell profile for the privilege level, and command sets that permit or deny each command.

This post builds that for one IOS XE router and two kinds of users. A network admin gets everything. A help desk user gets show commands but is blocked from show running-config and from config mode. Then I break the TACACS+ shared secret on purpose, to show what ISE logs and how the local fallback account keeps you from being locked out.

I built this in my home lab with Cisco ISE 3.5.0.527 and a Cisco IOS XE 17.18.2 router. All the output is real. Addresses are documentation values, and secrets and passwords are placeholders.

For the theory behind AAA, see AAA, TACACS+ and RADIUS for Device Administration. If ISE isn't installed yet, start with Cisco ISE 3.5 Initial Setup.

The lab

Device Role Addressing
ise35 Cisco ISE 3.5, TACACS+ server (TCP 49) 192.0.2.10
core-rtr5 IOS XE 17.18.2 router, TACACS+ client Ethernet0/0 10.86.251.11/24 in VRF MGMT
ops-01 Admin workstation, SSH client 10.86.251.21/24
Lab diagram: ops-01 connects by SSH to core-rtr5 Eth0/0, which sends TACACS+ on TCP 49 to ise35 for authentication, per-command authorization and accounting. A shared secret mismatch marks the server Dead and the router falls back to the local netadmin-local user. A policy card shows the NetOps-Admins and NetOps-Helpdesk results.
Lab topology: core-rtr5 sends TACACS+ to ise35, local fallback only when ISE is Dead
User ISE identity group Intended access
na-01 NetOps-Admins Privilege 15, every command
hd-11 NetOps-Helpdesk Privilege 15, read-only commands enforced by a command set
netadmin-local (local on the router) Break-glass account, only used when ISE is unreachable

Step 1: Enable Device Admin on the ISE node

TACACS+ is off by default. In Administration > System > Deployment, edit the node and tick Enable Device Admin Service. Until you do, ISE doesn't listen on TCP 49 and the router will mark the server dead.

Step 2: Add the router as a network device

In Administration > Network Resources > Network Devices, add core-rtr5 with IP 10.86.251.11, expand TACACS Authentication Settings, and set the shared secret. Use the same secret on the router. Step 7 shows what happens when they don't match.

Step 3: Identity groups and users

Create two user identity groups, NetOps-Admins and NetOps-Helpdesk, then two internal users: na-01 in NetOps-Admins and hd-11 in NetOps-Helpdesk. In production these would usually be AD groups, but the policy logic is identical.

Step 4: Shell profile and command sets

In Work Centers > Device Administration > Policy Elements > Results:

  • TACACS Profiles: create IOS_Priv15 with Default Privilege and Maximum Privilege set to 15.
  • TACACS Command Sets: create two sets.
Command set Rules
CS-Permit-All Permit any command that is not listed below ticked, no rules
CS-Helpdesk-Show DENY_ALWAYS show running-config.*; PERMIT terminal length.*; PERMIT show; PERMIT ping; PERMIT traceroute; PERMIT exit. Unlisted commands are denied

Order matters less than you'd think for DENY_ALWAYS: it wins over any permit in any set, which is why show running-config stays blocked even though plain show is permitted.

Why the help desk gets privilege 15. My first attempt gave hd-11 privilege 1. That doesn't work for this design: at privilege 1 IOS rejects show running-config and configure terminal itself with % Invalid input, before command authorization ever asks ISE. You get no Live Logs entry and nothing to audit. Giving priv 15 and restricting with a command set means every command goes to ISE, gets a decision and gets logged.

Step 5: The Device Admin policy set

In Work Centers > Device Administration > Device Admin Policy Sets, add a policy set IOS-Device-Admin with the condition DEVICE:Device Type EQUALS All Device Types and the Default Device Admin protocol.

  • Authentication policy: Default rule, identity source All_User_ID_Stores, reject if the user isn't found or authentication fails.
  • Authorization policy:
Rule Condition Command set Shell profile
NetOps-Admins-Priv15 IdentityGroup:Name EQUALS User Identity Groups:NetOps-Admins CS-Permit-All IOS_Priv15
NetOps-Helpdesk-ReadOnly IdentityGroup:Name EQUALS User Identity Groups:NetOps-Helpdesk CS-Helpdesk-Show IOS_Priv15
Default (none) DenyAllCommands Deny All Shell Profile

Step 6: Router configuration

username netadmin-local privilege 15 secret <LOCAL_PASSWORD>
enable secret <ENABLE_SECRET>
!
aaa new-model
tacacs server ISE-1
 address ipv4 192.0.2.10
 key <TACACS_SHARED_SECRET>
 timeout 5
aaa group server tacacs+ ISE-TAC
 server name ISE-1
 ip vrf forwarding MGMT
 ip tacacs source-interface Ethernet0/0
!
aaa authentication login CON none
aaa authentication login VTY group ISE-TAC local
aaa authorization exec VTY group ISE-TAC local if-authenticated
aaa authorization commands 1 VTY group ISE-TAC local if-authenticated
aaa authorization commands 15 VTY group ISE-TAC local if-authenticated
aaa accounting exec VTY start-stop group ISE-TAC
aaa accounting commands 1 VTY start-stop group ISE-TAC
aaa accounting commands 15 VTY start-stop group ISE-TAC
!
line con 0
 login authentication CON
line vty 0 4
 login authentication VTY
 authorization exec VTY
 authorization commands 1 VTY
 authorization commands 15 VTY
 accounting exec VTY
 accounting commands 1 VTY
 accounting commands 15 VTY
 transport input ssh

Notes on this config:

  • Named method lists on the VTYs only. The console uses CON none here because it's a lab. In production, give the console its own list with local so you're never locked out by a bad AAA change.
  • group ISE-TAC local falls back to the local database only when ISE is unreachable (marked dead), not when ISE rejects the password. That's the break-glass path tested in Step 7.
  • ip vrf forwarding MGMT plus the source interface keeps TACACS+ in the management VRF.
  • IOS XE 17.18 printed %TAC-4-NON_TLS_SERVER_CONFIGURED, a warning that this server uses classic TACACS+ rather than TACACS+ over TLS. It works as shown; TLS is a separate project.

Step 7: Test the admin

From ops-01, SSH as na-01:

core-rtr5#show privilege
Current privilege level is 15
core-rtr5#show running-config | include ^hostname
hostname core-rtr5
core-rtr5#configure terminal
Enter configuration commands, one per line.  End with CNTL/Z.
core-rtr5(config)#interface Loopback0
core-rtr5(config-if)#description set-by-na-01
core-rtr5(config-if)#end

Everything is allowed. Open Operations > TACACS > Live Logs:

TACACS Live Logs showing passing na-01 and hd-11 sessions, the hd-11 command denials and the shared secret failures
TACACS Live Logs showing passing na-01 and hd-11 sessions, the hd-11 command denials and the shared secret failures

The authorization detail for na-01 shows the policy set and rule that matched and the shell profile returned:

TACACS authorization detail for na-01: IOS-Device-Admin policy set, shell profile IOS_Priv15
TACACS authorization detail for na-01: IOS-Device-Admin policy set, shell profile IOS_Priv15

Step 8: Test the help desk user

SSH as hd-11:

core-rtr5#show privilege
Current privilege level is 15
core-rtr5#show ip interface brief | include Ethernet0/0
Ethernet0/0            10.86.251.11    YES TFTP   up                    up
core-rtr5#show running-config
core-rtr5#show running-config | include hostname

core-rtr5#configure terminal
core-rtr5#show clock
*07:28:56.165 UTC Sat Oct 31 2026

show ip interface brief and show clock run. show running-config and configure terminal just return to the prompt with no output. On this IOS XE build there's no "Command authorization failed" message at the CLI, so the help desk user only sees that nothing happened. The reason is on ISE.

show running-config hit the DENY_ALWAYS rule:

TACACS authorization detail for hd-11: 13023 Command matched a Deny-Always rule for show running-config, command set CS-Helpdesk-Show
TACACS authorization detail for hd-11: 13023 Command matched a Deny-Always rule for show running-config, command set CS-Helpdesk-Show

configure terminal matched nothing in CS-Helpdesk-Show, so it was denied by default:

TACACS authorization detail for hd-11: 13025 Command failed to match a Permit rule for configure terminal
TACACS authorization detail for hd-11: 13025 Command failed to match a Permit rule for configure terminal

That difference is useful when you're auditing: 13023 means someone tried something you explicitly banned, 13025 means they tried something you never allowed.

Step 9: Fault case, a shared secret mismatch

I changed the TACACS+ shared secret on the ISE network device entry and left the router alone, then tried to SSH as na-01. The login was refused. ISE logged a failed authentication with no username:

TACACS authentication detail: 13011 Invalid TACACS+ request packet - possibly mismatched Shared Secrets from core-rtr5
TACACS authentication detail: 13011 Invalid TACACS+ request packet - possibly mismatched Shared Secrets from core-rtr5

TACACS+ encrypts the whole packet body with the shared secret, so with the wrong key ISE can't even read the username. That's why the Username field is blank and the steps stop at 13011. Authorization requests from the same router in that window logged 13078 Invalid TACACS+ authorization request packet - possibly malformed packet, which is the same problem.

On the router, the server got marked dead, so the next login used the local fallback:

core-rtr5#show tacacs
Tacacs+ Server -  public  :
               Server name: ISE-1
            Server address: 192.0.2.10
               Server port: 49
...
             Server Status: Dead
core-rtr5#show logging | include SEC_LOGIN
*Oct 31 07:31:46.382: %SEC_LOGIN-5-LOGIN_SUCCESS: Login Success [user: netadmin-local] [Source: 10.86.251.21] [localport: 22] at 07:31:46 UTC Sat Oct 31 2026

Fix: set the ISE network device secret back to match the router's key. One thing that caught me out: the first na-01 login straight after the fix still failed, and ISE logged nothing for it, because the router still had the server marked Dead. About 40 seconds later the login worked and show tacacs showed Server Status: Alive. If you fix a key and it "still doesn't work", wait out the dead timer (or set aaa dead-criteria and deadtime deliberately) before changing anything else.

Troubleshooting table

Live Logs code Message Likely cause Fix
13011 Invalid TACACS+ request packet - possibly mismatched Shared Secrets Router key and ISE network device TACACS secret differ Make them match, then wait for the router to mark the server alive
13078 Invalid TACACS+ authorization request packet - possibly malformed packet Usually the same key mismatch, seen on authorization requests Same as 13011
13017 Received TACACS+ packet from unknown Network Device or AAA Client The source IP isn't a network device in ISE, or TACACS isn't enabled on that entry Add the device or fix the source interface
13023 Command matched a Deny-Always rule A DENY_ALWAYS rule in the command set Working as designed, or move the user to another group
13025 Command failed to match a Permit rule Command not in the command set and unlisted commands are denied Add a PERMIT rule if the user should have it
(nothing logged) Router says login failed, ISE shows no entry Device Admin service off, TCP 49 blocked, or server marked dead Enable Device Admin, check reachability and show tacacs
% Invalid input at the CLI IOS rejects the command, ISE never sees it User's privilege level is too low for the command to exist Use priv 15 plus command sets, or custom privilege levels

Takeaways

  • Device Admin is a separate ISE service. Enable it on the node before anything else.
  • Give restricted users privilege 15 and limit them with command sets, so every command reaches ISE and is logged. Low privilege levels make IOS reject commands before ISE sees them.
  • DENY_ALWAYS beats every permit. Use it for the few commands that must never run, like show running-config for a help desk.
  • 13023 and 13025 tell you whether a denial was an explicit ban or just never permitted.
  • A key mismatch shows as 13011 with no username. The local fallback only kicks in once the server is dead, and recovery waits for the dead timer.

Related: ISE Live Logs Casebook: Five 802.1X Failures, Reproduced covers the RADIUS side of the same troubleshooting habit, and ISE 11007: Could Not Locate Network Device is the RADIUS cousin of 13017.

Read next