Downloadable ACLs API
Overview
Downloadable ACLs (dACLs) are pushed to network devices during authorization. They provide fine-grained access control per endpoint.
Base URL |
|
Methods |
GET, POST, PUT, DELETE |
Key Fields |
name, dacl (content), daclType |
Setup
dsource d000 dev/network
ISE_HOST="${ISE_PAN_IP}"
ISE_AUTH="${ISE_API_USER}:${ISE_API_PASS}"
BASE_URL="https://${ISE_HOST}:9060/ers/config"
List All dACLs
netapi
netapi ise get-dacls
curl
# List all dACLs
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl" \
-H "Accept: application/json" | jq '.SearchResult.resources[] | {name, id}'
Get dACL by Name
netapi
netapi ise get-dacl "Linux-Permit-AD-Only"
curl
# Get dACL by name (includes ACL content)
DACL_NAME="Linux-Permit-AD-Only"
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/name/${DACL_NAME}" \
-H "Accept: application/json" | jq '.DownloadableAcl'
Get Content Only
# Get just the ACL content
DACL_NAME="Linux-Permit-AD-Only"
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/name/${DACL_NAME}" \
-H "Accept: application/json" | jq -r '.DownloadableAcl.dacl'
Create dACL
Permit All
# Create permit-all dACL
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-X POST \
-d '{
"DownloadableAcl": {
"name": "Linux-Permit-All",
"description": "Full network access for trusted Linux workstations",
"dacl": "permit ip any any",
"daclType": "IPV4"
}
}'
Zero-Trust AD-Only
# Create AD-only dACL (zero-trust)
# Variables for AD DC
AD_DC_IP="10.50.1.50"
cat > /tmp/dacl-content.txt << EOF
remark ### AD Authentication - Kerberos ###
permit udp any host ${AD_DC_IP} eq 88
permit tcp any host ${AD_DC_IP} eq 88
remark ### LDAP/LDAPS ###
permit tcp any host ${AD_DC_IP} eq 389
permit tcp any host ${AD_DC_IP} eq 636
remark ### DNS ###
permit udp any host ${AD_DC_IP} eq 53
permit tcp any host ${AD_DC_IP} eq 53
remark ### Global Catalog ###
permit tcp any host ${AD_DC_IP} eq 3268
permit tcp any host ${AD_DC_IP} eq 3269
remark ### NTP ###
permit udp any host ${AD_DC_IP} eq 123
remark ### SMB for GPO ###
permit tcp any host ${AD_DC_IP} eq 445
remark ### DENY ALL OTHER ###
deny ip any any
EOF
DACL_CONTENT=$(cat /tmp/dacl-content.txt | jq -Rs .)
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-X POST \
-d '{
"DownloadableAcl": {
"name": "Linux-Permit-AD-Only",
"description": "Zero-trust: Only AD authentication traffic",
"dacl": '"${DACL_CONTENT}"',
"daclType": "IPV4"
}
}'
MAB Onboarding
# Create MAB onboarding dACL (DHCP + limited access)
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-X POST \
-d '{
"DownloadableAcl": {
"name": "MAB-Onboard-DACL",
"description": "Limited access for MAB onboarding",
"dacl": "remark ### DHCP ###\npermit udp any any eq 67\npermit udp any any eq 68\nremark ### DNS ###\npermit udp any any eq 53\nremark ### ISE for posture ###\npermit tcp any host 10.50.1.20 eq 8443\nremark ### DENY ALL OTHER ###\ndeny ip any any",
"daclType": "IPV4"
}
}'
Update dACL
# Update dACL content
DACL_NAME="Linux-Permit-AD-Only"
# Get current dACL
DACL=$(curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/name/${DACL_NAME}" \
-H "Accept: application/json")
DACL_ID=$(echo "$DACL" | jq -r '.DownloadableAcl.id')
# New content with additional rule
NEW_CONTENT="remark ### UPDATED ###
permit udp any host 10.50.1.50 eq 88
permit tcp any host 10.50.1.50 eq 88
permit tcp any host 10.50.1.50 eq 389
permit tcp any host 10.50.1.50 eq 636
permit udp any host 10.50.1.50 eq 53
permit tcp any host 10.50.1.50 eq 53
permit tcp any host 10.50.1.50 eq 3268
permit udp any host 10.50.1.50 eq 123
permit tcp any host 10.50.1.50 eq 445
remark ### Added: ICMP for troubleshooting ###
permit icmp any host 10.50.1.50
deny ip any any"
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/${DACL_ID}" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-X PUT \
-d '{
"DownloadableAcl": {
"id": "'"${DACL_ID}"'",
"name": "'"${DACL_NAME}"'",
"dacl": "'"$(echo "$NEW_CONTENT" | jq -Rs .)"'",
"daclType": "IPV4"
}
}'
Delete dACL
netapi
netapi ise delete-dacl "Test-DACL"
curl
# Delete dACL (must not be in use by any authz profile)
DACL_ID="abc123-def456"
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/${DACL_ID}" \
-X DELETE
Common Patterns
Compare dACLs
# Compare two dACLs
DACL1="Linux-Permit-AD-Only"
DACL2="Linux-Permit-AD-Only-v2"
echo "=== ${DACL1} ==="
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/name/${DACL1}" \
-H "Accept: application/json" | jq -r '.DownloadableAcl.dacl'
echo ""
echo "=== ${DACL2} ==="
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/name/${DACL2}" \
-H "Accept: application/json" | jq -r '.DownloadableAcl.dacl'
# Diff them
diff <(curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/name/${DACL1}" \
-H "Accept: application/json" | jq -r '.DownloadableAcl.dacl') \
<(curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/name/${DACL2}" \
-H "Accept: application/json" | jq -r '.DownloadableAcl.dacl')
Find Unused dACLs
# Find dACLs not used by any authz profile
# Get all dACL names
DACLS=$(curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl" \
-H "Accept: application/json" | jq -r '.SearchResult.resources[].name')
# Get all dACLs used in profiles
USED_DACLS=$(curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/authorizationprofile" \
-H "Accept: application/json" | \
jq -r '.SearchResult.resources[].id' | while read ID; do
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/authorizationprofile/${ID}" \
-H "Accept: application/json" | jq -r '.AuthorizationProfile.daclName // empty'
done | sort -u)
# Find unused
echo "Unused dACLs:"
echo "$DACLS" | while read DACL; do
if ! echo "$USED_DACLS" | grep -q "^${DACL}$"; then
echo " $DACL"
fi
done
Export All dACLs
# Export all dACLs to files
mkdir -p dacl-backup
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl" \
-H "Accept: application/json" | jq -r '.SearchResult.resources[] | "\(.id) \(.name)"' | \
while read ID NAME; do
SAFE_NAME=$(echo "$NAME" | tr ' /' '_')
curl -sk -u "${ISE_AUTH}" \
"${BASE_URL}/downloadableacl/${ID}" \
-H "Accept: application/json" | jq -r '.DownloadableAcl.dacl' > "dacl-backup/${SAFE_NAME}.acl"
echo "Exported: ${NAME}"
done
Validate Syntax
# Validate dACL syntax before creating (basic check)
validate_dacl() {
local content="$1"
local errors=0
while IFS= read -r line; do
# Skip empty lines and remarks
[[ -z "$line" || "$line" =~ ^remark ]] && continue
# Check for valid ACL format
if ! [[ "$line" =~ ^(permit|deny)[[:space:]]+(ip|tcp|udp|icmp) ]]; then
echo "Invalid line: $line"
((errors++))
fi
done <<< "$content"
return $errors
}
# Example usage
DACL_CONTENT="permit ip any any
deny tcp any any eq 22
invalid line here"
if validate_dacl "$DACL_CONTENT"; then
echo "dACL syntax valid"
else
echo "dACL has syntax errors"
fi