Amazon S3からオブジェクトをダウンロードしたり、アップロードしたりする際に使うgenerate_presigned_urlですが、いくつかはまりがちなポイントがあるのでまとめておきます。
前提
Presigned URLの生成はAWS LambdaからBoto3を用いて、こんな感じでやるパターンを想定します。
import boto3
s3_client = boto3.client("s3")
upload_url = s3_client.generate_presigned_url(
ClientMethod = "put_object",
Params = {
'Bucket': "sample-bucket",
'Key': "folder/object.json",
'ContentType': "image/png"
},
ExpiresIn = 300,
HttpMethod = "PUT"
)
トラブルシューティング
-
URLの有効期限が切れてないか
URLの有効期限、例では300
は秒数です。デフォルトでは3600
秒なので、1時間です。 -
Bucketが存在するか
このgenerate_presigned_urlはBucketが存在しなくても結果が返ってきます・・・
Bucketを変数で指定している場合など、特にBucket名をもう一度ログに出力するなどして確認してください。 -
アップロードやダウンロードの際のHTTPリクエストは
HttpMethod
と一致しているか
この場合HttpMethod
にはPUTを指定していますから、実際にPresigned URLを使うときはPUTを使います。 CURLならcurl -X PUT
です。PUT指定したのにPOSTしてるとかよくあるので確認してください。 -
ContentType
が一致してるか
これもPresigned URLを使ってコンテンツをアップロードする場合など、Content-Typeが一致してないと受け付けません。
また、ワイルドカードContent-Type(image/*
など)もうまくいきません。Content-Typeは明示してください。
Curlなら、curl -H "Content-Type: image/png"
です。 -
S3 BucketにCORSの設定がされているか
Presigned URLを使ってコンテンツをダウンロードしたり、アップロードする場合にも、そのBucketのCORSの設定が影響します。
上記の例はPUTメソッドを使いますので、S3 BucketのCORSはPUTを許可してください。[ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "PUT" ], "AllowedOrigins": [ "*" ], "ExposeHeaders": [] } ]
-
Presigned URLを生成するLambda関数にS3へのアクセス権限があるかどうか
Presigned URLをLambda関数から生成する場合に、生成するLambdaのロールには、Assume Roleする関係上、S3へのアクセス権が必要です。
上記の例のようにput_object
を使う場合は書き込み権限が必要ですから、SAMのテンプレートを確認して、以下のようにS3へ権限が設定されているかS3WritePolicy
確認してください。
SAMを使っていない場合は、個別にLambdaのロールを確認して、S3へのWriteがあるか確認する必要があります。
CreateUploadUrlFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions/create_upload_url
Handler: handler.lambda_handler
Runtime: python3.9
Policies:
- S3WritePolicy:
BucketName: sample-bucket
まとめ
Presigned URLが動くかは、特にcurlで確認してください。上記のコードを確認するCurlコマンドは
curl -X PUT -H "Content-Type: image/png" -T uploadfile.png https://PRESIGNED_URL
です。
特にLambdaからBoto3を使う場合、LambdaにS3の権限が設定されてないことが原因だったりします。誰かの役に立ちますように。