Skip to content
Linuxbeast
Subscribe
  • Home
  • Today in Tech
  • Who is Hiring?
  • About Me
  • Work With Me
  • Lab
    • DevOps Onboarding
    • Tag Network
    • Tools
      • VPC Subnet Planner
  • Contact
Subscribe
Home › AWS › How to Copy S3 Bucket Objects Across AWS Accounts
AWS

How to Copy S3 Bucket Objects Across AWS Accounts

When you manage multiple AWS accounts, you'll eventually need to copy S3 bucket objects across AWS accounts — for data migrations, backups, or sharing…

Linuxbeast Developer May 16, 2024 4 min read 1.1K views
How to Copy S3 Bucket Objects Across AWS Accounts
Share:
In This Article
Prerequisites› Method 1: Bucket Policy (Simplest)› Fixing Object Ownership› Method 2: AssumeRole›

How to Copy S3 Bucket Objects Across AWS Accounts

March 9, 2026May 16, 2024 by Linuxbeast Developer
4 min read
1.1K views

When you manage multiple AWS accounts, you’ll eventually need to copy S3 bucket objects across AWS accounts — for data migrations, backups, or sharing data between environments. This guide covers two approaches: a simple bucket policy method and an AssumeRole method for tighter access control.

The examples here are run on WSL2 Ubuntu in Windows, but the AWS CLI commands work the same on any system.

Advertisement

Prerequisites

  • AWS CLI v2 installed and configured with profiles for both accounts
  • The source bucket name and the destination bucket name
  • IAM permissions to modify bucket policies (source account) and write to S3 (destination account)

In the examples below:

  • Account A (111111111111) — source account, owns the bucket with the data
  • Account B (222222222222) — destination account, where you want to copy the data

Method 1: Bucket Policy (Simplest)

This is the fastest approach. You add a policy to the source bucket that grants Account B read access, then run aws s3 sync from Account B.

1. Add a bucket policy on the source bucket (Account A)

In Account A, add this bucket policy to allow Account B to list and read objects:

Advertisement
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::222222222222:root"
            },
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::source-bucket"
        },
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::222222222222:root"
            },
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::source-bucket/*"
        }
    ]
}

Note that s3:ListBucket applies to the bucket ARN (no /*), while s3:GetObject applies to the objects ARN (with /*). Mixing these up is a common cause of AccessDenied errors.

2. Grant S3 permissions in the destination account (Account B)

The IAM user or role in Account B that runs the copy command needs permission to read from the source bucket and write to the destination bucket. Attach this policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::source-bucket",
                "arn:aws:s3:::source-bucket/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::destination-bucket",
                "arn:aws:s3:::destination-bucket/*"
            ]
        }
    ]
}

3. Copy the objects from Account B

From Account B, sync the entire source bucket to the destination:

aws s3 sync s3://source-bucket s3://destination-bucket --profile account-b

To copy a single object or a prefix:

aws s3 cp s3://source-bucket/data/export.csv s3://destination-bucket/data/export.csv --profile account-b
aws s3 sync s3://source-bucket/logs/2025/ s3://destination-bucket/logs/2025/ --profile account-b

Fixing Object Ownership

By default, when Account B copies objects from Account A’s bucket, Account A still owns the objects — even though they’re now in Account B’s bucket. This means Account B may not be able to read or manage the copied objects.

The fix depends on whether the destination bucket uses Bucket owner enforced (the default for new buckets) or the legacy ACL model:

New buckets (Bucket owner enforced — default)

If the destination bucket was created with the default settings (ACLs disabled, “Bucket owner enforced”), Account B automatically owns all objects written to the bucket. No extra flags needed.

Older buckets (ACLs enabled)

If the destination bucket has ACLs enabled, add the --acl bucket-owner-full-control flag to transfer ownership:

aws s3 sync s3://source-bucket s3://destination-bucket \
  --acl bucket-owner-full-control \
  --profile account-b

This grants Account B full control over the copied objects. Without this flag on ACL-enabled buckets, the objects belong to Account A and Account B can’t access them.

Method 2: AssumeRole

If you can’t modify the source bucket policy (maybe you don’t have admin access to Account A), use AssumeRole instead. Account A creates a role that Account B can assume, and Account B runs the copy using that role’s temporary credentials.

This approach is covered in detail in How to Set Up Cross-Account Access in AWS with AssumeRole. The short version:

  1. Account A creates an IAM role with S3 read permissions and a trust policy allowing Account B
  2. Account B adds a profile in ~/.aws/config that assumes the role
  3. Account B runs the sync using that profile

Add this to ~/.aws/config in Account B:

[profile account-a-s3-reader]
role_arn = arn:aws:iam::111111111111:role/S3CrossAccountReader
source_profile = account-b

Then run the sync using the assumed role profile to read from Account A, and write to Account B’s bucket:

aws s3 sync s3://source-bucket s3://destination-bucket --profile account-a-s3-reader

Verify the Transfer

List the destination bucket and compare object counts:

aws s3 ls s3://source-bucket --recursive --summarize --profile account-a-s3-reader
aws s3 ls s3://destination-bucket --recursive --summarize --profile account-b

The --summarize flag shows the total number of objects and size at the end of the output. Both counts should match.

Troubleshooting

Error Cause
AccessDenied on ListBucket The bucket policy is missing s3:ListBucket on the bucket ARN (without /*)
AccessDenied on GetObject The bucket policy is missing s3:GetObject on the objects ARN (with /*)
Objects copied but can’t be read in destination Object ownership issue — use --acl bucket-owner-full-control or enable “Bucket owner enforced” on the destination bucket
KMS.AccessDeniedException Source objects are encrypted with a KMS key. Add kms:Decrypt permission for the source key and kms:GenerateDataKey for the destination key
Copy is slow for many small files Use aws s3 sync instead of aws s3 cp --recursive — sync skips files that already exist and haven’t changed

Conclusion

For most cases, the bucket policy method is all you need — add a policy to the source bucket, then aws s3 sync from the destination account. Use AssumeRole when you can’t modify the source bucket policy or need stricter access control.

For other cross-account patterns, see How to Access AWS Secrets Manager from Another Account or Setting Up Cross-Account S3 Upload with Lambda.

Advertisement

On This Page
Prerequisites Method 1: Bucket Policy (Simplest) 1. Add a bucket policy on the source bucket (Account A) 2. Grant S3 permissions in the destination account (Account B) 3. Copy the objects from Account B Fixing Object Ownership New buckets (Bucket owner enforced — default) Older buckets (ACLs enabled) Method 2: AssumeRole Verify the Transfer Troubleshooting Conclusion

Key Takeaways

  • AWS CLI v2 installed and configured with profiles for both accounts
  • The source bucket name and the destination bucket name
  • IAM permissions to modify bucket policies (source account) and write to S3 (destination account)

Tags

AssumeRole AWS CLI Bucket Policy Cross-Account IAM S3

Level Up Your DevOps Skills

Practical guides, tutorials, and real-world best practices delivered weekly.

No spam, ever. Unsubscribe anytime.

Popular Articles

How to Mount S3 Bucket on Ubuntu with s3fs-fuse How to Mount S3 Bucket on Ubuntu 22.04 with S3FS Fuse 9.9K views How to Fix WSL CreateVm/HCS/ERROR_FILE_NOT_FOUND on Windows How to Fix WSL CreateVm/HCS/ERROR_FILE_NOT_FOUND on Windows 6.5K views How to Install and Configure Claude Code CLI on Windows PowerShell How to Install and Configure Claude Code CLI on Windows PowerShell 5.6K views How to Install Ubuntu in WSL 2 on Windows 10 and 11 How to Install Ubuntu in WSL 2 on Windows 10 and Windows 11 5.3K views How to Configure MCP Servers in VS Code, Claude Desktop, and Claude Code on WSL How to Configure MCP Servers in VS Code, Claude Desktop, and Claude Code on WSL 4.5K views
Advertisement
How to Add and Delete Users on Ubuntu (EC2, WSL, or Any Server)← PreviousHow to Add and Delete Users on Ubuntu (EC2, WSL, or Any Server)Next →How to Combine All Commits into One with GitLens Interactive Rebase in VSCodeHow to Combine All Commits into One with GitLens Interactive Rebase in VSCode

Related Articles

How to Copy Files to Amazon EC2 Ubuntu Instance Using Rsync
AWS

How to Copy Files to Amazon EC2 Ubuntu Instance Using Rsync

2.1K views  •  May 3, 2024
How to Add and Delete Users on Ubuntu (EC2, WSL, or Any Server)
AWS

How to Add and Delete Users on Ubuntu (EC2, WSL, or Any Server)

818 views  •  May 16, 2024
Automate-Internal-Workflows-with-REST-APIs-diagram
AWS

How to Automate Internal Workflows with REST APIs — Without Writing a Backend

294 views  •  Apr 28, 2026
linuxbeast-logo

Built for DevOps, Cloud & Automation.

Popular Topics

  • AWS
  • WSL & Windows
  • Git
  • DevOps
  • Developer Tools
  • Programming

Resources

  • Home
  • Today in Tech
  • Who is Hiring?
  • About Me
  • Work With Me
  • Contact

Legal

  • Privacy Policy
  • Cookie Policy

Stay updated with LinuxBeast

Get the best Linux, DevOps, and Cloud content delivered to your inbox.

No spam, ever. Unsubscribe anytime.

© 2026 LinuxBeast. All rights reserved. Made with ♥ for the DevOps community.
© 2026 Linuxbeast · All rights reserved.
Manage Consent
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes. The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.
  • Manage options
  • Manage services
  • Manage {vendor_count} vendors
  • Read more about these purposes
View preferences
  • {title}
  • {title}
  • {title}
Esc to closeCtrl+K to open