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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions