2
0

More than 1 year has passed since last update.

Presigned URLの発行と取得したURLを使用して画像ファイルをGET/PUTする。

Last updated at Posted at 2022-03-02

目的

コンテンツをサーバー上にアップロード・ダウンロードして配信するというユースケースがある。コンテンツを保持しておくサービスとして、AWSにS3というサービスがあるのでそれを利用する。

環境

  • AWS Lambda Python 3.9

Lambdaコード

# -- coding: utf-8 --
import boto3
from botocore.client import Config
import os

REGION_NAME = os.environ['REGION_NAME']
S3_BUCKET_NAME = os.environ['S3_BUCKET_NAME']
DURATION_SECONDS = os.environ['DURATION_SECONDS']
KEY_NAME = os.environ['KEY_NAME']

s3 = boto3.client('s3', config=Config(signature_version='s3v4'))

def lambda_handler(event, context):
    
    put_presigned_url = s3.generate_presigned_url(
            ClientMethod = 'put_object', 
            Params = {
                'Bucket' : S3_BUCKET_NAME,
                'Key' : KEY_NAME,
            }, 
            # ExpiresIn = DURATION_SECONDS, 
            HttpMethod = 'PUT'
        )
    
    get_presigned_url = s3.generate_presigned_url(
            ClientMethod = 'get_object', 
            Params = {
                'Bucket' : S3_BUCKET_NAME,
                'Key' : KEY_NAME,
            }, 
            # ExpiresIn = DURATION_SECONDS, 
            HttpMethod = 'GET'
        )
    
    print('PUT Presigned URL: ', put_presigned_url)

    print('GET Presigned URL: ', get_presigned_url)

    return {
       'statusCode': 200,
       'statusDescription': '200 OK',
       'isBase64Encoded': False,
       'headers': {
           'Content-Type': 'text/html; charset=utf-8'
        },
        'body': ''
    }

実行環境の設定

Lambda環境変数

以下、私の設定です。

  • REGION_NAME=us-east-1
  • S3_BUCKET_NAME=sample-s3-presignedurl
  • DURATION_SECONDS=300
  • KEY_NAME=upload/sample.jpg

スクリーンショット 2022-03-02 22.14.00.png

S3_BUCKET_NAMEはGlobalで一意である必要があった気がするので変える必要があります。

S3バケットの作成

環境変数で設定したS3_BUCKET_NAMEのバケット名でS3にバケットを作成する。

IAM

LambdaのExecution RoleにS3へのPUTとGETを許すように変更する。
Lambdaの作成段階で割当たっているロールに、以下のようなポリシーをアタッチする。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::sample-s3-presignedurl/*"
        }
    ]
}

動作確認

Lambdaのテスト機能を利用して、実行し、PresignedURLを取得する。
PUTはcurlを叩くことでsample.jpgをアップロードする。

export url="<出力されたPUTのPresignedURL>"
curl -X PUT --upload-file sample.jpg $url

GETはブラウザに取得したPresignedURLを直打ちすることでダウンロードもしくは表示されることが確認できる。

詰まったところ

さまざまなサイトで、

presigned_url = s3.generate_presigned_url(
            ClientMethod = 'get_object', 
            Params = {
                'Bucket' : S3_BUCKET_NAME,
                'Key' : KEY_NAME,
                'ContentType' : 'img/jpeg',
            }, 
            # ExpiresIn = DURATION_SECONDS, 
            HttpMethod = 'GET'
        )

と記載がありましたが、ContentTypeを指定すると、アップロードもダウンロードもできませんでした。。
ContentTypeを指定していたことが原因で、だいぶ時間がかかってしまいました。# もしかしたら、指定の仕方が悪かったのかもしれませんが。。
実は今回はECSで動いていたアプリ上のコードを検証のためにLambdaで動かしていた形になる。そのため、ECSで動かす時には、s3:PutObjectとs3:GetObjectの実行権限がタスクロールに割り当てられているかを確認する。

参考

2
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0