Guide 144 checklist

How to review cloud IAM permissions behind an application

Review application IAM permissions against real operations, effective policy and recovery needs, with bounded reductions and evidence for the changed grant.

Review an application's cloud identity from the request it is meant to perform: who can obtain the role, which actions can it call, on which resources, under which conditions, and what happens if its own code is wrong? Inspect both the role trust policy and its effective permissions, including resource policies, session policies and organization controls. Then compare those permissions with the application's real jobs. A policy that looks narrow in one file may be broadened by another attachment or resource policy; a policy that names the right table may still allow every tenant partition inside it.

The answer changes with the architecture. A single-purpose worker may need one read and one write. A multi-tenant API often needs a second boundary inside a shared data resource. IAM is an independent guardrail, not a replacement for application authorization: it cannot decide whether a human user should see a particular invoice unless the request's identity and resource scope are reliably carried into the cloud permission decision. AWS documents how identity, resource, boundary and organization policies interact; reviewing one Allow statement alone is insufficient.

Illustrative case: the narrow role with a second grant

Synthetic design exercise, not a deployed CodeSecPilot assessment: Northstar's InvoiceReader role has an identity policy allowing s3:GetObject only for invoices/approved/*. In the same AWS account, the bucket policy separately grants that role s3:GetObject on invoices/legacy/*. For this simplified case, assume no permissions boundary, session restriction, applicable organization or endpoint restriction, ACL dependency, KMS requirement, or explicit deny changes these requests.

Under those stated assumptions, looking only at the role's identity policy gives the wrong answer. AWS policy evaluation considers both identity and resource grants in same-account access. The legacy prefix is allowed by the resource policy even though it is absent from the identity policy.

Request under the stated policy set Identity policy Bucket policy Effective reasoning
Get approved invoice Allow No relevant grant needed Allowed
Get legacy invoice No allow Allow to this role Allowed; violates Northstar's intended role purpose
Delete approved invoice No allow No allow Denied

The table is intentionally bounded. Role ARN versus role-session principal, explicit denies, boundaries, cross-account access and encryption can change evaluation. Collect those facts in a real review rather than extending this example to every AWS request.

The reviewer also finds an AssumeRole permission and a quarterly recovery requirement. An apparently small data role could obtain a larger role if the target trust and other controls permit it. Conversely, the export read appears unused during a one-month audit window because its legitimate job runs quarterly. Neither code search nor recent inactivity settles those paths.

1. Start at the running workload, not a policy file

Input: deployed service or job identity, environment, account and region. Owner: cloud security with application owner. Action: determine which IAM principal the workload actually uses. Output: principal-to-workload map. Check: a read-only observation of the running configuration or authorized audit event matches the proposed role.

Many repositories contain old templates, example roles and planned policies. Map the immutable release or deployment to the live role and note any drift. Separate production, staging, administrative and CI identities. A container task, function and build runner may have different principals even when they all call the same application. If one broad role serves unrelated actions, document that as a design choice; it enlarges the impact of a bug in any of those actions.

Read the trust policy first. Which AWS service, account, federated identity or external principal may assume the role? Are the conditions specific to the expected workload? Can an attacker with control of a different workflow or account get the same role? A fine-grained permission policy is of little value if the wrong principal can obtain its credentials. Prefer temporary workload credentials over stored long-lived access keys where supported, consistent with AWS IAM best practices.

2. Enumerate what the role can do, including indirect paths

Collect inline and attached identity policies, role boundary, session policy where one is supplied, relevant resource policies, service control policies and resource control policies. AWS's policy evaluation logic explains why an identity Allow, a resource-based Allow and an explicit Deny can change the outcome. Include permission-changing actions such as role assumption, iam:PassRole, secret reads, KMS decrypt and policy edits when relevant; a small-looking data permission can lead to more authority through a delegated service role.

Do not equate Resource: "*" with an automatic exploit. Some AWS actions do not support resource-level scoping, and a restrictive condition or organization control may still apply. But ask why the wildcard is necessary, which request context limits it, and whether a narrower resource or separate role is possible. Conversely, a named table ARN can still be too broad for a multi-tenant table. Express the required access as a tuple: principal, action, exact resource or partition, purpose, duration.

For Northstar, the reviewer requests an owner for s3:GetObject. If exports no longer use it, remove the permission after checking all known consumers. If they do, split the export path from the invoice reader and scope the object set. A code search showing no caller is useful but incomplete; scheduled or out-of-repository consumers may exist.

3. Compare intended work with observed activity carefully

List legitimate API calls for normal read, write, maintenance and failure recovery. AWS IAM Access Analyzer policy generation can use CloudTrail activity over a selected period to propose a narrower policy, but AWS notes limits: it does not identify action-level activity for data events in its generated policy, and iam:PassRole is not tracked there. An unused action may be needed for a rare recovery path. Treat generated policies and last-used views as evidence for review, not an automatic safe replacement.

For each permission, record either the named current use, a planned use with approval, or “no justified use found.” Distinguish evidence gaps from absence of use. If the log window covers only the past month and the recovery job runs quarterly, the job has not been disproved. Seek the job's owner and runbook before removal. This prevents least-privilege work from silently breaking recovery while still forcing every grant to earn its place.

4. Check the failure boundary with a specific negative request

Define one operation that must succeed and one that must be denied. For Northstar's InvoiceReader, an approved-prefix synthetic object must remain readable after the change, while a legacy-prefix synthetic object must be denied with the same role. Use an authorized nonproduction environment and the complete policy context. Confirm the actual caller, object ARN, policy revisions and denial location; an HTTP-layer refusal may conceal a still-permitted S3 read.

AWS's IAM policy simulator can help review an action and resource without making a service call, but AWS says it does not use production context key values and recommends checking against the live environment afterward. Access Analyzer policy checks can flag policy issues and certain new or public access; they do not know Northstar's invoice ownership rule. A simulation pass is one piece of evidence, not runtime tenant isolation proof.

A negative request only demonstrates the named operation under the recorded context. If role assumption, recovery exports or a different resource policy remain unexamined, keep them open. The decision worksheet should not borrow a successful S3 denial to clear those independent authority paths.

Decide what to remove, retain and split

Northstar's completed synthetic decision worksheet separates four grants:

Grant/path Evidence and product need Decision
Approved-prefix GetObject Current invoice-read operation requires it Retain, scoped to exact necessary objects
Legacy-prefix resource grant No current InvoiceReader operation needs it; separate historical export role owns that data Remove the bucket-policy grant to InvoiceReader and check effective denial
AssumeRole to maintenance role Identity permission found; target trust and caller conditions incomplete Investigate before declaring the escalation path possible or impossible
Recovery export read Quarterly runbook and owner establish legitimate need, absent from recent activity Split into recovery identity; retain the need while removing it from routine API authority

The positive check is an authorized invoice read. The negative check is the formerly permitted legacy-prefix read with the actual InvoiceReader credentials and complete policy context. A denial at the HTTP layer alone does not prove the cloud grant was removed. Record permission-policy and resource-policy revisions together, because changing only the role file would leave the original extra grant intact.

If the same role accesses a shared tenant table, a named table ARN is not a tenant or purpose boundary. Review that separate data-model and credential question with temporary tenant credentials. Do not mix a tenant-partition redesign into this worksheet unless it is required to fix the specific operation being reviewed.

Close the permission change when the intended deployment has the revised grant and the relevant allowed/denied checks support it. Keep unrelated authority paths in separate work items. A small, well-understood reduction can proceed with a rollback plan while the broader inventory continues; it need not wait for proof of an exploitable application bug.

Preserve rare operations without preserving routine excess

The quarterly recovery requirement is a common point of disagreement in Northstar's review. The application team worries that removing export access will break recovery; the reviewer sees no recent use and wants the role narrowed. Resolve this by describing the recovery operation independently: who starts it, what data it needs, how the recovery identity is obtained, and which evidence would show that the route remains available. The legitimate requirement is to recover invoices, not to keep every normal API process capable of recovery exports.

A staged change can preserve that requirement. First, identify the actual recovery owner and approved launch path. Next, prepare the separate identity and its narrow access. Then obtain proportionate evidence that the recovery path uses it before removing the routine role's extra grant. If the recovery route cannot be exercised immediately, record the limitation and choose a release decision under the organization's availability and security priorities. Recent inactivity alone should not make that decision.

There is also a rollback question. Restoring the previous broad policy would restore the excess legacy access as well. The change record should name the expected failure signals and the least broad repair that could address them. A missing permission for one recovery object need not justify restoring access to every historical export. During an outage, a clear resource-and-action requirement helps the operator avoid making a hurried account-wide grant.

After rollout, inspect any denied requests relevant to the changed role. Match them to an intended workload before treating them as evidence that the narrowing was wrong. An obsolete consumer may need retirement, a legitimate operation may need a precise permission, and an unexplained request may need investigation. Keep those branches separate.

The result is a smaller routine role with a documented recovery path, or an honestly bounded pending change. Both are more useful than an unqualified “least privilege achieved” label that conceals a rare operation nobody checked.

Take one application role and fill the matrix with its actual workload and a forbidden operation. If the role comes from infrastructure code, use IaC exposure prioritization to distinguish proposed from live grants. If it is assumed by a deployment workflow, continue with the CI token scope review.