Boto3でS3のpre-signed URLを生成する

Amazon S3

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

AWS は認証付き URL を生成することで AWS のリソースを第三者が操作できるようにする仕組みがあります。

今回は、この機能を活用し

  • S3 にオブジェクトを PUT
  • S3 のオブジェクトを GET

の2パターンに対して Python SDK boto3 を使って認証付きのURL(pre-signed URL)を生成したいと思います。

Boto3 の低レイヤーの botocoregenerate_presigned_url というメソッドがあるので、このメソッドを活用します。

S3 にオブジェクトを PUT

import boto3

BUCKET = 'YOUR_BUCKET'
KEY = 'YOUR_KEY'

s3 = boto3.client('s3')
print s3.generate_presigned_url(
  ClientMethod = 'put_object',
  Params = {'Bucket' : BUCKET, 'Key' : KEY},
  ExpiresIn = 3600,
  HttpMethod = 'PUT')
引数 意味
ClientMethod S3へのリクエストで利用するAPIです
Params ClientMethodで利用する引数です
ExpiresIn URLの有効期間を秒で指定します
HttpMethod S3へのリクエストで利用するHTTPメソッドです

実際に実行すると以下のような URL が生成されます。

https://YOUR_BUCKET.s3.amazonaws.com/YOUR_KEY?AWSAccessKeyId=AKIAIXXXXXXXXXXXXXXX&Expires=1451119930&Signature=wfs8QjbToDFannh6po33DAxvO34%3D

では、この URL を使って S3 にオブジェクトを登録してみましょう。

$ export URL=https://YOUR_BUCKET.s3.amazonaws.com/YOUR_KEY?AWSAccessKeyId=AKIAIXXXXXXXXXXXXXXX&Expires=1451119930&Signature=wfs8QjbToDFannh6po33DAxvO34%3D # generated pre-signed URL
$ echo abcde > test.txt
$ curl -D - -X PUT --upload-file test.txt $URL
HTTP/1.1 100 Continue

HTTP/1.1 200 OK
x-amz-id-2: 9J3B1F6kcpjEszB8w0RJCyOlJPdjWyNDHxRhiQ0bl9NmZGD64iysF/e9Wr9vDWxj4MN1KyOoIlo=
x-amz-request-id: 251BCE507696A64B
Date: Sat, 26 Dec 2015 07:36:39 GMT
ETag: "9b9af6945c95f1aa302a61acf75c9bd6"
Content-Length: 0
Server: AmazonS3

登録したオブジェクトを確認して見ます。

$ aws s3 cp s3://YOUR_BUCKET/YOUR_KEY -
abcde

アップロードしたものと同じですね。

S3 のオブジェクトを GET

今度は pre-signed URL を使って S3 オブジェクトを GET します。

素の GET リクエストでは 403 Forbidden エラーが発生します。

$ curl http://YOUR_BUCKET.s3.amazonaws.com/YOUR_KEY
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>D191003BF8C99932</RequestId><HostId>/4KatDswKFl3MTgyCUNY8MIqwYR1eI2DuKjqVfw/LtJSnnEhtP5KJ5TgnHF9XPpZRZ4xoE1r+0I=</HostId></Error>

先ほどと同じく generate_presigned_url で pre-signed URL を生成します。 S3 get_object API を使うように書き換えています。

import boto3

BUCKET = 'YOUR_BUCKET'
KEY = 'YOUR_KEY'

s3 = boto3.client('s3')
print s3.generate_presigned_url(
  ClientMethod = 'get_object',
  Params = {'Bucket' : BUCKET, 'Key' : KEY},
  ExpiresIn = 3600,
  HttpMethod = 'GET')

生成された URL を使って実際にアクセスしてみましょう。

$ URL="https://YOUR_BUCKET.s3.amazonaws.com/YOUR_KEY?AWSAccessKeyId=AKIAIXXXXXXXXXXXXXXX&Expires=1451119240&Signature=CjKICKWpx7vOs5wQgtpBxghioqs%3D"
$ curl -D - -X GET $URL
HTTP/1.1 200 OK
x-amz-id-2: 4O+FU7EUoRXkEBIT1tlimhVqUGgUZ1GhydBDZvKhQOcuLXywWaK2l5T3vHmFDPG36L34P63xnYs=
x-amz-request-id: 694599C7F47D22AC
Date: Sat, 26 Dec 2015 08:01:57 GMT
Last-Modified: Sat, 26 Dec 2015 07:56:33 GMT
ETag: "9b9af6945c95f1aa302a61acf75c9bd6"
Accept-Ranges: bytes
Content-Type: binary/octet-stream
Content-Length: 6
Server: AmazonS3

abcde

アップロードしたものと同じオブジェクトを取得出来ています。

まとめ

S3 オブジェクトを取得する pre-signed URL はよく使われますが、S3 オブジェクトを更新するときにも pre-signed URL は使えます。 この機能を利用すると、モバイル端末や外部サービスなどから一時的に権限を付与し、S3 に直接アップロードさせることもできるようになります。

参考ページ