Hi Rahul,
If the AD account is not being moved by SailPoint, this behaviour will occur. Itās a classic sticky entitlement scenario where SailPoint is trying to maintain the integrity of access being governed by the platform by ensuring if something was revoked outside of ISC it will re-provision to the original AD OU
My recommendations:
- Move these AD OU moves into SailPoint using a transform and the service standard before prov rule. That should resolve the issue
- If 1. is not possible:
- Set up native change detection on the DN attribute
- Set up a workflow that responds to this native change detection, compiles a list of access assigned to that AD account, and then un-assigns the access
- The access will then be ādetectedā
Iāve done 2. with an implementation before to get around the native OU moves because the organization was not ready to have SailPoint handle all OU moves.
Sample to get you started belowā¦
{
"id": "xxx",
"name": "xxx",
"description": "",
"modifiedBy": {
"type": "IDENTITY",
"id": "xxx",
"name": "xxx"
},
"definition": {
"start": "Define Variable",
"steps": {
"Define Variable": {
"attributes": {
"id": "sp:define-variable",
"variables": [
{
"description": "",
"name": "oldDN",
"transforms": [],
"variableA.$": "$.trigger.singleValueAttributeChanges.[?(@.name == \"distinguishedName\")]"
},
{
"description": "",
"name": "oldDistinguishedName",
"transforms": [],
"variableA.$": "$.trigger.singleValueAttributeChanges.[?(@.name == \"distinguishedName\")].oldValue"
},
{
"description": "",
"name": "identityID",
"variableA.$": "$.trigger.identity.id"
}
]
},
"displayName": "",
"nextStep": "HTTP Request",
"type": "Mutation"
},
"Get Revocable Access": {
"actionId": "sp:http",
"attributes": {
"authenticationType": "OAuth",
"method": "post",
"oAuthClientId": "xxxxx",
"oAuthClientSecret": "",
"oAuthCredentialLocation": "oAuthInHeader",
"oAuthScope": null,
"oAuthTokenUrl": "xxxxx",
"requestContentType": "text",
"requestHeaders": "Content-Type:application/json",
"textRequestBody": "{\"indices\":[\"identities\"],\"query\":{\"innerHit\":{\"query\":\"revocable:true AND type:ACCESS_PROFILE\ - REVISE THIS AS NEEDED FOR YOUR IMPLEMENTAION",\"type\":\"access\"},\"query\":\"id:\\\"{{$.trigger.identity.id}}\\\"\"}}",
"url": "xxxxx"
},
"description": "Get all Revocable Access",
"nextStep": "Has Revocable Access?",
"type": "action",
"versionNumber": 2
},
"HTTP Request": {
"actionId": "sp:http",
"attributes": {
"authenticationType": "OAuth",
"method": "get",
"oAuthClientId": "xxxxx",
"oAuthClientSecret": "",
"oAuthCredentialLocation": "oAuthInHeader",
"oAuthTokenUrl": "xxxxx",
"requestContentType": "json",
"requestHeaders": {
"Accept": "application/json"
},
"url": "xxxxxxxxx/beta/access-request-approvals/completed/?filters=requestedFor.id%20eq%20\"{{$.defineVariable.identityID}}\""
},
"description": "Get entitlements from the identity that were requested for the old distinguished name",
"displayName": "",
"nextStep": "Loop Standalone Entitlements",
"type": "action",
"versionNumber": 2
},
"Has Revocable Access?": {
"choiceList": [
{
"comparator": "IsPresent",
"nextStep": "Revoke Revocable Access",
"variableA.$": "$.getRevocableAccess.body[0].id"
}
],
"defaultStep": "No Revocable Access",
"type": "choice"
},
"Loop Standalone Entitlements": {
"actionId": "sp:loop:iterator",
"attributes": {
"context.$": "$.trigger.identity.id",
"input.$": "$.hTTPRequest.body[*].requestedObject.id",
"start": "Has Entitlement Id?",
"steps": {
"Get Access": {
"actionId": "sp:access:get",
"attributes": {
"accessprofiles": true,
"entitlements": true,
"getAccessBy": "searchQuery",
"query": "id:$.loop.loopInput",
"roles": true
},
"description": null,
"displayName": "",
"nextStep": "Verify Data Type",
"type": "action",
"versionNumber": 1
},
"Has Entitlement Id?": {
"choiceList": [
{
"comparator": "IsPresent",
"nextStep": "Get Access",
"variableA.$": "$.loopStandaloneEntitlements.loopInput"
}
],
"defaultStep": "No Entitlement to Revoke",
"type": "choice"
},
"No Entitlement to Revoke": {
"description": "No Entitlement to Revoke",
"type": "success"
},
"Revoke Standalone Entitlement": {
"actionId": "sp:access:manage",
"attributes": {
"comments": "Native Change - Handling Sticky Entitlements",
"removeIdentity.$": "$.loop.context.identity.id",
"requestType": "REVOKE_ACCESS",
"requestedItems.$": "$.getAccess.accessItems[*]"
},
"nextStep": "Standalone Entitlement Revoked",
"type": "action",
"versionNumber": 1
},
"Standalone Entitlement Revoked": {
"type": "success"
},
"Verify Data Type": {
"choiceList": [
{
"comparator": "IsPresent",
"nextStep": "Revoke Standalone Entitlement",
"variableA.$": "$.getAccess.accessItems"
}
],
"defaultStep": "No Entitlement to Revoke",
"displayName": "",
"type": "choice"
}
}
},
"nextStep": "Get Revocable Access",
"type": "action",
"versionNumber": 1
},
"No Revocable Access": {
"description": "No standing entitlements to revoke",
"type": "success"
},
"Revoke Revocable Access": {
"actionId": "sp:access:manage",
"attributes": {
"comments": "Native Change Detection",
"removeIdentity.$": "$.trigger.identity.id",
"requestType": "REVOKE_ACCESS",
"requestedItems.$": "$.getRevocableAccess.body[*]"
},
"nextStep": "Standing Access Revoked",
"type": "action",
"versionNumber": 1
},
"Standing Access Revoked": {
"description": "Remediated Sticky Access for OU Move",
"type": "success"
}
}
},
"enabled": false,
"creator": {
"type": "IDENTITY",
"id": "xxxxxxx",
"name": "xxxxxxxxx"
},
"owner": {
"type": "IDENTITY",
"id": "xxxxxx",
"name": "xxxxxxxxxx"
},
"trigger": {
"type": "EVENT",
"attributes": {
"filter.$": "$.singleValueAttributeChanges[?(@.name == \"distinguishedName\")]",
"id": "idn:native-change-account-updated"
}
}
}