TLをマルチパートアップロードしよう; DR
組み合わせるブラウザにJavaScriptが AWS SDKによって提供s3.upload()
方法を使用してブラウザから直接ファイルをアップロードしようとしIAMクレジットAWS.STS.getFederationToken()
への呼び出しによって生成されます。マルチパート以外のアップロードではすべて正常に動作し、はマルチパートアップロードの最初の部分であるになります。 しかしときS3が403 Access Denied
エラーで応答マルチパートアップロードの第二の部分を送信するためにs3.upload()
試み。
なぜですか?
コンテキスト
は私がマルチパート(チャンク)を有効に私のS3バケットにブラウザから直接アップロードします私のアプリでアップローダーを実施しています。これを達成するために、私はnew AWS.S3.ManagedUpload()
の基本的な利用のために砂糖以上であると理解しているAWS SDK for Javascript in the Browserのs3.upload()
メソッドを利用しています。私がしようとしてるかの
簡単な図がここで見つけることができます:https://aws.amazon.com/blogs/developer/announcing-the-amazon-s3-managed-uploader-in-the-aws-sdk-for-javascript/
はさらに、私はまた、アップロードを許可するために、私のAPI層からの一時的IAMユーザー資格情報を、販売するための手段としてAWS.STS.getFederationToken()
を使用しています。
は1,2,3:
- ユーザーは、標準のHTML
<input type="file">
を経由してファイルを選択してアップロードを開始します。 - このアクションを実行するために、自分のシステムに必要な特権があることを確認するために、APIレイヤーへの最初のリクエストがトリガーされます。
AWS.STS.getFederationToken()
Policy
paramを呼び出してアップロードするだけです提供されたキーへのファイルそして結果の一時的な信用をブラウザに返します。 - ブラウザに必要な一時信用があるので、新しい
AWS.S3
クライアントを作成してAWS.S3.upload()
メソッドを実行して、ファイルの(複数の)自動マートマルチパートアップロードを実行することができます。
コード
api.myapp.com/vendUploadCreds.js
これは一時的なアップロードcredsをを生成し、販売すると呼ばれるAPI層方法です。プロセスのこの時点で、アカウントはすでに認証されており、信用を受け取り、ファイルをアップロードする権限を持っています。
module.exports = function vendUploadCreds(request, response) {
var account = request.params.account;
var file = request.params.file;
var bucket = 'cdn.myapp.com';
var sts = new AWS.STS({
AccessKeyId : process.env.MY_AWS_ACCESS_KEY_ID,
SecretAccessKey : process.env.MY_AWS_SECRET_ACCESS_KEY
});
/// The following policy is *exactly* the same as the S3 policy
/// attached to the IAM user that executes this STS request.
var policy = {
Version : '2012-10-17',
Statement : [
{
Effect : 'Allow',
Action : [
's3:ListBucket',
's3:ListBucketMultipartUploads',
's3:ListBucketVersions',
's3:ListMultipartUploadParts',
's3:AbortMultipartUpload',
's3:GetObject',
's3:GetObjectVersion',
's3:PutObject',
's3:PutObjectAcl',
's3:PutObjectVersionAcl',
's3:DeleteObject',
's3:DeleteObjectVersion'
],
Resource : [
'arn:aws:s3:::' + bucket + '/' + account._id + '/files/' + file.name
],
Condition : {
StringEquals : {
's3:x-amz-acl' : ['private']
}
}
}
]
};
sts.getFederationToken({
DurationSeconds : 129600, /// 36 hours
Name : account._id + '-uptoken',
Policy : JSON.stringify(policy)
}, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
response.send(data);
});
}
console.myapp.com/uploader.js
これは最初vendUploadCreds
APIメソッドを呼び出し、次に、得られた一時的を使用し、ブラウザ側のアップローダの切断図でありますマルチパートアップロードを実行するためのcreds。
uploader.getUploadCreds(account, file) {
/// A request is sent to api.myapp.com/vendUploadCreds
/// Upon successful response, the creds are returned.
request('https://api.myapp.com/vendUploadCreds', {
params : {
account : account,
file : file
}
}, function(error, data) {
upload.credentials = data.credentials;
this.uploadFile(upload);
});
}
uploader.uploadFile : function(upload) {
var uploadID = upload.id;
/// The `upload` object coming through via the args has
/// a `credentials` property containing the creds obtained
/// via the `vendUploadCreds` method above.
var credentials = new AWS.Credentials({
accessKeyId : upload.credentials.AccessKeyId,
secretAccessKey : upload.credentials.SecretAccessKey,
sessionToken : upload.credentials.SessionToken
});
AWS.config.region = 'us-east-1';
var s3 = new AWS.S3({
credentials,
signatureVersion : 'v2', /// 'v4' also attempted
params : {
Bucket : 'cdn.myapp.com'
}
});
var uploader = s3.upload({
Key : upload.key,
ACL : 'private',
ContentType : upload.file.type,
Body : upload.file
},{
queueSize : 3,
partSize : 1024 * 1024 * 5
});
uploader.on('httpUploadProgress', function(event) {
var total = event.total;
var loaded = event.loaded;
var percent = loaded/total;
percent = Math.ceil(percent * 100);
console.log('Uploaded ' + percent + '% of ' + upload.key);
});
uploader.send(function(error, result) {
console.log(error, result);
});
}
cdn.myapp.com S3バケットCORS設定
CORSは問題ではありませんので、これまでのところ、私が言うことができるように、これは、広く開いているのですか?私はファイルをアップロードしようとすると
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<ExposeHeader>ETag</ExposeHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
エラー
わかりましたが、そう、それは本当に混乱取得します。
- うまく5Mbのアップロードの下で任意のファイルを。 5Mb(S3マルチパートアップロードの最小パーツサイズ)以下のファイルはマルチパートアップロードを必要としないため、
s3.upload()
はそれらを標準のPUTリクエストとして送信します。理にかなって、うまくいく。 - 5MBを超えるファイルは、アップロードするにはと思われますが、最初の部分のみです。そして、
s3.upload()
が2番目の部分を送信しようとすると、S3は403 Access Denied
エラーで応答します。
私はここで私はアストラッド・ジルベルトの憂鬱古典"So Nice (Summer Samba)"(MP3、6をアップロードしようとしたとき、私はChromeから取得エラーのダンプですので、あなたは情報のファンだ願っています。6MB):
一般
Request URL:https://s3.amazonaws.com/cdn.myapp.com/5a2cbda70b9b741661ad98df/files/Astrud-Gilberto-So-Nice-1512903188573.mp3?partNumber=2&uploadId=ljaviv9n25aRKwc4HKGhBbbXTWI3wSGZwRRi39fPSEvU2dcM9G7gO6iu5w7va._dMTZil4e_b53Iy5ngojJqRr5F6Uo_ZXuF27yaqizeARmUVf5ZVeah8ZjYwkZV8C0i3rhluYoxFHUPxlLMjaKLww--
Request Method:PUT
Status Code:403 Forbidden
Remote Address:52.216.165.77:443
Referrer Policy:no-referrer-when-downgrade
レスポンスヘッダ
Access-Control-Allow-Methods:GET, PUT, POST, DELETE
Access-Control-Allow-Origin:*
Access-Control-Expose-Headers:ETag
Access-Control-Max-Age:3000
Connection:close
Content-Type:application/xml
Date:Sun, 10 Dec 2017 10:53:12 GMT
Server:AmazonS3
Transfer-Encoding:chunked
Vary:Origin, Access-Control-Request-Headers, Access-Control-Request-Method
x-amz-id-2:0Mzo7b/qj0r5Is7aJIIJ/U2VxTTulWsjl5kJpTnEhy/B0fQDlRuANcursnxI71LA16AdePVSc/s=
x-amz-request-id:DA008A5116E0058F
リクエストヘッダ
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.9
Authorization:AWS ASIAJAR5KXKAOPTC64PQ:Wo9lbflZuVVS9+UTTDSjU0iPUbI=
Cache-Control:no-cache
Connection:keep-alive
Content-Length:1314943
Content-Type:application/octet-stream
DNT:1
Host:s3.amazonaws.com
Origin:http://132.12.23.145:8080
Pragma:no-cache
Referer:http://132.12.23.145:8080/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
X-Amz-Date:Sun, 10 Dec 2017 10:53:09 GMT
x-amz-security-token:FQoDYXdzENT//////////wEaDK9srK2+5FN91W+T+SLSA/LdEwpOiY7wDkgggOMhuGEiqIXAQrFMk/EqvZFl8Npqx414WsL9E310rj5mU1RGXsxuN+ers1r6NVPpJIlXSDG7bnwlGabejNvDL9vMX5HJHGbZOEVUoaL60/T5NM+0TZtH61vHAEVmRVFKOB0tSez8TEU1jQ2cJME0THn5RuV/6CuIpA9dlEYO7/ajB5UKT3F1rBkt12b0DeWmKG2pvTJRwa8nrsF6Hk6dk1B1Hl1fUwAh9rD17O9Roi7MFLKisPH+96WX08liC8k+n+kPPOox6ZZM/lOMwlNinDjLc2iC+JD/6uxyAGpNbQ7OHAUsF7DOiMvw6Nv6PrImrBvnK439BhLOk1VXCfxxmtTWGim8TD1w1EciZcJhsuCMpDF8fMnhF/JFw3KNOJXHUtpTGRjNbOPcPojVs3FgIt+9MllIA0pGMr2bYmA3HvKewnhD2qeKkG3DPDIbpwuRoY4wIXCP5OclmoHp5nE5O94aRIvkBvS1YmqDQO+jTiI7/O7vlX63q9sGqdIA4nwzh5ASTRJhC2rKgxepFirEB53dCev8i9f1pwXG3/4H3TvPCLVpK94S7/csNJexJP75bPBpo4nDeIbOBKKIMuUDK1pQsyuGwuUolKS00QU=
X-Amz-User-Agent:aws-sdk-js/2.164.0 callback
クエリ文字列のparams
partNumber:2
uploadId:ljaviv9n25aRKwc4HKGhBbbXTWI3wSGZwRRi39fPSEvU2dcM9G7gO6iu5w7va._dMTZil4e_b53Iy5ngojJqRr5F6Uo_ZXuF27yaqizeARmUVf5ZVeah8ZjYwkZV8C0i3rhluYoxFHUPxlLMjaKLww--
実際の応答ボディ
そしてここでは、S3からの応答の本文です:
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>AccessDenied</Code><Message>Access Denied</Message><RequestId>8277A4969E955274</RequestId><HostId>XtQ2Ezv0Wa81Rm2jymB5ZwTe+OHfwTcnNapYMgceqZCJeb75YwOa1AZZ5/10CAeVgmfeP0BFXnM=</HostId></Error>
質問
sts.generateFederationToken()
リクエストによって作成されたクレジットに問題はないことは明らかです。小さい方の(マルチパートでない)アップロードも失敗するからです。cdn.myapp.com
バケットのCORS設定に問題がないことは明らかです。小さい方の(マルチパート以外の)アップロードも失敗する可能性があるからです。- S3が複数アップロードの
partNumber=1
を受け入れ、同じアップロードのpartNumber=2
で403を受け入れるのはなぜですか?