-
Notifications
You must be signed in to change notification settings - Fork 105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add AWS session token as optional parameter for S3 #96
Conversation
Are you sure that the client can be trusted with the session token? |
I'm not sure I understand your question exactly; this code itself runs on the server, correct? Do you mean is it safe to add the token to the request? As far as I know it's standard procedure for calls made with temporary security credentials. |
Yes it is running on the server, but you are effectively sending the token to the client, because the client uploads it directly to S3. |
`AWSSecretAccessKey` String or Function (**required**) - Can also be set in `Meteor.settings`. If it is a function, | ||
there are no arguments and the key (a string) is returned. | ||
|
||
`AWSSessionToken` String or Function (optional) - Session token included in temporary security credentials. If it is a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As session tokens are by definition temporary, I am thinking we should not support constant Strings, but functions only, so that people will not be walking into a trap here. Also expiry time does matter. Slingshot could provide the desired expiry time as an argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool; makes sense to me, updated.
Are there any other issues that need to be addressed? |
Sorry for the delay. It looks good to me. But I am wondering about the practicality of this. As far as I understand you get a temporary So I am looking for easier way... Would you like to share your code where you use |
I see your concern; I suppose a different approach would be passing a function to the directive which returns an object containing each of the three credentials. Let me know if you think that is preferable. Here is essentially the code I am using: var Future = Npm.require('fibers/future');
var fetchTemporaryCredentials = function () {
var future = new Future();
AWS.config.credentials = new AWS.EC2MetadataCredentials();
AWS.config.credentials.get(function (err) {
if (err != null) {
future.throw(err);
} else {
future.return();
}
});
return future.wait();
};
var getTemporaryCredential = function (key) {
if (AWS.config.credentials == null || AWS.config.credentials.needsRefresh()) {
fetchTemporaryCredentials();
}
return AWS.config.credentials[key];
};
var getAccessKeyId = function () {
return getTemporaryCredential('accessKeyId');
};
var getSecretAccessKey = function () {
return getTemporaryCredential('secretAccessKey');
};
var getSessionToken = function () {
return getTemporaryCredential('sessionToken');
};
Slingshot.createDirective('myUploads', Slingshot.S3Storage, {
bucket: 'myBucket',
AWSAccessKeyId: getAccessKeyId,
AWSSecretAccessKey: getSecretAccessKey,
AWSSessionToken: getSessionToken
}); |
Thank you. That is a reasonable approach. I finally found a way how to test temporary keys without an EC2 instance. I agree to your suggested solution, however slingshot will not take that in easily as it will insist on getting the keys when the directive is instantiated. I think that can be circumvented by extending So basically something like this: var getSessionToken = Meteor.wrapAsync(function (params, callback) {
sts.getSessionToken(params, callback);
});
Slingshot.createDirective('myUploads', Slingshot.S3Storage.TempCredentials, {
bucket: 'myBucket',
sessionToken: function (expiry) {
return sts.getSessionToken({
DurationSeconds: Math.round((expiry - Date.now()) / 1000 )
});
}
}); |
I'm not sure I understand this. Where is the code gets the keys when the directive is instantiated? And why is that an issue? This code has been working correctly for me. |
I was not referring to your code, as far as I can tell should work fine. I was referring to your other suggested approach:
(I think that would be preferable and I am working on it right now) My snippet shows how it will be used with I will push the actual implementation of that API soon. |
Ok, I understand. What I was imagining was simply an optional param, a function that returns all of the temporary credentials. So its use would be something this with EC2MetadataCredentials (and based on the documentation for STS, I think something similar could be done with that): Slingshot.createDirective('myUploads', Slingshot.S3Storage, {
bucket: 'myBucket',
temporaryCredentials: function () {
if (AWS.config.credentials == null || AWS.config.credentials.needsRefresh()) {
fetchTemporaryCredentials();
}
return {
AWSAccessKeyId: AWS.config.credentials.accessKeyId,
AWSSecretAccessKey: AWS.config.credentials.secretAccessKey,
AWSSessionToken: AWS.config.credentials.sessionToken
};
}
}); I'm confused as to why a separate directive type would be needed. |
The problem is that Slingshot will insist that you have So the extension removes that requirement and replaces it with the requirement to have a function that retrieves the temporary keys whenever they are actually needed. I've got that working now (tested with |
Ah, yes I understand now. This is working fine for me with |
Great thank you, I would like to add your snippet to the readme. I think your approach would be very handy to those running on EC2. Can you please check if this refactored version work for you: var credentials = new AWS.EC2MetadataCredentials();
var updateCredentials = Meteor.wrapAsync(credentials.get, credentials);
Slingshot.createDirective('myUploads', Slingshot.S3Storage.TempCredentials, {
bucket: 'myBucket',
temporaryCredentials: function () {
if (credentials.needsRefresh()) {
updateCredentials();
}
return {
AccessKeyId: credentials.accessKeyId,
SecretAccessKey: credentials.secretAccessKey,
SessionToken: credentials.sessionToken
};
}
}); |
Yep, that code works fine. Thanks for getting this change in! |
If using temporary security credentials, for example when on an EC2 instance with IAM role policies setting S3 access, requests need to include the session token.