Presigned Post を使い、 Amazon S3 のバケツにデータをアップロードを許可する方法です。この方法により AWS のクレデンシャルを持たないエンドユーザーに対してパブリックな URL を発行し、 S3 バケツへの限定的なアクセスを許可することができます。
インフラ#
当該のバケツに対して CORS の許可を与えたください。
$ aws s3api put-bucket-cors --bucket <あなたのバケツ名> --cors-configuration file://bucket-cors.json
// ./bucket-cors.json
{
"CORSRules": [
{
"AllowedOrigins": ["*"],
"AllowedHeaders": ["*"],
"AllowedMethods": ["POST"],
"MaxAgeSeconds": 3000
}
]
}
サーバーサイド#
サーバーサイドでは Presigned Post の機能を使いデータアップロード用の URL を生成します。処理の実行にあたって当該のバケツに対する s3::PutObject
のアクションを許可してください。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:PutObject"
],
"Resource": "arn:aws:s3:::<あなたのバケツ名>/*",
"Effect": "Allow"
}
]
}
以下の2つのライブラリを使います。
$ npm install @aws-sdk/client-s3 @aws-sdk/s3-presigned-post -D
import { S3Client } from '@aws-sdk/client-s3'
import { createPresignedPost } from '@aws-sdk/s3-presigned-post'
const s3Client = new S3Client({})
const { url, fields } = await createPresignedPost(client, {
Bucket: '<あなたのバケツ名>',
Key: `<オブジェクトのキー>`,
Expires: 3600, // URL の有効期限を秒で指定
})
なお、この際に Conditions
パラメーターを利用することでさまざまなポリシーを設定することができます。例えば content-length-range
を指定してアップロードのサイズを制限したり。詳細は以下に記載されています。
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html
ここで生成された url
と fields
をエンドユーザー(クライアントサイド)に渡します。
これらのデータは以下のようなフォーマットです。
{
"url": "https://<あなたのバケツ名>.s3.<バケツのリージョン名>.amazonaws.com/",
"fields": {
"bucket": "<あなたのバケツ名>",
"X-Amz-Algorithm": "AWS4-HMAC-SHA256",
"X-Amz-Credential": "...",
"X-Amz-Date": "20240328T080640Z",
"X-Amz-Security-Token": "...",
"key": "<オブジェクトのキー>",
"Policy": "...",
"X-Amz-Signature": "..."
}
}
クライアントサイド#
クライアントサイドでは、上記で得られた url
に対して fields
をフォームデータとして送信し、その際に送信したいデータを file
として追加します。
async function presignedPost(file: File) {
const formData = new FormData()
for (const key in fields) {
formData.append(key, fields[key])
}
formData.append('file', file)
await fetch(url, {
method: 'POST',
body: formData
})
}
この処理を実行することで当該のキーの S3 オブジェクトとしてデータがアップロードされます。
エンドユーザーにアバター画像をアップロードさせたり、何らかの処理を行うために大きなファイルをアップロードするような用途に適していると思います。アップロードしたデータは S3 のストリームイベントなどを通して別の処理をトリガーさせることができます。