Keep this bookmarked
This is a reference you will come back to whenever you write, review, or audit IAM policies. It is designed for scanning, not reading end to end. Use it as a lookup when you need the exact syntax, the correct ARN format, or the right condition key for a policy you are writing.
Every IAM policy follows this skeleton. The annotated version below shows every field you will encounter:
{
"Version": "2012-10-17",
"Id": "OptionalPolicyId",
"Statement": [
{
"Sid": "HumanReadableStatementId",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:role/ExampleRole"
},
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-bucket",
"arn:aws:s3:::my-bucket/*"
],
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-exampleorgid"
}
}
}
]
}
| Field | Required | Notes |
|---|---|---|
| Version | Yes | Always "2012-10-17". This is the policy language version, not a date you choose. |
| Id | No | Optional identifier for the policy. Used mainly in resource-based policies. |
| Statement | Yes | Array of one or more permission blocks. Each is evaluated independently. |
| Sid | No | Statement ID. Human-readable label. Use it — it makes policies auditable. |
| Effect | Yes | "Allow" or "Deny". Only two options. |
| Principal | Conditional | Required in resource-based and trust policies. Not used in identity-based policies. |
| Action | Yes | One or more API actions in service:ActionName format. Supports wildcards (s3:Get*, s3:*). |
| NotAction | No | Inverse of Action — matches everything except the listed actions. Use carefully. |
| Resource | Yes | One or more ARNs the statement applies to. "*" means all resources. |
| NotResource | No | Inverse of Resource — matches everything except the listed ARNs. Rarely needed. |
| Condition | No | Additional constraints. See condition operators and keys below. |
Every AWS resource has an Amazon Resource Name. The format is:
arn:aws:service:region:account-id:resource-type/resource-id
| Resource | ARN |
|---|---|
| S3 bucket | arn:aws:s3:::my-bucket |
| S3 objects in bucket | arn:aws:s3:::my-bucket/* |
| IAM user | arn:aws:iam::123456789012:user/alice |
| IAM role | arn:aws:iam::123456789012:role/MyRole |
| DynamoDB table | arn:aws:dynamodb:us-east-1:123456789012:table/MyTable |
| Lambda function | arn:aws:lambda:us-east-1:123456789012:function:MyFunction |
| KMS key | arn:aws:kms:us-east-1:123456789012:key/key-id |
| CloudWatch log group | arn:aws:logs:us-east-1:123456789012:log-group:/aws/lambda/my-function:* |
| SQS queue | arn:aws:sqs:us-east-1:123456789012:my-queue |
| SNS topic | arn:aws:sns:us-east-1:123456789012:my-topic |
Note: S3 and IAM ARNs omit the region and account fields (they are global). Most other services require both.
| Service | Common Actions | When GRC Engineers Care |
|---|---|---|
| S3 | GetObject, PutObject, DeleteObject, ListBucket, GetBucketPolicy, PutBucketPolicy | Data access controls, encryption enforcement, public access prevention |
| IAM | CreateUser, CreateRole, AttachRolePolicy, AttachUserPolicy, CreateAccessKey, PutRolePermissionsBoundary | Privilege escalation paths, credential management, delegation controls |
| CloudTrail | StopLogging, DeleteTrail, CreateTrail, PutEventSelectors, GetTrailStatus | Audit log integrity — deny StopLogging and DeleteTrail in SCPs |
| STS | AssumeRole, AssumeRoleWithSAML, AssumeRoleWithWebIdentity, GetSessionToken | Cross-account access, federation, temporary credential issuance |
| KMS | Encrypt, Decrypt, GenerateDataKey, CreateKey, ScheduleKeyDeletion, CreateGrant | Data protection, encryption key lifecycle, key access control |
| Organizations | CreatePolicy, AttachPolicy, LeaveOrganization, DeleteOrganization | SCP management, organizational structure changes |
| Config | StopConfigurationRecorder, DeleteConfigRule, PutConfigRule | Configuration compliance monitoring — deny StopConfigurationRecorder |
| GuardDuty | DeleteDetector, DisableOrganizationAdminAccount, UpdateDetector | Threat detection — deny DeleteDetector and disable actions |
Conditions add constraints beyond Action and Resource. The syntax is:
"Condition": {
"Operator": {
"ConditionKey": "Value"
}
}
| Operator | Type | Use Case |
|---|---|---|
StringEquals | Exact match | Tag values, organization ID, requested region |
StringNotEquals | Negated match | Exclude specific values |
StringLike | Wildcard match | Pattern matching with * and ? |
NumericEquals | Number match | Port numbers, counts |
NumericLessThan | Number comparison | Maximum values |
DateGreaterThan | Date comparison | Time-based access windows |
DateLessThan | Date comparison | Expiration dates |
Bool | Boolean | MFA present, secure transport |
IpAddress | CIDR match | Source IP restrictions |
NotIpAddress | Negated CIDR | Exclude IP ranges |
ArnLike | ARN pattern | Principal ARN matching with wildcards |
ArnEquals | Exact ARN | Principal ARN exact matching |
Null | Key existence | Check if a condition key is present or absent |
| Condition Key | Description | Example Use |
|---|---|---|
aws:SourceIp | Requester's IP address | Restrict API calls to corporate IP range |
aws:PrincipalOrgID | Organization ID of the requester | Ensure access only from your organization |
aws:MultiFactorAuthPresent | Whether MFA was used | Require MFA for sensitive actions |
aws:MultiFactorAuthAge | Seconds since MFA authentication | Require recent MFA for critical operations |
aws:RequestedRegion | Region the action targets | Restrict to approved regions only |
aws:PrincipalTag/key | Tag on the requesting principal | Attribute-based access control (ABAC) |
aws:ResourceTag/key | Tag on the target resource | Restrict actions based on resource tags |
s3:x-amz-server-side-encryption | Encryption header | Deny unencrypted uploads |
aws:SecureTransport | Whether HTTPS was used | Deny non-TLS requests |
aws:PrincipalArn | ARN of the requesting principal | Restrict to specific roles or users |
aws:CalledVia | Service that made the call | Detect service chaining |
kms:ViaService | Service using the KMS key | Restrict which services can use a key |
Principals identify who is allowed or denied access. Used in resource-based and trust policies.
"Principal": { "AWS": "arn:aws:iam::123456789012:root" }
"Principal": { "AWS": "arn:aws:iam::123456789012:role/MyRole" }
"Principal": { "AWS": "arn:aws:iam::123456789012:user/alice" }
"Principal": { "AWS": "123456789012" }
"Principal": { "Service": "lambda.amazonaws.com" }
"Principal": { "Federated": "cognito-identity.amazonaws.com" }
"Principal": "*"
| Principal | Meaning |
|---|---|
| Account root | Any principal in that account |
| Role ARN | Only that specific role |
| User ARN | Only that specific user |
| Account ID | Same as account root — any principal in the account |
| Service | An AWS service (Lambda, EC2, etc.) |
| Federated | An identity provider (Cognito, SAML, OIDC) |
"*" | Anyone — public access. Use with extreme caution. |
| Policy Type | Attaches To | Grants Access? | Can Deny? | Cross-Account? |
|---|---|---|---|---|
| Identity-based (managed) | Users, groups, roles | Yes | Yes | No (source side only) |
| Identity-based (inline) | Users, groups, roles | Yes | Yes | No (source side only) |
| Resource-based | S3 buckets, KMS keys, SQS, SNS, etc. | Yes | Yes | Yes (can grant cross-account) |
| Trust policy | IAM roles | Defines who can assume | No | Yes (specifies cross-account principals) |
| SCP | OUs, accounts | No (restricts only) | Yes | N/A (organization-level) |
| Permission boundary | Users, roles | No (restricts only) | No (limits allow) | No |
| Session policy | Assumed role sessions | No (restricts only) | No (limits allow) | No |
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["us-east-1", "us-west-2"]
}
}
}
{
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
}
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"NotIpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::shared-bucket/*",
"Condition": {
"StringEquals": {
"aws:PrincipalOrgID": "o-exampleorgid"
}
}
}