Identities (CIEM)
The identities collected, the effective permissions computed in the graph for each cloud, unused permissions, cross-cloud correlation and the Identity page.
The identity module collects the users, service accounts, roles and policies of each cloud account, then computes in the graph what each identity can reach. The "Identity & Access" page presents the result.
What is collected
| Cloud | Identities and objects collected |
|---|---|
| AWS | IAM users (with the credential report: MFA, last sign-in), groups, roles (service roles told apart, last use), managed and inline policies, access keys |
| Azure | Entra users (on-premises sync, last sign-in, password age, MFA registration, privileged directory roles), service principals and their credentials (secrets, certificates, expiry), RBAC role assignments |
| Google Cloud | Service accounts and their keys; project and organization IAM bindings. Users and groups named in a binding are recorded from the binding; the inventory itself only lists service accounts |
| Scaleway | Users (MFA), applications, groups, policies and their rules, API keys |
| OVHcloud | Identity users, API applications and their application keys, IAM policies |
| OUTSCALE | EIM users and their access keys (including the root account's keys when the inventory runs with them), groups, managed and inline policies, the account's API access policy |
OUTSCALE users, groups and policies take the same types as AWS ones, so the same rules and the same attack paths apply to them.
Effective permissions
After each inventory, Ctadel recomputes a "can access" relationship between each identity and each resource it reaches, with a level (read, write, delete, admin). The relationships are rebuilt from scratch at each inventory, in this order:
- Owner users get
adminon every resource. - Groups get what their policies grant; their members reach those resources through group membership.
- Users and service accounts get what their own policies grant.
- Roles get what their policies grant.
- Google Cloud IAM bindings (project and organization) are folded into the same model.
- Azure role assignments are too, limited to their scope: an assignment on a resource group only reaches what lies under that group, not the whole subscription.
- The compute that carries an identity inherits its access: an instance behind an instance profile or a service account, a function or a task definition behind its execution role, a Kubernetes workload behind its service account.
Levels only add up within one scope (project, organization, account). A read on one project and a write on another do not become admin everywhere. An identity never leaves its cloud nor, for AWS and OUTSCALE, its account.
Each cloud expresses permissions its own way; Ctadel translates them, cloud by cloud, into resource types and levels:
| Cloud | Vocabulary translated | What is not translated |
|---|---|---|
| AWS | IAM action prefixes (s3:GetObject), longest prefix wins | An action Ctadel does not know grants nothing; only a bare * grants everything |
| Google Cloud | Predefined roles (roles/editor) | Custom roles and predefined roles Ctadel does not know grant nothing |
| Azure | Built-in role names (Owner, Contributor, Storage Blob Data Reader) and RBAC action prefixes (Microsoft.Compute/virtualMachines/write) | Custom roles, known by their identifier, grant nothing |
| Scaleway | Permission set names as the Scaleway documentation spells them | Sets for products not inventoried (billing, support, observability) grant nothing |
| OVHcloud | Actions <product>:apiovh:<route>/<method> and managed permission groups by URN | Products outside the inventory |
| OUTSCALE | EIM actions api:<Verb><Noun> with wildcards, OOS verbs | Nouns outside the inventoried families |
Reachable resources are buckets, instances, volumes, databases, Kubernetes clusters, load balancers, private networks, security groups, secrets, registries, serverless functions and containers, DNS zones, gateways, flexible IPs, encryption keys, dedicated servers, snapshots, projects and VPCs. These relationships feed the explorer and the attack paths.
Unused permissions
For each identity that carries policies, the module compares what it is granted with what the cloud's audit logs show it using, and produces one recommendation per identity: granted actions, observed actions, unused actions, and one piece of advice per unused action (remove a destructive, administrative or write action never exercised).
Usage telemetry comes from the cloud's audit logs, read by Ctadel and aggregated per identity and per action. That reading is part of detection on audit logs, which is under internal validation. Without telemetry for a cloud, no identity of that cloud gets a recommendation: "never used" would only mean "never seen".
Granted permissions and observed calls are not in the same vocabulary. The matching is done for AWS (action patterns with wildcards), OUTSCALE (oapi:ReadVms in the log for api:ReadVms in the policy), Scaleway (permission sets against product.Method) and OVHcloud (actions against METHOD /route). An identity with a call that cannot be placed in the vocabulary of its grants gets no recommendation rather than a wrong one. Recommendations of identities that disappeared are removed.
Cross-cloud correlation
The module links identities that designate the same person or the same machine in two different clouds:
| Identities | Criterion | Confidence | "Match" value |
|---|---|---|---|
| People | Same email address | High | email |
| People | User name equal to the local part of an email (AWS IAM users carry no email) | Medium | email_local_part |
| Machines (service accounts, roles) | Same name, separators aside (deploy_role and deploy-role) | Medium | name |
Local parts too generic to identify a person (admin, root, ops, support and a few others) match nobody; a full email equality still matches. Provider-owned service roles (AWSServiceRoleFor…) are never correlated. The correlation is rebuilt after each permission computation.
Risk flags
- "Over-privileged": an attached policy is judged administrative at inventory time (Scaleway, OVHcloud and OUTSCALE), or a policy grants every action (
*or*:*). - "No MFA": the user has no second factor according to the cloud's inventory.
- "Unused actions": the identity has a least-privilege recommendation.
The Identity page
The "Identity & Access" page ("Identity" entry of the menu, under "Inventory") has four tabs. Each tab has a search field, filters and an "Export CSV" button.
| Tab | Columns | Filters |
|---|---|---|
| "Users" | "User", "Cloud", "Status", "MFA", "Over-privileged", "Policies", "Groups", "Unused actions" | "Cloud", "Status", "MFA", "Risk" |
| "Service Accounts" | "Name", "Cloud", "Policies", "API keys", "Unused actions" | "Cloud", "Permissions" |
| "Roles" | "Role", "Cloud", "Type" ("Service" or "Custom"), "Last used", "Policies", "Unused actions" | "Cloud", "Type", "Used" |
| "Cross-Cloud" | "Source", "Match", "Target", "Resources" (number of resources reached on each side) | "Source cloud", "Target cloud", "Match" |
The "Service Accounts" tab gathers Scaleway and OVHcloud applications, Google Cloud service accounts and Azure service principals.
Limits
- Effective permissions only cover the resource types listed above and the permissions Ctadel knows how to translate. A permission outside them grants nothing: the module underestimates rather than overestimates.
- Google Cloud and Azure custom roles are not translated.
- Least-privilege recommendations depend on audit-log telemetry, which is under internal validation; without it, the "Unused actions" column stays empty. They only concern identities carrying policies (users, service accounts, roles), never Google Cloud and Azure identities, whose calls are not matched against grants.
- A role's "Last used" and its "Service" or "Custom" type come from AWS; roles of the other clouds do not carry that information.
- OUTSCALE exposes no per-user MFA fact: the "No MFA" filter is meaningless for that cloud.
- The "Over-privileged" flag relies on attached policies. Privileged Entra directory roles are collected on the user and on the service principal, but do not set this flag on this page.
- On Google Cloud, human users and groups only exist in the graph when a binding names them; they have no status and no MFA.
- For Azure, some properties stay unknown when the matching Microsoft Graph permission is missing (directory roles, sign-in activity, MFA registration); they are not set to
false. - An identity is never correlated with another one of the same cloud.