Amazon Web Services ブログ
マルチリージョンでの高可用性のための SQL データベースのクライアント側暗号化の実行
Amazon Relational Database Service (RDS) と Amazon Aurora は、データベースインスタンス、自動バックアップ、リードレプリカ、およびスナップショットの基盤となるストレージを保護するために保存時の暗号化をネイティブに提供しますが、時折、使用中のデータを暗号化することによって機密性を強化する方法について尋ねられるお客様がおられます。
たとえば、プライマリアカウントナンバーをセキュアに保存してから読み込むときなど、トークナイゼーションソリューションが適切ではない場合には暗号化が必要となります。
お客様にとって、データベース列に保存された機密情報 (社会保障番号や銀行口座番号など) がデータベース管理者などの社内の人物に表示されないようにすることが必要であるという例もあります。
これらの暗号化シナリオでは、暗号化された列データで SQL WHERE 句述語のクエリを実行する必要はありません。列レベルでの暗号化を有効にするには、SQL データベースに永続化する前にクライアント側暗号化を使用できます。
この記事では、SQL データベースでのクライアント側暗号化を行うために考えられる 1 つのアプローチを段階的に説明します。暗号化キーは AWS Key Management Service (KMS) によって保護されており、復号化に必要なキーの制御を可能にします。その後、Amazon Aurora MySQL データベースエンジンに書き込む前にクライアント側暗号化を実行するサンプルアプリケーションについて説明します。
AWS 暗号化コンセプトの概要
ソリューションの概要を説明する前に、AWS KMS の機能の一部と AWS 暗号化 SDK について見直したいと思います。
AWS KMS は、キーポリシーを使用して、暗号化と復号化に必要なカスタマー管理の CMK の使用を制御することを可能にします。AWS KMS の CMK は、決して KMS を暗号化されていない状態のままにしておかず、エクスポートできません。さらに、AWS KMS は AWS CloudTrail にキー使用の監査証跡を提供します。
AWS 暗号化 SDK は、開発者がセキュリティのベストプラクティスに従いながら、アプリケーションのコア機能に集中することを可能にするクライアント側の暗号化ライブラリです。AWS 暗号化 SDK は、KMS にも統合します。
暗号化フローは以下の通りです。
- AWS 暗号化 SDK が AWS KMS を使用してデータキーを生成する。
- KMS API コールが、プレーンテキストデータキーと、CMK を使って暗号化された同じデータキーを返す。
- プレーンテキストデータキーがプレーンテキストデータの暗号化に使用され、暗号化されたデータキーが暗号化されたデータと共に保存される。
CMK は AWS KMS によって保護されています。別のキーを使ってデータキーを暗号化するこの暗号化戦略は、エンベロープ暗号化と呼ばれています。AWS 暗号化 SDK は、データに対して機密性、データ整合性、および真正性の保証を同時に提供することに留意してください。これは認証付き暗号化とも呼ばれます。
AWS 暗号化 SDK はまた、秘密ではないデータを指定することによって、暗号化されたデータで追加の整合性および真正性チェックを実行することもできます。これは追加認証データとも呼ばれます。この追加認証データは、暗号化コンテキストと呼ばれるオプションのキー/値ペアのセットとして指定されます。
暗号化コンテキストには機密情報または個人情報を含めないでください。暗号化コンテキストは秘密ではなく、アクセスコントロールメカニズムでもないことに注意してください。暗号化コンテキストはデータを認証する手段であり、呼び出し元ではありません。AWS KMS は暗号化コンテキストを保存しませんが、AWS 暗号化 SDK は、暗号化メッセージ形式のプレーンテキストで暗号化コンテキストを保存します。また、暗号化コンテキストは AWS CloudTrail によってプレーンテキストでログに記録されます。
たとえば、カード保有者のアカウントナンバー (一意の値) が暗号化コンテキストに保存されているとしましょう。以下の図にあるように、複合化が正常に行われるのは、暗号化されたカード保有者のデータが改ざんされていないことを確実にするための追加の整合性および認証チェックとしてアカウントナンバーが提供される場合に限定されます。
アプリケーションのアーキテクチャとデータフロー
アプローチは以下の通りです。
- AWS KMS を使用してデータキーが生成されます。データキーが複数の CMK (リージョンごとに 1 つ) で暗号化され、マルチリージョンデプロイメントにより優れた可用性を提供します。マルチリージョンデプロイメントの設計上の考慮事項については、この後のセクションで説明します。
- 次に、データキーがプレーンテキスト列の値を暗号化して、暗号化列の値を生成します。暗号化データキーは、暗号化列の値と共に保存されます。
- 暗号化列の値と暗号化データキーで構成される暗号化メッセージは、SQL データベースに保存されます。単一データ構造が使用され、AWS 暗号化 SDK のメッセージ形式に従います。
マルチリージョンデプロイメントのコンセプト
お客様の中には、アプリケーションが異なるリージョンで読み込みをスケールする、またはアプリケーションにクロスリージョンの災害復旧要件があることから、データベースをマルチリージョンアーキテクチャでデプロイするお客様がおられます。
データベースのマルチリージョンデプロイメントでのキー管理設計は、注意深く検討する必要があります。単一リージョンのマスターキーで暗号化されてから、異なるリージョンに伝播されるデータキーには、データキーの復号化にクロスリージョンの AWS KMS コールが必要です。その代わりに、各リージョンで CMK を使ってデータキーを暗号化することもできます。
各リージョンの暗号化データキーは、AWS 暗号化 SDK の暗号化されたメッセージ形式で保存されるため、複合時にクロスリージョンの AWS KMS コールを回避することが可能になります。さらに、データキーが各リージョンで暗号化されているため、単一リージョンへの復号化依存性の発生を回避することもできます。
マルチリージョン CMK でのデータの暗号化は、次のワークフローが伴います。アプリケーションがローカルリージョンに 1 つの KMS リクエストを行ってから、追加のリージョンごとに後続の AWS KMS リクエストを行います。複合時、アプリケーションはデータキーの復号化にローカルリージョンのみへの呼び出しを行います。
設計上の考慮事項
考慮事項には、マルチリージョン CMK でクライアント側での暗号化を行う前に注意深く検討する必要がある、容量の活用、計算パフォーマンス、およびクエリ制限に関するものがいくつかあります。
- データベーススキーマ設計は、暗号化されたデータを特定の列データに関連付けられている判読不能なブロブとして扱う必要があります。AWS 暗号化 SDK のメッセージ形式は、256 ビット AES GCM データキー、暗号化コンテキストのキー/値タグ、および暗号文のサイズに加えて、少なくとも 100 バイトを追加します。テーブルスキーマ設計、CPU 使用率、メモリ使用率、ディスク容量、およびクエリの応答時間に対する影響を測定し、評価するようにしてください。
- アプリケーションは、各リージョンで CMK を使用して暗号化される必要があります。この操作では、それぞれの暗号化操作で、1 行ごとに 1 つのクロスリージョン KMS リクエストを行う必要があります。行ごとのクロスリージョンリクエストのレイテンシーが許容可能であるかどうかを判断するために、アプリケーションを測定し、評価してください。
- ユースケースによっては、データキーのキャッシングがあまり役に立たない場合があります。キャッシュされたデータキーは、その暗号化コンテキストが一致する場合にのみ再利用されるからです。たとえば、暗号化されたアカウントプロファイル情報の認証にアカウントナンバーなどの一意の値が使用される場合、データキーキャッシングを使用することは不可能ですが、暗号化コンテキストで使用される一意のキー/値ペアは整合性保証を提供し、暗号化されたデータを認証します。データキーのキャッシングは常にセキュリティとコスト間のトレードオフになります (たとえば、財務コスト、レイテンシー、および整合性)。
- 行ごとの複合化操作は、データキーの複合化のために AWS KMS へのローカルリージョン API コールを実行します。行ごとのデータキー複合化リクエストのレイテンシーが許容可能かどうかを判断するために、アプリケーションを測定し、評価してください。
- また、データキーのキャッシングを使用している場合は、データキーを再利用しすぎないようにしてください。データキーの再利用は、いずれもセキュリティとコスト (経済的なコストとレイテンシーコストなど) 間の妥協です。最大寿命、メッセージの最大数、およびキャッシュされたデータキーが暗号化できる最大バイト数を注意深く検討してください。データキーキャッシングに関する詳しい情報については、AWS Encryption SDK: How to Decide if Data Key Caching is Right for Your Application を参照してください。
- テーブルに保存されている暗号化されたデータは、暗号化された列で WHERE 句述語を実行するクエリを除外します。さらに、暗号文で作成されたインデックスはまったく役に立ちません。
- KMS API の 1 秒あたりのリクエストクォータにも注意してください。AWS では、AWS リソースの可用性を保証する、および新しいお客様の請求リスクを最小限に留めることができるように、アカウントおよびリージョンごとのサービスクォータを維持しています。1 秒あたりの KMS リクエストの具体的なクォータは、お客様の AWS クォータのためのセルフサービスの一元管理ポータルを提供するサービスクォータを通じて引き上げられます。
- 暗号化コンテキストに設定されたデータ要素が行を検索するために使用される一意の値である場合、選択された行にある暗号化されたデータは整合性保証で認証することができます。逆に、暗号化されたデータの認証に月/日付などの一意ではない値のみが使用される場合、行の整合性は保証できません。このサンプルアプリケーションでは、行を検索し、暗号化されたデータを認証して整合性保証を提供するための一意のインデックスとしてアカウントナンバーを使用します。
- 暗号化されたデータを認証するための暗号化コンテキストの使用は、暗号化されたデータに対してのみ整合性保証を提供します。暗号化されていない列については、行レベルでの整合性保証は提供されません。
クライアント側暗号化の仕組み
以下のステップは、クライアント側暗号化の仕組みを要約したものです。
- マルチリージョンアプリケーションがデプロイされている各リージョンからの KMS CMK ARN を指定します。データキーは、各リージョンの CMK で暗号化されます。
- 暗号化コンテキストのインスタンスを作成します。暗号化された行を検索し、暗号化されたデータを認証するための一意のインデックスとしてアカウントナンバーが使用されます。
- 列データを暗号化します。データキーは各リージョンの CMK、および指定された暗号化コンテキストを使って暗号化されます。
- 暗号化されたデータキーと暗号化された列を同じ列に保存します。AWS 暗号化 SDK のメッセージ形式は、暗号文、およびすべての暗号化されたデータキーの両方が含まれる単一データ構造です。詳細はこちらで説明されています。
クライアント側復号化の仕組み
以下のステップは、クライアント側復号化の仕組みを要約したものです。
- アプリケーションが実行されているローカルリージョンの KMS CMK ARN を指定します。AWS 暗号化 SDK が AWS KMS CMK ARN を適切なデータキーと一致させ、ローカルリージョンの CMK を使って復号化します。
- データを復号化します。
- 暗号化コンテキストのインスタンスを作成します。暗号化された行の値を取得するための一意のインデックスとしてアカウントナンバーが使用されるため、暗号化されたデータに関する整合性保証が提供されます。
- 暗号化コンテキストを検証し、不一致がある場合はセキュリティオペレーションセンターに警告します。
サンプルアプリケーションのアーキテクチャとデータフロー
クライアント側暗号化の機能をさらに詳しく紹介するため、この記事ではクライアント側暗号化を実行するサンプルアプリケーションを使用します。ユーザーがフォームに記入し、フォームをウェブアプリケーションに送信します。ウェブアプリケーションが機密フィールドに対してクライアント側暗号化を実行します。別のフォームがユーザーの元の入力を検証し、一致させます。この検証は、データベースから暗号文を取得し、値を復号化してから、ユーザーの入力と比較することによって実行されます。サンプルアプリケーションは、クライアント側暗号化の機能性を説明することのみを目的としており、本番での使用向けではありません。
ウェブアプリケーションがコンテナとして AWS Fargate にデプロイされ、AWS Secrets Manager からデータベース認証情報を読み込みます。AWS Fargate は、サーバーまたはクラスターを管理することなくコンテナを実行することを可能にするマネージドコンテナサービスです。AWS Secrets Manager は、データベース認証情報などの秘密を保護し、秘密を簡単にローテーションして管理するために役立ちます。
この例では、AWS CloudFormation が AWS Fargate と Amazon Aurora リソースの作成、設定、およびプロビジョニングを行います。AWS CloudFormation は、シンプルなテキストファイルのコードを使用してインフラストラクチャを記述および管理することを可能にします。ネストされたスタックは、Fargate、Aurora、および Amazon VPC 専用のテンプレートを提供します。Aurora は、クラウド用に構築された MySQL および PostgreSQL との互換性がある専用リレーショナルデータベースで、従来のエンタープライズデータベースのパフォーマンスと可用性、およびオープンソースデータベースのシンプルさとコスト効率性を併せ持っています。
以下の図は、このサンプルアプリケーションのアーキテクチャとデータフローを表したものです。
AWS CloudFormation ソリューションをデプロイします。CloudFormation とサンプルアプリケーションは Github から利用できます。
CloudFormation ソリューションをデプロイする前に、AWS CodePipeline が Docker イメージを構築できるように、プライマリおよびセカンダリリージョンで AWS CodeCommit リポジトリを作成する必要があります。Github リポジトリをクローンして、各リージョンの CodeCommit にプッシュすることができます。
サンプルアプリケーションに含まれているサーバーレスアプリケーション依存性をデプロイするために、AWS Serverless Application Model (AWS SAM) をインストールします。AWS SAM テンプレートは、AWS CloudFormation テンプレートの拡張です。AWS SAM CLI のインストール手順は、こちらに記載されています。
また、CMK を管理する AWS KMS キー管理者も作成します。たとえば、以下の IAM ポリシーを使って「KeyAdministratorRole」という名前のロールを作成します。
CloudFormation ソリューションをデプロイするには、これらのステップに従います。
1.) ひとつをプライマリリージョン、もうひとつはセカンダリリージョンとして 2 つのリージョンを選択します。
2.) プライマリリージョンをデプロイします。
AWS CloudFormation のネストされたテンプレートを構築してパッケージ化します。Amazon S3 バケットを指定します。必要に応じて、希望するリージョンのパラメータを更新します。
入力パラメータ | 入力パラメータの説明 |
SecondaryRegion | セカンダリ AWS KMS CMK と Aurora リードレプリカが含まれるセカンダリリージョンです。 |
KeyAdministratorRole | CMK を管理している IAM ロールです。作成するキーポリシーが、現在のユーザーによる KMS CMK の管理を許可するようにしてください。 |
ネストされた CloudFormation スタックをデプロイします。スタックに適切な名前を選択します。AWS のサービスの作成には約 30 分かかる場合があります。
3.) セカンダリリージョンをデプロイします。
ネストされた CloudFormation テンプレートをパッケージ化します。Amazon S3 バケットを指定します。必要に応じて、希望するリージョンのパラメータを更新します。
入力パラメータ | 入力パラメータの説明 |
PrimaryRegion | プライマリ KMS CMK と、読み込みおよび書き込みのためのプライマリ Aurora クラスターが含まれるプライマリリージョンです。 |
KeyAdministratorRole | CMK を管理している IAM ロールです。作成するキーポリシーが、現在のユーザーによる KMS CMK の管理を許可するようにしてください。 |
SourceDBInstanceIdentifier | プライマリリージョンの Aurora のクラスター ARN を入力します。この値は、CloudFormation 出力のデータベーススタック値 AuroraClusterArn にあります。Aurora のクロスリージョンリードレプリカがセカンダリリージョンに作成されます。 |
ネストされた AWS CloudFormation スタックを作成します。AWS のサービスの作成には約 30 分かかる場合があります。
サンプルアプリケーションのテスト
以下のステップを使用して、クライアント側暗号化でサンプルアプリケーションをテストします。
- ウェブブラウザでプライマリリージョンのサンプルアプリケーションを開きます。CloudFormation スタックで、[出力]、[CreateURL] と選択します。たとえば、https://example.execute-api.PRIMARY_REGION.amazonaws.com/create です。前のステップから AWS CodePipeline がコンテナイメージを構築してデプロイするまでには数分間かかる場合があります。この間は、サンプルアプリケーションにアクセスできないことがあります。
- このページで HTML フォームに記入し、送信します。
- [アカウントナンバー] および [ユーザー ID] の 2 つのフォームフィールドに入力します。
- [OK] を選択します。
- ウェブブラウザでセカンダリリージョンのサンプルアプリケーションを開きます。CloudFormation スタックで、[出力]、[Authenticate] と選択します。たとえば、https://example.execute-api.PRIMARY_REGION.amazonaws.com/authenticate です。前のステップから AWS CodePipeline がコンテナイメージを構築してデプロイするまでには数分間かかる場合があります。この間は、サンプルアプリケーションにアクセスできないことがあります。
- このページで HTML フォームに記入し、送信します。
- [アカウントナンバー] および [ユーザー ID] の 2 つのフォームフィールドに入力します。
- [OK] を選択します。
まとめ
この記事では、Amazon Relational Database Services (RDS) および Amazon Aurora のために AWS Key Management Services (KMS) に基づく AWS 暗号化 SDK を使ってクライアント側暗号化を可能にする方法を説明しました。このクライアント側暗号化アプローチは、列指向のプレーンテキストへの不正アクセスを防ぐ必要がある場合に、より強固なセキュリティコントロールを提供できます。このアプローチがどのようにマルチリージョンデプロイメントをサポートするかについても説明しました。これに加えて、暗号化キーは AWS KMS を使用して保護されており、複合化 (KMS を使用) に必要なキーを制御することを可能にします。
著者について
Josh Joy は AWS Professional Services のセキュリティトランスフォーメーションコンサルタントで、お客様のために AWS へのセキュアな旅を実現し、最も機密性の高いワークロードを AWS に移行するにあたって、お客様のセキュリティ体制を強化する支援を行っています。Josh は、お客様が前向きな結果を得ることができるように詳しい調査を行い、逆から考えていくことを楽しんでいます。