Service Reference
IAM — Identity and Access Management
IAM uses the AWS Query protocol (POST / with form-encoded body). Actions are dispatched by the Action parameter. Overcast emulates IAM resource management (users, roles, groups,...
IAM — Identity and Access Management
AWS docs: IAM API Reference
IAM uses the AWS Query protocol (POST / with form-encoded body). Actions are dispatched by
the Action parameter. Overcast emulates IAM resource management (users, roles, groups,
policies, instance profiles) for CDK/IaC compatibility — credentials are accepted but not
validated.
[!CAUTION] Policies are not enforced by default. IAM resources are created and stored, and every API call succeeds regardless of attached policies unless you opt in to enforcement with
OVERCAST_ENFORCE_IAM(see below). Overcast is not a security boundary: credentials are accepted but never verified, and the evaluator covers a subset of the IAM policy language.
Notes
- Policy versions are counters, not history.
CreatePolicyVersionwithSetAsDefault=truereplaces the operative document and bumpsDefaultVersionId(which is what CloudFormation’sAWS::IAM::ManagedPolicyupdate dispatches), but superseded documents are not retained — there is noGetPolicyVersion,ListPolicyVersionsorDeletePolicyVersion. GetGroupreturns the group’s members. Membership recorded byAddUserToGroup/RemoveUserFromGroupis resolved into the response’sUserscollection, paginated withMarker/MaxItems(AWS’s documented default of 100 and cap of 1000). A membership entry whose user record has since gone, or cannot be decoded, is skipped rather than failing the call — one bad stored record cannot make a group unreadable. AMarkerthat does not decode is rejected withInvalidInputinstead of silently restarting at the first page.- Event bus integration. User, role, policy and group lifecycle events are published to the internal event bus for topology/UI updates.
Deletes enforce dependencies
DeleteUser, DeleteRole, DeleteGroup and DeletePolicy refuse with AWS’s DeleteConflict
(HTTP 409) while the entity still has dependencies, and the message names what to clear — the
same behaviour Terraform, CDK, aws-nuke and eksctl already expect from real IAM.
| Delete | Refused while | Message |
|---|---|---|
DeleteUser | access keys exist | Cannot delete entity, must delete access keys first. |
| inline policies exist | Cannot delete entity, must delete policies first. | |
| managed policies are attached | Cannot delete entity, must detach all policies first. | |
| the user is in a group | Cannot delete entity, must remove users from group first. | |
DeleteRole | the role is in an instance profile | Cannot delete entity, must remove roles from instance profile first. |
| inline policies exist | Cannot delete entity, must delete policies first. | |
| managed policies are attached | Cannot delete entity, must detach all policies first. | |
DeleteGroup | the group has members | Cannot delete entity, must remove users from group first. |
| inline policies exist | Cannot delete entity, must delete policies first. | |
| managed policies are attached | Cannot delete entity, must detach all policies first. | |
DeletePolicy | attached to any user, role or group, or used as one of their permissions boundaries | Cannot delete a policy attached to entities. |
A non-existent entity is still NoSuchEntity (404): existence is checked before dependencies.
When several dependencies block at once the checks run in the order listed above, which is the
order AWS’s own API Reference lists the prerequisites in; AWS does not document which one wins,
so clearing them top to bottom is what a caller should expect.
Overcast does not model login profiles, signing certificates, SSH keys, Git credentials or MFA devices, so the AWS conflicts for those cannot arise here.
[!NOTE] Local teardown scripts that used to delete an IAM entity without unwinding it first will now get a 409. Remove the dependency through the modeled API —
DeleteAccessKey,DeleteUserPolicy,DetachUserPolicy,RemoveUserFromGroup,RemoveRoleFromInstanceProfile,DeleteRolePolicy,DetachRolePolicy,DeleteGroupPolicy,DetachGroupPolicy— exactly as you would against AWS. CloudFormation stack teardown handles the dependencies a stack owns itself:AWS::IAM::Policyremoves its inline document from the entities it named, roles, users, groups and managed policies detach theManagedPolicyArns/Policies/Groups/ attachment-list relationships their own template properties declared, and reverse dependency order puts instance profiles before their roles.
A DeleteConflict a stack cannot clear for itself — something outside the stack attached a
policy, minted an access key, or added the user to a group — fails the stack. DeleteStack
reports DELETE_FAILED with IAM’s own message on the resource’s event and status reason, and
leaves the entity standing, as real CloudFormation does. Clear the dependency and delete the
stack again. See CloudFormation § Teardown failure.
Policy simulation
SimulateCustomPolicy and SimulatePrincipalPolicy run a real evaluation of the IAM policy
language and return AWS’s decision vocabulary — allowed, explicitDeny, implicitDeny —
with MatchedStatements naming the policy and statement that decided it, and
MissingContextValues naming condition keys the call did not supply. Simulation reads
nothing else and changes nothing: it is the “what would happen” view, and it is available
whether or not enforcement is switched on.
Each MatchedStatements entry carries SourcePolicyId/SourcePolicyType plus AWS’s
StartPosition/EndPosition (Line/Column), which point at the deciding statement’s
opening { and closing } in the exact document text supplied on the call (a
PolicyInputList entry, an inline/managed policy document, or ResourcePolicy). This is
what lets a caller tell two statements apart when they come from the same document — for
example an Allow and a Deny in one policy — which SourcePolicyId/SourcePolicyType
alone cannot do. The positions are Overcast’s own byte-accurate computation against the
document text it was given; they are not copied from any upstream source, and a caller
should not expect them to match what real AWS would report for the same document down to
the byte.
What the evaluator covers:
Effect,Action/NotAction,Resource/NotResource, with*and?wildcards. Actions match case-insensitively, as on AWS; resource ARNs match case-sensitively.- Explicit deny wins, then allow, otherwise the default implicit deny.
Conditionoperators: theString*,Numeric*,Date*,Bool,IpAddress/NotIpAddress,Arn*andNullfamilies, including the…IfExistssuffix.- Policy variables (
${aws:username},${aws:userid}, …) in resources and condition values. - Resource-based policies passed as
ResourcePolicy, includingPrincipal/NotPrincipalmatching. Within the single account Overcast emulates, an allow in either the identity policies or the resource policy is sufficient, and a deny in either is final. - Permissions boundaries — both the one attached to the simulated principal and one supplied
as
PermissionsBoundaryPolicyInputList— reported throughPermissionsBoundaryDecisionDetail. See below.
What it does not cover, and says so rather than guessing: a condition operator or principal
type it does not implement makes the call fail with AWS’s PolicyEvaluation error naming the
construct, instead of resolving to an allow or a deny. Service control policies, session
policies, and the ForAllValues/ForAnyValue set operators are not implemented. A policy
document that cannot be parsed is rejected with InvalidInput.
Permissions boundaries granted through a ResourcePolicy are not exempted: on AWS a
resource-based policy that names an IAM user principal directly is allowed to bypass that
user’s boundary, and Overcast applies the boundary to the combined identity/resource decision
instead. That divergence only shows up when a simulation supplies a ResourcePolicy and the
principal carries a boundary.
Permissions boundaries
PutUserPermissionsBoundary / PutRolePermissionsBoundary attach a managed policy as a user’s
or role’s permissions boundary, and CreateUser / CreateRole accept one directly through
their PermissionsBoundary parameter (which is what AWS::IAM::User passes from a template).
GetUser, GetRole, ListUsers, ListRoles and GetAccountAuthorizationDetails report it as
AWS’s AttachedPermissionsBoundary. A boundary naming a policy that does not exist is refused
with NoSuchEntity, and DeletePolicy refuses with DeleteConflict while a policy is still
bounding an entity.
A boundary grants nothing on its own: it caps what the entity’s identity policies can grant, so
the effective permissions are the intersection of the two, and an explicit deny in either is
final. Both SimulatePrincipalPolicy and opt-in request-time enforcement read the stored
boundary, so a boundary attached out of band takes effect on the very next call — attaching,
replacing or removing one invalidates the enforcement middleware’s compiled-policy cache, as any
other policy change does.
Supplying PermissionsBoundaryPolicyInputList to SimulatePrincipalPolicy uses that boundary
instead of the stored one: AWS allows only one boundary per simulation, and asking “what would
this boundary do” is the reason to supply it.
A boundary that is attached but cannot be read — its managed policy has been deleted out of band, its stored record does not decode, or its document is not a valid policy — allows nothing. Reading it as absent would grant exactly the permissions it was attached to withhold, and failing the whole call would let one corrupt record break an otherwise healthy principal. The reason is logged at warn level.
Request-time enforcement (opt-in)
Set OVERCAST_ENFORCE_IAM=true to have every request evaluated against the calling
principal’s policies before it reaches the service handler. It is off by default, and with
it off the evaluator reads nothing and decides nothing — behaviour is exactly as it was.
When it is on:
- The caller is resolved from the SigV4 access key to an IAM user (its inline, attached and group policies) or to a role assumed through STS (its inline and attached policies), plus that entity’s permissions boundary if it has one.
- A request the policies do not allow is refused with the calling service’s own
AccessDenied-shaped error, in that service’s wire format. - The action evaluated is
<prefix>:<Operation>, where the operation is the one the request invokes and the prefix is the IAM action prefix AWS uses for that service — so write policies with the names the AWS documentation gives. Most services are called the same thing throughout, but ten are not: MSK authorizes askafka:, Step Functions asstates:, EFS aselasticfilesystem:, OpenSearch ases:, ELBv2 aselasticloadbalancing:, Service Catalog AppRegistry asservicecatalog:, Cognito user pools ascognito-idp:, and WAF aswafv2:— each a distinct AWS signing name reused as the action prefix. DynamoDB Streams and AppConfig Data are the other two, and differ in kind rather than degree: AWS gives neither its own IAM action namespace at all, sodynamodb:GetRecords/dynamodb:DescribeStream/dynamodb:GetShardIterator/dynamodb:ListStreamsauthorize DynamoDB Streams requests under DynamoDB’s own prefix, andappconfig:authorizes AppConfig Data’sGetLatestConfiguration/StartConfigurationSessionunder AppConfig’s. - Enforcement is fail-closed: an unsigned request, a policy that cannot be parsed, or a construct the evaluator does not implement all deny. The reason is logged at debug level.
- The one exception is a request whose operation cannot be named, which is not gated. S3
reaches this routinely, because its sub-resource operations (
?tagging,?restore,?legal-hold, …) are identified by query parameters rather than by path. Denying them would break ordinary S3 traffic the moment enforcement was switched on. The gap is logged at debug level rather than passing silently. - Resource-based policies (S3 bucket policies, Lambda/SQS/SNS policies) are not consulted at request time yet — only identity policies are. The simulator accepts a resource policy explicitly, which is the way to test one today.
Enforcement decides only what the emulator’s own evaluator can see. It is a development aid for catching missing permissions early, not a security control.
Summary
| Category | ✅ Supported | ⚠️ Partial |
|---|---|---|
| Users | 5 | |
| Access keys | 3 | |
| User inline policies | 4 | |
| User managed policies | 3 | |
| Permissions boundaries | 4 | |
| User tagging | 3 | |
| Roles | 7 | |
| Role inline policies | 4 | |
| Role managed policies | 3 | |
| Role tagging | 3 | |
| Managed policy tagging | 3 | |
| Instance profile tagging | 3 | |
| Instance profiles | 7 | |
| Managed policies | 4 | 1 |
| Groups | 7 | |
| Group inline policies | 4 | |
| Group managed policies | 3 | |
| Policy simulation | 2 | |
| Account details | 1 |
Endpoints
Users
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateUser | ✅ Supported | Inline Tags applied at creation | docs |
GetUser | ✅ Supported | docs | |
ListUsers | ✅ Supported | docs | |
UpdateUser | ✅ Supported | docs | |
DeleteUser | ✅ Supported | DeleteConflict (409) while access keys, inline or attached policies, or group memberships remain | docs |
Access keys
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateAccessKey | ✅ Supported | Generates AKIA-prefixed key + secret | docs |
ListAccessKeys | ✅ Supported | docs | |
DeleteAccessKey | ✅ Supported | docs |
User inline policies
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
PutUserPolicy | ✅ Supported | docs | |
GetUserPolicy | ✅ Supported | docs | |
DeleteUserPolicy | ✅ Supported | docs | |
ListUserPolicies | ✅ Supported | docs |
User managed policies
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
AttachUserPolicy | ✅ Supported | docs | |
DetachUserPolicy | ✅ Supported | docs | |
ListAttachedUserPolicies | ✅ Supported | docs |
Permissions boundaries
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
PutUserPermissionsBoundary | ✅ Supported | Applied by SimulatePrincipalPolicy and by opt-in enforcement; NoSuchEntity if the policy does not exist | docs |
DeleteUserPermissionsBoundary | ✅ Supported | docs | |
PutRolePermissionsBoundary | ✅ Supported | Applied by SimulatePrincipalPolicy and by opt-in enforcement; NoSuchEntity if the policy does not exist | docs |
DeleteRolePermissionsBoundary | ✅ Supported | docs |
User tagging
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
TagUser | ✅ Supported | docs | |
UntagUser | ✅ Supported | docs | |
ListUserTags | ✅ Supported | docs |
Roles
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateRole | ✅ Supported | Inline Tags applied at creation | docs |
GetRole | ✅ Supported | docs | |
ListRoles | ✅ Supported | docs | |
DeleteRole | ✅ Supported | DeleteConflict (409) while an instance profile association or inline/attached policies remain | docs |
UpdateRole | ✅ Supported | An empty Description clears it; an omitted one is left unchanged | docs |
UpdateAssumeRolePolicy | ✅ Supported | docs | |
CreateServiceLinkedRole | ✅ Supported | docs |
Role inline policies
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
PutRolePolicy | ✅ Supported | docs | |
GetRolePolicy | ✅ Supported | docs | |
ListRolePolicies | ✅ Supported | docs | |
DeleteRolePolicy | ✅ Supported | docs |
Role managed policies
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
AttachRolePolicy | ✅ Supported | docs | |
DetachRolePolicy | ✅ Supported | docs | |
ListAttachedRolePolicies | ✅ Supported | docs |
Role tagging
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
TagRole | ✅ Supported | docs | |
UntagRole | ✅ Supported | docs | |
ListRoleTags | ✅ Supported | docs |
Managed policy tagging
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
TagPolicy | ✅ Supported | docs | |
UntagPolicy | ✅ Supported | docs | |
ListPolicyTags | ✅ Supported | docs |
Instance profile tagging
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
TagInstanceProfile | ✅ Supported | docs | |
UntagInstanceProfile | ✅ Supported | docs | |
ListInstanceProfileTags | ✅ Supported | docs |
Instance profiles
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateInstanceProfile | ✅ Supported | Inline Tags applied at creation | docs |
GetInstanceProfile | ✅ Supported | docs | |
DeleteInstanceProfile | ✅ Supported | docs | |
AddRoleToInstanceProfile | ✅ Supported | docs | |
RemoveRoleFromInstanceProfile | ✅ Supported | docs | |
ListInstanceProfiles | ✅ Supported | docs | |
ListInstanceProfilesForRole | ✅ Supported | docs |
Managed policies
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreatePolicy | ✅ Supported | Inline Tags applied at creation | docs |
GetPolicy | ✅ Supported | docs | |
ListPolicies | ✅ Supported | docs | |
DeletePolicy | ✅ Supported | DeleteConflict (409) while the policy is attached to any user, role or group, or used as one of their permissions boundaries | docs |
CreatePolicyVersion | ⚠️ Partial | SetAsDefault=true replaces the operative document and bumps DefaultVersionId; superseded versions are not retained and cannot be read back | docs |
Groups
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
CreateGroup | ✅ Supported | docs | |
GetGroup | ✅ Supported | Returns the group’s members, paginated with Marker/MaxItems (default 100, max 1000) | docs |
DeleteGroup | ✅ Supported | DeleteConflict (409) while members or inline/attached policies remain | docs |
ListGroups | ✅ Supported | docs | |
AddUserToGroup | ✅ Supported | docs | |
RemoveUserFromGroup | ✅ Supported | docs | |
ListGroupsForUser | ✅ Supported | docs |
Group inline policies
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
PutGroupPolicy | ✅ Supported | docs | |
GetGroupPolicy | ✅ Supported | docs | |
DeleteGroupPolicy | ✅ Supported | docs | |
ListGroupPolicies | ✅ Supported | docs |
Group managed policies
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
AttachGroupPolicy | ✅ Supported | docs | |
DetachGroupPolicy | ✅ Supported | docs | |
ListAttachedGroupPolicies | ✅ Supported | docs |
Policy simulation
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
SimulatePrincipalPolicy | ✅ Supported | Real evaluation of the principal’s identity policies (plus an optional ResourcePolicy and permissions boundary): allowed / explicitDeny / implicitDeny with MatchedStatements and MissingContextValues | docs |
SimulateCustomPolicy | ✅ Supported | Evaluates the supplied PolicyInputList without touching any stored entity | docs |
Account details
| Operation | Status | Notes | AWS Docs |
|---|---|---|---|
GetAccountAuthorizationDetails | ✅ Supported | Returns all users, groups, roles, and managed policies in one call | docs |