search

S3 Cross-Account Replication with KMS: Step-by-Step Guide

calendar_today Đăng ngày: 14/10/2026

S3 cross-account replication with KMS copies new objects from a source bucket in Account A to a destination bucket in Account B, and re-encrypts them with the destination KMS key. You need versioning on both buckets, one IAM replication role, a destination bucket policy, a destination KMS key policy, and a replication rule.

What do we build in this S3 replication setup?

We build a one-way copy of data from a source bucket to a destination bucket in another AWS account. Both buckets use SSE-KMS, and each bucket uses its own key.

Item Account A (source) Account B (destination)
Account ID SOURCE_ACCOUNT_ID DEST_ACCOUNT_ID
S3 bucket source-bucket-name destination-bucket-name
KMS key source-kms-key destination-kms-key
IAM role s3-replication-role –

How do I create the source KMS key in the console?

Log in to Account A. This key encrypts the objects in the source bucket. Follow these steps.

  1. Open the AWS KMS console. Check that the Region is ap-southeast-1.
  2. Click Create key.
  3. On Configure key:
    • Key type: Symmetric
    • Key usage: Encrypt and decrypt
    • Advanced options → Key material origin: KMS
    • Regionality: Single-Region key

    Click Next.

  4. On Add labels:
    • Alias: source-kms-key
    • Description: Key for the source S3 bucket
    • Tags: optional (for example Name = source-kms-key)

    Click Next.

  5. On Define key administrative permissions: choose the IAM user or role that will manage the key. Keep Allow key administrators to delete this key checked only if you want admins to be able to delete it. Click Next.
  6. On Define key usage permissions: choose the users or roles that use the key. You can skip the replication role for now. Click Next.
  7. On Review: check the key policy. The default policy is fine, because it gives Account A full control through the root principal. Click Finish.
  8. Open the new key and copy the ARN. You need it later.

How do I create the source S3 bucket?

Stay in Account A. The source bucket needs versioning and SSE-KMS. Replication does not work without versioning.

  1. Open the S3 console and click Create bucket.
  2. General configuration:
    • Bucket type: General purpose
    • Bucket name: source-bucket-name (must be globally unique)
    • AWS Region: Asia Pacific (Singapore) ap-southeast-1
  3. Object Ownership: ACLs disabled (recommended).
  4. Block Public Access settings: keep Block all public access checked.
  5. Bucket Versioning: choose Enable.
  6. Tags: optional.
  7. Default encryption:
    • Encryption type: Server-side encryption with AWS Key Management Service keys (SSE-KMS)
    • AWS KMS key: choose Choose from your AWS KMS keys, then select source-kms-key
    • Bucket Key: Enable (this lowers KMS request cost)
  8. Advanced settings → Object Lock: Disable.
  9. Click Create bucket.

How do I create the destination KMS key?

Now log in to Account B. This key will encrypt the copied objects. The steps are the same as the source key, with a different alias.

  1. Open the AWS KMS console in ap-southeast-1 and click Create key.
  2. Configure key: Symmetric, Encrypt and decrypt, Key material origin = KMS, Single-Region key. Click Next.
  3. Add labels:
    • Alias: destination-kms-key
    • Description: Key for the destination S3 bucket

    Click Next.

  4. Choose the key administrators and the key users in Account B. Click Next.
  5. Review and click Finish.
  6. Copy the key ARN. You will paste it into the replication rule in Step 8.

How do I create the destination S3 bucket?

Stay in Account B. The destination bucket also needs versioning, and it uses the destination KMS key.

  1. Open the S3 console and click Create bucket.
  2. Bucket type: General purpose. Bucket name: destination-bucket-name. Region: ap-southeast-1.
  3. Object Ownership: ACLs disabled (recommended).
  4. Block Public Access: keep Block all public access checked.
  5. Bucket Versioning: Enable.
  6. Default encryption: SSE-KMS, select destination-kms-key, and set Bucket Key to Enable.
  7. Click Create bucket.

How do I create the IAM replication role in the source account?

S3 uses this role to read from the source bucket and write to the destination bucket. Create it in Account A. It has a trust policy and a permission policy.

Create the role in the console

  1. Open the IAM console → Roles → Create role.
  2. Trusted entity type: Custom trust policy. Paste the trust policy below.
  3. Click Next, then Create policy in a new tab. Choose the JSON tab and paste the permission policy below. Name it s3-replication-policy.
  4. Back on the role page, attach s3-replication-policy.
  5. Role name: s3-replication-role. Click Create role.

Trust policy

This policy lets the S3 service assume the role.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowServiceAssumeRole",
      "Effect": "Allow",
      "Principal": {
        "Service": "s3.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

Permission policy

This policy has four parts: read the source bucket, write to the destination bucket, decrypt with the source key, and encrypt with the destination key. Replace the placeholder values with yours.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "SourceRead",
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetReplicationConfiguration",
        "s3:GetObjectVersionForReplication",
        "s3:GetObjectVersionAcl",
        "s3:GetObjectVersionTagging",
        "s3:GetObjectVersionAnnotationForReplication",
        "s3:GetObjectRetention",
        "s3:GetObjectLegalHold"
      ],
      "Condition": {
        "StringEquals": {
          "aws:ResourceAccount": "SOURCE_ACCOUNT_ID"
        }
      },
      "Resource": [
        "arn:aws:s3:::source-bucket-name",
        "arn:aws:s3:::source-bucket-name/*"
      ]
    },
    {
      "Sid": "DestinationReplicate",
      "Effect": "Allow",
      "Action": [
        "s3:ReplicateObject",
        "s3:ReplicateDelete",
        "s3:ReplicateTags",
        "s3:ReplicateObjectAnnotation",
        "s3:GetObjectVersionTagging",
        "s3:ObjectOwnerOverrideToBucketOwner"
      ],
      "Condition": {
        "StringEquals": {
          "aws:ResourceAccount": [
            "DEST_ACCOUNT_ID"
          ]
        },
        "StringLikeIfExists": {
          "s3:x-amz-server-side-encryption": [
            "aws:kms",
            "aws:kms:dsse",
            "AES256"
          ]
        }
      },
      "Resource": [
        "arn:aws:s3:::destination-bucket-name/*"
      ]
    },
    {
      "Sid": "KmsDecryptSource",
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt"
      ],
      "Condition": {
        "StringLike": {
          "kms:EncryptionContext:aws:s3:arn": [
            "arn:aws:s3:::source-bucket-name",
            "arn:aws:s3:::source-bucket-name/*"
          ],
          "kms:ViaService": "s3.ap-southeast-1.amazonaws.com"
        }
      },
      "Resource": "arn:aws:kms:ap-southeast-1:SOURCE_ACCOUNT_ID:key/SOURCE_KMS_KEY_ID"
    },
    {
      "Sid": "KmsEncryptDestination",
      "Effect": "Allow",
      "Action": [
        "kms:Encrypt"
      ],
      "Condition": {
        "StringLike": {
          "kms:EncryptionContext:aws:s3:arn": [
            "arn:aws:s3:::destination-bucket-name",
            "arn:aws:s3:::destination-bucket-name/*"
          ],
          "kms:ViaService": [
            "s3.ap-southeast-1.amazonaws.com"
          ]
        }
      },
      "Resource": "arn:aws:kms:ap-southeast-1:DEST_ACCOUNT_ID:key/DEST_KMS_KEY_ID"
    }
  ]
}

How do I set the bucket policy on the destination bucket?

The destination bucket must trust the replication role from Account A. Without this policy, S3 gets an access denied error when it writes the copy.

In Account B, go to S3 → destination-bucket-name → Permissions → Bucket policy → Edit, paste this policy, and click Save changes.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowSourceReplication",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::SOURCE_ACCOUNT_ID:role/s3-replication-role"
      },
      "Action": [
        "s3:ReplicateObject",
        "s3:ReplicateDelete",
        "s3:ReplicateTags",
        "s3:ObjectOwnerOverrideToBucketOwner",
        "s3:GetBucketVersioning",
        "s3:PutBucketVersioning"
      ],
      "Resource": [
        "arn:aws:s3:::destination-bucket-name",
        "arn:aws:s3:::destination-bucket-name/*"
      ]
    }
  ]
}

How do I set the KMS key policy on the destination key?

The destination key must allow the replication role to encrypt data. This is the most common step people forget in a cross-account S3 replication with KMS.

In Account B, open KMS → Customer managed keys → destination-kms-key → Key policy → Edit. Use this policy, then click Save changes.

{
  "Version": "2012-10-17",
  "Id": "key-consolepolicy-3",
  "Statement": [
    {
      "Sid": "Enable IAM User Permissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::DEST_ACCOUNT_ID:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "AllowSourceReplicationRoleEncrypt",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::SOURCE_ACCOUNT_ID:role/s3-replication-role"
      },
      "Action": [
        "kms:Encrypt",
        "kms:GenerateDataKey",
        "kms:GenerateDataKey*",
        "kms:ReEncrypt*",
        "kms:DescribeKey"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "s3.ap-southeast-1.amazonaws.com"
        }
      }
    }
  ]
}

Keep the Enable IAM User Permissions statement. If you remove it, you can lock Account B out of its own key.

How do I create the replication rule on the source bucket?

The rule tells S3 what to copy and where to send it. Log in to Account A and follow these steps.

  1. Go to S3 → source-bucket-name → Management tab → Replication rules → Create replication rule.
  2. Replication rule name: for example replicate-to-account-b. Set Status to Enabled.
  3. Source bucket → Choose a rule scope: select Limit the scope of this rule using one or more filters. In Prefix, enter your folder, for example logs/. Leave the prefix empty if you want to copy the whole bucket.
  4. Destination: select Specify a bucket in another account.
    • Account ID: DEST_ACCOUNT_ID
    • Bucket name: destination-bucket-name
    • Optional: check Change object ownership to destination bucket owner. This matches the s3:ObjectOwnerOverrideToBucketOwner permission in our policies.
  5. IAM role: choose Choose from existing IAM roles, then select s3-replication-role.
  6. Encryption: check Replicate objects encrypted with AWS KMS.
    • Source objects: keep the source key source-kms-key selected.
    • AWS KMS key for encrypting destination objects: choose Enter AWS KMS key ARN and paste the ARN of destination-kms-key.
  7. Destination storage class: keep the default (same as source).
  8. Additional replication options: leave the defaults, unless you need delete marker replication or metrics.
  9. Click Save. If the console asks Replicate existing objects?, choose No, do not replicate existing objects. S3 replication only copies new objects by default.

How do I test that S3 replication works?

Upload a new file to the source bucket and check the destination bucket. Replication usually takes a few seconds to a few minutes.

  1. In Account A, open source-bucket-name and upload a small file under your prefix, for example logs/test.txt.
  2. Click the file and check Replication status. It should change from PENDING to COMPLETED.
  3. In Account B, open destination-bucket-name and check that logs/test.txt is there.
  4. Click the file and check Server-side encryption settings. It should show destination-kms-key.

If the status shows FAILED, check these points first:

  • Versioning is enabled on both buckets.
  • The role name and account IDs in both policies are correct.
  • The destination KMS ARN in the rule is correct.
  • The destination KMS key policy allows the replication role.