-
-
Save Riebart/dd68c852ca7fbaccaf3bdac4919f351f to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3 | |
""" | |
Provides a simple Python wrapper for invoking an API Gateway endpoint using IAM signed requests. | |
Example: | |
python3 apigateway-invoke.py GET \ | |
https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/default/MethodName | jq . | |
""" | |
try: | |
from urllib.parse import urlparse, urlencode, parse_qs | |
except ImportError: | |
from urlparse import urlparse, parse_qs | |
from urllib import urlencode | |
import re | |
import sys | |
import requests | |
from boto3 import Session | |
from botocore.auth import SigV4Auth | |
from botocore.awsrequest import AWSRequest | |
def signing_headers(method, url_string, body): | |
# Adapted from: | |
# https://github.com/jmenga/requests-aws-sign/blob/master/requests_aws_sign/requests_aws_sign.py | |
region = re.search("execute-api.(.*).amazonaws.com", url_string).group(1) | |
url = urlparse(url_string) | |
path = url.path or '/' | |
querystring = '' | |
if url.query: | |
querystring = '?' + urlencode( | |
parse_qs(url.query, keep_blank_values=True), doseq=True) | |
safe_url = url.scheme + '://' + url.netloc.split( | |
':')[0] + path + querystring | |
request = AWSRequest(method=method.upper(), url=safe_url, data=body) | |
SigV4Auth(Session().get_credentials(), "execute-api", | |
region).add_auth(request) | |
return dict(request.headers.items()) | |
if __name__ == "__main__": | |
method = sys.argv[1] | |
url = sys.argv[2] | |
if not sys.stdin.isatty(): | |
body = sys.stdin.read() | |
else: | |
body = None | |
r = requests.get(url, headers=signing_headers(method, url, body)) | |
print(r.content.decode("utf-8")) |
Depends on the error you're getting. I'd start by making sure that the body you're sending exactly matches what was signed.
Specifically, sys.stdin.read()
returns a string, which is (eventually) utf-8
encoded, but if you're passing in a dict other things happen.
Since requests.post()
expects that data
be, among other things, a bytes-like-object, you'll need to ensure that you are transforming your string into bytes exactly like the botocore AWS signing functions do.
@Riebart - thanks for the response! I needed to transform the body into a JSON object and it worked.
I tried to use json.loads('json:str') with requests.post(url, signed_headers, json=jsonData)
, it does not work, finally it turned out that if your APIGateWay's auth method is None
, you don't need to pass the signed_headers
, just do post as:
r = requests.post(url, json)
This worked great for GET requests, but I am not able to get it to run with POST request. I am trying to run an sql query in the the body... any tips?