-
Notifications
You must be signed in to change notification settings - Fork 21
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
Continue feedback on AWS signing #29
Conversation
536a1a7
to
481bcca
Compare
481bcca
to
1965caf
Compare
@@ -108,16 +107,17 @@ function createCanonicalHeaders(headers) { | |||
"\n" | |||
); | |||
}) | |||
.sort() |
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.
We need to move the sort()
to occur after the toLowerCase()
call in the block, as the case change modifies the sorting outcome.
.map(function (name) { | ||
return name.toLowerCase().trim(); | ||
}) | ||
.sort() |
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.
Same story here, re: moving the sort()
options.headers["X-Amz-Date"] = toTime(options.timestamp) | ||
var host = service.concat(".", options.region, ".amazonaws.com") | ||
options.headers["Host"] = host |
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.
These are both required at least for Sagemaker requests.
if (options.sessionToken) { | ||
options.headers["X-Amz-Security-Token"] = options.sessionToken | ||
} |
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.
From https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
You can use temporary security credentials provided by the AWS Security Token Service (AWS STS) to sign a request. The process is the same as using long-term credentials, but when you add signing information to the query string you must add an additional query parameter for the security token. The parameter name is
X-Amz-Security-Token
, and the parameter's value is the URI-encoded session token (the string you received from AWS STS when you obtained temporary security credentials).For some services, you must include the
X-Amz-Security-Token
query parameter in the canonical (signed) query string. For other services, you add theX-Amz-Security-Token
parameter at the end, after you calculate the signature. For details, see the API reference documentation for that service.
var svc = service.split(".").pop() | ||
var credential = options.key + | ||
"/" + | ||
createCredentialScope(options.timestamp, region, service); | ||
createCredentialScope(options.timestamp, options.region, svc); |
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.
This is an example of what I mean when I say the API still needs to be ironed out. Sagemaker URLs use runtime.sagemaker.${REGION}.amazonaws.com
, but the service name for the purposes of request signing is simply sagemaker
.
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.
I haven't looked at every AWS service and how it handles it, but IMO this should just be one more parameter:
- we have the
service
which is whatsvc
is here serviceSubdomain
which if not set is just equal toservice
And then for the services that have this be different the user will need to provide both or do a wrapper, that can then be added to the jslib ;)
", SignedHeaders=", | ||
signedHeaders, | ||
" Signature=", | ||
", Signature=", |
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.
There is no comma between the algorithm and Credential. However, the SignedHeaders and Signature are separated from the preceding values with a comma.
Is there a particular error that is being returned? Looking at Also, the |
I now have a working Lambda example that uses a real endpoint with this library, after also having done so with a browserified aws4.js. Running the example script will require access to the endpoint, and I'm not sure about making it public, so not sure whether it would be appropriate to include as a test for Lambda. WDYT? Incidentally, I also tested it with #11, not realizing that the code has progressed a bit since then. This PR allowed me to skip passing in any const method = 'POST';
const service = 'lambda';
const region = 'us-west-2';
const path = '/2015-03-31/functions/hello-world/invocations';
const body = '{"key1":"value1","key2":"value2","key3":"value3"}';
// these used to be necessary
// const headers = {
// 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
// 'Content-Length': body.length.toString(),
// 'Host': `${service}.${region}.amazonaws.com`,
// 'X-Amz-Date': new Date().toISOString().replace(/[:\-]|\.\d{3}/g, '')
// }
const signed = signWithHeaders(
method,
service,
region,
"",
path,
body,
"",
// headers
{}
); This also resulted in less headers being used for the actual request signing ( The eventual let res = http.post(
signed.url,
body,
{
headers: signed.headers
}
);
console.log(res.body); Which is great! A few unrelated comments:
|
@@ -19,33 +19,42 @@ function fillOptions(options) { | |||
function signWithHeaders(method, service, region = "", target = "", path = "", body = null, query = "", headers = {}) { | |||
var options = { headers: headers } |
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.
I found I needed to set region
in the options
object based on receiving it as a parameter, otherwise it generated an undefined
later on in core.js
:
var options = { headers: headers } | |
var options = { | |
headers: headers, | |
region: region | |
} |
This was my original idea in #29 (comment)
This was my original idea in grafana/jslib.k6.io#29 (comment)
as mentioned in grafana/jslib.k6.io#29 (comment)
I wouldn't call this ready to go just yet, but this is the first setup that actually works (for Sagemaker calls, at least).
There's still some work to be done to iron out the API. Perhaps we need to take a full endpoint (
scheme://fqdn/path?query
) as well as an AWS service name (e.g.sagemaker
). I'm not sure.In the current iteration, we are dropping a lot more requests than in my fork that uses the AWS go library for signing instead.
Load test using this JS library for request signing
Load test using AWS Go SDK for request signing
@mstoykov