Skip to content

cp (local→S3) fails with BadRequest 400 on KMS-encrypted cross-account bucket  #865

@swapnilkamthe

Description

@swapnilkamthe

Bug Report

Description

s5cmd cp (local → S3) fails with BadRequest 400 when uploading to a cross-account
S3 bucket with default SSE-KMS encryption. All IAM, KMS, and bucket permissions are
verified correct. The same operation succeeds with AWS CLI using the same IAM role.


Steps to Reproduce

  1. Run a container in Account A (us-east-1)
  2. Download files from a source S3 bucket to local disk using s5cmd
  3. Upload local files to a KMS-encrypted S3 bucket in Account B (eu-west-1):
    s5cmd --json cp /tmp/staging/part-00000-xxxx.snappy.parquet \                                                                                                                                                                     
      s3://account-b-bucket/data/part-00000-xxxx.snappy.parquet                                                                                                                                                                       

Expected Behavior

File uploads successfully to the destination bucket using the bucket's default KMS encryption.


Actual Behavior

{
  "operation": "cp",
  "command": "cp /tmp/staging/part-00000-xxxx.snappy.parquet s3://account-b-bucket/data/part-00000-xxxx.snappy.parquet",
  "error": "BadRequest: Bad Request\n\tstatus code: 400, request id: N2E3G725KKPRC61S, host id: wXOiImny5jJFhh+3DrHyCvC1NcnK8IIugRcTlfzNbzRGOafK6oJNCTZ4+g5xKaHhtkLSlKjmC4GaxK3yhYf0hAZB+WiQcTfF"                                     
}                                                                                                                                                                                                                                     
                                                                                                                                                                                                                                      
---                                                                                                                                                                                                                                   
Environment                                           

- s5cmd version: pip-installed (pip install s5cmd)
- Platform: AWS Batch Fargate (Linux/amd64)
- Source: Account A (111111111111), us-east-1                                                                                                                                                                                         
- Destination: Account B (222222222222), eu-west-1
- Bucket encryption: Default SSE-KMS (aws:kms), BucketKeyEnabled: true, no Deny policy                                                                                                                                                
                                                                                                                                                                                                                                      
---                                                                                                                                                                                                                                   
Permissions Verified                                                                                                                                                                                                                  
                                                      
All three permission layers are correctly configured:
                                                                                                                                                                                                                                      
┌───────────────────────────────────────────────────────────────────────────────┬────────┐
│                                     Layer                                     │ Status │                                                                                                                                            
├───────────────────────────────────────────────────────────────────────────────┼────────┤
│ IAM role (Account A): kms:GenerateDataKey, kms:Decrypt         │              │ ✅     │
├───────────────────────────────────────────────────────────────────────────────┼────────┤
│ KMS key policy (Account B): explicitly grants above actions to Account A role │ ✅     │                                                                                                                                             
├───────────────────────────────────────────────────────────────────────────────┼────────┤                                                                                                                                            
│ Bucket policy (Account B): explicitly allows s3:PutObject for Account A role  │ ✅     │                                                                                                                                             
└───────────────────────────────────────────────────────────────────────────────┴────────┘                                                                                                                                            
                                                      
The error is 400 Bad Request, not 403 AccessDenied, ruling out a permissions issue.                                                                                                                                                                                                                                                                                                                                               
                                                                                                                                                                                                                                      
---                                                                                                                                                                                                                                   
What Works                                                                                                                                                                                                                            
                                                      
AWS CLI (same role, same bucket, same KMS key):
aws s3 cp /tmp/staging/part-00000-xxxx.snappy.parquet \
  s3://account-b-bucket/data/part-00000-xxxx.snappy.parquet \
  --sse aws:kms \                                                                                                                                                                                                                     
  --region eu-west-1
                                                                                                                                                                                                                                      
s5cmd Go binary with explicit SSE flag:                                                                                                                                                                                               
s5cmd cp --sse aws:kms \
  /tmp/staging/part-00000-xxxx.snappy.parquet \                                                                                                                                                                                       
  s3://account-b-bucket/data/part-00000-xxxx.snappy.parquet

---                                                                                                                                                                                                          

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions