Keycloak Built-In Analysis

Cartography includes several automatic analyses for Keycloak that help identify inheritance relationships and derived permissions in a Keycloak realm. These analyses are defined in cartography/data/jobs/analysis/keycloak_inheritance.json.

1. Group Membership Inheritance

Description: Propagates user memberships to parent groups when a user is a member of a subgroup.

Query:

MATCH (u:KeycloakUser)-[:MEMBER_OF|INHERITED_MEMBER_OF]->(g:KeycloakGroup)-[:SUBGROUP_OF]->(pg:KeycloakGroup)
MERGE (u)-[r:INHERITED_MEMBER_OF]->(pg)
ON CREATE SET r.firstseen = $UPDATE_TAG
SET r.lastupdated = $UPDATE_TAG

Configuration: Iterative (iteration size: 100)

Graph result:

        graph LR
    U(KeycloakUser) -- MEMBER_OF --> SG(KeycloakGroup)
    SG -- SUBGROUP_OF --> PG(KeycloakGroup)
    U == INHERITED_MEMBER_OF ==> PG
    

2. Group-Based Role Assignment

Description: Automatically assigns roles to users based on their group membership (direct or inherited).

Query:

MATCH (u:KeycloakUser)-[:MEMBER_OF|INHERITED_MEMBER_OF]->(g:KeycloakGroup)-[:GRANTS]->(r:KeycloakRole)
MERGE (u)-[r0:ASSUME_ROLE]->(r)
ON CREATE SET r0.firstseen = $UPDATE_TAG
SET r0.lastupdated = $UPDATE_TAG

Configuration: Non-iterative

Graph result:

        graph LR
    U(KeycloakUser) -- MEMBER_OF --> G[KeycloakGroup]
    G -- GRANTS --> R(KeycloakRole)
    U == ASSUME_ROLE ==> R
    

3. Composite Role Grants Propagation

Description: Propagates scope permissions from included roles to composite roles.

Query:

MATCH (r:KeycloakRole)-[:INCLUDES]->(c:KeycloakRole)-[:GRANTS|INDIRECT_GRANTS]->(s:KeycloakScope)
MERGE (r)-[r0:INDIRECT_GRANTS]->(s)
ON CREATE SET r0.firstseen = $UPDATE_TAG
SET r0.lastupdated = $UPDATE_TAG

Configuration: Iterative (iteration size: 100)

Graph result:

        graph LR
    R(KeycloakRole) -- INCLUDES --> CR(KeycloakRole)
    CR -- GRANTS --> S(KeycloakScope)
    R == INDIRECT_GRANTS ==> S
    

4. Legitimate User Scope Assignment

Description: Identifies all scopes that a user can legitimately use based on the roles they assume.

Query:

MATCH (u:KeycloakUser)-[:ASSUME_ROLE]->(:KeycloakRole)-[:GRANTS|INDIRECT_GRANTS]->(s:KeycloakScope)
MERGE (u)-[r:ASSUME_SCOPE]->(s)
ON CREATE SET r.firstseen = $UPDATE_TAG
SET r.lastupdated = $UPDATE_TAG

Configuration: Non-iterative

Graph result:

        graph LR
    U(KeycloakUser) -- ASSUME_ROLE --> R(KeycloakRole)
    R -- GRANTS --> S(KeycloakScope)
    U == ASSUME_SCOPE ==> S
    

5. Orphan Scope Assignment

Description: Automatically assigns “orphan” scopes (not granted by any role) to all users in the realm.

Query:

MATCH (s:KeycloakScope)<-[:RESOURCE]-(r:KeycloakRealm)
MATCH (u:KeycloakUser)<-[:RESOURCE]-(r)
WHERE NOT (s)<-[:GRANTS|INDIRECT_GRANTS]-(:KeycloakRole)
MERGE (u)-[r0:ASSUME_SCOPE]->(s)
SET r0.firstseen = $UPDATE_TAG
SET r0.lastupdated = $UPDATE_TAG

Configuration: Non-iterative

Graph result:

        graph LR
    R(KeycloakRealm) -- RESOURCE --> U(KeycloakUser)
    R -- RESOURCE --> S(KeycloakScope)
    R -- RESOURCE --> ROLE(KeycloakRole)
    subgraph "No relationship"
        S
        ROLE
    end
    U == ASSUME_SCOPE ==> S