Iiq Role Profile Integrity Checker
Detects stale entitlement references in IIQ role profiles — before they cause provisioning failures, silent certification errors, or degraded role scoring — for IAM engineers managing 500+ connectors.
IIQ Role Profile Integrity Checker
Detects stale entitlement references in IIQ role profiles — before they cause provisioning failures, silent certification errors, or degraded role scoring — for IAM engineers managing 500+ connectors.
Date: 2026-06-29 Type: Utility Theme: Protect + Detect Platform: SailPoint IdentityIQ Status: Idea
What it is
A Python utility that connects to the IdentityIQ REST API, retrieves all Bundle (role) definitions and their Application Profiles, then cross-references each profile's entitlement constraints against the live ManagedAttribute catalog. It reports every stale reference — entitlements cited in role profiles that no longer exist as managed attributes — grouped by application, severity-ranked, with a concrete remediation checklist. The utility is read-only: it fetches and reports; it never modifies IIQ objects.
Who it serves
IAM engineers and role administrators at organisations running IIQ with dozens to hundreds of IT Roles spanning 500+ connector applications. Most useful before a major aggregation refresh, a connector retirement, or the opening of a quarterly role certification campaign, where stale profile references silently corrupt what certifiers see.
The IIQ pain it addresses
When a managed attribute is deleted from IIQ (e.g., a role or group is removed from an application's aggregated entitlement catalog), the corresponding row in spt_bundle_profile_relation is not automatically removed — confirmed in IIQ 8.4 by the SailPoint Developer Community. The orphaned reference remains inside the Bundle's Profile indefinitely, causing:
- Provisioning failures: IIQ attempts to provision a non-existent entitlement, generating
ProvisioningTransactionerrors that surface as connector-level noise — individually small, cumulatively misleading in log analysis. - Broken certifications: Certifiers see entitlement display names that resolve to
[Unknown]or empty strings. At scale this drives rubber-stamping because certifiers stop trusting what they're reviewing. - Degraded role scoring: Role correlation and risk scoring degrade because the Bundle's expected entitlements cannot be matched to live Links, producing artificially low role coverage percentages.
At 500+ connectors, even a 0.1% entitlement churn rate per aggregation cycle generates dozens of stale bundle constraints over a single quarter. IIQ has no native alert or integrity scan for this condition — the problem accumulates silently with no dashboard indicator.
How it works
- Connect — reads
sample-config.jsonfor the IIQ base URL and service-account username. Password is sourced exclusively from the environment variable named inconfig["password_env"]. - Fetch Bundles — paginates
GET /identityiq/rest/bundlesto retrieve all IT Role and Business Role Bundle objects, extracting each Bundle'sprofiles[]array (Application name + entitlement constraint triples: attributeName + value). - Fetch ManagedAttributes — for each unique Application referenced across all profiles, paginates
GET /identityiq/rest/managedAttributes?applicationName=<app>to build an in-memory lookup of live(application, attributeName, value)triples. - Cross-reference — for each profile constraint in each Bundle, checks whether the
(application, attributeName, value)triple exists in the live managed-attribute lookup. Misses are flaggedSTALE. - Score and rank — computes per-Bundle severity:
HIGHif >50% of constraints are stale,MEDIUMif 10–50%,LOWif <10%. - Report — prints a structured findings table to stdout (summary totals, affected Bundles ranked by severity, per-constraint detail) and writes
role-integrity-findings.jsonfor downstream tooling or ticketing unless--dry-runis passed.
What's in this folder
README.md— this filerequirements.md— functional, non-functional, and security requirementsscript.py— Python 3.10+ utility; one third-party dependency (requests)sample-config.json— illustrative configuration (.invalidTLD server URLs, no real credentials)sample-output.txt— annotated stdout from a sample run against a synthetic 87-role, 12-application IIQ environment
How to run / read it
export IIQ_SERVICE_PASSWORD="<service account password>"
python3 script.py --config sample-config.json
Pass --dry-run to print findings to stdout without writing role-integrity-findings.json. Install the one required dependency first:
pip install "requests>=2.31"
Read sample-output.txt to see exactly what the utility prints for a deployment with 8 affected bundles and 15 stale constraints across SAP, Active Directory, Salesforce, ServiceNow, GitHub, and AWS connectors.
Estimated impact
At a 500-connector IIQ deployment with quarterly connector refresh cycles, accumulated stale bundle constraints typically number in the dozens. Each stale constraint produces one provisioning error or one [Unknown] certifier display per campaign. At 50 certifiers reviewing 3 campaigns per year, that is 150+ avoidable support tickets annually from a problem that takes under 2 minutes to detect. Scheduling this utility as a pre-campaign gate — via OS cron or IIQ's native Run Rule task invocation mechanism — converts a month-long post-mortem into a 2-minute fix list delivered before the campaign opens.
Why this fits an IIQ shop with 500+ connectors
At scale, entitlements churn continuously. Connectors are reconfigured, application schemas evolve during platform upgrades, managed attributes are renamed or removed when an application decommissions a role, and occasional hard-deletes via the IIQ admin console leave no downstream cleanup signal. The spt_bundle_profile_relation accumulation is invisible to standard IIQ dashboards and reports — it does not surface in the System Dashboard, the Role Management UI, or any out-of-box report. An organisation managing SAP ECC, Active Directory, ServiceNow, Workday, Salesforce, and 490+ additional applications will experience entitlement churn in multiple connectors every sprint cycle. The larger the estate, the more stale references accumulate. This utility runs as a scheduled pre-campaign gate, not a one-time remediation, because the problem regenerates continuously.
Sources
- Entitlement role relationship — SailPoint Developer Community — Community thread (IIQ 8.4) confirming
spt_bundle_profile_relationis not automatically cleaned up when managed attributes are deleted; confirmed by SailPoint community member Naveen Kumar - Roles in IdentityIQ — SailPoint Compass Wiki — IIQ role taxonomy (Organizational, Business, IT, Entitlement Role types) and profile-entitlement relationship model
- Role Management Concepts — SailPoint IdentityIQ documentation — canonical IIQ role modeling vocabulary; Bundle, Profile, Constraint, and ManagedAttribute terminology
- IdentityIQ API Specifications — SailPoint Developer Community — REST endpoint catalogue used to anchor
/rest/bundlesand/rest/managedAttributescall patterns in the script
Requirements
Requirements — IIQ Role Profile Integrity Checker
Functional
- Connect to SailPoint IdentityIQ 8.x REST API using HTTP Basic auth over HTTPS.
- Retrieve all Bundle objects whose
typematches the configuredrole_typeslist (default:["IT Role", "Business Role"]) via paginatedGET /identityiq/rest/bundles. - For each Bundle, extract its
profiles[]— each Profile references an Application name and a list of entitlement constraints (attributeName + value pairs representingspt_bundle_profile_relationentries). - For each unique Application referenced across all profiles, retrieve the complete live ManagedAttribute catalog via paginated
GET /identityiq/rest/managedAttributes?applicationName=<name>. - Cross-reference every profile constraint against the live ManagedAttribute catalog. A constraint is
STALEwhen no ManagedAttribute with matching application, attributeName, and value exists. - Compute per-Bundle severity:
HIGH— more than 50% of profile constraints are staleMEDIUM— 10% to 50% (inclusive) of constraints are staleLOW— more than 0% but fewer than 10% of constraints are staleCLEAN— zero stale constraints (not included in findings)
- Emit a structured findings report to stdout:
- Summary header: total Bundles scanned, total with findings, total stale constraints
- Table of affected Bundles sorted by severity (HIGH first) then alphabetically by name
- Per-Bundle detail: Application name, stale attributeName, stale value, percentage stale
- Remediation checklist at the end
- Write
role-integrity-findings.jsonto the working directory on exit unless--dry-runis passed. - Exit codes:
0— no stale constraints found1— stale constraints detected2— fatal error (connection, auth, configuration)
Non-Functional
- Runtime: Python 3.10 or later. One third-party dependency:
requests(HTTP client). No other pip packages. - Pagination: All list endpoints are paginated using
limitandstartquery parameters. Default page size: 250. Adjust viaconfig["page_size"]. - Timeout: All HTTP calls time out after
config["timeout_seconds"]seconds (default: 30). Applies per-request, not for the entire run. - Performance: Must complete in under 3 minutes against a deployment with 1,000 roles and 500 applications, assuming 500ms average API response time.
- Safety: Exclusively GET requests. Safe to run while IIQ is live.
Security
- Password must be read from the environment variable named in
config["password_env"]. No plaintext passwords in config files, CLI arguments, or log output. verify_ssl: falseis accepted for test environments only; the script emits aWARNINGto stderr when SSL verification is disabled.- TLS 1.2+ enforced via the
requests+ system CA bundle default. role-integrity-findings.jsoncontains no identity PII — only Bundle names, Application names, attributeNames, and entitlement values (all visible to any IIQ admin via the Role Editor).- The
IIQ_SERVICE_PASSWORDenvironment variable must not appear in any log line or output file.
Error Handling
401 / 403— print auth error with the HTTP status; exit code 2. No retry.404— print endpoint-not-found with the URL; exit code 2. Indicates misconfigurediiq_base_url.429 / 5xx— retry once after a 5-second back-off; exit code 2 if the retry also fails.ConnectionError / Timeout— print the error with the target URL; exit code 2.
Dependency Declaration
The script declares its only dependency at the top in a comment parseable by pip-based tooling:
# requires: requests>=2.31
Operational
- Designed to run as a pre-campaign gate: schedule via OS cron, IIQ
Run Ruletask invocation, or a CI/CD pipeline step that blocks campaign creation if exit code is 1. - The JSON output (
role-integrity-findings.json) is structured for downstream consumption by ticketing systems (ServiceNow, Jira) or monitoring pipelines (Splunk, Sentinel). - No state is persisted between runs; each invocation is a fresh point-in-time integrity snapshot.
More from IAM Ideas