INC-2026-02-14-001: ISE SAML SSO Restoration
Incident Summary
Incident ID |
INC-2026-02-14-001 |
Severity |
Medium (Admin access impacted) |
Detection |
2026-02-14 ~18:00 |
Resolution |
2026-02-14 ~19:30 |
Duration |
~90 minutes |
Status |
Resolved |
Executive Summary
Successfully restored ISE Admin Portal SAML SSO authentication with Keycloak IdP after restoring ise-02 backup to ise-01. All configuration changes performed via Keycloak REST API - no GUI interaction required.
Timeline
| Time | Event |
|---|---|
~16:00 |
Restored ise-02 backup to ise-01 (ISE 3.4 → ISE 3.4) |
~17:30 |
Attempted SAML login - redirect loop detected |
~18:00 |
Identified root cause: Keycloak SAML client redirect URIs point to |
~18:15 |
Downloaded ISE SP metadata (keycloak_01.zip) |
~18:30 |
Extracted Entity ID: |
~18:45 |
Verified Keycloak client exists with matching Entity ID |
~19:00 |
Updated Keycloak client via REST API (ise-02 → ise-01) |
~19:15 |
Tested SAML login - SUCCESS |
~19:30 |
Documented resolution |
Impact
-
ISE Admin Portal SAML SSO unavailable for ~90 minutes
-
Local admin account (
admin) remained available as fallback -
No impact to RADIUS/802.1X authentication
-
No impact to pxGrid, ERS, or OpenAPI services
Root Cause
When restoring an ISE backup to a different hostname:
-
ISE SAML Service Provider (SP) configuration remains intact
-
ISE Entity ID is per-deployment (UUID-based), not hostname-based
-
Keycloak SAML client had redirect URIs hardcoded to
ise-02 -
SAML assertion destination URL mismatched new hostname
Entity ID Structure
ISE generates a unique Entity ID per deployment:
http://CiscoISE/{deployment-uuid}
This Entity ID survived the backup/restore because it’s stored in the ISE database.
Resolution
Approach: Keycloak REST API
Used Keycloak Admin REST API for: * Reproducibility - commands can be scripted * Documentation - exact steps captured * Skill building - API-first approach for automation
CLI Mastery: Keycloak REST API
Step 1: Retrieve Admin Token
KC_ADMIN_PASS="<password-from-dsec>"
KC_TOKEN=$(curl -s -X POST \
"https://keycloak-01.inside.domusdigitalis.dev:8443/realms/master/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin" \
-d "password=$KC_ADMIN_PASS" \
-d "grant_type=password" \
-d "client_id=admin-cli" \
--insecure | jq -r '.access_token')
Step 2: List SAML Clients
curl -s "https://keycloak-01.inside.domusdigitalis.dev:8443/admin/realms/domusdigitalis/clients" \
-H "Authorization: Bearer $KC_TOKEN" \
--insecure | jq '.[] | select(.protocol=="saml") | {id, clientId, name}'
Output:
{
"id": "0d7b3b6b-d32f-49a0-9563-6cc8e645b59c",
"clientId": "http://CiscoISE/a486c6ef-6c77-4bc1-bf6d-4e479b3aeae8",
"name": "Cisco ISE Admin Portal (ise-02)"
}
Step 3: Export Full Configuration
CLIENT_UUID="0d7b3b6b-d32f-49a0-9563-6cc8e645b59c"
curl -s "https://keycloak-01.inside.domusdigitalis.dev:8443/admin/realms/domusdigitalis/clients/$CLIENT_UUID" \
-H "Authorization: Bearer $KC_TOKEN" \
--insecure > /tmp/ise-saml-client.json
Step 4: Transform with sed
sed 's/ise-02/ise-01/g' /tmp/ise-saml-client.json > /tmp/ise-saml-client-updated.json
Changes applied:
| Field | New Value |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Step 5: Apply Update via PUT
curl -s -X PUT \
"https://keycloak-01.inside.domusdigitalis.dev:8443/admin/realms/domusdigitalis/clients/$CLIENT_UUID" \
-H "Authorization: Bearer $KC_TOKEN" \
-H "Content-Type: application/json" \
-d @/tmp/ise-saml-client-updated.json \
--insecure -w "\nHTTP_STATUS: %{http_code}\n"
Result: HTTP_STATUS: 204 (No Content = success)
Step 6: Verify
curl -s "https://keycloak-01.inside.domusdigitalis.dev:8443/admin/realms/domusdigitalis/clients/$CLIENT_UUID" \
-H "Authorization: Bearer $KC_TOKEN" \
--insecure | jq '{name, rootUrl, redirectUris}'
Output:
{
"name": "Cisco ISE Admin Portal (ise-01)",
"rootUrl": "https://ise-01.inside.domusdigitalis.dev",
"redirectUris": [
"https://ise-01.inside.domusdigitalis.dev:8443/*",
"https://ise-01.inside.domusdigitalis.dev/*"
]
}
Step 7: Test SAML Login
-
Navigate to
ise-01.inside.domusdigitalis.dev/admin/ -
Click "Log in with SAML"
-
Redirect to Keycloak login
-
Authenticate as
evanusmodestus -
Redirect to ISE Admin Portal - SUCCESS
Key Lessons
| Lesson | Action |
|---|---|
ISE SAML is GUI-only |
No ERS/OpenAPI endpoint exists for SAML IdP configuration |
Keycloak is fully API-driven |
All SAML client updates can be automated via REST API |
Entity ID survives restores |
ISE Entity ID is deployment-specific, not hostname-specific |
sed is powerful |
Simple |
PUT requires full object |
Keycloak doesn’t support PATCH - GET/modify/PUT workflow required |
Prevention Checklist
Pre-Restore
-
Document current ISE Entity ID from SP metadata
-
Export Keycloak SAML client configuration
-
Note all hostname-specific URLs
Post-Restore
-
Verify ISE Entity ID unchanged
-
Update Keycloak SAML client redirect URIs
-
Update ACS URL in client attributes
-
Test SAML login before declaring restore complete
Automation Opportunity
Create netapi keycloak update-saml-client command:
netapi keycloak update-saml-client \
--realm domusdigitalis \
--client-id "http://CiscoISE/a486c6ef-6c77-4bc1-bf6d-4e479b3aeae8" \
--old-hostname ise-02 \
--new-hostname ise-01
Metadata
| Field | Value |
|---|---|
Incident ID |
INC-2026-02-14-001 |
Author |
Evan Rosado |
Date Created |
2026-02-14 |
Status |
Resolved |
Category |
Identity / SAML SSO |