tl; dr –サーバーから取得した署名済みURL(AWS S3)へのブラウザーからのOPTIONS
リクエストは200
を取得しますが、次のPUT
リクエストは403
を取得します
これは、AWSとそのS3サービスを担当する私のサーバー側コードです。
const AWS = require('aws-sdk');
const config = {
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
region: process.env.AWS_BUCKET_REGION,
};
AWS.config.update(config);
const S3Bucket = new AWS.S3({
signatureVersion: 'v4',
params: { Bucket: process.env.AWS_BUCKET_NAME },
});
const uploadImage = async (fileData) => {
// fileData contains `name` and `type` properties
const Key = `images/${fileData.name}`;
const params = {
Bucket: process.env.AWS_BUCKET_NAME,
Key,
Expires: 15 * 60, // 15 minutes
ContentType: fileData.type,
ACL: 'public-read',
};
const url = await S3Bucket.getSignedUrlPromise('putObject', params);
return url;
};
上記のコードのIAMユーザー(AWS_ACCESS_KEY_ID
、AWS_SECRET_ACCESS_KEY
)には、次のポリシーが添付されています。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Stmt1418647210000",
"Effect": "Allow",
"Action": [
"s3:Put*"
],
"Resource": [
"arn:aws:s3:::my-actual-bucket-name-here/*"
]
}
]
}
実際のバケットにはBucket policy
が設定されておらず、次のCORS設定があります。
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
ブラウザからサーバーにリクエストを送信すると、レスポンスに署名付きURLが表示されます。次に、このURLを使用して、次のコードを使用してput要求を実行します。
// `file` is a File class object (that inherits from `FilePrototype` which inherits from `BlobPrototype` that has the following attributes
// lastModified: 1556044130023
// name: "profile.jpg"
// size: 788956
// type: "image/jpeg"
// uid: "rc-upload-1578069253604-2"
// webkitRelativePath: ""
const url = 'https://my-actual-bucket.s3.eu-central-1.amazonaws.com/images/profile.jpg?Content-Type=image%2Fjpeg&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=MYCREDENTIALCODE%2F20200103%2Feu-central-1%2Fs3%2Faws4_request&X-Amz-Date=20200103T163418Z&X-Amz-Expires=900&X-Amz-Signature=b90ed9cbdfadc6401521f80f5d4a65e7d4182becd392ad274ffbe3405d626055&X-Amz-SignedHeaders=Host%3Bx-amz-acl&x-amz-acl=public-read`
const response = await fetch(url, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type,
},
});
[ネットワーク]タブには、_200
を返すOPTIONS
リクエストと、403
で終わる次のPUT
リクエストがあります。
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>BFBCD6D538B3EB6A</RequestId><HostId>BtQuuVJw63Ixvir1ghCu0QLq/FKORNSIyyIh9AoYhul1TnsaoZZ1V0p/FBooM/0HTNhM7ZSegM8=</HostId></Error>
ここで何が間違っているのでしょうか?
IAMポリシーにS3:GetObject
権限を追加する必要があります。ユーザー(この場合はアプリケーション)が最終的に他のユーザーに、事前に署名されたURLを介してオブジェクトを "読み取る"(取得する)ためのアクセス許可を与えるため、このアクセス許可が必要です。したがって、「読み取り」(取得)権限も必要です。