How to Fix “Access Denied” When Cross-Account Syncing Between S3 Buckets Using AWS CLI


10 views

When attempting to sync between S3 buckets across different AWS accounts, the error AccessDenied when calling the ListObjects operation typically indicates insufficient IAM permissions or bucket policy misconfiguration. Let's break down the proper setup:

// Required bucket policy on SOURCE bucket
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::DESTINATION_ACCOUNT_ID:user/DESTINATION_IAM_USER"
      },
      "Action": [
        "s3:ListBucket",
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::SOURCE_BUCKET_NAME",
        "arn:aws:s3:::SOURCE_BUCKET_NAME/*"
      ]
    }
  ]
}

The IAM user executing the sync command needs these minimum permissions:

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

The complete sync command should include proper region specification and optional parameters:

aws s3 sync s3://SOURCE_BUCKET_NAME/ s3://DESTINATION_BUCKET_NAME/ \
  --region eu-central-1 \
  --source-region us-west-2 \
  --delete \
  --exclude "*.tmp" \
  --include "*.jpg"

If you still encounter access denied errors:

  • Verify AWS credentials are configured properly using aws configure list
  • Check for S3 Block Public Access settings that might override permissions
  • Ensure bucket policies don't have explicit Deny statements
  • Confirm the IAM user has sts:AssumeRole permission if using role switching

For large-scale sync operations, consider S3 Batch Operations:

// Create manifest file
{
  "Rules": [
    {
      "Id": "CopyRule",
      "Status": "Enabled",
      "Prefix": "",
      "Destination": {
        "Bucket": "arn:aws:s3:::DESTINATION_BUCKET_NAME"
      }
    }
  ]
}

When working with multiple AWS accounts, syncing data between S3 buckets often hits permission barriers. The error message:

fatal error: An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied

typically appears even after setting up basic bucket policies, indicating deeper IAM configuration requirements.

The aws s3 sync command requires more extensive permissions than aws s3 cp because it needs to:

  • List source bucket contents (ListBucket)
  • Read source objects (GetObject)
  • List destination bucket (ListBucket)
  • Write to destination (PutObject)

For the source bucket, implement this expanded policy:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::DESTINATION_ACCOUNT_ID:user/DESTINATION_IAM_USER"
            },
            "Action": [
                "s3:ListBucket",
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::SOURCE_BUCKET",
                "arn:aws:s3:::SOURCE_BUCKET/*"
            ]
        }
    ]
}

The destination IAM user needs these permissions:

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

With permissions properly configured, the sync command should work:

aws s3 sync s3://SOURCE_BUCKET s3://DESTINATION_BUCKET \
    --source-region SOURCE_REGION \
    --region DESTINATION_REGION \
    --acl bucket-owner-full-control
  • Enable S3 access logs for both buckets
  • Use --debug flag with AWS CLI
  • Verify IAM user has no explicit deny policies
  • Check bucket encryption requirements match