Dynamic Access Policies (DAP) on the Cisco ASA are the runtime override layer for VPN sessions. They evaluate at login time, can match against AAA attributes plus endpoint posture (HostScan / Cisco Secure Endpoint) plus connection attributes, and they can override anything the group-policy or AAA pushed. In other words, DAP is the place where "the user is in the Contractors AD group AND they are not on a corporate-managed laptop" gets translated into "downgrade their access to a tighter ACL". This article walks the DAP record structure, the matching logic, and the precedence rules. All output is from a live ASAv 9.23(1) in the PingLabz ASA reference lab.
Before working through DAP, make sure you have the AAA layer wired up (see Cisco ASA AAA for VPN: LDAP, RADIUS, and TACACS+) and you understand the group-policy / tunnel-group inheritance chain (see Cisco ASA VPN Group Policies and Tunnel Groups). DAP runs after both of those, and it can override them. Without that foundation, DAP behavior looks magical and impossible to debug.
Where DAP Sits in the Connection Pipeline
For a remote-access VPN session, attribute resolution runs in this order:
- Tunnel-group selected (by alias, group-url, or default).
- User authenticated against the tunnel-group's authentication-server-group.
- User authorized; AAA may push back attributes including a per-user group-policy.
- Group-policies merged (DfltGrpPolicy > tunnel-group default > AAA-pushed group-policy).
- DAP records evaluated. All matching DAP records are merged. The merged record can override anything from steps 1-4.
This last layer is the one most engineers underestimate. DAP runs every time, on every login, and silently overrides whatever the group-policies decided. If a user reports "I have a different ACL than my colleague even though we're in the same group", suspect DAP first.
DAP Record Anatomy
A DAP record has four sections:
| Section | What it does |
|---|---|
| Selectors (criteria) | Match conditions: AAA attributes (LDAP groups, RADIUS class), endpoint attributes (OS, anti-malware version, registry keys), connection attributes (tunnel-group, client OS, time-of-day). |
| Action | continue (apply attributes and continue to next record), terminate (drop the connection with a user message), or quarantine. |
| Network ACL list | Pushed to the client as the runtime filter. Trumps the group-policy ACL. |
| Other attributes | Banner / user message, URL list, file browsing, port forwarding, smart tunnel. |
The DfltAccessPolicy Record
Every ASA ships with a DfltAccessPolicy record that you cannot delete. It has no selectors and is therefore always considered. It is the "if no custom DAP record matched, here's what to do" floor.
ASA-PERIM# show running-config dynamic-access-policy-record
dynamic-access-policy-record NO-AC-NO-ENTRY
description "Block any client without AnyConnect (catch-all hygiene)"
user-message "Cisco Secure Client required. Re-launch from the AnyConnect app."
action terminate
priority 10
dynamic-access-policy-record DfltAccessPolicy
dynamic-access-policy-record FULL-ACCESS
description "Employees in NetAdmins LDAP group: full inside subnet"
priority 20
dynamic-access-policy-record CONTRACTOR-RESTRICT
description "Contractor login: read-only network range"
user-message "Contractors: limited access only. Contact NetOps for full perms."
network-acl SPLIT-CONTRACTOR
priority 30
Four DAP records are present, and the configured priority drives which records get evaluated and merged on a session. Higher priority records are evaluated first.
Priority + Action: How Records Combine
Multiple DAP records can match a single session. The ASA processes them in priority order (highest first). Each matched record's action determines what happens:
action continue: apply this record's attributes (ACL, banner, etc.) into the running session profile, then continue to the next matching record.action terminate: apply the user message and drop the connection. No further records are evaluated.action quarantine: apply this record but mark the session as quarantined. Quarantine ACLs typically restrict to a remediation segment.
The merged result of all continue records (plus the DfltAccessPolicy) becomes the final DAP attribute set applied to the session.
The Three Example Records Walked Through
Walk our four records in priority order, top down:
CONTRACTOR-RESTRICT (priority 30)
dynamic-access-policy-record CONTRACTOR-RESTRICT
description "Contractor login: read-only network range"
user-message "Contractors: limited access only. Contact NetOps for full perms."
network-acl SPLIT-CONTRACTOR
priority 30
If a session matches this record (selectors not shown above; configured separately via the GUI or via add-aaa-attribute CLI), the runtime ACL becomes SPLIT-CONTRACTOR instead of whatever the group-policy specified. The user sees the message via the AnyConnect login banner. A typical selector for this record would be: AAA LDAP attribute memberOf=Contractors,OU=Groups,DC=pinglabz,DC=lab.
The selector here is the powerful part. Selectors evaluate against AAA attributes (any RADIUS or LDAP attribute returned for the user), endpoint attributes (OS family/version, anti-malware vendor, file existence, registry value, hotfix presence), and connection attributes (tunnel-group name, client IP, time-of-day, certificate fingerprint).
FULL-ACCESS (priority 20)
dynamic-access-policy-record FULL-ACCESS
description "Employees in NetAdmins LDAP group: full inside subnet"
priority 20
Matched when the user is in the LDAP NetAdmins group. No network-acl override means the user gets whatever ACL the group-policy specified (typically the SPLIT-TUNNEL ACL that permits 10.10.0.0/16). Action is continue (the default), so other records still get a chance.
NO-AC-NO-ENTRY (priority 10)
dynamic-access-policy-record NO-AC-NO-ENTRY
description "Block any client without AnyConnect (catch-all hygiene)"
user-message "Cisco Secure Client required. Re-launch from the AnyConnect app."
action terminate
priority 10
The hygiene rule. If a session is not from a Cisco Secure Client (selector: connection attribute endpoint.application.clienttype eq AnyConnect negated), the connection is dropped with a clear message. This catches clientless / browser-only attempts and forces the use of the full client.
DfltAccessPolicy (no priority, evaluated last)
dynamic-access-policy-record DfltAccessPolicy
Empty in our config. Some deployments configure DfltAccessPolicy with a tight default ACL (deny everything) so that an unmatched session lands in the safest possible state. Others configure a banner and continue.
Selector Categories
| Selector type | Examples | Source |
|---|---|---|
| AAA attribute | LDAP memberOf, RADIUS Class, RADIUS Filter-Id, AAA Cisco AVP attributes | Authentication / authorization response from the AAA server. |
| Endpoint posture | OS version, anti-malware vendor + version, registry key value, file existence and hash, running process, hotfix list | HostScan / Cisco Secure Client posture module on the endpoint. |
| Connection attribute | Tunnel-group name, client IP range, client OS, AnyConnect version, certificate subject/issuer, time-of-day | The session's own metadata available to the gateway. |
Selectors combine via AND / OR. A typical realistic record might say: "AAA: memberOf contains Contractors AND endpoint.os.version < Windows 10 22H2 OR endpoint.av.norton.version < 22.x" then push a tighter ACL.
DAP Override Behavior in Detail
For each attribute, there's a defined precedence between group-policy and DAP. The summary table:
| Attribute | Group-policy says | DAP says | Wins |
|---|---|---|---|
| Network ACL filter | vpn-filter NAME | (no override) | Group-policy ACL |
| Network ACL filter | vpn-filter A | network-acl B | DAP ACL B (DAP wins) |
| Banner / user message | banner none | user-message "..." | DAP message |
| WebVPN URL list | list X | list Y | DAP merges Y on top of X |
| Action (terminate) | (no concept) | action terminate | DAP terminates the session |
The ACL handling is the most important to understand. Whatever the group-policy ACL was, a DAP record's network-acl attribute completely replaces it. There is no merge of ACLs; it is a clean swap.
Verify Which Record Fired
The single most useful command for DAP debugging is show vpn-sessiondb anyconnect detail after the session is established. It shows the matched DAP record and the resulting filter ACL applied to the session. debug dap trace shows the per-record selector evaluation as it happens, which is the only way to find out why a record you thought would match did not. Be cautious with debug output in production: a single user login produces a few dozen lines.
From the running configuration side, show running-config dynamic-access-policy-record shows all configured records and their priority order; show dap test <name> simulates a record evaluation against a synthetic session for sanity checking.
DAP Records Behind the Scenes
Although the records show in show running-config, the full DAP record (including selectors) is stored in an XML file at flash:/dap.xml. This is because the selector grammar is too rich for the single-line CLI; ASDM's DAP editor edits the XML directly, and only a subset of the structure is reflected in the CLI show output.
If you need to back up DAP, copy flash:/dap.xml ftp://... and copy startup-config ftp://... together. Restoring DAP requires both files.
Common Gotchas
- Forgetting that DAP runs every login. Engineers configure a "fix" via group-policy and find it inexplicably overridden. The DAP layer is silently winning. Always check
show running-config dynamic-access-policy-recordfor unexpected records. - Network ACL must be type extended. The
network-aclattribute requires an extended ACL (the opposite ofsplit-tunnel-network-liston a group-policy, which requires standard). Pasting a standard ACL throws an error: "The access list ... is of type 'ipv6' or 'standard' or 'advanced'. Only access lists of type 'extended' are allowed." - action terminate without user-message. The session drops with no clear reason. Always pair
action terminatewith auser-messageso the user sees a real explanation in the AnyConnect log. - Endpoint posture selectors require HostScan. All the rich endpoint matching (anti-malware version, registry, etc.) only works if the Cisco Secure Client has the posture module installed and HostScan is configured. Without it, only AAA + connection attribute selectors evaluate; endpoint selectors silently never match.
- DfltAccessPolicy not tightened. The default DfltAccessPolicy is empty. If no custom record matches, the user gets the group-policy attributes unchanged. For a tighter posture, configure DfltAccessPolicy with a deny-all ACL and require an explicit DAP record with action continue to grant access.
Key Takeaways
Dynamic Access Policies are the runtime override layer for VPN sessions. They evaluate after AAA and after group-policy resolution, and they can override anything those layers set. Selectors combine AAA attributes, endpoint posture, and connection metadata. Multiple matching records are merged; action terminate drops the session immediately. Use DAP for layered policy: "users in this group AND on this OS AND with this AV vendor get this ACL".
For the full Cisco ASA reference, including site-to-site IPsec, NAT, ACLs, failover, and the troubleshooting tools, see the Cisco ASA pillar. To wire AAA correctly so DAP has rich attributes to match against, see Cisco ASA AAA for VPN: LDAP, RADIUS, and TACACS+; to understand the group-policy layer DAP overrides, see Cisco ASA VPN Group Policies and Tunnel Groups.