KMSで暗号化されたS3オブジェクトに対し、署名付きURLを発行してダウンロードする
はじめに
S3バケットへのパブリックアクセスを禁止しつつ、一時的なアップロード・ダウンロードを行いたいという場合、署名付きURL(Pre-Signed URL)の利用がまず候補に上がるかと思います。
署名付きURLを利用すると、予め決めた時間まで有効なURLをAWSが払い出してくれ、そのURLに対してアップロード・ダウンロードを行うことができます。
暗号化されていないオブジェクトであれば、特につまずくこともなくすんなり行くかと思いますが、今回KMSで暗号化されたS3オブジェクトに対して署名付きURLを発行する場合に少しつまずいたので、共有させていただきます。
普通に署名付きURLを発行してみる
Python(boto3)でダウンロードを行う署名付きURLを発行しようとすると、次のようなコードになると思います。
import boto3 s3 = boto3.client('s3') url = s3.generate_presigned_url( ClientMethod='get_object', Params={ 'Bucket': bucketname, 'Key': key })
しかし、KMSで暗号化されたS3オブジェクトに対して上記のように発行してアクセスすると、
<Error> <Code>InvalidArgument</Code> <Message> Requests specifying Server Side Encryption with AWS KMS managed keys require AWS Signature Version 4. </Message> <ArgumentName>Authorization</ArgumentName> <ArgumentValue>null</ArgumentValue> <RequestId>24057D1234567890</RequestId> <HostId> jqdIuhcHLQRrv1nqb/YrfPWXmVTpIarsldIdedHB+OGi1z1234567890= </HostId> </Error>
と署名バージョン4を要求され、ファイルのダウンロードができません。
解決策
Python側で署名バージョン4を次のようなコードで指定してやる必要があります。
import boto3 from botocore.client import Config s3 = boto3.client('s3', config=Config(signature_version='s3v4')) url = s3.generate_presigned_url( ClientMethod='get_object', Params={ 'Bucket': bucketname, 'Key': key })
以上で払い出されたURLにアクセスすると、
$ curl "https://testbucketname12345.s3.amazonaws.com/test.txt?\ X-Amz-Algorithm=AWS4-HMAC-SHA256&\ X-Amz-Credential=AKIAILSPFRZJADABCDEF%2F20180827%2Fap-northeast-1%2Fs3%2Faws4_request&\ X-Amz-Date=20180827T012248Z&X-Amz-Expires=3600&\ X-Amz-SignedHeaders=host&\ X-Amz-Signature=9db6efcc2ea2594b9f08e4cc9873494c75ec381122245b37dfca082d12345678" testtxtbody
ちゃんとダウンロードできました。
おわりに
KMSによって暗号化されたオブジェクトが、署名バージョン4でないと取得できないということは、S3のドキュメントに書かれていました。 AWS KMS で管理されたキーによるサーバー側の暗号化 (SSE-KMS) を使用したデータの保護 - Amazon Simple Storage Service
また、解決策はboto3のドキュメントに書かれています。 S3 - Boto 3 Docs 1.7.84 documentation