Application authorization with Verified Permissions

Lesson 3 of 4 in Designing and Reviewing Access.

There is a line in every application that IAM cannot cross, and Amazon Verified Permissions exists on the other side of it.

IAM authorises AWS API calls. Can this principal call s3:GetObject on this bucket? Can it call dynamodb:Query on this table? Those are the only questions IAM is asked, and it answers them for every request to an AWS service.

Verified Permissions authorises your application's actions. May this user comment on that document? May this manager approve an expense over £10,000? May this customer view that other customer's order? IAM has no vocabulary for any of it — a DynamoDB table policy cannot express "the author of the parent thread, or a moderator, but only during business hours".

Historically that logic lived scattered through controllers and service classes: an if here, a role check there, a query filter somewhere else. Verified Permissions pulls it out into Cedar policies held in a managed policy store, so application authorization becomes something you can review, version, and reason about rather than something you grep for.

Cedar is the language, and it is open source — the same engine runs outside Verified Permissions if you need it embedded. A policy reads close to the sentence it encodes:

permit (
  principal in Group::"regional-managers",
  action == Action::"ApproveExpense",
  resource in Region::"emea"
)
when { context.amount <= 10000 && context.mfa == true };

forbid (
  principal,
  action == Action::"ApproveExpense",
  resource
)
when { resource.submittedBy == principal };

Four things to notice. The triple is always principal, action, resource, with context for everything else. when adds a requirement and unless adds an exception. forbid beats permit — the same precedence rule as IAM's explicit deny, which makes the second policy above a clean separation-of-duties control: nobody approves their own expense, regardless of group. And Cedar is designed for automated reasoning, so tools can analyse what a policy set permits rather than only testing examples.

The pieces around it: a policy store holds the policies; an optional schema declares your entity types, their attributes, and which actions apply to which resource types, so the console and SDK can validate policies as you write them; policy templates are parameterised policies instantiated per resource (one template, ten thousand "owner of this document" policies); and identity sources connect a Cognito user pool or an OIDC provider so IsAuthorizedWithToken can read the principal straight from a JWT.

IAM and Verified Permissions — the line between them
IAMAmazon Verified Permissions

Authorises

Calls to AWS service APIs

Actions defined by your application

Who asks

AWS, on every API request, automatically

Your code, explicitly, by calling IsAuthorized

Language

IAM JSON policy documents

Cedar

Vocabulary

Service actions and ARNs

Your entity types, attributes, and actions, declared in a schema

Precedence rule

Explicit Deny beats Allow

forbid beats permit — the same shape

Typical question

"May this role read this bucket?"

"May this user edit this document?"

If you try to use the other one

An IAM policy cannot express per-record, per-user business rules

Cedar cannot authorise an S3 or DynamoDB API call — AWS does not consult it

One more organizational device the exam guide names alongside these: IAM paths.

A path is a slash-delimited namespace inside an IAM entity's ARN, chosen at creation and fixed thereafter:

arn:aws:iam::111122223333:role/teams/payments/deploy
arn:aws:iam::111122223333:role/teams/search/deploy
arn:aws:iam::111122223333:policy/boundaries/TeamBoundary

It turns a flat list of names into a hierarchy you can match with a wildcard, which is what makes delegated administration expressible: allow a team administrator to manage role/teams/payments/* and nothing else; allow iam:PassRole over one branch rather than over every role in the account. Without paths the same intent depends on a naming convention, and a naming convention is one typo away from granting more than you meant.

Two practical notes. Paths are not changeable after creation — plan them with the account structure, not after it. And you have already seen one: IAM Identity Center puts its generated roles under /aws-reserved/sso.amazonaws.com/, which is exactly why a resource policy should match that path with a wildcard instead of pinning the unstable role suffix.

Key terms: Amazon Verified Permissions, Cedar, IAM path, Cognito user pool

Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.