Kinesisストリームのサーバーサイド暗号を使ってみた
コンプライアンスや情報セキュリティの観点から、データの暗号化が求められるケースは多々あります。 S3やRDSでは以前から保存時のデータ暗号化(encryption at rest)を提供してきました。
この度、KinesisストリームもKMSと連携したサーバーサイド暗号に対応したため、早速触ってみました。
Kinesisストリームの暗号化の方針
Kinesisストリームの暗号化は大きく以下の2方針があります。
- サーバーサイド暗号 : Kinesisストリームがストレージに保存・取り出すタイミングで暗号・復号
- クライアント暗号 : Producerが暗号化したデータをKinesisストリームにPut。ConsumerがGetしたデータを復号
今回紹介する機能は前者のサーバーサイド暗号です。 後者のクライアント暗号については、次のブログを参考にして下さい。
Encrypt and Decrypt Amazon Kinesis Records Using AWS KMS | AWS Big Data Blog
サーバーサイド暗号の処理の流れ
サーバーサイド暗号では、Kinesisストリームのストレージ I/O のタイミングで暗号・復号処理を行います。
AWS Big Data Blogに解説記事があるため、こちらをベースに紹介します。
Under the Hood of Server-Side Encryption for Amazon Kinesis Streams | AWS Big Data Blog
AWs CLIからの利用は次のブログを参照下さい。
共通処理
Amazon KMSでエンベロープ暗号します。 そのため、マスターキーとは別にデータ毎に異なるデータキーが生成されます。
参照 : エンベロープ暗号の流れ
暗号処理
画像はブログから
登場人物
- Data Producer
- AWS KMS
- Kinesis Streams Front End
- Kinesis Streams Storage
処理の流れ
Kinesis Streams Front End は Data Producer からプレインデータを受け取り、AWS KMSで暗号化したあと、Kinesis Streams Storage に保存します。
復号処理
画像はブログから
登場人物
- Data Producer
- AWS KMS
- Kinesis Streams Front End
- Kinesis Streams Storage
処理の流れ
Kinesis Streams Front End は Kinesis Streams Storage から暗号化されたデータを取得し、AWS KMSで復号したあと、Data Consumerにプレインデータを渡します。
実際に試してみる
サーバーサイド暗号の流れを確認した上で、実際に操作してみましょう。
作業の流れ
- Kinesis ストリームの作成
- Kinesis ストリームの暗号を有効化
- Kinesis ストリームにデータを投入
- Kinesis ストリームからデータを取得
1. Kinesis ストリームの作成
Kinesisストリームを作成します。 サーバーサイド暗号が対応している以下のリージョンで作成して下さい。
- US East (N. Virginia)
- US West (N. California and Oregon)
- EU (Ireland)
- Asia Pacific (Tokyo)
- Asia Pacific (Singapore)
今回は EU (Ireland) を利用しました。
2. Kinesis ストリームの暗号を有効化
Kinesis ストリームの暗号化を有効します。
管理画面でストリームの"Details"画面に移動します。 "Server-side encryption"のセクションが追加されているため、"Edit"ボタンで編集モードに入ります。
初期状態ではServer-side encryptionは無効化(Disabled)されているため、Enabled を選択肢、KMS master keyを選択します。
KMS master key には、AWSが用意するKinesisストリーム専用のデフォルトのマスターキーの他、ユーザーがストリームと同じリージョンに作成したマスターキー(CMK)も選択可能です。
20秒程度すると、暗号化は有効化されます。
CLI で暗号化されたストリームを確認
Kinesisストリームの describe-stream APIで暗号前後のKinesisストリームの表示の違いを確認してみましょう。
暗号有効前
- KeyId
- EncryptionType
が今回追加された項目です。 暗号有効化前はどちらも null/None と未設定です。
$ aws kinesis describe-stream --stream-name foo { "StreamDescription": { "KeyId": null, "EncryptionType": "NONE", "StreamStatus": "ACTIVE", "StreamName": "foo", "Shards": [ { "ShardId": "shardId-000000000000", "HashKeyRange": { "EndingHashKey": "340282366920938463463374607431768211455", "StartingHashKey": "0" }, "SequenceNumberRange": { "StartingSequenceNumber": "49575028884351352808466151260471461389056657087524765698" } } ], "StreamARN": "arn:aws:kinesis:eu-west-1:123456789012:stream/foo", "EnhancedMonitoring": [ { "ShardLevelMetrics": [] } ], "RetentionPeriodHours": 24 } }
暗号有効後
- KeyID に KMS のマスターキーの ARN
- EncryptionType に KMS
と出力されているのがわかります。
$ aws kinesis describe-stream --stream-name foo { "StreamDescription": { "KeyId": "arn:aws:kms:eu-west-1:123456789012:key/DUMMY-DUMMY", "EncryptionType": "KMS", "StreamStatus": "ACTIVE", "StreamName": "foo", "Shards": [ { "ShardId": "shardId-000000000000", "HashKeyRange": { "EndingHashKey": "340282366920938463463374607431768211455", "StartingHashKey": "0" }, "SequenceNumberRange": { "StartingSequenceNumber": "49575028884351352808466151260471461389056657087524765698" } } ], "StreamARN": "arn:aws:kinesis:eu-west-1:123456789012:stream/foo", "EnhancedMonitoring": [ { "ShardLevelMetrics": [] } ], "RetentionPeriodHours": 24 } }
3. Kinesis ストリームにデータを投入
ストリームにデータを投入します。
暗号処理はサーバーサイドで行われるため、クライアント側の特別な対応は不要です。
注意
暗号鍵にKMSにCMKを設定した場合は、後述の手順に従い、IAMパーミッションを見直して下さい。 デフォルトのマスターキー(aws/kinesis)を設定した場合は、特別なIAM対応は不要です。
暗号化前
$ aws kinesis put-record --stream-name foo --data a --partition-key a { "ShardId": "shardId-000000000000", "SequenceNumber": "49574905023871648630326283351695319731000495113848750082" }
暗号化後
暗号化後は、レスポンスに "EncryptionType": "KMS" という情報が追加されます
$ aws kinesis put-record --stream-name foo --data b --partition-key b { "ShardId": "shardId-000000000000", "EncryptionType": "KMS", "SequenceNumber": "49574905023871648630326283351698946508459383806471700482" }
4. Kinesis ストリームからデータを取得
ストリームからデータを取得します。
暗号処理はサーバーサイドで行われるため、クライアント側の特別な対応は不要です。
暗号化を有効にしたストリームに取り込まれたデータは、get-records 時に "EncryptionType" 属性が追加されます。
注意
暗号鍵にKMSにCMKを設定した場合は、後述の手順に従い、IAMパーミッションを見直して下さい。 デフォルトのマスターキー(aws/kinesis)を設定した場合は、特別なIAM対応は不要です。
$ aws kinesis get-shard-iterator --stream-name foo --shard-id shardId-000000000000 --shard-iterator-type TRIM_HORIZON { "ShardIterator": "DUMMY" } $ aws kinesis get-records --shard-iterator "DUMMY" { "Records": [ { "Data": "YQ==", "PartitionKey": "a", "ApproximateArrivalTimestamp": 1499878905.118, "SequenceNumber": "49575030693030991390093810531762068269413316054617161730" }, { "Data": "Yg==", "PartitionKey": "b", "ApproximateArrivalTimestamp": 1499878938.69, "EncryptionType": "KMS", "SequenceNumber": "49575030693030991390093810531763277195232933088973553666" } ], "NextShardIterator": "DUMMY-NEXT", "MillisBehindLatest": 0 } ## base64デコードして実データを確認 $ echo "YQ==" | base64 -d a $ echo "Yg==" | base64 -d b
KMSにCMKを利用する場合の対応
暗号鍵にはAWSが管理するデフォルトのマスターキーとは別に、ユーザーが作成したKMSマスターキー(CMK)を設定する事もできます。
この場合、追加で以下の手順が発生します。
- KMS マスターキーの作成
- IAM パーミッションの設定
なお、CMK は API 利用費とは別に月あたり1ドルの利用費が発生します。ご注意下さい。
KMS マスターキーの作成
暗号化したいKinesis ストリームと同じリージョンに マスターキーを作成します。
具体的な手順は次のページを参照下さい。
AWS Documentation » AWS KMS » Developer Guide » Getting Started » Creating Keys
IAM パーミッションの設定
暗号鍵にデフォルト鍵を設定する場合、IAMパーミッションの特別な対応は不要ですが、CMK を設定する場合、クライアントがその鍵を使えるようにパーミッションを修正する必要があります。
Producer向けパーミッション
データを生成するProducer向けパーミッションです。 データを暗号化するためのデータキーを生成出来るようにします。
- 8行目には作成した KMS CMK の ARN を設定
- 15行目には Kinesis Stream の ARN を設定
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "kms:GenerateDataKey" ], "Resource": "arn:aws:kms:eu-west-1:123456789012:key/Dummy" }, { "Effect": "Allow", "Action": [ "kinesis:PutRecord", "kinesis:PutRecords" ], "Resource": "arn:aws:kinesis:*:123456789012:foo" } ] }
パーミッションが足りない場合は、以下のようなエラーメッセージが表示されます
$ aws kinesis put-record --stream-name foo --data f --partition-key f --region eu-west-1 An error occurred (KMSAccessDeniedException) when calling the PutRecord operation: User ASDF is not authorized to encrypt records in stream 123456789012:foo:1499523089
Consumer向けパーミッション
データを受け取るConsumer向けパーミッションです。 暗号化されたデータキーをマスターキーで復号出来るようにします。
- 8行目には作成した KMS CMK の ARN を設定
- 15行目には Kinesis Stream の ARN を設定
{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "kms:Decrypt" ], "Resource": "arn:aws:kms:eu-west-1:123456789012:key/Dummy" }, { "Effect": "Allow", "Action": [ "kinesis:GetRecords", "kinesis:DescribeStream" ], "arn:aws:kinesis:*:123456789012:foo" } ] }
パーミッションが足りない場合は、以下のようなエラーメッセージが表示されます
$ aws kinesis get-records --shard-iterator "DUMMY" An error occurred (KMSAccessDeniedException) when calling the GetRecords operation: User DUMMY is not authorized to decrypt records in stream 1234556789012:foo:1499523089
利用可能なリージョン
2017/07/12 時点では以下のリージョンでのみ利用できます
- US East (N. Virginia)
- US West (N. California and Oregon)
- EU (Ireland)
- Asia Pacific (Tokyo)
- Asia Pacific (Singapore)
2017/07/19更新
対応リージョンが以下に増えました
- US East (Ohio) us-east-2
- US East (N. Virginia) us-east-1
- US West (Oregon) us-west-2
- US West (N. California) us-west-1
- AWS GovCloud (US) us-gov-west-1
- Canada (Central) ca-central-1
- EU (Ireland) eu-west-1
- EU (London) eu-west-2
- EU (Frankfurt) eu-central-1
- Asia Pacific (Tokyo) Region ap-northeast-1
- Asia Pacific (Seoul) Region ap-northeast-2
- Asia Pacific (Singapore) ap-southeast-1
- Asia Pacific (Mumbai) ap-south-1
- Asia Pacific (Sydney) ap-southeast-2
- South America (São Paulo) sa-east-1
コスト
Kinesis ストリーム
追加コストは発生しません。
KMS
- データキーの生成
- マスターキーによるデータキーの復号
などで KMS の API を呼び出します。 月当り数ドル以下と予想されます。
また、CMK を作成すると月あたり $1 のコストが発生します。 AWSが管理するマスターキーは無料です。
パフォーマンス
マニュアルによると、暗号処理のオーバーヘッドにより、PUT/GETともに 0.1ミリ秒(100μs)以下のレイテンシーが発生すると記載があります。
Due to the service overhead of applying encryption, applying server-side encryption will increase the typical latency of PutRecord, PutRecords, and GetRecords by less than 100μs.
AWS Big Data Blogによると、暗号処理のオーバーヘッドにより、PUT/GET ともにレコードあたり 0.2 ミリ秒以下のレイテンシーが観測されました。
During testing, AWS discovered that there was a slight increase (typically 0.2 millisecond or less per record) with put and get record latencies due to the additional overhead of encryption.
まとめ
- ちょっとした設定変更
- 軽微なコスト増加
- 微小なレイテンシー
を受け入れれば、クライアント側の変更無しに、サクッとKinesisストリームのサーバーサイド暗号を実現できます。
参考
- Under the Hood of Server-Side Encryption for Amazon Kinesis Streams | AWS Big Data Blog
- Amazon Kinesis Streams Introduces Server-Side Encryption
- AWS Documentation » Amazon Kinesis Streams » Developer Guide » Working With Amazon Kinesis Streams » Using Server-Side Encryption - New: Server-Side Encryption for Amazon Kinesis Streams | AWS Blog