いくつかの研究とテストの後、私はこれを自分で解決しました。私の究極の解決策は、Sヘッダーを使用してS3バケットへのアクセスを制限することでした。私はより安全で詳細なソリューションを作成しましたが(下記参照)、それは私のアプリケーションではうまくいかないパフォーマンスヒットを伴いました。私のアプリは、写真やビデオを見ることに基づいており、即座に近くで負荷をかけられないようにすることはできませんでした。しかし、ほとんどのユースケースでは十分な解決策になると思います。私のアプリは非常に敏感ではないので、referer
ヘッダーで十分です。 AmazonのSTSを使用してHere is how to use the http header referer
to limit access to a bucket.
ソリューション:
まず、あなたはserverとclient.そこには、最大利用可能流星の日付パッケージになかったので、私は自分自身を作成し、両方にAWS SDKを持っている必要があります。
サーバーでは、役割を引き受ける権限を持つ資格情報を使用する必要があります。想定される役割は、その役割を担っているユーザーとの信頼関係を持っていなければなりません。 Article on using IAM. - Article on using credentials with SDK
server.js
ファイルでは、クライアントから呼び出せるメテオメソッドを作成しました。最初にユーザーがログインしているかどうかを確認します。それが真の場合、次の5分で現在の一時的な資格情報が期限切れになっているかどうかを確認します。もしそうであれば、私は新しい証明書を発行し、それらをユーザー文書に書き込んだり、コールバックとして返す。次の5分間で期限切れになっていない場合は、現在の身分証明書を返します。
コールバックにはMeteor.bindEnvironment
を使用する必要があります。See docs
Meteor.methods({
'awsKey': function(){
if (Meteor.userId()){
var user = Meteor.userId();
var now = moment(new Date());
var userDoc = Meteor.users.findOne({_id: user});
var expire = moment(userDoc.aws.expiration);
var fiveMinutes = 5 * 60 * 1000;
var fut = new Future();
if(moment.duration(expire.diff(now))._milliseconds < fiveMinutes){
var params = {
RoleArn: 'arn:aws:iam::556754141176:role/RoleToAssume',
RoleSessionName: 'SessionName',
DurationSeconds: 3600 //1 Hour
};
var sts = new AWS.STS();
sts.assumeRole(params, Meteor.bindEnvironment((err, data) => {
if (err){
fut.throw(new Error(err));
}else{
Meteor.users.update({_id: user}, {$set: {aws: {accessKey: data.Credentials.AccessKeyId, secretKey: data.Credentials.SecretAccessKey, sessionToken: data.Credentials.SessionToken, expiration: data.Credentials.Expiration}}});
fut.return(data.Credentials);
}
}));
return fut.wait();
}else{
return userDoc.aws;
}
}
}
}
});
その後、手動またはMeteor.startup
上setInterval
でこのメソッドを呼び出すことができます。
Meteor.setInterval(function(){
if(Meteor.userId()){
Meteor.call('awsKey', function(err, data){
if (err){
console.log(err);
}else{
if(data.accessKey){
Session.set('accessKey', data.accessKey);
Session.set('secretKey', data.secretKey);
Session.set('sessionToken', data.sessionToken);
}else{
Session.set('accessKey', data.AccessKeyId);
Session.set('secretKey', data.SecretAccessKey);
Session.set('sessionToken', data.SessionToken);
}
}
});
}
}, 300000); //5 Minute interval
この方法では、セッション変数のキーをコールバックから設定するだけです。これを行うには、ユーザーのドキュメントを照会して取得することもできます。
次に、これらの一時的な認証情報を使用して、バケットでアクセスしようとしているオブジェクトの署名付きURLを取得できます。
私はテンプレートでそれにオブジェクト名を渡すことで、テンプレートのヘルパーでこれを置く:これだけです
{{getAwsUrl imageName}}
Template.templateName.helpers({
'getAwsUrl': function(filename){
var accessKey = Session.get('accessKey');
var secretKey = Session.get('secretKey');
var sessionToken = Session.get('sessionToken');
var filename = filename;
var params = {Bucket: 'bucketName', Key: filename, Expires: 6000};
new AWS.S3({accessKeyId: accessKey, secretAccessKey: secretKey, sessionToken: sessionToken, region: 'us-west-2'}).getSignedUrl('getObject', params, function (err, url) {
if (err) {
console.log("Error:" +err);
}else{
result = url;
}
});
return result;
}
});
を!私はこれがより良くなるよう洗練されていると確信していますが、これは本当に速いテストで思いついたものです。私が言ったように、それはほとんどのユースケースでうまくいくはずです。私の特定の人はそうしなかった。なんらかの理由で、visibility: visible|hidden;
をimg src
のsignedURLで切り替えると、URLを直接設定するだけではなく、読み込みに時間がかかります。 Amazonがオブジェクトを返す前に署名されたURLを復号化しなければならないからです。
方向のためにMikkelのおかげで。
アプリでは、S3画像のアクセスが認証されていますか?もしそうであれば、認証されたGETへのアクセスを許可し、あなたのバケットへのパブリックアクセスを拒否することができます。 – Mikkel
いいえ、今は開発中の公的に利用可能なイメージですが、私は実際にクライアントからの認証を行う方法を知らず、URLとヘッダーの両方に鍵と秘密を渡します。両方とも見ることができます。ヘッダーを渡すのはURLよりはいいが、固い解決策ではないだろうと思う。 – gkrizek
鍵を渡したくないのは間違いありませんが、Meteorサーバーを使用してHTTP認証要求(ブラウザからは表示されません)を送信して、渡すことができる認証トークンを取得できます画像のGETリクエスト – Mikkel