Command Reference

Environment Variables

# ISE API credentials
export ISE_PAN_IP=10.50.1.20
export ISE_API_TOKEN=<base64-encoded-credentials>
export ISE_MNT_TOKEN=<base64-encoded-credentials>

# Switch credentials (via dsec)
eval "$(dsec source d000 dev/network)"

Certificate Paths

File Path Permissions

Private Key

/etc/ssl/private/workstation01.key

600 root:root

Certificate

/etc/ssl/certs/workstation01.pem

644 root:root

CA Certificate

/etc/ssl/certs/DOMUS-ROOT-CA.pem

644 root:root

wpa_supplicant config

/etc/wpa_supplicant/wpa_supplicant-wired.conf

600 root:root

Systemd Services

# wpa_supplicant
sudo systemctl enable wpa_supplicant-wired@enp0s31f6
sudo systemctl start wpa_supplicant-wired@enp0s31f6
sudo systemctl status wpa_supplicant-wired@enp0s31f6

# ClamAV
sudo systemctl enable clamav-daemon
sudo systemctl start clamav-daemon
sudo systemctl status clamav-daemon

# UFW
sudo ufw enable
sudo ufw status

netapi ISE Commands

The netapi ise CLI automates ISE configuration and monitoring.

Network Access Conditions

# List all conditions
netapi ise get-conditions

# List posture conditions (Session dictionary)
netapi ise get-conditions --dict Session

# Get specific condition
netapi ise get-condition "Compliant_Devices"

# Create posture condition
netapi ise create-posture-condition "My_Compliant_Check" \
    --attr PostureStatus --value Compliant

# Create generic condition (any dictionary)
netapi ise create-condition "My_Condition" \
    --dict "Session" --attr "PostureStatus" --value "Compliant"

# Delete condition
netapi ise delete-condition "My_Condition"
netapi ise delete-condition "My_Condition" --force

Dictionary Discovery

# List all ISE dictionaries
netapi ise get-dictionaries

# Get dictionary details (shows available attributes)
netapi ise get-dictionary Session
netapi ise get-dictionary RADIUS

ISE Session Verification

Always use netapi with properly sourced credentials. Never expose secrets in command history.

# Source credentials (proper way)
source <(DSEC_SECURITY_MODE=permissive ~/.secrets/bin/dsec source d000 dev/network)

Basic Session Information

# Get active sessions
netapi ise mnt sessions

# Get session by MAC address
netapi ise mnt session 98:bb:1e:1f:a7:13

# Get session by IP address
netapi ise mnt session-ip 10.50.10.100

# Get session by username
netapi ise mnt session-user modestus-razer$

# Get active session count
netapi ise mnt count

Detailed Authorization Context

# Get comprehensive session view (includes auth rule, profile, DACL)
netapi ise dc session 98:bb:1e:1f:a7:13

# Get authentication history timeline
netapi ise dc auth-history 98:bb:1e:1f:a7:13

# Get recent authentication attempts
netapi ise dc recent --limit 10

# Get failed authentication attempts
netapi ise dc failed --limit 10

Authorization Profile Management

# List all authorization profiles
netapi ise get-authz-profiles

# Get specific authorization profile details
netapi ise get-authz-profile Linux_EAPTLS_Admins

# Update VLAN assignment (use VLAN name, NOT number)
netapi ise update-authz-profile Linux_EAPTLS_Admins --vlan DATA_VLAN

# Update DACL assignment
netapi ise update-authz-profile Linux_EAPTLS_Admins --dacl LINUX_EAPTLS_PERMIT_ALL

# Update both VLAN and DACL
netapi ise update-authz-profile Linux_EAPTLS_Admins \
  --vlan DATA_VLAN \
  --dacl LINUX_EAPTLS_PERMIT_ALL

# Remove DACL from profile
netapi ise update-authz-profile Linux_EAPTLS_Admins --no-dacl

CRITICAL: Always use switch VLAN names (e.g., DATA_VLAN), NOT numeric IDs (e.g., 10 or VLAN0010).

Using numeric VLAN IDs will cause authorization to fail silently - the switch won’t apply the VLAN even though ISE shows success.

Correct vs Incorrect
# ✓ CORRECT - Use VLAN name
netapi ise update-authz-profile MyProfile --vlan DATA_VLAN

# ✗ WRONG - Numeric ID will fail silently
netapi ise update-authz-profile MyProfile --vlan 10
netapi ise update-authz-profile MyProfile --vlan VLAN0010

DACL Management

# List all DACLs
netapi ise get-dacls

# Get specific DACL content
netapi ise get-dacl LINUX_EAPTLS_PERMIT_ALL

# Create new DACL
netapi ise create-dacl LINUX_EAPTLS_PERMIT_ALL \
  --acl "permit ip any any" \
  --descr "Full network access for Linux Admin workstations"

# Delete DACL
netapi ise delete-dacl OLD_DACL_NAME

Change of Authorization (CoA)

# Send CoA reauthentication
netapi ise mnt coa-reauth 98:bb:1e:1f:a7:13

# Apply ANC policy (quarantine)
netapi ise anc-apply 98:bb:1e:1f:a7:13 Quarantine

# Clear ANC policy
netapi ise anc-clear 98:bb:1e:1f:a7:13

Output Formats

All commands support --format / -f option:

netapi ise get-conditions -f table  # Default
netapi ise get-conditions -f json   # JSON for scripting
netapi ise get-conditions -f yaml   # YAML output

Advanced Command Patterns

Senior engineer-level awk, sed, and pipeline patterns for diagnostics and configuration.

File Inspection with awk

# Show specific line range
awk 'NR>=10 && NR<=20' /etc/sssd/sssd.conf

# Show line with line number
awk 'NR==73 {print NR": "$0}' /etc/ssh/sshd_config

# Find pattern and show line number
awk '/GSSAPIAuthentication/{print NR": "$0}' /etc/ssh/sshd_config

# Find pattern and show N lines of context after
awk '/pattern/{found=NR} found && NR<=found+5' filename

SSH Config Block Inspection

# Show Host block from match until next Host or empty line (range pattern)
awk '/^Host.*modestus-aw/,/^Host [^*]|^$/' ~/.ssh/config

# Find Host entry and show N lines after (context capture)
awk '/modestus-aw/{found=NR} found && NR<=found+5' ~/.ssh/config

# Find IP pattern and print with line numbers
awk '/10\.50\.40/{print NR": "$0}' ~/.ssh/config

# Find all Host entries with their line numbers
awk '/^Host /{print NR": "$0}' ~/.ssh/config

# Show specific Host block
awk '/^Host modestus-aw$/,/^Host [^*]/' ~/.ssh/config | head -10

SSH Config Block Editing (Range-Scoped sed)

The Force: Edit ONLY within a specific Host block, not globally. This prevents accidentally modifying other hosts with similar patterns.

# Update HostName ONLY within modestus-aw block
sed -i '/^Host modestus-aw$/,/^Host /s/HostName .*/HostName 10.50.10.130/' ~/.ssh/config
Table 1. Anatomy of the Command
Component Purpose

/^Host modestus-aw$/

Start of range - exact match for Host line

,

Range separator

/^Host /

End of range - next Host line (any host)

s/HostName .*/HostName 10.50.10.130/

Substitution applied ONLY within range

Why range-scoped? Without the range, s/HostName .*/…​ would change EVERY HostName in the file. The range /start/,/end/ constrains the substitution to only lines between those patterns.

Verification workflow
# 1. Find line number first
awk '/modestus-aw/{found=1} found && /HostName/{print NR": "$0; exit}' ~/.ssh/config

# 2. Apply range-scoped edit
sed -i '/^Host modestus-aw$/,/^Host /s/HostName .*/HostName 10.50.10.130/' ~/.ssh/config

# 3. Verify change
awk '/modestus-aw/{found=NR} found && NR<=found+2' ~/.ssh/config
Other range-scoped examples
# Update User within a block
sed -i '/^Host modestus-aw$/,/^Host /s/User .*/User newuser/' ~/.ssh/config

# Add IdentityFile after HostName within a block
sed -i '/^Host modestus-aw$/,/^Host /{/HostName/a\    IdentityFile ~/.ssh/id_ed25519_new
}' ~/.ssh/config

# Delete a line within a block
sed -i '/^Host modestus-aw$/,/^Host /{/ProxyJump/d}' ~/.ssh/config

Network Diagnostics

# IP addresses (clean output)
ip -4 -o addr show | awk '{print $2, $4}' | grep -v "^lo"

# Filter to physical interfaces only
ip -4 -o addr show | awk '{print $2, $4}' | grep -E "^(enp|eth|wlan)"

# Listening ports (clean)
ss -tlnp | awk '{print $4}' | sort -u

# TCP connections with state
ss -tnp | awk 'NR>1 {print $1, $4, $5}' | column -t

# Port connectivity test (no nc required) - Kerberos to DC
timeout 3 bash -c "</dev/tcp/10.50.1.50/88" && echo "OK" || echo "BLOCKED"

Configuration Editing with sed

# Verify line before change
sed -n '73p' /etc/ssh/sshd_config

# In-place edit specific line
sed -i '73s/#GSSAPIAuthentication no/GSSAPIAuthentication yes/' /etc/ssh/sshd_config

# Insert after specific line
sed -i '47a\
    GSSAPIAuthentication yes\
    GSSAPIDelegateCredentials yes' ~/.ssh/config

# Uncomment a line
sed -i 's/^#\(GSSAPIAuthentication\)/\1/' /etc/ssh/sshd_config

# Comment a line
sed -i 's/^\(PasswordAuthentication\)/#\1/' /etc/ssh/sshd_config

# Replace in specific line range only
sed -i '10,20s/old/new/g' /etc/sssd/sssd.conf

NSSwitch Configuration

# View passwd/group/shadow lines
awk 'NR>=4 && NR<=6' /etc/nsswitch.conf

# Add sss to passwd line
sed -i '4s/passwd: files systemd/passwd: files sss systemd/' /etc/nsswitch.conf

# Add sss to all auth lines (lines 4-6)
sed -i '4s/passwd: files/passwd: files sss/' /etc/nsswitch.conf
sed -i '5s/group: files/group: files sss/' /etc/nsswitch.conf
sed -i '6s/shadow: files/shadow: files sss/' /etc/nsswitch.conf

Service Verification

# sshd effective config
sudo sshd -T | grep -E "gssapi|pubkey|password"

# SSSD domain status
sudo sssctl domain-status inside.domusdigitalis.dev

# Kerberos ticket status
klist | awk '/Default principal|Expires/{print}'

# Check if service offers GSSAPI
ssh -v user@host 2>&1 | awk '/Authentications that can continue/{print}'

Hexdump for Config File Debugging

# Detect hidden characters (BOM, CRLF)
hexdump -C /etc/sssd/sssd.conf | head -5

# Remove UTF-8 BOM
sed -i '1s/^\xEF\xBB\xBF//' /etc/sssd/sssd.conf

# Convert CRLF to LF
sed -i 's/\r$//' /etc/sssd/sssd.conf
Table 2. Common Hex Values
Hex Character Notes

0a

LF

Unix newline - correct

0d 0a

CRLF

Windows newline - convert

ef bb bf

UTF-8 BOM

Remove from configs

ISE Profile/dACL Discovery Loops

# Find which profile uses a specific dACL
for p in Linux_EAPTLS_Admins Linux_EAPTLS_Permit Linux_Posture_Compliant; do
  dacl=$(netapi ise get-authz-profile "$p" 2>/dev/null | awk '/daclName/{print $NF}')
  echo "$p -> ${dacl:-NONE}"
done
# Search ALL profiles for a specific dACL pattern
PROFILES="Linux_EAPTLS_Admins Linux_EAPTLS_Permit Linux_Posture_Compliant \
  Linux_Posture_NonCompliant Linux_Posture_Unknown Domus_Research_Profile \
  Research_Onboard Domus_Secure_Profile Domus_Admin_Profile"

for p in $PROFILES; do
  dacl=$(netapi ise get-authz-profile "$p" 2>/dev/null | awk '/daclName/{print $NF}')
  [[ "$dacl" == *"ZERO_TRUST"* ]] && echo "FOUND: $p -> $dacl"
done

dACL Update Workflow (When In Use)

dACLs cannot be deleted while referenced by an authorization profile. Use the detach-delete-recreate-reattach pattern.

# 1. Find profile using the dACL
for p in Linux_EAPTLS_Admins Linux_EAPTLS_Permit Linux_Posture_Compliant; do
  dacl=$(netapi ise get-authz-profile "$p" 2>/dev/null | awk '/daclName/{print $NF}')
  [[ "$dacl" == "TARGET_DACL_NAME" ]] && echo "FOUND: $p"
done

# 2. Detach dACL from profile
netapi ise update-authz-profile "<profile-name>" --dacl ""

# 3. Delete old dACL
netapi ise delete-dacl "<dacl-name>" --force

# 4. Create updated dACL
netapi ise create-dacl "<dacl-name>" --file /tmp/dacl-updated.txt --descr "Description"

# 5. Reattach dACL to profile
netapi ise update-authz-profile "<profile-name>" --dacl "<dacl-name>"

# 6. Apply via CoA
netapi ise mnt coa "<mac-address>"

Quick Reference

Task Command

View line N

awk 'NR==N' file

View lines X-Y

awk 'NR>=X && NR⇐Y' file

Find with line number

awk '/pattern/{print NR": "$0}' file

Edit line N

sed -i 'Ns/old/new/' file

Insert after line N

sed -i 'Na\newtext' file

IP addresses

ip -4 -o addr show | awk '{print $2, $4}'

Listening ports

ss -tlnp | awk '{print $4}' | sort -u

Port test (no nc)

timeout 3 bash -c "</dev/tcp/IP/PORT"

Profile dACL check

netapi ise get-authz-profile "name" | awk '/daclName/{print $NF}'

Detach dACL

netapi ise update-authz-profile "name" --dacl ""

Verification Checklist

  • Certificate valid and not expired

  • Private key password correct in config

  • CA certificate imported to ISE

  • Authentication policy configured

  • Authorization profiles created

  • ClamAV running with recent definitions

  • UFW enabled with default deny