こんにちは。松本です。
この記事は TECHSCORE Advent Calendar 2016 の 12 日目の記事です。
Amazon S3 でストレージ上のオブジェクトを暗号化して保存する方法は 5 通りあります。
暗号化/復号をサーバー側 (SSE : Server Side Encryption) とクライアント側 (CSE : Client Side Encryption) のいずれで行うかで 2 通りに分類でき、それらをさらに暗号化キーの管理方法で分類しています。下の表がそれをまとめたものです。
暗号化/復号 | 暗号化キー管理 | |
---|---|---|
SSE-S3 | サーバー | S3 |
SSE-KMS | サーバー | KMS |
SSE-C | サーバー | クライアント |
CSE-KMS | クライアント | KMS |
CSE-C | クライアント | クライアント |
※CSE の 2 つの方式は明示的に名前で区別されていないようなので、上記表では仮に -C、-KMS と付けています。
今回はこれらのうち、暗号化/復号をサーバー側で担う SSE (Server Side Encryption) についてご紹介します。
SSE-S3
暗号化キーを Amazon S3 上で自動生成、管理する方式で、3 つの方式のうち最も運用が簡単です。
AWS-SDK for Java (1.11.63) を使った PutObject のサンプルコードです。
1 2 3 4 5 |
ObjectMetadata metadata = new ObjectMetadata(); metadata.setSSEAlgorithm(ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION); PutObjectRequest request = new PutObjectRequest(bucketName, key, file) .withMetadata(metadata); PutObjectResult result = s3.putObject(request); |
ObjectMetadata の SSEAlgorithm プロパティにアルゴリズムを指定するだけです。指定できるアルゴリズムは AES-256 (ObjectMetadata.AES_256_SERVER_SIDE_ENCRYPTION) のみです。
GetObject では SSEAlgorithm を指定する必要はなく、通常通りの操作でオブジェクトの取得が行えます。
SSE-KMS
暗号化キーを AWS KMS (AWS Key Management Service) で管理する方法です。IAM コンソールの「暗号化キー」メニューからキーの作成が行えます。
KMS は有料ですが、全ての暗号化キーの使用ログを記録できるので、高いセキュリティ要求にも応えることができます。
下記が PutObject のサンプルコードです。String 型の変数 keyId には、KMS に作成済みの暗号化キーの ARN を設定します。
1 2 3 4 |
SSEAwsKeyManagementParams kmParams = new SSEAwsKeyManagementParams(keyId); PutObjectRequest request = new PutObjectRequest(bucketName, key, file) .withSSEAwsKeyManagementParams(kmParams); PutObjectResult result = s3.putObject(request); |
SSE-KMS でも GetObject では暗号化キーを指定する必要はなく、通常通りの操作でオブジェクトの取得が行えます。
SSE-C
暗号化キーの作成、管理をアプリケーション側(クライアント側)で行う方式です。作成した暗号化キーを渡せば S3 が暗号化と復号を行います。
PutObject のサンプルです。
1 2 3 4 5 6 7 |
KeyGenerator generator = KeyGenerator.getInstance("AES"); generator.init(256, new SecureRandom()); SecretKey secretKey = generator.generateKey(); SSECustomerKey customerKey = new SSECustomerKey(secretKey); PutObjectRequest request = new PutObjectRequest(bucketName, key, file) .withSSECustomerKey(customerKey); PutObjectResult result = s3.putObject(request); |
暗号化キー作成時には、アルゴリズム(およびキー長)に AES-256 を指定する必要があります。
GetObject でも同じ暗号化キーを指定する必要があります。
1 2 3 |
GetObjectRequest request = new GetObjectRequest(bucketName, key) .withSSECustomerKey(customerKey); S3Object result = s3.getObject(request); |
暗号化の強制
バケットポリシーで x-amz-server-side-encryption ヘッダーのチェックを行えば、S3 へのオブジェクト保存時に暗号化を強制することができます。
次のポリシーは AWS Documentation からの引用です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
{ "Version": "2012-10-17", "Id": "PutObjPolicy", "Statement": [ { "Sid": "DenyIncorrectEncryptionHeader", "Effect": "Deny", "Principal": "*", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::YourBucket/*", "Condition": { "StringNotEquals": { "s3:x-amz-server-side-encryption": "AES256" } } }, { "Sid": "DenyUnEncryptedObjectUploads", "Effect": "Deny", "Principal": "*", "Action": "s3:PutObject", "Resource": "arn:aws:s3:::YourBucket/*", "Condition": { "Null": { "s3:x-amz-server-side-encryption": "true" } } } ] } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "Version":"2012-10-17", "Id":"PutObjPolicy", "Statement":[{ "Sid":"DenyUnEncryptedObjectUploads", "Effect":"Deny", "Principal":"*", "Action":"s3:PutObject", "Resource":"arn:aws:s3:::YourBucket/*", "Condition":{ "StringNotEquals":{ "s3:x-amz-server-side-encryption":"aws:kms" } } } ] } |
ところで AES って?
AES (Advanced Encryption Standard)は、アメリカ合衆国商務省配下の技術部門である国立標準技術研究所 (NIST : National Institute of Standards and Technology) によってアメリカ合衆国標準規格として導入された標準暗号の総称です(DES (Data Encryption Standard) の後継)。
日本でも暗号技術検討会(経済産業省、総務省)と、暗号技術評価委員会(NICT、IPA)、暗号技術活用委員会で構成される日本発の暗号技術評価プロジェクト CRYPTREC (Cryptography Research and Evaluation Committees) によって策定された電子政府推奨暗号リストに AES が含まれています。
まとめ
本記事を書くに当たって暗号化に関する記事をいくつか見ている時に、「復号化」という言葉が誤りで、正しくは「復号」だという記事をいくつか見かけました。
私自身、以前にある人から指摘を受けて「復号」という言葉を使うようになりました。「暗号化」という操作を行うことで「暗号」という状態に変化させる訳ですが、「復号」という状態はないので「復号化」することは出来ないと考えるからです。
ただ色々と調べてみると、ネット上の辞書に「復号化」という言葉があったり、Microsoft のディベロッパー向けドキュメントには「復号化」という言葉が使われてもいます。
言葉というのはなかなか面白いものだなあ……と、特にオチの無い話でした。