« AWS Black Belt Online Seminar 「Amazon S3」資料公開 | メイン | AWS Black Belt Online Seminar「Amazon RDS」資料公開 »

AWS KMSを使ってS3のオブジェクトを暗号化するためのREST APIの使用法

AWS Key Management Service(AWS KMS)は、ユーザーが管理する鍵を利用してAmazon S3に保管するデータの暗号化を行うことが出来ます。暗号化を実装する主要な方法は、サーバサイド暗号化(SSE)とクライアントサイド暗号化(CSE)の2つで、そのそれぞれについて複数のインターフェースやAPIが選択可能です。この記事では、KMSの鍵を使ってS3のオブジェクトをSSEで保護するためのAWS REST APIの利用法についてお伝えします。AWS SDKを使うのに対して、クロスプラットフォームのコードを開発しようと考えていたり、アプリケーションの中でAPIの利用をコントロールしたい場合にはネイティブなREST APIを使うことはより良いオプションになりえます。

 

REST API コール認証の概要

AWS REST APIコールを行う際にクリティカルな要素の一つは、リクエストの認証に利用される署名です。認証されたユーザーのみがデータにアクセスできるようにしたい場合に署名は極めて重要です。署名を必要としない匿名アクセスを許可するオプションもありますが、これは世界中にデータを公開することになります。セキュリティの観点から、AWSでは署名付きの認証されたリクエストのみを利用することを推奨しています。これによって、リクエスターのアイデンティティを検証することができ、in-transitのデータインテグリティを保護し、リプレイアタック用として署名されたリクエストを部分再利用される事を防ぐ事が出来ます。ここでは、AWS REST APIに署名を行うアプローチについて記述します。そして、ユーザーがKMSを利用してアカウント内で管理している鍵を使ってS3サービスがユーザーに代わってオブジェクトを暗号化するためのリクエストを行うためのテクニックについて解説します。

 署名は、HTTP POSTリクエストからPOSTポリシーとして文字列を形成するためのリクエスト要素を結合することで計算されます。これをstring to signと呼びます。次に、string to signの鍵付きハッシュメッセージ認証コード(HMAC)を計算するために署名キーが利用されます。AWSバージョン4署名では、シークレットアクセスキーが署名キーの作成に利用されます。S3がリクエストを受信すると、署名が一致するか確認するために、提供された認証情報を利用して署名を再生成します。もし一致すれば、リクエストは許可され、データが返されますが、一致しなければエラーが返されます。

次の図は、署名作成の例です。

 

KMSデフォルトキー vs お客様独自キー

SSEを使うかCSEを使うかを決定する際、使用する暗号鍵は重要な要素です。コスト、柔軟性、セキュリティ、メンテナンスの観点から最適なオプションを決定するために、幾つかの要素を考慮する必要がありますが、最も重要な要素はアクセスコントロールです。確かなセキュリティレベルを保つためには、許可されたユーザーのみが復号に必要な暗号鍵にアクセスできることの保証が求められます。KMSでは、ポリシーを利用してこのようなアクセス許可をコントロールすることが出来ます。
 
加えて、KMSを利用すれば全てのAPIコールはAWS CloudTrailによってログに記録され、いつ、どこで、誰があなたのカスタマー管理キー(CMK) を利用したかを確認することができます。このログによって鍵に対する完全な監査機能が提供されます。また、各アカウントおよびサービスにKMSとインテグレートされたデフォルトCMKがあります。この鍵は、デフォルトサービスキーとしてKMSコンソール内にaws/[サービス名] (例えば, aws/s3)というエイリアスで常にリストされます。 KMS内にカスタムキーを作らない場合は、このデフォルトサービスキーが利用されます。

初めて特定のリージョンのS3バケットにSSE-KMSでオブジェクトを暗号化して格納する際、アカウント内のユーザーにのみ使用する許可があるs3用のデフォルトサービスキーを利用することができます。しかしながら、独自のカスタムCMKを作成することで、鍵のアクセスコントロール、監査、ローテーション、削除をより柔軟に行うことが出来ます。また、独自CMKは、複数のAWSサービスをまたがって自身のアプリケーションから利用することも出来ます。

デフォルトサービスCMKには、ユーザーが変更できないデフォルトのキーポリシーが割り当てられています。次のAWS CLIコマンドを実行することで、このポリシーを参照することが出来ます。(プレースホルダーの値は自身の値に置き換えてください)

aws kms get-key-policy --key-id arn:aws:kms:region:111122223333:key/<32-char keyId>

次のポリシーサンプルは、デフォルトaws/s3 CMK に割り当てられているデフォルトキーポシリーです。このポリシーはアカウント内の全てのAWS Principals が、S3リソースに対してIAMポリシー内で適切な許可を持っている限り、リストされた Actionsを実行できるということを示しています。 またこのポリシーは、キーのメタデータ(アカウントID、ARN、description、キーステート)を取得することも許可しています。

 

{
      "Version": "2012-10-17",
      "Id": "auto-s3-2",
      "Statement": [{
            "Sid": "Allow access through S3 for all principals in the account that are authorized to use S3",
            "Effect": "Allow",
            "Principal": {
                  "AWS": "*"
            },
            "Action": [
                  "kms:Encrypt",
                  "kms:Decrypt",
                  "kms:ReEncrypt*",
                  "kms:GenerateDataKey*",
                  "kms:DescribeKey"
            ],
            "Resource": "*",
            "Condition": {
                  "StringEquals": {
                        "kms:CallerAccount": "111122223333",
                        "kms:ViaService": "s3.region.amazonaws.com"
                  }
            }
      }, {
            "Sid": "Allow direct access to key metadata in the account itself",
            "Effect": "Allow",
            "Principal": {
                  "AWS": "arn:aws:iam::111122223333:root"
            },
            "Action": [
                  "kms:Describe*",
                  "kms:Get*",
                  "kms:List*"
            ],
            "Resource": "*"
      }]

}

これに対してカスタムCMKでは、誰が鍵の管理および利用できるか、AWSリソース利用時に自身の代わりにKMSにアクセスできるのは誰かを制限することができます。次のポリシーはカスタムCMK作成時に割り当てたポリシーの例です。

{
      "Version": "2012-10-17",
      "Id": "key-consolepolicy-2",
      "Statement": [{
            "Sid": "Enable IAM user permissions",
            "Effect": "Allow",
            "Principal": {
                  "AWS": "arn:aws:iam::111122223333:root"
            },
            "Action": "kms:*",
            "Resource": "*"
      }, {
            "Sid": "Allow access for key administrators",
            "Effect": "Allow",
            "Principal": {
                  "AWS": "arn:aws:iam::111122223333:user/IAMuser"
            },
            "Action": [
                  "kms:Describe*",
                  "kms:Put*",
                  "kms:Create*",
                  "kms:Update*",
                  "kms:Enable*",
                  "kms:Revoke*",
                  "kms:List*",
                  "kms:Disable*",
                  "kms:Get*",
                  "kms:Delete*"
            ],
            "Resource": "*"
      }, {
            "Sid": "Allow use of the key",
            "Effect": "Allow",
            "Principal": {
                  "AWS": "arn:aws:iam::111122223333:user/IAMuser"
            },
            "Action": [
                  "kms:DescribeKey",
                  "kms:GenerateDataKey*",
                  "kms:Encrypt",
                  "kms:ReEncrypt*",
                  "kms:Decrypt"
            ],
            "Resource": "*"
      }, {
            "Sid": "Allow attachment of persistent resources",
            "Effect": "Allow",
            "Principal": {
                  "AWS": "arn:aws:iam::111122223333:user/IAMuser"
            },
            "Action": [
                  "kms:ListGrants",
                  "kms:CreateGrant",
                  "kms:RevokeGrant"
            ],
            "Resource": "*",
            "Condition": {
                  "Bool": {
                        "kms:GrantIsForAWSResource": "true"
                  }
            }
      }]
}

鍵に対するカスタムポリシー以前に、IAMで鍵にアクセスできるユーザー、ロール、サービスについて制限を行うことができます。これはKMSのCMKを利用する利点の一つです。KMSのキーポリシーについての詳細は、キーポリシーをご参照下さい。

 

署名バージョンとリクエストヘッダー

KMSで保護されたS3オブジェクトに対して全てのGET/PUTリクエストを実行するためには、バージョン4署名を使う必要があります。(バージョン2署名はサポートされていません) バージョン4署名は、どのようにリクエストに署名するかの選択に応じて、以下のいくつかあるいは全てを利用して認証を行うことができます:

  • リクエスト者のアイデンティティ検証
  • In-transit データの保護
  • リクエストの署名部分の再利用に対する保護
リクエストヘッダーは、HTTPリクエストの中の名前/値のペアを含む一連の情報です。これはどんな順序で記述することもできるオリジナルのリクエストに関する情報です。一般的なリクエストヘッダの例として、Content-Length, Content-Type, Date, Host, x-amz-security-token等があります。次の例は、ヘッダを含む基本的なリクエストです:
GET /ObjectName HTTP/1.1
Host: BucketName.s3.amazonaws.com
Date: date Authorization: authorization string
SSEには、幾つかのヘッダが必要になります。主に必要なヘッダはx-amz-server-side-encryptionであり、こちらはオブジェクトアップロードのための暗号化フォーマットとしてaws:kmsを用いてSSE-KMSをリクエストするのに利用されます。また使用するKMS CMKのIDを指定するために、x-amz-server-side-encryption-aws-kms-key-idヘッダも必須となります。受信者にオブジェクトに対するコンテキスト情報のマッチングを強制するための更なるセキュリティレイヤーを追加するために、x-amz-server-side-encryption-contextを使うこともできます。より詳細な情報についてはKMSドキュメントのEncryption Context および、こちらのブログ記事 をご参照下さい。

次のREST APIでは、S3オブジェクトアップロード時の暗号化フォーマットとしてaws:kms を指定するために必要なヘッダとしてx-amz-server-side-encryptionリクエストヘッダを受け付けます。

REST APIコールを発行する最も簡単な手段の一つはRESTful アドオンの入ったブラウザを利用することです。Google Chrome用の Postman - REST Client 、Mozilla Firefox用の RESTClient の2つのオプションがあります。アドオンをインストールすれば、ブラウザからS3オブジェクトに対するREST APIコールを発行することが出来ます。これはアプリケーションをプログラミングすること無くデータにアクセスするための、早く、効果的な方法です。

この記事では、次のスクリーンショットのように、FirefoxとRESTClient アドオンを利用しています。

 

SSE-KMSを使ってS3オブジェクトをセキュアにするREST API使用法

ここまでにS3でSSE-KMSを使い、REST APIコールを行うための主要なコンポーネントについて説明しました。これでSSE-KMSを利用してS3オブジェクトをセキュアにするためにREST APIを使用するプロセスを開始できます。

 

Step 1: バージョン4署名とお好きなプログラミング言語を利用して認証用署名を作成する

S3への認証用署名は保管されるデータを認証されたユーザーにのみ利用可能にするためにS3へのAPIリクエストを認証するのに使われます。署名は、オブジェクトのデータとシークレットキー及びその他のメタデータから作成されたハッシュ値を結合して作成されます。

署名の作成はさまざまなプログラミング言語で行うことができますが、この記事の例ではJavaScriptを使用しています。次のコードスニペットは、どうやってstring to signを作成するか、どうやって署名鍵のハッシュを作成するかを示し、APIコールの認証のための完全な署名を提供するかを示します。


次のリクエストは認証のための署名を利用していません。
GET https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08 HTTP/1.1 Content-Type: application/x-www-form-urlencoded; charset=utf-8 Host: iam.amazonaws.com X-Amz-Date: 20150830T123600Z

次のリクエストは認証のための署名を利用しています。Signatureフィールドがあることに注目してください:

GET https://iam.amazonaws.com/?Action=ListUsers&Version=2010-05-08 HTTP/1.1 Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/iam/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7 content-type: application/x-www-form-urlencoded; charset=utf-8 host: iam.amazonaws.com x-amz-date: 20150830T123600Z

署名鍵のハッシュを作成するのに利用したJavaScriptコードはforge.bundle.jsです。Ruby, .NET, Pythonおよびその他 の中から好きな言語を利用することができます。これを使って最終的な署名を作る時に利用されるHMACを作成します。

このグループでのヘビーリフター(訳注:困難な作業を簡単にしてくれるコンポーネントの比喩)は、ダウンロード可能なPresigned URL JavaScript code for Browser-based JavaScript POST スクリプトです。このスクリプトは forge.bundle.jsで作成されたハッシュ値、ファイルの情報、暗号化に利用するKMSの鍵の情報を結合して、署名の値を作成します。この署名はREST API コールのrequest bodyの中のAuthorizationセクションの下に配置されます。

これで、S3へのREST APIリクエストを認証するための署名を完了しました。次のステップでは、オブジェクトの要素とCMKを結合することで PUT REST APIコールを作成することにフォーカスします。

 

Step 2: PUT REST APIリクエストの作成

ここではPOSTの代わりにPUTリクエストを使用します。なぜならPUTは作成または更新のためのものであり、POSTは作成だけのためのリクエストだからです。このリクエストはオブジェクトの重複を防ぎます。PUTリクエストは、後日取り出せるようにデータあるいはオブジェクトをサーバ上に配置します。

REST APIを使用してS3へデータをアップロードするには、PUTリクエストを作成する必要があります。これを実施するために、MethodPUTに設定し、URLとしてS3 URL(例えばhttps://s3-us-east-1.amazonaws.com)を指定し、request bodyをBodyの箱に置きます。暗号化方式として aws:kms を指定するため、および実際のデータ暗号化に使用したいKMS CMK のキーIDを指定するために x-amz ヘッダーを含めることを忘れないで下さい。PUT REST APIコールの例は以下です。
PUT /example_image.jpg HTTP/1.1
Host: example-bucket.s3.amazonaws.com
Accept: */*  
Authorization: 5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
Date: Wed, 28 May 2014 19:31:11 +0000  
x-amz-server-side-encryption:aws:kms 
x-amz-server-side-encryption-aws-kms-key-id:arn:aws:kms:us-east-1:111122223333:key/0695f802-503c-40n2-d17d-16d702f79f01

以下のようなレスポンスを受け取ります。 (続くスクリーンショットはブラウザアドオンでどのようにレスポンスが表示されるかを示しています)

HTTP/1.1 200 OK   
x-amz-id-2: 7qoYGN7uMuFuYS6m7a4lszH6in+hccE+4DXPmDZ7C9KqucjnZC1gI5mshai6fbMG   
x-amz-request-id: 06437EDD40C407C7   
Date: Wed, 28 May 2014 19:31:11 +0000  
x-amz-server-side-encryption:aws:kms 
x-amz-server-side-encryption-aws-kms-key-id:arn:aws:kms:us-east-1:111122223333:key/0695f802-503c-40n2-d17d-16d702f79f01
ETag: "ae89237c20e759c5f479ece02c642f59"

 

Step 3: GET REST API リクエストの作成

GETリクエストはサーバ上に既に配されているデータを取り出すために利用されます。ファイルをオープンしたり、画像をダウンロードすると考えて下さい。GETリクエストは、事前に保管されている情報を取り出す方法です。

S3からデータを取り出すためには、GETリクエストを生成する必要があります。リクエストの成功は、アップロード済みのオブジェクトに対してユーザーがREADアクセスを持っているかどうかに依存します。READアクセスはユーザーがリクエストしたオブジェクトをオープンしたりダウンロードしたりすることを許可します。また、KMS で暗号化されたオブジェクトのためのリクエストには、以前作成された認証用署名も一緒に渡す必要があります。PUTリクエストと同じステップに従って、PUTのかわりにGET APIを利用します。GET REST APIコールの例は以下です。
GET /example_image.jpg HTTP/1.1
Host: example-bucket.s3.amazonaws.com  
Accept: */*  
Authorization: 5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7
Date: Wed, 28 May 2014 19:31:11 +0000  
x-amz-server-side-encryption: aws:kms 
x-amz-server-side-encryption-aws-kms-key-id:arn:aws:kms:us-east-1:111122223333:key/0695f802-503c-40n2-d17d-16d702f79f01

次のようなレスポンスを受け取ります。 (続くスクリーンショットははブラウザアドオンでどのようにレスポンスが表示されるかを示しています)

HTTP/1.1 200 OK
x-amz-id-2: ka5jRm8X3N12ZiY29Z989zg2tNSJPMcK+to7jNjxImXBbyChqc6tLAv+sau7Vjzh
x-amz-request-id: 195157E3E073D3F9   
Date: Wed, 28 May 2014 19:31:11 +0000  
Last-Modified: Wed, 28 May 2014 19:31:11 +0000  
ETag: "c12022c9a3c6d3a28d29d90933a2b096"   
x-amz-server-side-encryption: aws:kms   
x-amz-server-side-encryption-aws-kms-key-id:arn:aws:kms:us-east-1:111122223333:key/0695f802-503c-40n2-d17d-16d702f79f01

サマリー

この記事では、REST APIコールを認証するためになぜ署名が必要かについて説明し、署名には何が含まれ、どのように署名を作成するかについて説明しました。API認証に署名を利用すれば、アプリケーションのセキュリティを高めることができます。 SSE-KMSが、アクセスポリシー、Encryption Contextおよびリクエストヘッダー指定を用いて更なるレベルのセキュリティを追加できることについてもカバーしました。REST APIリクエストにどのように署名を追加するかのウォークスルーは、このプロセスをどうやって簡単に行えるか(このプロセス最も複雑な部分は署名の作成です)についての参考情報をお伝えしました。これであなたも、セキュアにデータを置いたり、取り出したりするためのREST APIリクエストを素早くかつ効率的に作成することができます。

コメントがある場合はコメント欄に、ご質問がある場合はIAMフォーラムで新しいスレッドを作成してください。

- Tracy(翻訳はSA布目が担当しました。原文はこちら

コメント

Twitter, Facebook

このブログの最新情報はTwitterFacebookでもお知らせしています。お気軽にフォローください。

2018年4 月

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