awscurl did not work with Lambda
starkshaw opened this issue · comments
Hi,
I installed the latest version of awscurl, 0.20. I attempt to invoke my Lambda function and it returned some error messages that I can't make out what went wrong.
The same request worked fine in Postman.
$ awscurl --service lambda --region eu-west-1 --profile default 'https://lambda.<region>.amazonaws.com/2015-03-31/functions/<function-name>/invocations?Qualifier=$LATEST' -H 'X-Amz-Invocation-Type:RequestResponse' -H 'X-Amz-Log-Type:Tail' -H 'Content-Type:application/json' -d '{"message":"Whats up."}'
The error message is:
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/bin/awscurl", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.7/site-packages/awscurl/awscurl.py", line 500, in main
inner_main(sys.argv[1:])
File "/usr/local/lib/python3.7/site-packages/awscurl/awscurl.py", line 463, in inner_main
headers = {k: v for (k, v) in map(lambda s: s.split(": "), args.header)}
File "/usr/local/lib/python3.7/site-packages/awscurl/awscurl.py", line 463, in <dictcomp>
headers = {k: v for (k, v) in map(lambda s: s.split(": "), args.header)}
ValueError: not enough values to unpack (expected 2, got 1)
The doc of the API can be found here: https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html
hmm, looks like split is done by ": " vs in your command it is separated only by ":" (note not space).
check if you add a space in there if that works.
Interesting. Can we make it accept either way as long as a ":" is present?
New error after the modification:
$ awscurl --service lambda --region eu-west-1 --profile default 'https://lambda.<region>.amazonaws.com/2015-03-31/functions/<function-name>/invocations?Qualifier=$LATEST' -H 'X-Amz-Invocation-Type: RequestResponse' -H 'X-Amz-Log-Type: Tail' -H 'Content-Type: application/json' -d '{"message":"Whats up."}'
b'<AccessDeniedException>\n <Message>Unable to determine service/operation name to be authorized</Message>\n</AccessDeniedException>\n'
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.6_1/Frameworks/Python.framework/Versions/3.7/bin/awscurl", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.7/site-packages/awscurl/awscurl.py", line 500, in main
inner_main(sys.argv[1:])
File "/usr/local/lib/python3.7/site-packages/awscurl/awscurl.py", line 494, in inner_main
response.raise_for_status()
File "/usr/local/lib/python3.7/site-packages/requests/models.py", line 940, in raise_for_status
raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 403 Client Error: Forbidden for url: https://lambda.<region>.amazonaws.com/2015-03-31/functions/<function-name>/invocations?Qualifier=$LATEST
please propose a change -- just trying to foster collaboration ...
your url looks wrong, the and other <> placeholders would require a value
The URL is not wrong. I masked my value out :)
then looks like general AccessDeniedException error
I attempted to do a more robust test. Here's what I have:
- An API Gateway POST API with no authorization
- An API Gateway POST API with IAM authorization
- The Lambda one mentioned above
Testing from regular curl
, if -d
is enabled, the method will be changed to POST
even -XPOST
is not explicitly defined.
Testing from awscurl
, if -d
is enabled, the method will still be GET
if -XPOST
is not explicitly defined.
Thus, adding -XPOST
to the command I used above:
$ awscurl -XPOST --service lambda --region <region> --profile default 'https://lambda.<region>.amazonaws.com/2015-03-31/functions/<function-name>/invocations?Qualifier=$LATEST' -H 'X-Amz-Invocation-Type: RequestResponse' -H 'X-Amz-Log-Type: Tail' -H 'Content-Type: application/json' -d '{"message":"Whats up."}'
The new error message is "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details."
Comparing the --verbose
log of awscurl
to --debug
output on AWS CLI, I found the following:
In AWS CLI, the canonical request is:
POST
/2015-03-31/functions/<function-name>/invocations
host:lambda.<region>.amazonaws.com
x-amz-date:<masked-out>
x-amz-invocation-type:RequestResponse
x-amz-log-type:Tail
host;x-amz-date;x-amz-invocation-type;x-amz-log-type
<masked out>
In awscurl
, the canonical request is:
('\n'
'CANONICAL REQUEST = POST\n'
'/2015-03-31/functions/<function-name>/invocations\n'
'Qualifier=$LATEST\n'
'host:lambda.<region>.amazonaws.com\n'
'x-amz-date:<masked-out>\n'
'\n'
'host;x-amz-date\n'
'<masked-out>')
You can see, the canonical request AWS CLI made has the URL query string Qualifier=$LATEST
removed. awscurl
has not. Also, x-amz-invocation-type:RequestResponse
and x-amz-log-type:Tail
headers are missing.