Skip to content

Fix handling of SSE-C keys when copying unencrypted to encrypted objects or objects with different keys #9559

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: v2
Choose a base branch
from

Conversation

ashovlin
Copy link
Member

@ashovlin ashovlin commented Jun 18, 2025

Issue #, if available: #6012, and supersedes #8345

Description of changes: When copying a file that originates in S3, the high level aws s3 commands make a HeadObject call for the file that is being copied.

When using server-side encryption with customer-provided keys (SSE-C), callers can specify the key for the source object(s) --sse-c-copy-source/--sse-c-copy-source-key and/or the destination object (--sse-c/--sse-c-key).

The CLI is incorrectly handling this for S3 -> S3 copies, by applying destination key to the copy source object.

  1. Copying an unencrypted object to an encrypted one: aws s3 cp s3://$bucket/file.txt s3://$bucket/ssec-copy-c.txt --sse-c AES256 --sse-c-key $key_1
  2. Copying an object with different encryption keys: aws s3 cp s3://$bucket/ssec.txt s3://$bucket/ssec-copy-diff-key.txt --sse-c-copy-source AES256 --sse-c-copy-source-key $key_1 --sse-c AES256 --sse-c-key $key_2

Arguably Incorrect Behavior, Leaving for Backwards Compatibility

I think we're arguably handling S3 -> local copies as well. aws s3 cp s3://$bucket/ssec.txt decrypt.txt --sse-c AES256 --sse-c-key $key_1 works, but I can see a case for applying --sse-c-copy-source/--sse-c-copy-source-key to the object that's originating to S3. But I'm preserving this behavior for backwards compatibility, the updated logic only runs for S3 -> S3 copies.

Manual Testing
I didn't add new integration tests, but manually ran the following

# bucket name and local paths
bucket=""
single_file=""
directory=""
key_1=""
key_2=""

echo "\nLocal -> S3 encrypted"
aws s3 cp $single_file s3://$bucket/ssec.txt --sse-c AES256 --sse-c-key $key_1
aws s3 cp --recursive $directory s3://$bucket/ssec-files --sse-c AES256 --sse-c-key $key_1

echo "\nS3 encrypted -> Local"
aws s3 cp s3://$bucket/ssec.txt decrypt.txt --sse-c AES256 --sse-c-key $key_1
aws s3 cp --recursive s3://$bucket/ssec-files decrypt/ --sse-c AES256 --sse-c-key $key_1

echo "\nS3 encrypted -> S3 Unencrypted"
aws s3 cp s3://$bucket/ssec.txt s3://$bucket/ssec-copy-unencrypted.txt --sse-c-copy-source AES256 --sse-c-copy-source-key $key_1
aws s3 cp --recursive s3://$bucket/ssec-files s3://$bucket/ssec-files-unencrypted --sse-c-copy-source AES256 --sse-c-copy-source-key $key_1

echo "\nS3 encrypted-> S3 encrypted (same key)"
aws s3 cp s3://$bucket/ssec.txt s3://$bucket/ssec-copy-c.txt --sse-c-copy-source AES256 --sse-c-copy-source-key $key_1 --sse-c AES256 --sse-c-key $key_1
aws s3 cp --recursive s3://$bucket/ssec-files s3://$bucket/ssec-files-copy --sse-c-copy-source AES256 --sse-c-copy-source-key $key_1 --sse-c AES256 --sse-c-key $key_1

echo "\nS3 encrypted -> S3 encrypted (different keys)"
aws s3 cp s3://$bucket/ssec.txt s3://$bucket/ssec-copy-diff-key.txt --sse-c-copy-source AES256 --sse-c-copy-source-key $key_1 --sse-c AES256 --sse-c-key $key_2
aws s3 cp --recursive s3://$bucket/ssec-files s3://$bucket/ssec-files-diff-key --sse-c-copy-source AES256 --sse-c-copy-source-key $key_1 --sse-c AES256 --sse-c-key $key_2

echo "\nS3 unencrypted -> S3 encrypted"
aws s3 cp --recursive $directory s3://$bucket/$directory
aws s3 cp s3://$bucket/ssec-copy-unencrypted.txt s3://$bucket/ssec-copy-c.txt --sse-c AES256 --sse-c-key $key_1
aws s3 cp --recursive s3://$bucket/$directory s3://$bucket/ssec-copy-from-s3 --sse-c AES256 --sse-c-key $key_1

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@FilipPyrek
Copy link

Awesome! Thanks @ashovlin 👏

@FilipPyrek
Copy link

Hi @ashovlin when do you think we could get this merged? 🙂

…cts or objects with different keys
@ashovlin ashovlin force-pushed the shovlia/s3-cp-sse-c branch from 4c38f23 to dddefe2 Compare July 9, 2025 15:17
@aemous aemous self-requested a review July 11, 2025 22:25
Copy link
Contributor

@hssyoo hssyoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. But for discussion:

aws s3 cp s3://$bucket/ssec.txt decrypt.txt --sse-c AES256 --sse-c-key $key_1 works, but I can see a case for applying --sse-c-copy-source/--sse-c-copy-source-key to the object that's originating to S3.

GetObject itself uses SSECustomerAlgorithm over CopySourceSSECustomerAlgorithm, so isn't the current S3->local behavior correct?

@ashovlin
Copy link
Member Author

Looks good. But for discussion:

aws s3 cp s3://$bucket/ssec.txt decrypt.txt --sse-c AES256 --sse-c-key $key_1 works, but I can see a case for applying --sse-c-copy-source/--sse-c-copy-source-key to the object that's originating to S3.

GetObject itself uses SSECustomerAlgorithm over CopySourceSSECustomerAlgorithm, so isn't the current S3->local behavior correct?

Ah, maybe it's more open to interpretation then:

  1. My mental model was that the --sse-c-copy-source pair is for the source object, and --sse-c for the destination object regardless of local vs. S3, so the current behavior slightly surprised me.
  2. But if you understand that the--see-c pair as maps toSSECustomerAlgorithm, then this makes sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants