# AWS permissions per service

> What each profile needs in AWS, read and write, for discovery, preflight and each kind of move.

Each profile acts in its own account: the source profile reads, the
destination profile writes. Grant each one what its side of the move needs.

## Reads for discovery and checks

| Service | Actions |
|---|---|
| STS | `GetCallerIdentity` |
| S3 | `ListBuckets`, `GetBucketLocation` |
| ECR | `DescribeRepositories`, `DescribeImages`, `BatchGetImage` (also covers `ListImageReferrers`) |
| CodeCommit | `BatchGetRepositories`, on both sides, before any Git operation |
| IAM Identity Center | `sso:GetRoleCredentials`, `sso:ListAccounts`, `sso:ListAccountRoles`; `sso-oidc:RegisterClient`, `StartDeviceAuthorization`, `CreateToken`; `sts:AssumeRole` only for a role chained after SSO |

## Optional reads for preflight

`s3:GetEncryptionConfiguration` on both buckets, `ecr:DescribeRepositories` on
the mapped repositories and `kms:DescribeKey` on the keys they name. Douklar
calls `kms:DescribeKey` directly, so do not put it under a `kms:ViaService`
condition. Without these reads, the encryption posture shows "unknown" and the
run is not blocked.

## Per service

| Move | Source profile | Destination profile |
|---|---|---|
| S3, worker relay | `s3:ListBucket`, `s3:GetObject` on the selected scope | `s3:ListBucket`, `s3:PutObject` on the destination scope |
| S3, server-side copy | One copy identity reads the source and writes the destination: the same S3 actions on both buckets | |
| DynamoDB | `dynamodb:DescribeTable`, `DescribeTimeToLive`, `Scan` | `dynamodb:DescribeTable`, `DescribeTimeToLive`, `PutItem` |
| ECR | Pull of the selected image and its referrers | Push and tag in the destination repository |
| CodeCommit | Git pull of the repository | Git push to the existing repository |

Copying an object's own metadata needs no version, tag, ACL or KMS-control
permission. DynamoDB needs no `UpdateTimeToLive`.

## S3 Batch Operations

In the destination account, after you confirm Prepare: `s3:CreateBucket` for
the operations bucket, `iam:CreateRole` and `iam:PutRolePolicy` for the Batch
role, then `s3:PutObject` for the manifest, `s3control:CreateJob` and
`s3control:UpdateJobStatus` (Cancel, and Start for a held job). Set
`S3_BATCH_ROLE_NAME` to use a role you already manage instead.

## Keys

The writing profile needs `kms:GenerateDataKey` and `kms:Decrypt` on the
destination key; the reading profile needs `kms:Decrypt` on the source key. A
key in another account also needs a key-policy statement there. Examples:
[Hand a change to the other account's admin](/docs/douklar/hand-over-to-the-other-account#a-key-in-another-account).

## Log delivery

To deliver audit and run logs to S3: `s3:PutObject` on the configured bucket
and prefix only, plus `kms:GenerateDataKey` when that bucket uses a customer
managed key.

Source: https://douklar.app/docs/douklar/aws-permissions (Douklar docs, last checked 2026-10-18)
