Skip to main content

Amazon API Gateway is not only for REST endpoints and microservices. It can proxy HTTP requests, to say, provide API key authorization or other workflows (like a Lambda authorizer) to protect an HTTP service. However, not all aspects of the request can be modified. For example, if you try to modify the Authorization header, it will fail with this error:

ERROR: Invalid mapping expression specified: Validation Result: warnings : [], errors: [Operations on header authorization are restricted]

One way to get around this is to use a Lambda as a proxy. You can write a Lambda function that will take all incoming requests and then pass them onto the destination webapp. This way you can add any other functionality you want and customize any headers you would like. You don’t even need any additional libraries – while requests are easier to use, the built in urllib3 library in Python will work just fine. Here is some example code:

import os

import urllib3

import json

def lambda_handler(event, context):

print(json.dumps(event))

#url = os.environ[‘URL’]

url = “http://ec2-3-87-252-207.compute-1.amazonaws.com:5000″

# Two way to have http method following if lambda proxy is enabled or not

if event.get(‘httpMethod’):

http_method = event[‘httpMethod’]

else:

http_method = event[‘requestContext’][‘http’][‘method’]

headers = ”

if event.get(‘headers’):

headers = event[‘headers’]

path = “”

if event.get(“path”):

path = event[“path”]

# Important to remove the Host header before forwarding the request

# if headers.get(‘Host’):

#     headers.pop(‘Host’)

# if headers.get(‘host’):

#     headers.pop(‘host’)

body = ”

if event.get(‘body’):

body = event[‘body’]

print(headers)

headers[“Authorization”] = “Basic YWRtaW46cGFzc3dvcmQ=”

try:

http = urllib3.PoolManager()

resp = http.request(method=http_method, url=url + path, headers=headers,

body=body)

print(json.dumps(resp.headers[“Content-Type”]))

body = resp.data.decode(‘utf-8’)

 

response = {

“statusCode”: resp.status,

‘headers’: {

‘Content-Type’: resp.headers[“Content-Type”]

},

“body”: body

}

print(“response: ” + json.dumps(response))

except urllib3.exceptions.NewConnectionError:

print(‘Connection failed.’)

response = {

“statusCode”: 500,

“body”: ‘Connection failed.’

}

return response

Some modifications of note from the author – the original function only proxied JSON requests and responses. Here we’re explicitly setting the Content-Type header to whatever the actual HTTP request returns. This lets you request _anything_ from the server whether it be HTML pages, images, JavaScript files, etc. Second, we’re modifying a header, in this case the Authorization header, which we could not modify through Amazon API Gateway. You could therefore put a Lambda authorizer in front of this Lambda’s route in API Gateway, which verifies that the user is logged in or any other criteria, and then pass on the request on to an app/server that only supports HTTP Basic Auth. The Lambda authorizer or the proxy Lambda itself can dynamically change the username/password at runtime (say if the app has an LDAP or database user store) and then pass on the HTTP Basic Auth header to the underlying server when it relays the request. You get better security than using straight up HTTP Basic Auth, the end user’s browser needs to know nothing about HTTP Basic Auth, and you don’t have to modify the end application/server.

Source: https://dev.to/aws-builders/serverless-proxy-with-aws-api-gateway-and-aws-lambda-3bd2