Day 87 – Cisco ISE Mastery Training: Automating User Creation via API

[Day 87] Cisco ISE Mastery Training: Automating User Creation via API


Table of Contents

Introduction

“Today we’ll automate Internal User lifecycle in Cisco ISE using ERS (External RESTful Services) API and validate authentications with MnT and NAD CLI. You’ll build single-user and bulk (CSV) workflows, enforce identity groups, password policy, and prove end-to-end RADIUS success in logs and on the switch.”

You will build & validate:

  • ERS enablement, least-privilege API admin, TLS trust
  • Create/Read/Update/Delete (CRUD) for Internal Users
  • Assign Identity Groups, set expiry, password change flags
  • Bulk user creation from CSV via Python
  • Validate with ISE GUI, Live Logs, MnT session queries, and switch CLI (test aaa / 802.1X)

Problem Statement

  • Helpdesks manually create hundreds of guest/contractor accounts → slow, error-prone, zero audit trail across systems.
  • SOC/IR needs rapid user disables or password resets during incidents.
  • Projects require bulk onboarding (contractors, pilots) with consistent group membership and expiry controls.
  • Engineers need repeatable APIs that integrate with ITSM/SOAR/HR.

Solution Overview

  • ERS API (HTTPS:9060) exposes /ers/config/internaluser for full CRUD.
  • Identity Groups bind users to policy outcomes; set during creation.
  • Password policy & expiry enforced at API layer (same as GUI).
  • MnT API (HTTPS:443) validates authentications/sessions.
  • Auditability: ANC/AAA/ERS actions visible in Operations and application logs.

Sample Lab Topology (VMware/EVE-NG)

Nodes:

  • ISE 3.2/3.3 (PAN+MnT+PSN; ERS enabled)
  • Catalyst 9300 (17.x) as NAD (802.1X/MAB/CoA; also used for test aaa)
  • WLC 9800-CL (optional Wi-Fi validation)
  • Windows 10/11 endpoint (wired or Wi-Fi supplicant)
  • Automation Workstation (Postman + Python 3.10+)

Pre-reqs: DNS/NTP aligned; ISE reachable; NAD configured as Network Device in ISE with shared secret; a Policy Set that allows Internal Users.


Step-by-Step GUI Configuration Guide (with CLI + API runbooks)

Format: each phase = do it → validate (GUI + CLI).

Phase 0 — Platform health (CLI quick checks)

ISE CLI

show clock
show ntp
show application status ise | include Application|Database|pxGrid
ping <NAD-IP>

Switch CLI

show clock
show authentication sessions

Phase 1 — Enable ERS & create API admin (GUI)

  1. Enable ERS
    GUI: Administration → System → Settings → ERS SettingsEnable ERS for Read/WriteSave
    [Screenshot: ISE ERS Settings – Enabled]
  1. Create ERS admin (least privilege)
    GUI: Administration → System → Admin Access → Administrators → Add
    • User: ers-user-svc
    • Roles: ERS Admin (+ MnT Read Only if you’ll call MnT with same account)
    • Optional: Restrict Allowed IPs (security)
      [Screenshot: Admin User with ERS role]
  1. Certificates (recommended)
    GUI: Administration → System → Certificates → System Certificates → bind CA-signed cert for HTTPS; import CA chain on Automation WS.
    [Screenshot: System Cert – CA signed]
  1. Developer Resources
    GUI: Administration → Developer Resources → confirm ERS doc available.
    [Screenshot: ERS API Docs]

Phase 2 — Identity Groups & Password Policy (GUI)

  1. Create Identity Groups
    GUI: Administration → Identity Management → Groups → User Identity Groups → Add
    • Contractors
    • Guests-24h
      [Screenshot: Identity Groups]
  1. Password Policy
    GUI: Administration → System → Settings → Password Policy
    • Complexity, length, reuse, expiration as per org policy.
      [Screenshot: Password Policy]

Phase 3 — Postman/cURL sanity (ERS + MnT)

Environment vars (Postman):
ISE_HOST, ERS_USER, ERS_PASS, BASE_ERS=https://{{ISE_HOST}}:9060/ers, BASE_MNT=https://{{ISE_HOST}}/admin/API/mnt
[Screenshot: Postman Environment]

ERS list version (smoke test):

curl -k -u $ERS_USER:$ERS_PASS -H "Accept: application/json" \
https://$ISE_HOST:9060/ers/config/version

Expect JSON with version.

MnT session (if any active):

curl -k -u $ERS_USER:$ERS_PASS \
"https://$ISE_HOST/admin/API/mnt/Session/ActiveList"

(Usually XML; set Accept: application/xml.)


Phase 4 — Create a single Internal User (ERS)

POST {{BASE_ERS}}/config/internaluser
Headers: Accept: application/json, Content-Type: application/json
Body (JSON):

{
  "InternalUser": {
    "name": "contractor01",
    "password": "C1sco!234",
    "enabled": true,
    "changePassword": false,
    "email": "contractor01@lab.local",
    "firstName": "Cont",
    "lastName": "Ractor",
    "identityGroups": "Contractors",
    "description": "Created by ERS API Day87",
    "expiryDate": "2025-12-31"
  }
}


Expected: HTTP 201 Created with Location header containing object ID.

Validate (GUI):
Administration → Identity Management → Identities → Users → search contractor01
[Screenshot: User present with Contractors group]


Phase 5 — Read / Search / Update / Delete

A) GET user by name
GET {{BASE_ERS}}/config/internaluser/name/contractor01
Expect JSON with user object (contains id).

B) UPDATE (PUT) – force password change at next login
PUT {{BASE_ERS}}/config/internaluser/{id}
Body (JSON):

{
  "InternalUser": {
    "name": "contractor01",
    "enabled": true,
    "changePassword": true,
    "identityGroups": "Contractors",
    "description": "Force PW change on next login"
  }
}

Expected: 200/204 success.

C) DELETE user (cleanup)
DELETE {{BASE_ERS}}/config/internaluser/{id}
Expected: 204 No Content.

[Screenshots: GET result / PUT success / DELETE success]


Phase 6 — Bulk creation (CSV → Python)

CSV example (users.csv):

name,password,email,firstName,lastName,identityGroup,expiryDate
contractor02,C1sco!234,contractor02@lab.local,Cont,Two,Contractors,2025-12-31
guest001,C1sco!234,guest001@lab.local,Guest,One,Guests-24h,2024-12-31

Python script (minimal, idempotent create/update):

import csv, requests, sys
BASE="https://ise.lab.local:9060/ers"
AUTH=("ers-user-svc","<password>")
H={"Accept":"application/json","Content-Type":"application/json"}
VERIFY=False  # set CA bundle in prod

def get_user_by_name(name):
    r=requests.get(f"{BASE}/config/internaluser/name/{name}",auth=AUTH,headers=H,verify=VERIFY)
    return r.json() if r.status_code==200 else None

def create_user(row):
    body={"InternalUser":{
        "name":row["name"],"password":row["password"],"enabled":True,
        "changePassword":False,"email":row["email"],
        "firstName":row["firstName"],"lastName":row["lastName"],
        "identityGroups":row["identityGroup"],"expiryDate":row["expiryDate"]
    }}
    r=requests.post(f"{BASE}/config/internaluser",json=body,auth=AUTH,headers=H,verify=VERIFY)
    if r.status_code not in (201,202):
        print("Create failed:", r.status_code, r.text)

def update_user(id, row):
    body={"InternalUser":{
        "name":row["name"],"enabled":True,"changePassword":False,
        "email":row["email"],"firstName":row["firstName"],"lastName":row["lastName"],
        "identityGroups":row["identityGroup"],"expiryDate":row["expiryDate"]
    }}
    r=requests.put(f"{BASE}/config/internaluser/{id}",json=body,auth=AUTH,headers=H,verify=VERIFY)
    if r.status_code not in (200,204):
        print("Update failed:", r.status_code, r.text)

with open("users.csv") as f:
    for row in csv.DictReader(f):
        obj=get_user_by_name(row["name"])
        if obj:
            update_user(obj["InternalUser"]["id"], row)
            print("Updated:", row["name"])
        else:
            create_user(row)
            print("Created:", row["name"])

Validate (GUI): Users appear with correct groups & expiry.
[Screenshot: Bulk users present]


Phase 7 — Policy & Authentication validation

A) Policy Set (ensure path for Internal Users)
GUI: Policy → Policy Sets

  • Allowed Protocols for this Policy Set include PAP/ASCII + MSCHAPv2 (for test aaa flexibility).
  • AuthC: Internal Users
  • AuthZ: simple “PermitAccess” or your lab profile.
    [Screenshot: Policy Set with Internal Users rule]

B) Validate via Switch CLI (RADIUS test aaa)
(uses PAP/CHAP; ensure Allowed Protocols permit PAP in the Policy Set used by the NAD)

conf t
aaa new-model
radius server ISE1
 address ipv4 <ISE-IP> auth-port 1812 acct-port 1813
 key ISEsecret123
aaa group server radius ISE-GRP
 server name ISE1
aaa authentication login TEST group ISE-GRP local
end

test aaa group radius ISE-GRP contractor01 C1sco!234 legacy
! expect "User was successfully authenticated"

C) Validate on ISE (GUI)

  • Operations → RADIUS → Live Logs → entry shows contractor01 Passed
  • Drill into details → Authentication Policy matched + Authorization Profile
    [Screenshot: Live Logs success]

D) Validate via MnT API

curl -k -u $ERS_USER:$ERS_PASS \
"https://$ISE_HOST/admin/API/mnt/Session/UserName/contractor01"

Expect XML with session attributes (IP/MAC/AuthZ result).


Phase 8 — Break & Fix drills (common errors)

  1. HTTP 401 Unauthorized → wrong creds / ERS role missing / ERS disabled.
  2. HTTP 409 Conflict on create → username exists → use PUT to update.
  3. HTTP 400 Bad Request → password violates policy or bad expiryDate format.
  4. User created but test aaa fails → Policy Set not matching the NAD / Allowed Protocols exclude PAP.
  5. Live Logs empty → request never hit ISE (NAD shared secret or IP not in Network Devices).

Phase 9 — Audit & Logs

ISE GUI:

  • Operations → Reports → RADIUS Authentications
  • Operations → Audit → Administrator Logins / Change Logs (ERS changes appear)

ISE CLI quick watchers:

show logging application ise-psc.log | include (Auth|User|InternalUser|Policy)
show logging application catalina.out | include ERS

Troubleshooting (User Creation via ERS API):

0) Rapid Triage Playbook (read top-to-bottom)

  1. API Up?
    • curl -k -u ers:pass https://ISE:9060/ers/config/version -H "Accept: application/json"
    • 200 = OK → go next; 401/403/5xx → see §1.
  2. AuthZ path OK? (for validation with test aaa)
    • GUI: Policy Sets → confirm NAD matches → Allowed Protocols include method you’ll test (PAP for test aaa, EAP for 802.1X).
  3. Create 1 user (golden payload)
    • POST /ers/config/internaluser with minimal body from §3.
    • 201 + Location header → verify in GUI; see §2–§4.
  4. Validate login
    • test aaa group radius ISE-GRP <user> <pw> legacy (switch CLI).
    • success in switch + ISE Live Logs; see §5.
  5. Bulk?
    • Run Python CSV importer (§7).
    • If failures: examine HTTP code → jump to matching section.

1) Connectivity, Auth, and Service State

A) ERS disabled or wrong port

Symptom: curl: (7) Failed to connect or HTTP 404 at port 9060.
Fix: GUI → Administration → System → Settings → ERS SettingsEnable ERS for Read/Write → Save.
CLI check:

show application status ise | include (Application|pxGrid|Database|M&T|API)
# Expect ERS/Tomcat components running

B) 401 Unauthorized / 403 Forbidden

Causes: Bad creds, wrong role, IP-restricted account.
Fixes:

  • GUI → Admin Access → Administrators → user = ERS Admin role.
  • Remove/adjust Allowed IPs restriction for this admin.
  • Verify Basic Auth in Postman (no extra spaces).
    Re-test:
curl -k -u ers-user-svc:'<password>' https://ISE:9060/ers/config/version -H "Accept: application/json"

C) TLS / Certificates

Symptom: Postman SSL error or Python SSLError.
Fix:

  • Lab: allow insecure (-k in curl, “Disable SSL verification” in Postman, verify=False in Python).
  • Prod: install CA-signed server cert on ISE; trust CA on client.

2) Payload & Schema Errors

A) 400 Bad Request

Common reasons:

  • Wrong JSON shape (missing InternalUser wrapper).
  • Field typo (identityGroup vs identityGroups).
  • Password violates policy.
  • Date format wrong.

Golden minimal POST body (known-good):

{
  "InternalUser": {
    "name": "contractor01",
    "password": "C1sco!234",
    "enabled": true,
    "identityGroups": "User Identity Group"
  }
}

Fix sequence:

  1. Switch to JSON headers:
Accept: application/json
Content-Type: application/json
  1. Remove optional fields; add back one by one.
  2. If still 400, check ISE Password Policy (GUI) and date format YYYY-MM-DD.

B) 415 Unsupported Media Type

Cause: Missing/incorrect Content-Type.
Fix: Set Content-Type: application/json.

C) 422 Unprocessable Entity

Cause: Field valid syntactically but invalid logically (e.g., group path doesn’t exist).
Fix: Confirm group name exactly as shown in GUI (case-sensitive). Use GET to enumerate groups:

GET /ers/config/identitygroup

3) Object Conflicts & Idempotency

A) 409 Conflict (user exists)

When: duplicate name.
Fix:

  • GET by name to retrieve id:
    GET /ers/config/internaluser/name/<username>
  • Then PUT to update:
    PUT /ers/config/internaluser/{id}

B) Idempotent create-or-update pattern (Python)

obj = get_user_by_name("contractor01")
if obj:
    put_update(obj["InternalUser"]["id"], payload)
else:
    post_create(payload)

4) Paging & Bulk Operations

A) Large result sets return paged

Symptom: only first page visible.
Fix: follow nextPage link or HTTP Link header until none remains.

B) 429 Too Many Requests / perceived slowness

Best practices:

  • Throttle to ~10 req/s per ISE node.
  • Use session reuse in Python (requests.Session()); keep-alive.
  • Stagger bulk imports (e.g., 100 users/batch with 0.2s delay).

5) Authentication Validation Failures (RADIUS)

A) test aaa fails but user created

Checklist:

  • NAD registered in ISE (Network Devices) with correct shared secret & correct NAD IP/subnet.
  • Policy Set selected by NAD conditions.
  • Allowed Protocols include PAP if using test aaa legacy.
  • AuthC rule: includes Internal Users as identity source.

Switch CLI quick config (lab):

radius server ISE1
 address ipv4 <ISE-IP> auth-port 1812 acct-port 1813
 key ISEsecret123
aaa group server radius ISE-GRP
 server name ISE1
aaa authentication login TEST group ISE-GRP local
test aaa group radius ISE-GRP contractor01 C1sco!234 legacy

ISE GUI validation:

  • Operations → RADIUS → Live Logs:
    • Passed vs Failed reason (e.g., “User not found”, “Password policy”).
    • Click details → Policy Set & AuthC rule hit.

B) 802.1X endpoint fails but test aaa passes

  • 802.1X uses EAP (PEAP/EAP-MSCHAPv2). Ensure Allowed Protocols include EAP methods.
  • Supplicant config on endpoint correct? Username/password?
  • Realtime check: Operations → Live Sessions; WLC/switch show authentication sessions interface ….

6) Expiry, Disable, and Password Policy

A) Expiry date format

  • Use YYYY-MM-DD.
  • If error persists, omit expiryDate to confirm creation then set via PUT.

B) Force password change next login

  • PUT /internaluser/{id} with "changePassword": true
  • Validate in GUI user properties; Live Logs will show change prompt flow for web portals.

C) Disable vs Delete

  • Disable = "enabled": false (audit-friendly, reversible).
  • Delete = DELETE /internaluser/{id} (irreversible).

7) Bulk CSV Import – Failure Patterns & Fixes

CSV sample (good):

name,password,email,firstName,lastName,identityGroups,expiryDate
contractor02,C1sco!234,contractor02@lab.local,Cont,Two,User Identity Group,2025-12-31
guest001,C1sco!234,guest001@lab.local,Guest,One,User Identity Group,2024-12-31

Common breakages:

  • Header mismatch (identityGroup vs identityGroups).
  • Hidden spaces/UTF-8 BOM → strip/normalize.
  • Password violates policy → 400; log it and continue next rows.

Python resilience tips:

  • try/except per row; collect failures to a CSV errors.csv.
  • Validate group existence once (cache group names).
  • Sleep(0.2) between requests, or batch 50–100.

8) Postman Troubleshooting

  • Auth tab: Basic Auth (username/password).
  • Headers:
    • Accept: application/json (ERS), application/xml (MnT typical).
    • Content-Type: application/json on POST/PUT.
  • SSL: Settings → disable verification in lab.
  • Tests (quick guardrail):
pm.test("201 Created", function () {
  pm.response.to.have.status(201);
});
  • Variables: Keep BASE_ERS, BASE_MNT, ERS_USER, ERS_PASS in Environment.

9) Sample Error/Success Payloads (recognize them fast)

A) 201 Created (Location header)

HTTP/1.1 201 Created
Location: https://ISE:9060/ers/config/internaluser/1a2b3c4d-...

B) 400 Bad Request (password policy)

{
  "ERSResponse": {
    "operation": "POST-create-internaluser",
    "messages": [{
      "title": "Invalid password: does not meet policy",
      "type": "ERROR",
      "code": "password-policy-violation"
    }]
  }
}

C) 409 Conflict (duplicate user)

{
  "ERSResponse": {
    "messages": [{
      "title": "Duplicate resource",
      "type": "ERROR",
      "code": "duplicate"
    }]
  }
}

D) 422 Invalid group

{
  "ERSResponse": {
    "messages": [{
      "title": "Identity group not found: 'Contractors'",
      "type": "ERROR",
      "code": "invalid-reference"
    }]
  }
}

10) Logs & Where to Look (GUI + CLI)

GUI:

  • Operations → Audit (who/what via ERS).
  • Operations → RADIUS → Live Logs (auth success/fail reason).
  • Operations → Reports → Authentication Summary.

CLI (typical quick grep):

show logging application ise-psc.log | include (InternalUser|ERS|Auth|Policy)
show logging application catalina.out | include ERS
# If needed:
# application stop ise ; application start ise   (last resort in lab)

11) Security & Governance (prod readiness)

  • Least-privilege ERS account; IP-restrict admin user.
  • CA-signed certs; enforce TLS verification in Postman/Python.
  • Secrets mgmt (Vault/Azure Key Vault); avoid plain CSV passwords at rest.
  • SIEM: ship Audit & RADIUS logs for immutable evidence.
  • Change control: scripts include ticket/reference IDs in comments/log lines.

12) Ready-to-Use “Golden” Requests

Create user (JSON)

POST https://ISE:9060/ers/config/internaluser
Headers: Accept: application/json, Content-Type: application/json
Body:
{
  "InternalUser": {
    "name": "contractor01",
    "password": "C1sco!234",
    "enabled": true,
    "identityGroups": "User Identity Group",
    "description": "ERS Day87"
  }
}

Get user by name

GET https://ISE:9060/ers/config/internaluser/name/contractor01
Accept: application/json

Update (force password change)

PUT https://ISE:9060/ers/config/internaluser/{id}
{
  "InternalUser": {
    "name": "contractor01",
    "enabled": true,
    "changePassword": true,
    "identityGroups": "User Identity Group"
  }
}

Disable user

PUT https://ISE:9060/ers/config/internaluser/{id}
{
  "InternalUser": { "name": "contractor01", "enabled": false }
}

Delete user

DELETE https://ISE:9060/ers/config/internaluser/{id}

13) Decision Trees (textual)

Create fails → which code?

  • 401/403 → creds/role/IP restrict/ERS off.
  • 415 → Content-Type.
  • 400 → schema/password/date.
  • 409 → user exists → GET id → PUT.
  • 422 → fix group path/name.
  • 5xx → ISE load/services; restart app in lab; check disk/CPU.

Auth fails in test aaa

  • No Live Log → NAD secret/IP mismatch.
  • Live Log “User not found” → wrong policy set or wrong ID store.
  • Live Log “Authentication failed” → password typo/policy/disabled.

14) Bulk-Run Guardrails (Python)

  • Use requests.Session(); set timeouts (timeout=10).
  • Add retry (backoff 0.5/1/2 up to 5).
  • Log CSV row + HTTP code + message to errors.csv.
  • Commit in chunks; print success counts.

15) Clean-Up Checklist

  • DELETE lab users you created.
  • Re-enable SSL verification in tools.
  • Rotate ERS admin password post-lab.
  • Export Audit report for your lab journal.

FAQs – ISE ERS API (User Creation)

1. What is the Cisco ISE ERS API and why do we use it instead of the GUI?

The External RESTful Services (ERS) API in Cisco ISE is a programmable interface that allows automation of tasks (like creating, updating, or deleting internal users). While the GUI is manual and time-consuming, the ERS API lets engineers integrate user creation with HR systems, scripts, or bulk automation tools—reducing errors and speeding up provisioning.


2. How do I enable ERS API access in Cisco ISE?

ERS API is disabled by default.
Steps:

  1. GUI → Administration → System → Settings → ERS Settings → enable ERS for Read/Write.
  2. Ensure you use an account with the ERS Admin role.
  3. Access via https://<ISE-FQDN>:9060/ers/....
    Without enabling this, you’ll see 401 Unauthorized or 404 Not Found when calling endpoints.

3. What’s the minimum JSON payload required to create a user?

At minimum, you need:

{
  "InternalUser": {
    "name": "contractor01",
    "password": "C1sco!234",
    "enabled": true,
    "identityGroups": "User Identity Group"
  }
}

If you omit required fields or misname them, ISE will respond with 400 Bad Request.


4. How do I troubleshoot 400 Bad Request errors during user creation?

Check for:

  • Missing InternalUser wrapper.
  • Wrong header (Content-Type: application/json).
  • Password doesn’t meet ISE’s password policy.
  • identityGroups doesn’t match exactly (case-sensitive).
    Pro tip: Always test with a golden minimal payload, then expand.

5. Can I bulk import users via ERS API?

Yes. A script (Python/Postman runner) can read a CSV file and loop API calls. Example CSV:

name,password,identityGroups
contractor02,C1sco!234,User Identity Group
contractor03,C1sco!234,User Identity Group

Bulk automation reduces errors, but throttle requests (e.g., 100 users/batch with slight delay) to avoid API overload.


6. How do I verify if a user was created successfully?

  • REST API check:
    GET /ers/config/internaluser/name/<username>
  • GUI check: Navigate to Administration → Identity Management → Identities.
  • RADIUS test: On switch/WLC:
    test aaa group radius ISE-GRP contractor01 C1sco!234 legacy
    ISE’s Live Logs will confirm authentication attempts.

7. How do I handle duplicate users (409 Conflict error)?

  • Error occurs if name already exists.
  • Solution:
    • GET /ers/config/internaluser/name/<username> → fetch user’s ID.
    • PUT /ers/config/internaluser/{id} → update user details instead of creating a duplicate.
      This makes your script idempotent (safe to re-run without breaking).

8. Can I set expiry dates or force password changes via API?

Yes.

  • Expiry date must be YYYY-MM-DD.
  • Example:
{
  "InternalUser": {
    "name": "guest01",
    "password": "C1sco!234",
    "enabled": true,
    "identityGroups": "Guest Identity Group",
    "expiryDate": "2025-12-31",
    "changePassword": true
  }
}

If the format is wrong, you’ll see 400 Bad Request.


9. How do I troubleshoot when users are created but can’t authenticate?

Checklist:

  • NAD registered in ISE with correct IP and RADIUS shared secret.
  • Correct Policy Set selected.
  • Allowed Protocols include PAP for test aaa or EAP methods for 802.1X.
  • Authentication rule includes Internal Users as identity source.
    Check Operations → RADIUS → Live Logs for the exact reason.

10. What are best practices for securing ERS API automation in production?

  • Use a least-privilege ERS account, restricted by IP.
  • Deploy CA-signed certificates (disable -k insecure mode).
  • Never hardcode passwords in scripts—use secrets vaults.
  • Log all API actions to SIEM for audit trails.
  • Test in lab first before running in production.

YouTube Link

For more in-depth Cisco ISE Mastery Training, subscribe to my YouTube channel Network Journey and join my instructor-led classes for hands-on, real-world ISE experience

[NEW COURSE ALERT] CISCO ISE (Identity Service Engine) by Sagar Dhawan
CCIE Security v6.1 Training – Ticket#1 Discussed
CCIE Security v6.1 – MAC Authentication Bypass (MAB) in Cisco ISE
CCNP to CCIE SECURITY v6.1 – New Online Batch

Closing Notes

  • Treat Internal User lifecycle as code: create/update/disable with guarantees and logs.
  • Always validate twice: ISE Live Logs and NAD CLI (test aaa / 802.1X session).
  • Productionize with CA certs, least-privilege ERS admin, IP-restricted access, and SIEM shipping of audit logs.

Upgrade Your Skills – Start Today

“For more in-depth Cisco ISE Mastery Training, subscribe to my YouTube channel Network Journey and join my instructor-led classes.

Fast-Track to Cisco ISE Mastery Pro — 4-month live cohort:

Enroll Now & Future‑Proof Your Career
Emailinfo@networkjourney.com
WhatsApp / Call: +91 97395 21088