AWS has hundreds of services, each with its own resources, spread across dozens of Regions and however many accounts an organization runs. An S3 bucket named logs in one account has nothing to do with a bucket of the same name in another — names alone can't identify a resource uniquely across all of AWS. An ARN is the string that can.
The short definition
An Amazon Resource Name (ARN) is a string that uniquely identifies one AWS resource, anywhere in AWS. You'll see it wherever a policy, API call, or template needs to point at a specific resource without ambiguity — an IAM policy's Resource element (see IAM Policy Basics for the rest of that document's anatomy), a CloudFormation output, a CLI command's --resource-arn flag. Per AWS's own documentation, ARNs aren't secret — they're identifiers, safe to log and share, the same way a URL is.
The format
arn:partition:service:region:account-id:resource-id
arn:partition:service:region:account-id:resource-type/resource-id
arn:partition:service:region:account-id:resource-type:resource-id- partition — which group of Regions the resource lives in:
aws(standard),aws-cn(China), oraws-us-gov(GovCloud). Almost everything you'll ever see isaws. - service — the service namespace, like
s3,iam, orlambda. - region — a Region code like
us-east-1. Some services are global and leave this empty. - account-id — the 12-digit AWS account that owns the resource, no hyphens. Also sometimes empty.
- resource — everything after the fifth colon. Depending on the service, this is a bare ID, a
type/idpair, or atype:idpair — and it can itself contain more colons or slashes.
Three different resources, three different shapes for that last field:
arn:aws:sns:us-east-1:123456789012:example-topic
arn:aws:ec2:us-east-1:123456789012:vpc/vpc-0e9801d129EXAMPLE
arn:aws:lambda:us-east-1:123456789012:function:my-function:1The Lambda example is worth noticing on its own: the resource part has two colons in it (function:my-function:1, a type, a name, and a version). Code that naively splits an ARN into exactly six colon-separated pieces breaks on this one — see How to Parse an ARN for the actual fix.
Fields that are allowed to be empty
region and account-id aren't always present, and an empty field isn't a malformed ARN. IAM is a global service, so IAM ARNs have no region: arn:aws:iam::123456789012:user/john. S3 bucket names are globally unique on their own, so S3 ARNs skip both region and account: arn:aws:s3:::amzn-s3-demo-bucket. Route 53 and CloudFront work the same way. If you're parsing ARNs yourself, check for an empty string in that position, not a missing field — the colons are still there.
Paths and wildcards
A resource identifier can include a path — an S3 object key with forward slashes, or an IAM user/role path. IAM paths are restricted to alphanumerics plus / + = , . @ _ -. Inside a Resource or NotResource policy element (never Principal), an ARN can also use * to match any number of characters or ? to match exactly one — arn:aws:iam::123456789012:role/* means every role in that account. Wildcards can appear inside any colon-delimited segment, not just the resource — an ARN like arn:aws:ec2:*:123456789012:volume/* matches every EBS volume in every Region for that account.
One AWS-specific quirk worth knowing: in an identity-based policy, an incomplete ARN — one with fewer than six fields — gets automatically padded with wildcards for the missing fields. Writing arn:aws:sqs is equivalent to arn:aws:sqs:*:*:*, granting access to every SQS resource in every Region and account. This auto-completion doesn't happen in session policies passed to AssumeRole and similar STS calls — an incomplete ARN there raises a MalformedPolicyDocumentException instead.
Where you'll run into ARNs
Beyond IAM policies, ARNs show up as the value CloudFormation's Ref and Fn::GetAtt often resolve to, as identifiers in cross-service configuration (an SNS topic ARN in an S3 event notification, a KMS key ARN in an encryption setting), and as the resource identifier passed to almost every AWS CLI and SDK call that operates on a specific, existing resource rather than creating a new one.
Try it yourself
Paste a real ARN into ARN Parser to see every field broken out, with warnings for a malformed account ID or an unrecognized partition — entirely in your browser. If you're writing code to parse ARNs yourself, see How to Parse an ARN for the common bug a naive split or regex hits.