Data Encryption with Amazon S3
If your application uses Amazon S3 and deals with sensitive data, then you should be taking advantage of the easy ways of increasing the security of your data using the AWS SDK for Java.
There are two easy options for locking down your data using Amazon S3 and the AWS SDK for Java. Which one you choose depends on the nature of your data and how much you want to be involved with the encryption process and key management. Both options give you solutions for ensuring your data is securely stored in Amazon S3.
Server-side data encryption with Amazon S3 is the easiest of the two options, and requires extremely little work to enable. All you need to do is enable server-side encryption in your object metadata when you upload your data to Amazon S3. As soon as your data reaches S3, it is encrypted and stored. When you request your data again, Amazon S3 automatically decrypts it as it’s streamed back to you. Your data is always encrypted when it’s stored in Amazon S3, with encryption keys managed by Amazon. This makes it incredibly easy to start using encryption, since your application doesn’t have to do anything other than set the server-side encryption flag when you upload your data.
The example below shows how to create a request to upload data to Amazon S3, then call the ObjectMetadata#setServerSideEncryption() method and specify the encryption algorithm (currently ObjectMetadata.html#AES_256_SERVER_SIDE_ENCRYPTION is the only supported encryption algorithm).
PutObjectRequest request = new PutObjectRequest(bucket, key, file); // Request server-side encryption. ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setServerSideEncryption( ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION); request.setMetadata(objectMetadata); s3client.putObject(request);
If you want to convert existing data stored in Amazon S3 to use server-side encryption, you can use the AmazonS3#copyObject() method to edit the object’s metadata (essentially you’re copying the object to the same location, and supplying new object metadata).
CopyObjectRequest request = new CopyObjectRequest(bucket, key, bucket, key); // Request server-side encryption. ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setServerSideEncryption( ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION); request.setNewObjectMetadata(objectMetadata); s3client.copyObject(request);
The second option for encrypting your sensitive data is to use the client-side encryption provided by the AWS SDK for Java. This option is a little more involved on your part, but can provide stronger security, since your data never leaves your machine in an unencrypted form and you manage the encryption keys.
To use client-side encryption for your Amazon S3 data, the first thing you need to do is switch to using the AmazonS3EncryptionClient instead of the basic AmazonS3Client. The encryption client’s interface is identical to the standard client’s interface, so switching to the new client in existing code is very straightforward. The encryption client handles automatically encrypting your data as it’s streamed to Amazon S3, and automatically decrypts your data as it streams back to your application from Amazon S3 when you download objects.
The major difference between server-side encryption and client-side encryption is who manages the encryption keys. With client-side encryption, you need to provide the AmazonS3EncryptionClient with EncryptionMaterials, which drive the encryption process.
The example below demonstrates how to create an instance of the encryption client and use it to encrypt and then decrypt data. It shows how to generate an RSA asymmetric key pair, but in a real application, you’d probably load your encryption keys from disk.
// Several good online sources explain how to easily create an RSA key pair // from the command line using OpenSSL, for example: // http://en.wikibooks.org/wiki/Transwiki:Generate_a_keypair_using_OpenSSL KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA"); keyGenerator.initialize(1024, new SecureRandom()); KeyPair myKeyPair = keyGenerator.generateKeyPair(); // Construct an instance of AmazonS3EncryptionClient EncryptionMaterials encryptionMaterials = new EncryptionMaterials(myKeyPair); AmazonS3EncryptionClient s3 = new AmazonS3EncryptionClient(credentials, encryptionMaterials); // Then just use the encryption client like the standard S3 client s3.putObject(bucket, key, myFile); // When you use the getObject method, the data retrieved from Amazon S3 // is automatically decrypted on the fly as it streams down to you S3Object downloadedObject = s3.getObject(bucketName, key);
For a much more in depth guide on how the client-side data encryption for Amazon S3 works, including how to extend it to integrate with existing private key management systems, see our article on Client-Side Data Encryption with the AWS SDK for Java and Amazon S3.
Are you already using either of these encryption features in the AWS SDK for Java? Let us know in the comments below!