Skip to main content

Set up S3 access with cross-account IAM role

TL;DR

The production-recommended way to connect Atlan to Amazon S3 - Atlan temporarily assumes a role in your AWS account, with no secret created or exchanged.

Connect

The production-recommended method: Atlan temporarily assumes a role in your AWS account. Five phases, each labeled with who performs it. No secret is created or exchanged.

New to IAM?

Read How cross-account access works first (5 minutes). It explains every term below - role, trust policy, External ID, AssumeRole - and the two-sided handshake this guide walks through.

Prerequisites

  • Someone with rights to create IAM roles and policies in the AWS account that owns the buckets.
  • The list of buckets (and prefixes, if you're scoping) you want cataloged, and each bucket's region.
  • If buckets use SSE-KMS encryption: someone who can edit the KMS key policy (Door 4).
  • More than ~1 million objects? Set up inventory reports first.

Five phases at glance

PhaseWhat happensOwnerTypical time
1. GatherGet Atlan's Node Instance Role ARN + account IDAtlan User + Atlan support1 business day (ticket)
2. PolicyCreate the S3 permission policyYour AWS admin15 minutes
3. RoleCreate the role: trust policy + External IDYour AWS admin15 minutes
4. AllowlistAtlan configures its side to assume your roleAtlan support1 business day (same ticket)
5. Connect & verifyEnter role ARN + External ID + region in the crawler; testAtlan User30 minutes

Phase 1 - Gather Atlan's identity

Owner: Atlan User + Atlan support

Raise a support request from within Atlan with your tenant URL. Use the three-part ask from Atlan identity details - ARN, account ID, and a heads-up that your role ARN is coming in Phase 4. Support replies with the Node Instance Role ARN, e.g. (illustrative):

arn:aws:iam::999988887777:role/example-tenant-nodeinstance-role
This ARN never goes in the crawler form

Atlan's Node Instance Role ARN belongs in your trust policy only (Phase 3). In the crawler's "IAM Role" field you will enter your own role's ARN (Phase 5). Pasting Atlan's ARN into the crawler field makes the connection catalog Atlan's internal buckets instead of yours.

Phase 2 - Create permission policy

Owner: Your AWS admin

In the AWS IAM console, create a policy (suggested name: AtlanS3CrawlerPolicy). This variant covers buckets, folders, and objects - trim per the scope table if you're cataloging less:

{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AtlanListAllBuckets",
"Effect": "Allow",
"Action": ["s3:ListAllMyBuckets"],
"Resource": "*"
},
{
"Sid": "AtlanReadBucketAndObjects",
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation", "s3:GetBucketTagging",
"s3:GetEncryptionConfiguration", "s3:GetBucketVersioning",
"s3:ListBucket",
"s3:GetObject", "s3:GetObjectTagging",
"s3:GetObjectRetention", "s3:GetObjectLegalHold"
],
"Resource": [
"arn:aws:s3:::example-data-bucket",
"arn:aws:s3:::example-data-bucket/*"
]
}
]
}

The ListAllMyBuckets statement must stay on "Resource": "*" - AWS ignores it when scoped to a bucket. Add s3:SelectObjectContent on the inventory destination bucket if using inventory ingestion.

The two rows people trim - and regret

s3:GetObjectRetention and s3:GetObjectLegalHold look exotic, but the crawler requests them for object metadata. Removing them produces mid-crawl AccessDenied errors even though Test connection passed.

Phase 3 - Create role and its trust policy

Owner: Your AWS admin

Create a role (suggested name: AtlanS3CrawlerRole), attach the Phase 2 policy, and set the trust policy to Atlan's Node Instance Role from Phase 1, with an External ID your team invents:

{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::999988887777:role/example-tenant-nodeinstance-role" },
"Action": "sts:AssumeRole",
"Condition": { "StringEquals": { "sts:ExternalId": "example-corp-atlan-2026" } }
}]
}
About the External ID

You choose the string - treat it like a shared passphrase, not a secret. It's strongly recommended for production (it prevents the "confused deputy" problem). Caveat: the S3 crawler form accepts an External ID, but some package workflows (e.g. Asset Import) cannot send one today - if you'll use those with the same role, see Special cases before adding the condition.

Phase 4 - Atlan allowlists your role

Owner: Atlan support

Reply on your Phase 1 ticket with your role ARN (e.g. arn:aws:iam::111122223333:role/AtlanS3CrawlerRole), your AWS account ID, and your External ID. Atlan grants its Node Instance Role permission to assume exactly your role, and confirms on the ticket.

Do not skip this phase

If Atlan's side isn't configured, the role borrow fails silently and Test connection shows AuthorizationHeaderMalformed: ... a non-empty Access Key (AKID) must be provided - an error that looks like your fault but isn't. This is among the most-misdiagnosed S3 failures.

Phase 5 - Connect and verify

Owner: Atlan User

  1. In Atlan, open New workflow → Amazon S3 Assets.
  2. Choose IAM Role authentication. Enter your role's ARN (not Atlan's!), your External ID (must match Phase 3 exactly), and the AWS region of your buckets.
  3. Click Test Authentication.
  4. Configure bucket/prefix filters (see prefix scoping) and choose direct or inventory ingestion.

Success checklist

  • Test Authentication passes in the Atlan UI
  • Preflight checks pass when you configure the crawler
  • A crawl scoped to one small bucket or prefix completes
  • A full crawl completes - the first real exercise of the GetObject* permissions and (if applicable) the KMS key

All four green? Done. If any step fails, see Troubleshooting S3 connectivity - it maps each verbatim error string to its door and fix.

Next steps

Crawl S3: Configure and run the crawler to extract metadata from Amazon S3