Cisco ASA AAA for VPN: LDAP, RADIUS, and TACACS+

Wire LDAP, RADIUS, and TACACS+ into the ASA for VPN authentication, authorization, and accounting. Full configuration of all three on a live ASAv 9.23, and when a production firewall uses each one.

Cisco ASA AAA for VPN: LDAP, RADIUS, and TACACS+ - PingLabz ASA article title card

Updated October 2026: I re-tested ASA RADIUS AAA against FreeRADIUS on ASAv 9.24(1), including wrong-NAS and wrong-secret faults that both time out (so a hang is not proof the secret is correct). Details are in the new section before Key Takeaways.

Authentication, Authorization, and Accounting (AAA) on a Cisco ASA decides three things for every VPN session: who is the user, what are they allowed to do, and what activity should be logged. The three protocols you can wire into the ASA for these jobs are LDAP (commonly Microsoft Active Directory), RADIUS, and TACACS+. Each one has its sweet spot, and a real production ASA frequently uses all three at the same time, just for different functions. This article walks the configuration of all three on Cisco ASA 9.x and shows when to use which. In October 2026 I re-tested the RADIUS part on ASAv 9.24(1) built in my home lab; LDAP, TACACS+, LOCAL fallback and accounting were not re-tested (see the PingLabz ASA reference notes and the re-test section).

Before configuring AAA, you should already have a working AnyConnect connection profile (see Cisco ASA AnyConnect SSL VPN Configuration) using local users. The AAA server group then plugs into the existing tunnel-group's authentication-server-group attribute, replacing or augmenting the local fallback.

When to Use Which Protocol

LDAP (most often Microsoft AD)
Best for
VPN authentication and authorization with group memberships from your existing directory.
Notes
Native to AD; no extra server needed. Use LDAPS (TCP/636) for production. Map AD group memberships to ASA group-policy attributes via ldap attribute-map.
RADIUS
Best for
VPN authentication where you want to layer in MFA (Cisco Duo, Microsoft Entra MFA Server, RSA SecurID) or where you want clean accounting.
Notes
Industry-standard. Most MFA solutions front-end RADIUS. Cleaner accounting than LDAP because RADIUS has Accounting-Start / Stop / Interim packets.
TACACS+
Best for
Administrator authentication into the ASA itself: SSH, console, ASDM. Very rarely for VPN.
Notes
Cisco-proprietary. Per-command authorization and per-command accounting (logs every CLI command run by an admin). Required for many regulatory regimes.

The common production split: LDAP for VPN authentication and group lookup, RADIUS for VPN authentication when MFA is required, TACACS+ for admin access into the ASA itself.

AAA Server Groups

All AAA on the ASA is configured in two layers: an aaa-server group (the protocol and the list of servers) and the references to that group from features that consume AAA (tunnel-groups, aaa authentication ssh console, etc.).

From the original build of this lab, three server groups are configured (one per protocol). Only the RADIUS group was re-tested in October 2026, and the secrets show as masked:

ASA-PERIM# show running-config aaa-server
aaa-server RADIUS-VPN protocol radius
aaa-server RADIUS-VPN (inside) host 10.10.0.10
 retry-interval 2
 timeout 5
 key *****
 authentication-port 1812
 accounting-port 1813
aaa-server LDAP-VPN protocol ldap
aaa-server LDAP-VPN (inside) host 10.10.0.20
 server-port 636
 ldap-base-dn dc=pinglabz,dc=lab
 ldap-scope subtree
 ldap-naming-attribute sAMAccountName
 ldap-login-password *****
 ldap-login-dn cn=svc-asa,ou=Service,dc=pinglabz,dc=lab
 ldap-over-ssl enable
 server-type microsoft
aaa-server TACACS-ADMIN protocol tacacs+
aaa-server TACACS-ADMIN (inside) host 10.10.0.30
 timeout 5
 key *****

Each server group has a name (RADIUS-VPN, LDAP-VPN, TACACS-ADMIN), a protocol, and one or more host entries. The ASA tries hosts in order; if the first is unreachable after the configured retry/timeout, it tries the second.

Configure RADIUS for VPN Authentication

Two-step pattern: declare the group with its protocol, then add hosts with their shared secret and timing.

ASA-PERIM(config)# aaa-server RADIUS-VPN protocol radius
ASA-PERIM(config)# aaa-server RADIUS-VPN (inside) host 10.10.0.10
ASA-PERIM(config-aaa-server-host)#  key <RADIUS_KEY>
ASA-PERIM(config-aaa-server-host)#  authentication-port 1812
ASA-PERIM(config-aaa-server-host)#  accounting-port 1813
ASA-PERIM(config-aaa-server-host)#  timeout 5
ASA-PERIM(config-aaa-server-host)#  retry-interval 2
ASA-PERIM(config-aaa-server-host)#  exit

Then bind the group into a tunnel-group:

ASA-PERIM(config)# tunnel-group SSL_PROFILE general-attributes
ASA-PERIM(config-tunnel-general)#  authentication-server-group RADIUS-VPN LOCAL
ASA-PERIM(config-tunnel-general)#  accounting-server-group RADIUS-VPN

The LOCAL after RADIUS-VPN means: try RADIUS first, and fall back to the local username database if all RADIUS hosts are unreachable. Including LOCAL fallback for VPN authentication means a RADIUS outage does not cut off all remote access at exactly the worst moment (when admins need to log in to fix it). I did not re-test the LOCAL fallback in my lab.

Then test it directly. This is from my home lab on ASAv 9.24(1), with the test password replaced by a placeholder. Note the 5-second timeout, which is what this server was configured with:

ASA-AAA58# test aaa-server authentication RADIUS-VPN host 10.58.0.10 username vpnuser password <TEST_PASSWORD>
INFO: Attempting Authentication test to IP address (10.58.0.10) (timeout: 5 seconds)
INFO: Authentication Successful

test aaa-server is the fastest check, but a timeout does not prove the shared secret is correct, or that the server is unreachable. On ASAv 9.24(1) with FreeRADIUS, both a wrong NAS IP in clients.conf and a wrong ASA key produced ERROR: Authentication Server not responding: No active server found after the 5-second timeout, while ping still succeeded and, for the secret fault, the server still received the requests. An immediate ERROR: Authentication Rejected: AAA failure is the wrong-password path. Confirm with the RADIUS server log or a capture, not the timeout alone.

Configure LDAP (Active Directory) for Authorization

LDAP setup needs more attributes than RADIUS because there is no standard "give me the user's password and let me see if it matches" call. The ASA binds to the directory as a service account, then performs a sub-tree search to find the user by their login attribute, then re-binds as the user with their typed password.

ASA-PERIM(config)# aaa-server LDAP-VPN protocol ldap
ASA-PERIM(config)# aaa-server LDAP-VPN (inside) host 10.10.0.20
ASA-PERIM(config-aaa-server-host)#  ldap-base-dn dc=pinglabz,dc=lab
ASA-PERIM(config-aaa-server-host)#  ldap-scope subtree
ASA-PERIM(config-aaa-server-host)#  ldap-naming-attribute sAMAccountName
ASA-PERIM(config-aaa-server-host)#  ldap-login-dn cn=svc-asa,ou=Service,dc=pinglabz,dc=lab
ASA-PERIM(config-aaa-server-host)#  ldap-login-password <LDAP_BIND_PASSWORD>
ASA-PERIM(config-aaa-server-host)#  server-type microsoft
ASA-PERIM(config-aaa-server-host)#  ldap-over-ssl enable
ASA-PERIM(config-aaa-server-host)#  server-port 636
ASA-PERIM(config-aaa-server-host)#  exit

The eight attributes:

  • ldap-base-dn: the root of the LDAP tree to search from. Typically your AD domain DN.
  • ldap-scope subtree: search the entire sub-tree below the base DN. The other choice (onelevel) only searches one level deep, which is rarely what you want.
  • ldap-naming-attribute sAMAccountName: the attribute that identifies a user. sAMAccountName is the AD short name (e.g. vpnuser). For OpenLDAP, it would be uid; for AD via UPN, use userPrincipalName.
  • ldap-login-dn + ldap-login-password: the service account the ASA binds as to perform the user search.
  • server-type microsoft: tells the ASA how to interpret password-expiry and account-locked responses. Other choices include generic, sun, openldap.
  • ldap-over-ssl enable + server-port 636: use LDAPS instead of clear-text LDAP. Always use LDAPS in production. Clear LDAP exposes the user's typed password to every device on the inside path between ASA and DC.

Bind to a tunnel-group as the authorization-server-group:

ASA-PERIM(config)# tunnel-group SSL_PROFILE general-attributes
ASA-PERIM(config-tunnel-general)#  authorization-server-group LDAP-VPN

This authorizes the user post-authentication: the ASA performs a second LDAP search to retrieve group memberships and attributes, which can be mapped to ASA group-policies via ldap attribute-map. The full attribute-map mechanism is covered in the DAP article (it ties cleanly into Dynamic Access Policies).

Configure TACACS+ for Admin Access

TACACS+ is rarely used for VPN authentication. Its strength is per-command authorization for admins logging into the ASA itself: every CLI command an admin runs is authorized by the TACACS+ server, and every command is logged via accounting.

ASA-PERIM(config)# aaa-server TACACS-ADMIN protocol tacacs+
ASA-PERIM(config)# aaa-server TACACS-ADMIN (inside) host 10.10.0.30
ASA-PERIM(config-aaa-server-host)#  key <TACACS_KEY>
ASA-PERIM(config-aaa-server-host)#  server-port 49
ASA-PERIM(config-aaa-server-host)#  timeout 5
ASA-PERIM(config-aaa-server-host)#  exit

Wire into the ASA's admin auth/authz/acct planes:

ASA-PERIM(config)# aaa authentication ssh console TACACS-ADMIN LOCAL
ASA-PERIM(config)# aaa authorization exec authentication-server
ASA-PERIM(config)# aaa accounting ssh console TACACS-ADMIN

What each line does:

  • aaa authentication ssh console TACACS-ADMIN LOCAL: authenticate SSH logins via TACACS+, fall back to local. The console keyword here means console-mode SSH (the standard SSH login flow).
  • aaa authorization exec authentication-server: when an authenticated admin enters exec mode, look up their privilege level on the same server that authenticated them. This drives the priv-15 vs priv-1 split.
  • aaa accounting ssh console TACACS-ADMIN: log SSH session start and stop, including duration.

For per-command logging (which most TACACS+ deployments want), add aaa accounting command privilege 15 TACACS-ADMIN to log every priv-15 command. This produces a full audit trail of who-typed-what.

Authentication, Authorization, Accounting Separated

You can mix protocols by feature. A common production pattern:

VPN (SSL_PROFILE tunnel-group)
Authentication
RADIUS-VPN (with MFA), fall back LOCAL
Authorization
LDAP-VPN (group lookup, attribute mapping)
Accounting
RADIUS-VPN (session start/stop with byte counts)
Admin SSH
Authentication
TACACS-ADMIN, fall back LOCAL
Authorization
TACACS-ADMIN (per-command)
Accounting
TACACS-ADMIN (per-command)

Each function points at the protocol best suited to it. That is the design configured in the original build of this lab: SSL_PROFILE uses RADIUS for auth + LDAP for authz + RADIUS for acct, while admin SSH uses TACACS+ for all three. In the October 2026 re-test only RADIUS authentication was exercised; LDAP authorization, TACACS+ admin access, LOCAL fallback and accounting were not re-tested.

Common Gotchas

  1. No LOCAL fallback. RADIUS or LDAP server has an outage, and now no one can log in. Always end the auth chain with LOCAL for VPN; always end with LOCAL for admin SSH.
  2. Clear-text LDAP. Without ldap-over-ssl enable, every VPN user's password traverses the inside network in clear-text inside an LDAP bind. Anyone on the path can sniff it. Use LDAPS (TCP/636) or STARTTLS (TCP/389 with negotiated TLS).
  3. Wrong service account permissions. The ldap-login-dn account must have read permission on the user OUs you intend to authenticate against. In AD, a domain user account is typically enough; service accounts often have explicit read-deny on Protected Users group, which breaks lookup.
  4. RADIUS shared-secret typo (or wrong NAS IP). Symptom: a timeout, ERROR: Authentication Server not responding: No active server found, not a clean reject, and ping can still succeed. In my lab both faults produced exactly that message. Verify with test aaa-server and the server log or a capture: a matching config returns INFO: Authentication Successful, while a wrong password returns ERROR: Authentication Rejected: AAA failure.
  5. Confusing authentication-server-group with authorization-server-group. The two attributes are independent. You can authenticate against RADIUS but authorize against LDAP. If you forget the authorization-server-group, no LDAP attribute-map firing will happen and the user gets the tunnel-group default group-policy regardless of their AD group memberships.

Re-tested in my home lab (October 2026)

Built in my home lab: RADIUS VPN authentication on ASAv 9.24(1) against FreeRADIUS 3.0.27 on Alpine Linux, with Message-Authenticator required on both sides. Direct test aaa-server is the primary proof. OpenConnect 9.12 --authenticate also exercised SSL_PROFILE and received an auth cookie, but there was no AnyConnect image and no VPN data tunnel was established, so AAA success here is not a working tunnel.

Lab diagram: ASA RADIUS test built in my home lab with an ASAv 9.24(1) firewall, a FreeRADIUS 3.0.27 server on the inside and an OpenConnect client on the outside. test aaa-server succeeds with the matching NAS entry and shared secret. A wrong NAS entry and a wrong shared secret both time out with "No active server found" rather than a reject, while a wrong password returns Authentication Rejected. Restoring the secret brings Authentication Successful back. No VPN data tunnel was tested.

Matching configuration

INFO: Attempting Authentication test to IP address (10.58.0.10) (timeout: 5 seconds)
INFO: Authentication Successful

Wrong password is an immediate reject (distinct from the timeout faults):

INFO: Attempting Authentication test to IP address (10.58.0.10) (timeout: 5 seconds)
ERROR: Authentication Rejected: AAA failure

Break it: wrong NAS IP

Registering FreeRADIUS for 10.58.0.99 while the ASA still sourced from 10.58.0.1 timed out:

INFO: Attempting Authentication test to IP address (10.58.0.10) (timeout: 5 seconds)
ERROR: Authentication Server not responding: No active server found

Break it: wrong shared secret

Same timeout message — not a reject — with ping still succeeding:

INFO: Attempting Authentication test to IP address (10.58.0.10) (timeout: 5 seconds)
ERROR: Authentication Server not responding: No active server found

Fix: restore the matching key

INFO: Attempting Authentication test to IP address (10.58.0.10) (timeout: 5 seconds)
INFO: Authentication Successful

LDAP and TACACS+ groups from the article were syntax-probed only (server-type generic was rejected on this image). LDAP runtime, TACACS+ admin authentication, LOCAL fallback, RADIUS accounting and VPN forwarding were not re-tested.

Key Takeaways

AAA on the Cisco ASA is configured in two layers: aaa-server groups (the protocol + hosts), then references to those groups from features (tunnel-groups, admin auth). RADIUS authentication was re-tested on ASAv 9.24(1) with FreeRADIUS: a wrong shared secret or NAS entry timed out with "No active server found" rather than rejecting. LDAP, TACACS+, LOCAL fallback and accounting were not re-tested, and AAA success is not the same as a working VPN tunnel; no data tunnel was tested. Keep a LOCAL fallback on the chains you care about surviving an AAA outage.

For the full Cisco ASA reference, including site-to-site IPsec, NAT, ACLs, failover, and the troubleshooting tools, see the Cisco ASA pillar. The next step after AAA is mapping the AAA-returned attributes (and endpoint posture) to runtime decisions: Cisco ASA Dynamic Access Policies (DAP) covers that. For the connection-profile foundation, see Cisco ASA VPN Group Policies and Tunnel Groups.

Read next