NetworkManager Wired 802.1X
Overview
This guide configures wired 802.1X EAP-TLS authentication using NetworkManager (nmcli). This is the recommended approach for modern Linux distributions with desktop environments.
|
For headless servers or minimal installs, see wpa_supplicant Configuration. |
Prerequisites
-
User certificate issued by trusted CA (AD CS or Vault)
-
CA certificate in ISE trust store
-
Switch port configured for 802.1X
Certificate Locations
/etc/ssl/certs/<hostname>-eaptls.pem # Client certificate
/etc/ssl/private/<hostname>-eaptls.key # Private key (chmod 600)
/etc/ssl/certs/HOME-ROOT-CA.pem # CA certificate (AD CS)
# OR
/etc/ssl/certs/DOMUS-ROOT-CA.pem # CA certificate (Vault)
Step 1: Obtain User Certificate
Option A: From AD CS (current)
# Generate CSR
openssl req -new -newkey rsa:2048 -nodes \
-keyout /tmp/$(hostname)-eaptls.key \
-out /tmp/$(hostname)-eaptls.csr \
-subj "/CN=$(hostname).inside.domusdigitalis.dev"
# Submit to AD CS (from Windows or via certreq)
# Download signed certificate as <hostname>-eaptls.pem
Option B: From Vault (future)
dsource d000 dev/vault
netapi vault pki-issue $(hostname).inside.domusdigitalis.dev \
-o /tmp/$(hostname)-eaptls
Install Certificates
# Install certificates
sudo cp /tmp/$(hostname)-eaptls.pem /etc/ssl/certs/
sudo cp /tmp/$(hostname)-eaptls.key /etc/ssl/private/
sudo chmod 644 /etc/ssl/certs/$(hostname)-eaptls.pem
sudo chmod 600 /etc/ssl/private/$(hostname)-eaptls.key
# Install CA certificate (if not already present)
sudo cp /tmp/HOME-ROOT-CA.pem /etc/ssl/certs/
# OR for Vault:
sudo cp /tmp/DOMUS-ROOT-CA.pem /etc/ssl/certs/
Step 2: Identify Network Interface
# List interfaces
nmcli device status
# Example output:
# DEVICE TYPE STATE CONNECTION
# enp0s31f6 ethernet disconnected --
# wlp4s0 wifi connected HomeWiFi
Step 3: Migration from wpa_supplicant (if applicable)
If currently using wpa_supplicant for wired 802.1X, disable it first.
3.1 Verify wpa_supplicant is Running
# Quick status check
systemctl status wpa_supplicant-wired@enp0s31f6.service | grep -E "Active:|loaded|running"
# Deep validation - confirm EAP-TLS is working
sudo wpa_cli -i enp0s31f6 status | grep -E "wpa_state|eap_state|suppPortStatus"
Loaded: loaded (/usr/lib/systemd/system/wpa_supplicant-wired@.service; enabled; preset: disabled)
Active: active (running) since ...
wpa_state=COMPLETED
suppPortStatus=Authorized
3.2 Stop and Disable wpa_supplicant
sudo systemctl stop wpa_supplicant-wired@enp0s31f6.service
sudo systemctl disable wpa_supplicant-wired@enp0s31f6.service
3.3 Verify it’s Stopped
systemctl status wpa_supplicant-wired@enp0s31f6.service | grep -E "Active:|loaded"
Loaded: loaded (/usr/lib/systemd/system/wpa_supplicant-wired@.service; disabled; preset: disabled)
Active: inactive (dead)
|
Keep WiFi connected during wired migration! If NetworkManager wired fails, you still have network access via WiFi to troubleshoot. |
Step 4: Create 802.1X Connection
Arch Linux doesn’t have hostname command by default. Use cat /etc/hostname or the literal hostname.
|
|
You MUST include |
# Get your hostname first
MYHOST=$(cat /etc/hostname)
echo "Hostname: $MYHOST"
# Create wired 802.1X connection
sudo nmcli connection add \
type ethernet \
con-name "Wired-802.1X" \
ifname enp0s31f6 \
802-1x.eap tls \
802-1x.identity "$<your-hostname>.inside.domusdigitalis.dev" \
802-1x.identity-flags 0 \
802-1x.ca-cert /etc/ssl/certs/HOME-ROOT-CA.pem \
802-1x.client-cert /etc/ssl/certs/$<your-hostname>-eaptls.pem \
802-1x.private-key /etc/ssl/private/$<your-hostname>-eaptls.key \
802-1x.private-key-password-flags 4 \
connection.autoconnect yes
| Flag | Meaning |
|---|---|
|
Store identity in connection file (not as secret) |
|
Not required (key has no password) |
With Private Key Password
If your private key has a password:
sudo nmcli connection add \
type ethernet \
con-name "Wired-802.1X" \
ifname enp0s31f6 \
802-1x.eap tls \
802-1x.identity "$(hostname).inside.domusdigitalis.dev" \
802-1x.ca-cert /etc/ssl/certs/HOME-ROOT-CA.pem \
802-1x.client-cert /etc/ssl/certs/$(hostname)-eaptls.pem \
802-1x.private-key /etc/ssl/private/$(hostname)-eaptls.key \
802-1x.private-key-password "your-password-here" \
connection.autoconnect yes
Step 6: Verify Authentication
6.1 Quick Validation
# NetworkManager connection state
nmcli connection show "Wired-802.1X" | grep -E "GENERAL.STATE|connection.type|802-1x"
# Device status
nmcli device show enp0s31f6 | grep -E "GENERAL.STATE|IP4.ADDRESS|WIRED-PROPERTIES"
GENERAL.STATE: 100 (connected)
connection.type: 802-3-ethernet
802-1x.eap: tls
802-1x.identity: modestus-p50.inside.domusdigitalis.dev
GENERAL.STATE: 100 (connected)
IP4.ADDRESS[1]: 10.50.40.xxx/24
6.2 Verify IP Assignment
ip addr show enp0s31f6 | grep -E "state|inet "
enp0s31f6: <BROADCAST,MULTICAST,UP,LOWER_UP> ... state UP ...
inet 10.50.40.xxx/24 brd 10.50.40.255 scope global dynamic ...
6.3 ISE Session Verification
# Load credentials
dsource d000 dev/network
# Check ISE session (should show dot1x/EAP-TLS)
netapi ise mnt session $(cat /sys/class/net/enp0s31f6/address)
Method: dot1x
Protocol: EAP-TLS
Username: <hostname>.inside.domusdigitalis.dev
Status: PASSED
6.4 Full Validation One-Liner
Quick validation that covers everything:
# All-in-one validation
echo "=== wpa_supplicant ===" && \
systemctl status wpa_supplicant-wired@enp0s31f6.service | grep -E "Active:|loaded" && \
echo "=== NetworkManager ===" && \
nmcli connection show --active | grep -E "Wired|enp0" && \
echo "=== 802.1X Config ===" && \
nmcli connection show "Wired-802.1X" | grep -E "GENERAL.STATE|802-1x.eap|802-1x.identity" && \
echo "=== IP Address ===" && \
ip addr show enp0s31f6 | grep "inet "
=== wpa_supplicant ===
Loaded: loaded (...; disabled; preset: disabled)
Active: inactive (dead)
=== NetworkManager ===
Wired-802.1X <uuid> ethernet enp0s31f6
=== 802.1X Config ===
802-1x.eap: tls
802-1x.identity: modestus-p50.inside.domusdigitalis.dev
GENERAL.STATE: activated
=== IP Address ===
inet 10.50.40.xxx/24 ...
Daily Operations Commands
Commands for daily 802.1X troubleshooting and monitoring.
NetworkManager Commands
# List all connections
nmcli connection show
# Show active connections
nmcli connection show --active
# Show connection details
nmcli connection show "Wired-802.1X"
# Show 802.1X specific settings
nmcli connection show "Wired-802.1X" | grep "802-1x"
# Reconnect (bounce the connection)
sudo nmcli connection down "Wired-802.1X" && sudo nmcli connection up "Wired-802.1X"
# Check device status
nmcli device status
nmcli device show enp0s31f6
# View connection file
sudo cat /etc/NetworkManager/system-connections/Wired-802.1X.nmconnection
wpa_cli Commands (for wpa_supplicant interfaces)
wpa_cli still works for interfaces managed by wpa_supplicant (e.g., WiFi before migration).
|
# Status (comprehensive)
sudo wpa_cli -i wlan0 status
# Key fields to check:
# - wpa_state=COMPLETED (authenticated)
# - key_mgmt=WPA2/IEEE 802.1X/EAP
# - EAP state=SUCCESS
# - selectedMethod=13 (EAP-TLS)
# - suppPortStatus=Authorized
# Quick status check
sudo wpa_cli -i wlan0 status | grep -E "wpa_state|key_mgmt|EAP state|selectedMethod|suppPortStatus"
# Scan for networks
sudo wpa_cli -i wlan0 scan
sudo wpa_cli -i wlan0 scan_results
# Reassociate (reconnect)
sudo wpa_cli -i wlan0 reassociate
# Disconnect
sudo wpa_cli -i wlan0 disconnect
# List configured networks
sudo wpa_cli -i wlan0 list_networks
# Get interface info
sudo wpa_cli -i wlan0 get_capability eap
ISE Verification (netapi)
# Load credentials first
dsource d000 dev/network
MnT API (Monitoring & Troubleshooting)
Real-time session data, live authentications.
# Session by MAC (most common)
netapi ise mnt session c8:5b:76:c6:59:62
# All active sessions
netapi ise mnt sessions
# Session count
netapi ise mnt count
# MnT version/health
netapi ise mnt version
# Auth status (recent auths for MAC)
netapi ise mnt auth-status c8:5b:76:c6:59:62
DataConnect API (SQL queries, historical data)
Deep historical analysis, detailed session info.
# Detailed session info
netapi ise dc session c8:5b:76:c6:59:62
# Auth history (last 24h for MAC)
netapi ise dc auth-history c8:5b:76:c6:59:62
# Recent authentications (all)
netapi ise dc recent
# Failed authentications
netapi ise dc failed
# Endpoint details
netapi ise dc endpoint c8:5b:76:c6:59:62
# Profiler data
netapi ise dc profiler
# Device types
netapi ise dc device-types
# Custom SQL query
netapi ise dc query "SELECT * FROM radius_authentications WHERE calling_station_id='C8:5B:76:C6:59:62' ORDER BY timestamp DESC LIMIT 10"
ERS API (Configuration, CRUD operations)
Endpoint management, policy objects.
# Get endpoint by MAC
netapi ise get-endpoint c8:5b:76:c6:59:62
# List all endpoints (paginated)
netapi ise get-endpoints --size 50
# Endpoint groups
netapi ise get-endpoint-groups
# Authorization profiles
netapi ise get-authz-profiles
# dACLs
netapi ise get-dacls
# Network devices (NADs)
netapi ise get-nads
# Policy sets
netapi ise get-policy-sets
# ISE nodes (deployment info)
netapi ise get-nodes --detailed
pxGrid API (Real-time events, pub/sub)
Live session tracking, CoA, threat response.
# pxGrid session by MAC
netapi ise pxgrid session c8:5b:76:c6:59:62
# pxGrid session by IP
netapi ise pxgrid session 10.50.40.101
# All active sessions
netapi ise pxgrid sessions
# ISE health metrics
netapi ise pxgrid health
# Performance stats
netapi ise pxgrid performance
Quick Reference Table
| Need | Command | API |
|---|---|---|
Live session status |
|
MnT |
Why auth failed |
|
DataConnect |
Detailed failure reason |
|
DataConnect |
Endpoint profile/group |
|
ERS |
Real-time session events |
|
pxGrid |
Change endpoint group |
|
ERS |
ISE node health |
|
pxGrid |
Custom SQL analysis |
|
DataConnect |
Quick Troubleshooting
# Check logs (last 5 min)
journalctl -u NetworkManager --since "5 minutes ago" | grep -iE "eap|tls|auth|fail|error"
# Check wpa_supplicant logs
journalctl -t wpa_supplicant --since "5 minutes ago"
# Certificate verification
openssl x509 -in /etc/ssl/certs/modestus-p50-eaptls.pem -noout -subject -dates
# Check cert chain
openssl verify -CAfile /etc/ssl/certs/HOME-ROOT-CA.pem /etc/ssl/certs/modestus-p50-eaptls.pem
Modifying Connection
# Change identity
sudo nmcli connection modify "Wired-802.1X" \
802-1x.identity "new-identity@domain"
# Update certificate paths
sudo nmcli connection modify "Wired-802.1X" \
802-1x.client-cert /etc/ssl/certs/new-cert.pem \
802-1x.private-key /etc/ssl/private/new-key.key
# Disable autoconnect
sudo nmcli connection modify "Wired-802.1X" \
connection.autoconnect no
DNS Configuration Issues
Issue: Empty /etc/resolv.conf
Symptom:
cat /etc/resolv.conf
# Generated by NetworkManager
# (file is empty)
# DNS queries fail
dig google.com
# connection timed out; no servers could be reached
Cause: NetworkManager isn’t configured to manage DNS, or dhcpcd is conflicting with NetworkManager.
Solution A: Configure NetworkManager DNS
# Check NetworkManager configuration
cat /etc/NetworkManager/NetworkManager.conf
# If empty or missing [main] section, add it
sudo nvim /etc/NetworkManager/NetworkManager.conf
# Add or ensure these lines exist:
[main]
dns=default
# Restart NetworkManager
sudo systemctl restart NetworkManager
# Reconnect to apply
sudo nmcli connection down "Wired-802.1X"
sudo nmcli connection up "Wired-802.1X"
# Verify resolv.conf is populated
cat /etc/resolv.conf
Solution B: Disable dhcpcd (if running)
# Check if dhcpcd is running
systemctl status dhcpcd
systemctl status dhcpcd@enp0s31f6
# If active, it's conflicting with NetworkManager
# Stop and disable it
sudo systemctl stop dhcpcd
sudo systemctl disable dhcpcd
sudo systemctl stop dhcpcd@enp0s31f6
sudo systemctl disable dhcpcd@enp0s31f6
# NetworkManager has its own internal DHCP client
# No need for dhcpcd when using NetworkManager
# Restart NetworkManager
sudo systemctl restart NetworkManager
# Reconnect
sudo nmcli connection up "Wired-802.1X"
# Verify DNS
cat /etc/resolv.conf
|
NetworkManager vs dhcpcd:
Do NOT run both simultaneously! Choose one:
|
Symptom: Multiple IPs on Same Interface
If you see duplicate IPs on one interface:
ip addr show wlan0
# inet 10.50.10.121/24 ...
# inet 10.50.10.126/24 scope global secondary ... ← TWO IPs!
Cause: Both NetworkManager and dhcpcd are requesting DHCP leases.
Diagnosis:
# Check if dhcpcd is running despite being disabled
ps aux | grep dhcpcd
# Check which IP is from NetworkManager
nmcli device show wlan0 | grep IP4.ADDRESS
# Or
nmcli connection show "Domus-Secure" | grep IP4.ADDRESS
# Test which IP responds
ping -c 2 10.50.10.121
ping -c 2 10.50.10.126
Solution:
# 1. Kill all dhcpcd processes
sudo killall dhcpcd
# 2. Remove dead/duplicate IP (keep the working one!)
# First verify which IP is from NetworkManager
nmcli device show wlan0 | grep IP4.ADDRESS
# Example output: IP4.ADDRESS[1]: 10.50.10.126/24
# Delete the OTHER IP (not the NetworkManager one!)
sudo ip addr del 10.50.10.121/24 dev wlan0
# 3. Mask dhcpcd permanently to prevent it from starting
sudo systemctl mask dhcpcd
# 4. Verify only one IP remains
ip addr show wlan0 | grep "inet "
# 5. Verify dhcpcd is gone
ps aux | grep dhcpcd
|
Before deleting ANY IP, verify which one is your active SSH connection! Test connectivity:
Delete the IP that does NOT respond. If you delete the wrong one, you’ll lose SSH access and need console/physical access to recover. |
Verify DNS is Received from DHCP
# Check what NetworkManager received from DHCP
nmcli device show enp0s31f6 | grep -E "IP4.DNS|IP4.GATEWAY|IP4.ADDRESS"
# Expected output:
# IP4.ADDRESS[1]: 10.50.40.101/24
# IP4.GATEWAY: 10.50.40.1
# IP4.DNS[1]: 10.50.1.50
# IP4.DNS[2]: 10.50.1.1
# If DNS is shown but resolv.conf is empty:
# NetworkManager is receiving DNS but not writing it
# Configure dns=default in NetworkManager.conf (see above)
# Check connection DNS settings
nmcli connection show "Wired-802.1X" | grep -E "ipv4.dns|ipv4.ignore-auto-dns"
# If ipv4.ignore-auto-dns is "yes", change it:
sudo nmcli connection modify "Wired-802.1X" ipv4.ignore-auto-dns no
sudo nmcli connection up "Wired-802.1X"
resolv.conf Management Comparison
| Tool | Manages resolv.conf | Notes |
|---|---|---|
NetworkManager |
Yes (with |
Recommended for desktops/laptops |
dhcpcd |
Yes (conflicts with NM) |
Use for servers without NetworkManager |
systemd-resolved |
Yes (via symlink) |
Alternative DNS resolver, can work with NetworkManager |
wpa_supplicant alone |
No (manual or script) |
Need separate DHCP client |
Troubleshooting
Check Logs
# NetworkManager logs
journalctl -u NetworkManager -f
# wpa_supplicant logs (NetworkManager uses this internally)
journalctl -t wpa_supplicant -f
Common Issues
| Issue | Solution |
|---|---|
"Secrets were required, but not provided" |
Missing |
"No secrets provided" |
Check certificate paths and permissions |
"TLS handshake failed" |
CA cert chain issue - see Fix: TLS Handshake Failed (Chain Certificate) |
"Authentication rejected" |
Check ISE logs, verify identity matches certificate CN |
Connection keeps disconnecting |
Check switch port configuration, verify VLAN assignment |
"IP configuration could not be reserved" |
EAP succeeded but DHCP slow/failed. Check switch port authorization, wait and retry |
"invalid message format" in journal |
Certificate path issue - verify files exist with |
Fix: "Secrets Required" Prompt
If NetworkManager prompts for identity/password on every connection, the flags weren’t saved properly.
# Check current connection file
sudo cat /etc/NetworkManager/system-connections/Wired-802.1X.nmconnection
# The [802-1x] section MUST have these flags:
# identity-flags=0
# private-key-password-flags=4
# Edit the connection file
sudo nvim /etc/NetworkManager/system-connections/Wired-802.1X.nmconnection
# Add to [802-1x] section:
# identity-flags=0
# private-key-password-flags=4
# Reload and retry
sudo nmcli connection reload
sudo nmcli connection up "Wired-802.1X"
[802-1x]
ca-cert=/etc/ssl/certs/HOME-ROOT-CA.pem
client-cert=/etc/ssl/certs/modestus-p50-eaptls.pem
eap=tls;
identity=modestus-p50.inside.domusdigitalis.dev
identity-flags=0
private-key=/etc/ssl/private/modestus-p50-eaptls.key
private-key-password-flags=4
Fix: TLS Handshake Failed (Chain Certificate)
Symptom: 802.1X authentication fails with "TLS handshake failed" or "SSL alert: unknown CA" in journal logs.
Cause: NetworkManager’s ca-cert points to the ROOT CA only, but ISE presents a certificate signed by a SUBORDINATE CA. The client needs the full chain to validate.
|
EAP-TLS certificate chain: ISE presents: ISE cert → Signed by SUBCA Client needs: ROOT CA → SUBCA chain to validate If client only has ROOT CA, handshake fails because it can't build the chain. Field-tested at CHLA (2026-02-06): SSL handshake failures resolved after creating combined chain cert. |
Step 1: Identify the Certificates
# List your CA certificates
ls -la /usr/local/share/ca-certificates/
# or
ls -la /etc/ssl/certs/ | grep -i "root\|sub\|chain"
# Example output:
# CHLAROOTCA.crt ← Root CA
# CHLASUBCA.crt ← Subordinate CA (signs endpoint certs)
Step 2: Create Combined Chain Certificate
The chain file must contain ROOT CA first, then SUBORDINATE CA(s), in order:
# Create chain file (ROOT CA first, then SUB CA)
cat /usr/local/share/ca-certificates/CHLAROOTCA.crt \
/usr/local/share/ca-certificates/CHLASUBCA.crt \
> /tmp/chla-chain.pem
# Install chain file
sudo cp /tmp/chla-chain.pem /etc/ssl/certs/chla-chain.pem
sudo chmod 644 /etc/ssl/certs/chla-chain.pem
|
Certificate order in chain file:
The chain builds from root → intermediates. OpenSSL reads top-to-bottom. |
Step 3: Update NetworkManager Connection
# Update 802.1X connection to use chain cert
sudo nmcli connection modify "Wired-802.1X" \
802-1x.ca-cert /etc/ssl/certs/chla-chain.pem
# Reload and reconnect
sudo nmcli connection reload
sudo nmcli connection down "Wired-802.1X"
sudo nmcli connection up "Wired-802.1X"
Step 4: Verify
# Check connection status
nmcli connection show "Wired-802.1X" | grep -E "GENERAL.STATE|802-1x.ca-cert"
# Check journal for TLS success
journalctl -u NetworkManager --since "2 minutes ago" | grep -iE "eap|tls|handshake"
Verify Certificate Chain Manually
# Test that client cert validates against chain
openssl verify -CAfile /etc/ssl/certs/chla-chain.pem \
/etc/ssl/certs/$(hostname)-eaptls.pem
# Expected output:
# /etc/ssl/certs/chlxsbg-eaptls.pem: OK
# If it fails, the chain is incomplete or wrong order
Alternative: System Trust Store
If you don’t want to manage a separate chain file, ensure both CA certs are in the system trust store:
# Copy CA certs to system trust directory
sudo cp CHLAROOTCA.crt CHLASUBCA.crt /usr/local/share/ca-certificates/
# Update system trust store
sudo update-ca-certificates
# Use system bundle in NetworkManager
sudo nmcli connection modify "Wired-802.1X" \
802-1x.ca-cert /etc/ssl/certs/ca-certificates.crt
|
Using the full system bundle ( |
Rollback (If Migration Fails)
If NetworkManager 802.1X fails and you need to revert to wpa_supplicant:
# 1. Delete the failed NetworkManager connection
sudo nmcli connection delete "Wired-802.1X"
# 2. Re-enable wpa_supplicant
sudo systemctl enable wpa_supplicant-wired@enp0s31f6.service
sudo systemctl start wpa_supplicant-wired@enp0s31f6.service
# 3. Verify wpa_supplicant is working
sudo systemctl status wpa_supplicant-wired@enp0s31f6.service
sudo wpa_cli -i enp0s31f6 status
GUI Alternative
For GNOME/KDE users:
-
Settings → Network → Wired → ⚙️ (gear icon)
-
Security tab → Enable 802.1X
-
Authentication: TLS
-
Identity:
hostname.inside.domusdigitalis.dev -
CA Certificate: Browse to
/etc/ssl/certs/HOME-ROOT-CA.pem -
User Certificate: Browse to
/etc/ssl/certs/<hostname>-eaptls.pem -
User Private Key: Browse to
/etc/ssl/private/<hostname>-eaptls.key -
Apply
Quick Reference
# Create connection
sudo nmcli connection add type ethernet con-name "Wired-802.1X" \
ifname enp0s31f6 802-1x.eap tls \
802-1x.identity "$(hostname).inside.domusdigitalis.dev" \
802-1x.ca-cert /etc/ssl/certs/HOME-ROOT-CA.pem \
802-1x.client-cert /etc/ssl/certs/$(hostname)-eaptls.pem \
802-1x.private-key /etc/ssl/private/$(hostname)-eaptls.key
# Activate
sudo nmcli connection up "Wired-802.1X"
# Status
nmcli device status
# Logs
journalctl -u NetworkManager -f
dACL Troubleshooting
Understanding dACLs
Downloadable ACLs (dACLs) from ISE are applied as egress ACLs on the switch port. Key characteristics:
|
Verifying Applied dACL
# Check what dACL is applied to session
netapi ios exec "show access-session interface GigabitEthernet1/0/5 detail" | grep "ACS ACL"
# Output shows:
# ACS ACL: xACSACLx-IP-LINUX_RESEARCH_HARDENED_V3-697858bf
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# This is the ISE dACL name
# View the actual ACL on switch
netapi ios exec "show ip access-lists xACSACLx-IP-LINUX_RESEARCH_HARDENED_V3-697858bf"
Common dACL Issues
Issue 1: No Connectivity Despite Authentication Success
Symptoms: - 802.1X authentication succeeds - VLAN assigned correctly - Cannot ping, browse, or SSH
Cause: dACL blocking traffic
Diagnosis:
# Check ISE dACL content
netapi ise get-dacl LINUX_RESEARCH_HARDENED
# Verify it's applied to session
netapi ise mnt session c8:5b:76:c6:59:62
Issue 2: ACL Ordering Problems
WRONG (specific permits after blanket deny):
deny ip any 10.0.0.0 0.255.255.255 ← Blocks ALL 10.x
permit udp any host 10.50.1.50 eq 53 ← Never reached!
CORRECT (specific permits BEFORE blanket deny):
permit udp any host 10.50.1.50 eq 53 ← DNS works
deny ip any 10.0.0.0 0.255.255.255 ← Then block rest
Issue 3: Missing Return Traffic
WRONG (outbound only):
permit tcp any any eq 80 ← Allows TO port 80
permit tcp any any eq 443 ← Allows TO port 443
deny ip any any log ← Blocks ALL return traffic!
CORRECT (with return traffic):
permit tcp any any eq 80 ← Allows TO port 80
permit tcp any any eq 443 ← Allows TO port 443
permit tcp any gt 1023 any ← Allows return traffic to ephemeral ports
permit udp any gt 1023 any ← Allows UDP return traffic
deny ip any any log
Updating dACL in Production
Step 1: Create New Version (Don’t Delete Old)
# Create V2 with fixes
netapi ise create-dacl LINUX_RESEARCH_HARDENED_V2 \
--acl "permit icmp any any; permit udp any host 10.50.1.1 eq 53; ... " \
--descr "Fixed version - correct ordering and return traffic"
Step 2: Update Authorization Profile
# Get current profile
netapi ise get-authz-profile Linux_EAPTLS_Permit
# Update to new dACL
netapi ise update-authz-profile Linux_EAPTLS_Permit --dacl LINUX_RESEARCH_HARDENED_V2
Step 3: Apply to Active Session
Method A: CoA Reauth (preferred for production):
# Trigger re-authentication (preserves session)
netapi ise mnt coa c8:5b:76:c6:59:62 --type Reauth
Method B: Manual Reconnect (if CoA fails):
# From the client machine
sudo nmcli connection down "Wired-802.1X"
sudo nmcli connection up "Wired-802.1X"
Step 4: Verify New ACL Applied
# Check switch session (look for new hash)
netapi ios exec "show access-session interface GigabitEthernet1/0/5 detail" | grep "ACS ACL"
# Expected: xACSACLx-IP-LINUX_RESEARCH_HARDENED_V2-<new-hash>
# Test connectivity from client
ping 8.8.8.8
dig google.com
curl -I https://google.com
Example: Zero-Trust Linux Workstation dACL (WORKING)
This is the final working version (V5) after troubleshooting ACL ordering issues.
Permits: - ICMP (ping/traceroute) - DNS to internal servers (10.50.1.1, 10.50.1.50) - NTP to any - ISE API access (10.50.1.21:8443, 8905) - Internet HTTP/HTTPS/SSH (outbound connections) - SSH/HTTP/HTTPS server return traffic (inbound from source ports) - All high-port return traffic (TCP/UDP gt 1023)
Blocks: - All other RFC1918 destinations (after all permits are evaluated) - All other traffic
netapi ise create-dacl LINUX_RESEARCH_HARDENED_V5 \
--acl "permit icmp any any; \
permit udp any host 10.50.1.1 eq 53; \
permit udp any host 10.50.1.50 eq 53; \
permit udp any any eq 123; \
permit tcp any host 10.50.1.21 eq 8443; \
permit tcp any host 10.50.1.21 eq 8905; \
permit tcp any any eq 80; \
permit tcp any any eq 443; \
permit tcp any any eq 22; \
permit tcp any eq 22 any; \
permit tcp any eq 80 any; \
permit tcp any eq 443 any; \
permit tcp any gt 1023 any; \
permit udp any gt 1023 any; \
deny ip any 10.0.0.0 0.255.255.255; \
deny ip any 172.16.0.0 0.15.255.255; \
deny ip any 192.168.0.0 0.0.255.255; \
deny ip any any" \
--descr "Zero-trust Linux research - working V5"
Critical ACL ordering rules:
-
Specific permits FIRST (DNS, ISE) before RFC1918 denies
-
Return traffic permits for services (tcp any eq 22/80/443 any)
-
High-port return traffic (tcp/udp any gt 1023 any)
-
RFC1918 denies LAST (after all legitimate permits)
-
NO
logkeyword on Cisco switches (not supported in dACLs)
ACL processing flow:
1. permit icmp any any ← ICMP allowed
2. permit udp any host 10.50.1.1 eq 53 ← DNS to pfSense
3. permit udp any host 10.50.1.50 eq 53 ← DNS to DC
4. permit udp any any eq 123 ← NTP to any
5. permit tcp any host 10.50.1.21 ... ← ISE API
6. permit tcp any any eq 80/443/22 ← Outbound connections
7. permit tcp any eq 22/80/443 any ← Server return traffic
8. permit tcp any gt 1023 any ← Client return traffic
9. deny ip any 10.0.0.0 ... ← Block other RFC1918
10. deny ip any any ← Block everything else
|
Common mistake: Placing RFC1918 denies before specific permits. This breaks DNS and ISE access because the deny catches traffic before the permit is evaluated! Wrong order (V1-V3):
Correct order (V5):
|
CoA Troubleshooting
If CoA fails but profile is updated, the new dACL still applies on next session:
# CoA may fail due to:
# - Switch not configured for CoA
# - Firewall blocking RADIUS CoA (UDP 1700)
# - Wrong shared secret
# Workaround: Manual reconnect
sudo nmcli connection down "Wired-802.1X"
sudo nmcli connection up "Wired-802.1X"
# Verify new ACL applied
netapi ios exec "show access-session interface GigabitEthernet1/0/5 detail"