Summary: How to enable MFA for IOS-XE VTY (SSH) access via TACACS+, with local authentication restricted to console only. VTY access is denied entirely if TACACS+ is unreachable — local credentials cannot be used to bypass MFA over SSH.
TACACS+ natively supports challenge-response, which is the mechanism MFA relies on. The IOS-XE device does not need to know about the MFA provider — it simply passes the challenge from the TACACS+ server to the user and returns the response.
User → SSH to IOS-XE → IOS-XE → TACACS+ Server → MFA Provider
↓
Challenge sent back
↓
User enters OTP / approves push
↓
TACACS+ grants access
The MFA logic lives entirely on the TACACS+ server (e.g. Cisco ISE, FreeRADIUS + Duo proxy, or tac_plus). No special IOS-XE configuration is required beyond standard TACACS+ AAA — provided the TACACS+ server is configured to issue a challenge.
Two named method lists are used — one for VTY (TACACS+ only, no fallback) and one for console (local only). This ensures local credentials cannot be used to bypass MFA over SSH even if TACACS+ is unreachable.
! Enable AAA
aaa new-model
! Define TACACS+ server(s)
tacacs server ISE-PRIMARY
address ipv4 192.168.1.100
key <shared-secret>
timeout 15
tacacs server ISE-SECONDARY
address ipv4 192.168.1.101
key <shared-secret>
timeout 15
! Server group
aaa group server tacacs+ TACACS-SERVERS
server name ISE-PRIMARY
server name ISE-SECONDARY
! VTY method list — TACACS+ only, no local fallback
! If TACACS+ is unreachable, VTY access is denied. This is intentional.
aaa authentication login VTY-MFA group TACACS-SERVERS
! Console method list — local only
aaa authentication login CONSOLE-LOCAL local
! Authorisation — VTY only, local fallback acceptable here
aaa authorization exec VTY-MFA group TACACS-SERVERS if-authenticated
aaa accounting exec VTY-MFA start-stop group TACACS-SERVERS
! VTY lines — MFA via TACACS+, SSH only, no local fallback
line vty 0 15
login authentication VTY-MFA
authorization exec VTY-MFA
transport input ssh
! Console line — local credentials only
line con 0
login authentication CONSOLE-LOCAL
⚠️ VTY Lockout When TACACS+ is Down
With no local fallback on VTY, if both TACACS+ servers are unreachable you cannot SSH into the device. Console access via local credentials remains available as the break-glass path. Ensure a local admin account exists before applying this config.
⚠️ Timeout Value
MFA adds latency — the user must receive and respond to a push notification or enter a TOTP code before the session times out. Settimeoutto at least 15 seconds on the TACACS+ server definition, or users will see authentication failures on the first attempt.
priv-lvl = 15 for admins).sdconf.rec configuration file.If not using ISE, the Duo Authentication Proxy can front a tac_plus server:
tac_plus to pass authentication requests to the Duo proxy.ssh admin@switch.corp.local
Password: <AD password>
Duo passcode or push: <enter OTP or press Enter for push>
If using RSA SecurID:
ssh admin@switch.corp.local
Password: <AD password>
Enter PASSCODE: <PIN + RSA token code>
| Symptom | Likely Cause | Fix |
|---|---|---|
| Authentication times out before MFA prompt appears | TACACS+ timeout too low |
Increase timeout to 15+ seconds on tacacs server definition |
| MFA prompt never appears — goes straight to failure | ISE/TACACS+ not configured for challenge-response | Verify MFA identity source is referenced in the TACACS+ policy set |
| SSH access denied — cannot log in at all | TACACS+ unreachable — expected behaviour with no local fallback | Use console with local credentials; restore TACACS+ connectivity |
| User authenticated but gets privilege 1 | ISE policy not returning priv-lvl |
Check TACACS+ authorisation profile in ISE — set priv-lvl = 15 |
| Push notification not received | Duo service unreachable from ISE | Verify ISE can reach api-<subdomain>.duosecurity.com on TCP 443 |
| Console login fails | Local account missing or password incorrect | Verify local account exists: show running-config \| include username |
! Test MFA auth end-to-end from the switch
test aaa group TACACS-SERVERS username <testuser> password <password> new-code
! Check active TACACS+ server status
show tacacs
! Debug (use in a maintenance window — verbose output)
debug tacacs
debug aaa authentication