Amazon CloudFront
開発者ガイド (API バージョン 2016-09-29)

フィールドレベル暗号化を使用した機密データの保護

HTTPS を使用して、オリジンサーバーへのセキュアなエンドツーエンド接続を確立するのに役立つように、CloudFront を設定できます。フィールドレベル暗号化では、HTTPS と共にセキュリティのレイヤーが追加されます。これにより、システムの処理中に特定のデータに特定のアプリケーションのみがアクセスできるように、そのデータを保護できます。

フィールドレベル暗号化により、ユーザーによって送信された機密情報をウェブサーバーに安全にアップロードできます。クライアントが提供した機密情報は、ユーザーに近いエッジで暗号化され、アプリケーションスタック全体で暗号化されたままになります。これにより、データを必要とするアプリケーションのみが (— 復号化するための認証情報があれば —) そのデータを復号化できます。

フィールドレベル暗号化を使用するには、CloudFront ディストリビューションの設定で、暗号化する POST リクエストの一連のフィールドと、それらの暗号化に使用するパブリックキーを指定します。リクエストの最大 10 個のデータフィールドを暗号化できます(フィールドレベル暗号化を使用して、リクエストのすべてのデータをまとめて暗号化することはできません。暗号化する個々のフィールドを指定する必要があります)。

フィールドレベル暗号化を含む HTTPS リクエストがオリジンに転送され、リクエストがオリジンサブシステム全体にルーティングされても、機密データは暗号化されたままです。それにより、機密データの漏洩や偶発的な損失のリスクが軽減されます。クレジット番号へのアクセスを必要とする支払い処理システムなど、ビジネス上の理由で機密データにアクセスする必要のあるコンポーネントは、適切なプライベートキーを使用してデータを復号化し、そのデータにアクセスできます。

フィールドレベル暗号化を使用するには、オリジンがチャンクエンコードをサポートしている必要があります。


				CloudFront でのフィールドレベル暗号化

CloudFront のフィールドレベル暗号化では、非対称暗号化 (パブリックキー暗号化とも呼ばれる) が使用されます。CloudFront にパブリックキーを渡すと、指定したすべての機密データが自動的に暗号化されます。CloudFront に渡したキーは、暗号化された値の復号化には使用できません。プライベートキーでのみ、それらの値を復号化できます。


				機密データのみの暗号化

フィールドレベル暗号化の概要

以下に示しているのは、フィールドレベル暗号化の設定手順の概要です。この手順の詳細については、「フィールドレベル暗号化の設定」を参照してください。

  1. パブリックキーとプライベートキーのペアを取得する。 CloudFront でフィールドレベル暗号化を設定する前に、パブリックキーを取得して追加する必要があります。

  2. フィールドレベル暗号化のプロファイルを作成する。 CloudFront で作成するフィールドレベル暗号化のプロファイルでは、暗号化するフィールドを定義します。

  3. フィールドレベル暗号化の設定を作成する。 設定では、特定のデータフィールドの暗号化に使用するプロファイル (— リクエストのコンテンツタイプまたはクエリ引数に基づく —) を指定します。また、さまざまなシナリオで、たとえば、リクエスト URL のクエリ引数で指定したプロファイル名が CloudFront に存在しない場合に、必要になるリクエスト転送動作のオプションを選択することもできます。

  4. キャッシュ動作にリンクする。 設定をディストリビューションのキャッシュ動作にリンクして、CloudFront がいつデータを暗号化するかを指定します。

フィールドレベル暗号化の設定

フィールドレベル暗号化を使用するには、以下の手順に従います。フィールドレベル暗号化の制限については、「制限」を参照してください。

ステップ 1: RSA キーペアを取得する

開始するには、パブリックキーとプライベートキーを含む RSA キーペアを取得する必要があります。パブリックキーは、CloudFront がデータの暗号化に使用します。プライベートキーは、オリジンにあるコンポーネントであり、暗号化されたフィールドの復号化に使用します。たとえば、Open SSL などのツールを使用してキーペアを作成できます。キーのサイズは 2,048 ビットであることが必要です。詳細については、「RSA キーペアを作成し、パブリックキーを AWS マネジメントコンソールにアップロードするには」を参照してください。

ステップ 2: パブリックキーを CloudFront に追加する

RSA キーペアを取得したら、パブリックキーを CloudFront に追加します。

パブリックキーを CloudFront に追加するには (コンソール)

  1. AWS マネジメントコンソール にサインインし、https://console.aws.amazon.com/cloudfront/ にある、CloudFront コンソールを開きます。

  2. ナビゲーションペインで、[Public key (パブリックキー)] を選択します。

  3. Add public key を選択します。

  4. [Key name (キー名)] にキーの一意の名前を入力します。キー名にはスペースを使用できません。英数字、アンダースコア (_)、ハイフン (-) のみを使用できます。最大長は 128 文字です。

  5. [Encoded key (エンコードされたキー)] で、パブリックキーのエンコードされたキー値 (" -----BEGIN PUBLIC KEY-----" と "-----END PUBLIC KEY-----" の行を含む) をコピーして貼り付けます。

  6. [Comment (コメント)] で、オプションのコメントを追加します。たとえば、パブリックキーの有効期限を含めることができます。

  7. Add key を選択します。

このステップの手順を繰り返して、CloudFront で使用するキーを追加できます。

ステップ 3: フィールドレベル暗号化のプロファイルを作成する

1 つ以上のパブリックキーを CloudFront に追加した後、CloudFront にどのフィールドを暗号化するかを指示するプロファイルを作成します。

フィールドレベル暗号化のプロファイルを作成するには (コンソール)

  1. ナビゲーションペインで、[Field-level encryption (フィールドレベル暗号化)] を選択します。

  2. Create profile を選択します。

  3. 以下のフィールドに入力します。

    Profile name

    プロファイルの一意の名前を入力します。キー名にはスペースを使用できません。英数字、アンダースコア (_)、ハイフン (-) のみを使用できます。最大長は 128 文字です。

    Public key name

    ドロップダウンリストで、ステップ 2 で CloudFront に追加したパブリックキーの名前を選択します。CloudFront はこのキーを使用して、このプロファイルで指定したフィールドを暗号化します。

    Provider name

    キーを識別するのに役立つフレーズ (キーペアを取得したプロバイダなど) を入力します。この情報は、プライベートキーと共に、アプリケーションがデータフィールドを復号化するときに必要になります。プロバイダ名にはスペースを使用できません。英数字、コロン (:)、アンダースコア (_)、ハイフン (-) のみを使用できます。最大長は 128 文字です。

    Field name pattern to match

    CloudFront で暗号化するデータフィールドの名前、またはリクエスト内のデータフィールド名を識別するパターンを入力します。+ オプションを選択して、このキーで暗号化するすべてのフィールドを追加します。

    フィールド名パターンには、データフィールドの名前全体を入力するか (DateOfBirth など)、ワイルドカード文字 (*) を使用して名前の最初の部分のみを入力します (CreditCard* など)。フィールド名パターンには、オプションのワイルドカード文字 (*) に加えて、英数字、角かっこ ([ および ])、ピリオド (.)、アンダースコア (_)、ハイフン (-) のみを含める必要があります。

    異なるフィールド名パターンに重複する文字を使用しないでください。たとえば、ABC * というフィールド名パターンがある場合、AB * という別のフィールド名パターンを追加することはできません。また、フィールド名は大文字と小文字が区別され、最大長は 128 文字です。

    Comment

    (オプション) このプロファイルに関するコメントを入力します。最大長は 128 文字です。

  4. フィールドに入力した後、[Create profile] を選択します。

  5. さらにプロファイルを追加する場合は、[Add profile (プロファイルの追加)] を選択します。

ステップ 4: 設定を作成する

1 つ以上のフィールドレベル暗号化のプロファイルを作成した後、リクエストのコンテンツタイプを指定する設定を作成します。この設定には、暗号化するデータ、暗号化に使用するプロファイル、および CloudFront による暗号化の処理方法を指定するその他のオプションが含まれます。

たとえば、CloudFront がデータを暗号化できないときに、CloudFront が以下のシナリオでリクエストをブロックするかオリジンに転送するかを指定できます。

  • リクエストのコンテンツタイプが設定にない場合。 コンテンツタイプを設定に追加していない場合に、CloudFront がそのコンテンツタイプのリクエストをデータフィールドの暗号化なしでオリジンに転送するか、ブロックしてエラーを返すかを指定できます。

    注意: コンテンツタイプを設定に追加するが、そのタイプで使用するプロファイルを指定していない場合、そのコンテンツタイプのリクエストは常にオリジンに転送されます。

  • クエリ引数で指定したプロファイル名が不明な場合。 fle-profile クエリ引数で、ディストリビューションに存在しないプロファイル名を指定している場合に、CloudFront がリクエストをデータフィールドの暗号化なしでオリジンに送るか、ブロックしてエラーを返すかを指定できます。

設定で、URL でクエリ引数としてプロファイルを提供するかどうかを指定して、そのクエリのコンテンツタイプにマッピングしたプロファイルを上書きすることもできます。デフォルトでは、CloudFront は、コンテンツタイプにマッピングしたプロファイル (指定していある場合) を使用します。これにより、デフォルトで使用されるプロファイルを提供できますが、特定のリクエストに使用される別のプロファイルを指定することもできます。

たとえば、使用するクエリ引数プロファイルとして (設定で) SampleProfile を指定できます。その後、https://d1234.cloudfront.net の代わりに URL https://d1234.cloudfront.net?fle-profile=SampleProfile を使用して、CloudFront がこのリクエストに、リクエストのコンテンツタイプ用に設定したプロファイルではなく SampleProfile を使用するようにできます。

1 つのアカウント用に最大 10 個の設定を作成し、いずれかの設定をそのアカウントの任意のディストリビューションのキャッシュ動作に関連付けることができます。

フィールドレベル暗号化の設定を作成するには (コンソール)

  1. [Field-level encryption (フィールドレベル暗号化)] ページで、[Create configuration] を選択します。

    注意: プロファイルを 1 つ以上作成していない場合、設定を作成するオプションは表示されません。

  2. 以下のフィールドに入力して、使用するプロファイルを指定します(一部のフィールドは変更できません)。

    Content type (変更不可)

    コンテンツタイプは application/x-www-form-urlencoded に設定されており、変更することはできません。

    Default profile ID (オプション)

    ドロップダウンリストから、[Content type (コンテンツタイプ)] フィールドでコンテンツタイプにマッピングするプロファイルを選択します。

    Content format (変更不可)

    コンテンツ形式は URLencoded に設定されており、変更することはできません。

  3. 以下のオプションの CloudFront のデフォルト動作を変更する場合は、該当するチェックボックスをオンにします。

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

    リクエストのコンテンツタイプに使用するプロファイルを指定していないときに、リクエストをオリジンに転送させる場合は、このチェックボックスをオンにします。

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

    クエリ引数で指定したプロファイルによって、コンテンツタイプ用に指定したプロファイルを上書する場合は、このチェックボックスをオンにします。

  4. このチェックボックスをオンにして、クエリ引数によってデフォルトプロファイルが上書きされるようにした場合は、設定で以下の追加フィールドを入力する必要があります。クエリで使用するこれらのクエリ引数マッピングは最大 5 つ作成できます。

    Query argument

    fle-profile クエリ引数の URL に含める値を入力します。CloudFront は、このクエリ引数の値に関連付けられたプロファイル ID (次のフィールドで指定) をこのクエリのフィールドレベル暗号化に使用します。

    最大長は 128 文字です。値にはスペースを含めることはできません。英数字、ダッシュ (-)、ピリオド (.)、アンダースコア (_)、アスタリスク (*)、プラス記号 (+)、パーセント (%) のみを使用する必要があります。

    Profile ID

    ドロップダウンリストから、[Query argument (クエリ引数)] に入力した値に関連付けるプロファイルを選択します。

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

    クエリ引数で指定したプロファイルが CloudFront で定義されていないときに、リクエストをオリジンに転送させる場合は、このチェックボックスをオンにします。

ステップ 5: キャッシュ動作に設定を追加する

フィールドレベル暗号化を使用するには、設定 ID をディストリビューション用の値として追加して、ディストリビューションのキャッシュ動作に設定をリンクします。設定をキャッシュ動作にリンクするには、ビューワープロトコルポリシーとオリジンプロトコルポリシーが HTTPS であることが必要です。

詳細については、「ディストリビューションを作成または更新する場合に指定する値」を参照してください。

オリジンでのデータフィールドの復号化

CloudFront は AWS Encryption SDK を使用してデータフィールドを暗号化します。データはアプリケーションスタック全体で暗号化されたままであり、復号化するための認証情報のあるアプリケーションによってのみアクセスできます。

暗号化の後、暗号テキストは base64 でエンコードされます。アプリケーションがオリジンでテキストを復号化するときには、まず暗号テキストをデコードしてから、AWS Encryption SDK を使用してデータを復号化する必要があります。

以下のサンプルコードでは、アプリケーションがオリジンでデータを復号化する方法を示しています。次の点に注意してください。

  • わかりやすい例になるように、このサンプルは作業ディレクトリのファイルからパブリックキーとプライベートキー (DER 形式) を読み込みます。実際には、オフラインのハードウェアセキュリティモジュールなどの安全なオフラインの場所にプライベートキーを保存し、開発チームにパブリックキーを配布します。

  • CloudFront はデータの暗号化時に特定の情報を使用します。また、オリジンで同じ一連のパラメータをデータの復号化に使用する必要があります。以下に示しているのは、MasterKey の初期化時に CloudFront が使用するパラメータです。

    • PROVIDER_NAME: フィールドレベル暗号化のプロファイルを作成したときにこの値を指定しました。同じ値をここで使用します。

    • KEY_NAME: パブリックキーを CloudFront にアップロードしたときにそのキーの名前を作成し、その名前をプロファイルで指定しました。同じ値をここで使用します。

    • ALGORITHM: CloudFront は暗号化アルゴリズムとして "RSA/ECB/OAEPWithSHA-256AndMGF1Padding" を使用するため、同じアルゴリズムを使用してデータを復号化する必要があります。

  • 暗号テキストを入力として以下のサンプルプログラムを実行すると、復号化されたデータがコンソールに出力されます。詳細については、AWS Encryption SDK の Java サンプルコードを参照してください。

サンプルコード

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)); } }