Menu
Amazon CloudFront
Developer Guide (API Version 2016-09-29)

Using Field-Level Encryption to Help Protect Sensitive Data

You can already configure CloudFront to help enforce secure end-to-end connections to origin servers by using HTTPS. Field-level encryption adds an additional layer of security along with HTTPS that lets you protect specific data throughout system processing so that only certain applications can see it.

Field-level encryption allows you to securely upload user-submitted sensitive information to your web servers. The sensitive information provided by your clients is encrypted at the edge closer to the user and remains encrypted throughout your entire application stack, ensuring that only applications that need the data—and have the credentials to decrypt it—are able to do so.

To use field-level encryption, you configure your CloudFront distribution to specify the set of fields in POST requests that you want to be encrypted, and the public key to use to encrypt them. You can encrypt up to 10 data fields in a request. (You can't encrypt all of the data in a request with field-level encryption; you must specify individual fields to encrypt.)

When the HTTPS request with field-level encryption is forwarded to the origin, and the request is routed throughout your origin sub-system, the sensitive data is still encrypted, reducing the risk of a data breach or accidental data loss of the sensitive data. Components that need access to the sensitive data for business reasons, such as a payment processing system needing access to a credit number, can use the appropriate private key to decrypt and access the data.

Be aware that in order to use field-level encryption, your origin must support chunked encoding.


				Field-level encryption in CloudFront

CloudFront field-level encryption uses asymmetric encryption, also known as public-key encryption. You provide a public key to CloudFront, and all sensitive data that you specify is encrypted automatically. The key you provide to CloudFront cannot be used to decrypt the encrypted values; only your private key can do that.


				Encrypt only sensitive data

Overview of Field-Level Encryption

The following steps provide an overview of setting up field-level encryption. For specific steps, see Setting Up Field-Level Encryption.

  1. Get a public key-private key pair. You must obtain and add the public key before you start setting up field-level encryption in CloudFront.

  2. Create a field-level encryption profile. Field-level encryption profiles, which you create in CloudFront, define the fields that you want to be encrypted.

  3. Create a field-level encryption configuration. A configuration specifies the profiles to use—based on the content type of the request or a query argument—for encrypting specific data fields. You can also choose the request-forwarding behavior options that you want for different scenarios; for example, when the profile name specified by the query argument in a request URL doesn't exist in CloudFront.

  4. Link to a cache behavior. Link the configuration to a cache behavior for a distribution, to specify when CloudFront should encrypt data.

Setting Up Field-Level Encryption

Follow these steps to get started using field-level encryption. To learn about limits in field-level encryption, see Limits.

Step 1: Get an RSA Key Pair

To get started, you must obtain a RSA key pair that includes a public key, so CloudFront can encrypt data, and a private key, so components at your origin to decrypt the fields that have been encrypted. For example, you can use Open SSL or another tool to create a key pair. The key size must be 2048 bits. For more information, see To create an RSA key pair and upload the public key in the AWS Management Console.

Step 2: Add Your Public Key to CloudFront

After you get your RSA key pair, add your public key to CloudFront.

To add your public key to CloudFront (console)

  1. Sign in to the AWS Management Console and open the CloudFront console at https://console.aws.amazon.com/cloudfront/.

  2. In the navigation pane, choose Public key.

  3. Choose Add public key.

  4. For Key name, type a unique name for the key. The name can't have spaces and can include only alphanumeric characters, underscores (_), and hyphens (-). The maximum number of characters is 128.

  5. For Encoded key, copy and paste the encoded key value for your public key, including the " -----BEGIN PUBLIC KEY-----" and "-----END PUBLIC KEY-----" lines.

  6. For Comment, add an optional comment. For example, you could include the expiration date for the public key.

  7. Choose Add key.

You can add more keys to use with CloudFront by repeating the steps in the procedure.

Step 3: Create a Profile for Field-Level Encryption

After you add at least one public key to CloudFront, create a profile that tells CloudFront which fields to encrypt.

To create a profile for field-level encryption (console)

  1. In the navigation pane, choose Field-level encryption.

  2. Choose Create profile.

  3. Fill in the following fields:

    Profile name

    Type a unique name for the profile. The name can't have spaces and can include only alphanumeric characters, underscores (_), and hyphens (-). The maximum number of characters is 128.

    Public key name

    In the dropdown list, choose the name of a public key that you added to CloudFront in step 2. CloudFront uses the key to encrypt the fields that you specify in this profile.

    Provider name

    Type a phrase to help identify the key, such as the provider where you got the key pair. This information, along with the private key, will be needed when applications decrypt data fields. The provider name can't have spaces and can include only alphanumeric characters, colons (:), underscores (_), and hyphens (-). The maximum number of characters is 128.

    Field name pattern to match

    Type the names of the data fields, or patterns that identify data field names in the request, that you want CloudFront to encrypt. Choose the + option to add all the fields that you want to encrypt with this key.

    For the field name pattern, you can type the entire name of the data field, like DateOfBirth, or just the first part of the name with a wildcard character (*), like CreditCard*. The field name pattern must include only alphanumeric characters, square brackets ([ and ]), periods (.), underscores (_), and hyphens (-), in addition to the optional wildcard character (*).

    Make sure that you don’t use overlapping characters for different field name patterns. For example, if you have a field name pattern of ABC*, you can’t add another field name pattern that is AB*. In addition, note that field names are case sensitive and the maximum number of characters that you can use is 128.

    Comment

    (Optional) Type a comment about this profile. The maximum number of characters that you can use is 128.

  4. After you fill in the fields, choose Create profile.

  5. If you want to add more profiles, choose Add profile.

Step 4: Create a Configuration

After you create one or more field-level encryption profiles, create a configuration that specifies the content type of the request that includes the data to be encrypted, the profile to use for encryption, and other options that specify how you want CloudFront to handle encryption.

For example, when CloudFront can’t encrypt the data, you can specify whether CloudFront should block or forward a request to your origin in the following scenarios:

  • When a request's content type isn't in a configuration. If you haven't added a content type to a configuration, you can specify whether CloudFront should forward the request with that content type to the origin without encrypting data fields, or block the request and return an error.

    Note: If you add a content type to a configuration but haven't specified a profile to use with that type, requests with that content type will always be forwarded to the origin.

  • When the profile name provided in a query argument is unknown. When you specify the fle-profile query argument with a profile name that doesn’t exist for your distribution, you can specify whether CloudFront should send the request to the origin without encrypting data fields, or block the request and return an error.

In a configuration, you can also specify whether providing a profile as a query argument in a URL overrides a profile that you’ve mapped to the content type for that query. By default, CloudFront uses the profile that you've mapped to a content type, if you specify one. This lets you have a profile that's used by default but decide for certain requests that you want to enforce a different profile.

So, for example, you might specify (in your configuration) SampleProfile as the query argument profile to use. Then you could use the URL https://d1234.cloudfront.net?fle-profile=SampleProfile instead of https://d1234.cloudfront.net, to have CloudFront use SampleProfile for this request, instead of the profile you'd set up for the content type of the request.

You can create up to 10 configurations for a single account, and then associate one of the configurations to the cache behavior of any distribution for the account.

To create a configuration for field-level encryption (console)

  1. On the Field-level encryption page, choose Create configuration.

    Note: If you haven't created at least one profile, you won't see the option to create a configuration.

  2. Fill in the following fields to specify the profile to use. (Some fields can't be changed.)

    Content type (can't be changed)

    The content format is set to application/x-www-form-urlencoded and can’t be changed.

    Default profile ID (optional)

    In the dropdown list, choose the profile that you want to map to the content type in the Content type field.

    Content format (can't be changed)

    The content format is set to URLencoded and can’t be changed.

  3. If you want to change the CloudFront default behavior for the following options, select the appropriate check box.

    Forward request to origin when request’s content type is not configured

    Select the check box if you want to allow the request to go to your origin if you have not specified a profile to use for the content type of the request.

    Override the profile for a content type with a provided query argument

    Select the check box if you want to allow a profile provided in a query argument to override the profile that you’ve specified for a content type.

  4. If you select the check box to allow a query argument to override the default profile, you must complete the following additional fields for the configuration. You can create up to five of these query argument mappings to use with queries.

    Query argument

    Type the value that you want to include in URLs for the fle-profile query argument. This value tells CloudFront to use the profile ID (that you specify in the next field) associated with this query argument for field-level encryption for this query.

    The maximum number of characters that you can use is 128. The value can’t include spaces, and must use only alphanumeric or the following characters: dash (-), period (.), underscore (_), asterisk (*), plus-sign (+), percent (%).

    Profile ID

    In the dropdown list, choose the profile that you want to associate with the value that you typed for Query argument.

    Forward request to origin when the profile specified in a query argument does not exist

    Select the check box if you want to allow the request to go to your origin if the profile specified in a query argument isn't defined in CloudFront.

Step 5: Add a Configuration to a Cache Behavior

To use field-level encryption, link a configuration to a cache behavior for a distribution by adding the configuration ID as a value for your distribution. Note that the Viewer Protocol Policy and Origin Protocol Policy must be HTTPS in order for you to link a configuration to a cache behavior.

For more information, see Values That You Specify When You Create or Update a Web Distribution.

Decrypting Data Fields at Your Origin

CloudFront encrypts data fields by using the AWS Encryption SDK. The data remains encrypted throughout your application stack and can be accessed only by applications that have the credentials to decrypt it.

After encryption, the cipher text is base64 encoded. When your applications decrypt the text at the origin, they must first decode the cipher text, and then use the AWS Encryption SDK to decrypt the data.

The following code sample illustrates how applications can decrypt data at your origin. Note the following:

  • To simplify the example, this sample loads public and private keys (in DER format) from files in the working directory. In practice, you would store the private key in a secure offline location, such as an offline hardware security module, and distribute the public key to your development team.

  • CloudFront uses specific information while encrypting the data, and the same set of parameters should be used at the origin to decrypt it. Parameters CloudFront uses while initializing the MasterKey include the following:

    • PROVIDER_NAME: You specified this value when you created a field-level encryption profile. Use the same value here.

    • KEY_NAME: You created a name for your public key when you uploaded it to CloudFront, and then specified the key name in the profile. Use the same value here.

    • ALGORITHM: CloudFront uses "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" as the algorithm for encrypting, so you must use the same algorithm to decrypt the data.

  • If you run the following sample program with cipher text as input, the decrypted data is output to your console. For more information, see the Java Example Code in the AWS Encryption SDK.

Sample Code

import java.nio.file.Files; import java.nio.file.Paths; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import org.apache.commons.codec.binary.Base64; import com.amazonaws.encryptionsdk.AwsCrypto; import com.amazonaws.encryptionsdk.CryptoResult; import com.amazonaws.encryptionsdk.jce.JceMasterKey; /** * Sample example of decrypting data that has been encrypted by CloudFront Field-Level Encryption. */ public class DecryptExample { private static final String PRIVATE_KEY_FILENAME = "private_key.der"; private static final String PUBLIC_KEY_FILENAME = "public_key.der"; private static PublicKey publicKey; private static PrivateKey privateKey; // CloudFront uses the following values to encrypt data, and your origin must use same values to decrypt it. // In your own code, for PROVIDER_NAME, use the provider name that you specified when you created your Field Level // Encryption Profile. This sample uses 'DEMO' for the value. private static final String PROVIDER_NAME = "DEMO"; // In your own code, use the Key name that you specified when you added your public key to CloudFront. This sample // uses 'DEMOKEY' for the Key name. private static final String KEY_NAME = "DEMOKEY"; // Cloudfront uses this algorithm when encrypting data. private static final String ALGORITHM = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding"; public static void main(final String[] args) throws Exception { final String dataToDecrypt = args[0]; // This sample uses files to get public and private keys. // In practice, you should distribute the public key and save the private key in secure storage. populateKeyPair(); System.out.println(decrypt(debase64(dataToDecrypt))); } private static String decrypt(final byte[] bytesToDecrypt) throws Exception { // You can decrypt the stream only by using the private key. // 1. Instantiate the SDK final AwsCrypto crypto = new AwsCrypto(); // 2. Instantiate a JCE master key final JceMasterKey masterKey = JceMasterKey.getInstance( publicKey, privateKey, PROVIDER_NAME, KEY_NAME, ALGORITHM); // 3. Decrypt the data final CryptoResult <byte[], ? > result = crypto.decryptData(masterKey, bytesToDecrypt); return new String(result.getResult()); } // Function to decode base64 cipher text. private static byte[] debase64(final String value) { return Base64.decodeBase64(value.getBytes()); } private static void populateKeyPair() throws Exception { final byte[] PublicKeyBytes = Files.readAllBytes(Paths.get(PUBLIC_KEY_FILENAME)); final byte[] privateKeyBytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_FILENAME)); publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(PublicKeyBytes)); privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes)); } }