Enforcing encryption on S3 buckets
Amazon S3 encryption increases the level of security and privacy of your data; it helps ensure that only authorized parties can read it. Even if an unauthorized person gains logical or physical access to that data, the data is unreadable if they don’t get a hold of the key to unencrypt it.
S3 supports encrypting data both at transit (as it travels to and from S3) and at rest (while it’s stored on disks in S3 data centers).
For protecting data at rest, you have two options. The first is server-side encryption (SSE), in which Amazon S3 will be handling the heavy encryption operation on the server side in AWS. By default, Amazon S3 encrypts your data using SSE-S3. However, you can change this to SSE-KMS, which uses KMS keys for encryption, or to SSE-C, where you can provide and manage your own encryption key. Alternatively, you can encrypt your data using client-side encryption, where Amazon S3 doesn’t play any role in the encryption process rather; you are responsible for all the encryption operations.
In this recipe, we’ll learn how to enforce SSE-KMS server-side encryption using customer-managed keys.
Getting ready
For this recipe, you need to have a KMS key in the same region as your bucket to use for encryption. KMS provides a managed key for S3 (aws/s3) that can be utilized for encryption. However, if you desire greater control over the key properties, such as modifying its policies or performing key rotation, you can create a customer-managed key. To do so, follow these steps:
- Sign in to the AWS Management Console (https://console.aws.amazon.com/console/home?nc2=h_ct&src=header-signin) and navigate to the AWS Key Management Service (AWS KMS) service.
- In the navigation pane, choose Customer managed keys and click on Create key.
- For Key type, choose Symmetric, while for Key usage, choose Encrypt and decrypt. Click on Next:
Figure 1.2 – KMS configuration
- Click on Next.
- Type an Alias value for the KMS key. This will be the display name. Optionally, you can provide Description and Tags key-value pairs for the key.
- Click on Next. Optionally, you can provide Key administrators to administer the key. Click on Finish to create the key.
How to do it…
- Sign in to the AWS Management Console (https://console.aws.amazon.com/console/home?nc2=h_ct&src=header-signin) and navigate to the S3 service.
- In the Buckets list, choose the name of the bucket that you want to change the encryption for and navigate to the Properties tab.
- Click on Edit in the Default encryption section.
- For Encryption type, choose Server-side encryption with AWS Key Management Service keys (SSE-KMS).
- For AWS KMS key, you can select Enter AWS KMS key ARN to enter the key you have created or browse it using Choose from your AWS KMS keys.
- Keep Bucket Key enabled and save your changes:
Figure 1.3 – Changing the default encryption
How it works…
By changing the default encryption for your bucket, all newly uploaded objects to your bucket, which don’t have an encryption setting, will be encrypted using the KMS you have provided. Already existing objects in your bucket will not be affected. Enabling the bucket key leads to cost savings in KMS service calls associated with the encryption or decryption of individual objects. This is achieved by KMS generating a key at the bucket level rather than generating a separate KMS key for each encrypted object. S3 uses this bucket-level key to generate distinct data keys for objects within the bucket, thereby eliminating the need for additional KMS requests to complete encryption operations.
There’s more…
By following this recipe, you can encrypt your objects with SSE-KMS but only if they don’t have encryption configured. You can enforce your objects to have an SSE-KMS encryption setting in the PUT
operation using a bucket policy, as shown here:
- Navigate to the bucket’s Permissions tab.
- Go to the Bucket Policy section and click on Edit.
- Paste the following policy. Make sure you replace
<your-bucket-name>
with the actual name of your S3 bucket and<your-kms-key-arn>
with the Amazon Resource Name (ARN) of your KMS key:{ "Version": "2012-10-17", "Id": "EnforceSSE-KMS", "Statement": [ { "Sid": "DenyNonKmsEncrypted", "Effect": "Deny", "Principal": "*", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::<your-bucket-name>/*", "Condition": { "StringNotEquals": { "s3:x-amz-server-side-encryption": "aws:kms" } } }, { "Sid": "AllowKmsEncrypted", "Effect": "Allow", "Principal": "*", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::<your-bucket-name>/*", "Condition": { "StringEquals": { "s3:x-amz-server-side-encryption": "aws:kms", "s3:x-amz-server-side-encryption-aws-kms-key-id": "<your-kms-key-arn>" } } } ] }
- Save your changes.
This policy contains two statements. The first statement (DenyNonKmsEncrypted
) denies the s3:PutObject
action for any request that does not include SSE-KMS encryption. The second statement (AllowKmsEncrypted
) only allows the s3:PutObject
action when the request includes SSE-KMS encryption and the specified KMS key.
See also
- SSE-C: https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html
- Client-side encryption: https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingClientSideEncryption.html
- Enforcing encryption in transit with TLS1.2 or higher with Amazon S3: https://aws.amazon.com/blogs/storage/enforcing-encryption-in-transit-with-tls1-2-or-higher-with-amazon-s3/
- Encrypting existing S3 objects: https://aws.amazon.com/blogs/storage/encrypting-existing-amazon-s3-objects-with-the-aws-cli/