AWS KMSを使ってアプリケーションレベルの暗号化処理を実装する
はじめに
機微情報などを暗号化したデータをDBに格納したくなることがありますよね。私はありました。
そういうとき、AWS KMSを活用すれば容易な実装が可能となります。
よくある実装例
各言語の公式ドキュメントには、実装例が記載されていることがあるのでそちらを読んでみましょう。
PHPを例にしますが、以下ページの「例1 PHP 7.1以降で、AES を GCMモードで使う例」にありました。
暗号化アルゴリズムにAES-GCMが採用されており、セキュアな暗号方式で実装されています。いいですね。
キーの生成処理はドキュメントにも記載の通り、
keyは、openssl_random_pseudo_bytesのように、暗号的に安全な方法で事前に生成しておく。
で良いとしても、問題はそのキーをどうやってプログラム側に渡すのか、だったりします。
漏洩リスクを考慮するとハードコーディングは避けるべきなので、環境変数で外部から注入するとか考えたり。
キーのローテーションがしたい、というような要件が出てくればなかなかに頭を悩ませてきます。
こうした差別化にならない箇所で複雑な実装はしたくない、と思う方もいるはず。
KMSでエンベロープ暗号化を実装する
そこでAWS KMSの出番です。
AWSのサービスを利用していると至る所で見かけるので、名前自体は馴染み深いかもしれません。
事前の準備として、カスタマーマネージドキーの作成とリソースベースポリシーの適切な設定が必要となります。
ここでは割愛しますが、詳しくは以下の記事を参考にしてみてください。
今回はいわゆるエンベロープ暗号化を用いて実装してみます。
実行環境は以下の通り。
- PHP 8.4
- AWS SDK for PHP - Version 3
<?php
require 'vendor/autoload.php';
use Aws\Kms\KmsClient;
// 暗号化したい文字列
$plainText = 'Hello World!!!';
$cipher = 'aes-256-gcm';
$kmsClient = new KmsClient([
'profile' => 'default',
'version' => '2014-11-01',
'region' => 'ap-northeast-1'
]);
// マスターキーからデータキーを生成する
$dataKey = $kmsClient->generateDataKey([
'KeyId' => 'arn:aws:kms:ap-northeast-1:AWSアカウントID:key/hoge-piyo', // 事前に作成したカスタマーマネージドキーのArn
'KeySpec' => 'AES_256'
]);
// 暗号論的擬似乱数生成器で初期ベクトルを生成
$iv = random_bytes(openssl_cipher_iv_length($cipher));
$tag = null;
// 暗号化
$encryptedText = openssl_encrypt($plainText, $cipher, $dataKey['Plaintext'], OPENSSL_ZERO_PADDING, $iv, $tag);
// 復号化のために、以下の情報をデータストアに保存する
// 暗号化された文字列: $encryptedText
// 暗号化されたデータキー: $dataKey['CiphertextBlob']
// 初期化ベクトル: $iv
// 認証タグ: $tag
// 復号化
$decryptedText = openssl_decrypt($encryptedText, $cipher, $dataKey['Plaintext'], OPENSSL_ZERO_PADDING, $iv, $tag);
キーのローテーションなどはAWS側でよしなに対応してくれますし、コード側でマスターキーを意識する必要はありません。
これで本質的なビジネスロジックの実装に集中できますね。
補足
PHPは公式でサポートされていないので今回は利用していませんが、可能であればAWS Encryption SDKのご利用をおすすめします。
2024年11月現在、サポートされている言語は以下の通りです。
- C
- .NET
- Java
- JavaScript
- Python
以下の記事も合わせてご覧下さい。