0

I was trying to deploy a API created with flask and serverless framework to AWS lambda and API gateway, however I was not able to read the proper header.

I did read some post from https://stackoverflow.com/a/43830950/2806237, which indicates that request details will be available in event of the handler function.

However, I am use wsgi.handler as my handler, so how am I supposed to read event variable which exists in wsgi.hander? Should I create my own handler or I can get the request details of event from somewhere?

FYI, I am using AWS V4 signature to sign each request from both client side and server side, then compare each signature to ensure the request is secured. This will generate a header like below:

Host: 10.0.0.48:9998
Connection: keep-alive
Content-Length: 37
Origin: xxxxxxxxxxxxxxxxxxxx
Authorization: AWS4-HMAC-SHA256 Credential=usernameHere/20181220///aws4_request, SignedHeaders=content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-target, Signature=c57780866a6380b92678e8a9d52d8220d3ecc836f4475b8334c553cf4dbb9ad4
Content-Type: application/json;charset=UTF-8
X-Amz-Content-Sha256: 615d42718684ea2b59442a6ce3dc6302404839b0875bca365a6e07e0d65f577c
Accept: application/json, text/javascript, */*; q=0.01
X-Amz-Target: SchoolLearnMeter_1980121.GetPassword
X-Amz-Date: 20181220T021132Z
User-Agent: Mozilla/5.0 (X11; CrOS x86_64 11210.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3593.0 Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9.

However,the header I am getting like this:

Content-Length: 36
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip, deflate
Cache-Control: no-cache
Cloudfront-Forwarded-Proto: https
Cloudfront-Is-Desktop-Viewer: true
Cloudfront-Is-Mobile-Viewer: false
Cloudfront-Is-Smarttv-Viewer: false
Cloudfront-Is-Tablet-Viewer: false
Cloudfront-Viewer-Country: AU
Host: XXXXX.execute-api.ap-southeast-2.amazonaws.com
Postman-Token: 8742a77d-4e1a-4d0c-ba6a-6df15795e7c8
User-Agent: PostmanRuntime/7.4.0
Via: 1.1 098fddbcdf00e65b8479d1d17b41d28a.cloudfront.net (CloudFront)
X-Amz-Cf-Id: HafOPHJfXOungGylHkX4Y3klvdBR-kzoC-xz1aqNXo-4K2KbbsD_lg==
X-Amz-Date: 20181220T034409Z
X-Amzn-Trace-Id: Root=1-5c1b100a-7a69d8e08c9ee3e0e6b799e0
X-Forwarded-For: 115.187.209.206, 70.132.29.75
X-Forwarded-Port: 443
X-Forwarded-Proto: https 

This is the application.py code

from flask import Flask, request, jsonify
import os, sys
import hashlib
import json
from dbConnection import DBConncetion
from awssigner import AWSSigner

application = Flask(__name__)
db_conn_str = os.environ["Chrome_DB"]
responseMessage = {"ResponseMessage":""}

@application.route("/u", methods=["POST"])
def getUserPasswordByUsername():
    try:
        serverSignature = AWSSigner(request).getSignature(json.dumps(request.get_json(Force=true)).replace(": ",":"))
        agentSignature = request.headers.get("Authorization").split("Signature=",1)[1]
        if(serverSignature == agentSignature):
            #Do something here
        else:
            raise Exception
    except:
        responseMessage["ResponseMessage"] = "There are some errors occured, please try again later"
        response = application.response_class(
            response= json.dumps(responseMessage),
            status=500,
            mimetype = "application/json"
        )
        return response

if __name__ == "__main__":
    application.run()
    #application.run("0.0.0.0", 9998, debug = True)

This is the serverless.yml file

service: testapiservices

plugins:
 - serverless-python-requirements
 - serverless-wsgi

custom:
 wsgi:
   app: application.application
   packRequirements: false
 pythonRequirements:
   dockerizePip: non-linux

provider:
 name: aws
 runtime: python3.7
 stage: dev
 region: ap-southeast-2

functions:
 app:
   handler: wsgi.handler
   environment:
     AppId: XXX
     Chrome_DB: XXX
   events:
     - http:
         cors: true
         method: post
         path: /
     - https: 'ANY{proxy+}'
   vpc:
     securityGroupIds:
       - XXX
     subnetIds:
       - XXX
       - XXX
Lehtia
  • 159
  • 1
  • 3
  • 12
  • Seems to be a bug with `serverless-wsgi` if you are not getting the original `event` from Lambda. I would not recommend the use of `flask` and `serverless-wsgi` unless only temporarily for migrating existing Flask apps to Lambda. – Noel Llevares Dec 20 '18 at 19:04

1 Answers1

0

serverless-wsgi provides a flask wrapper for you to use, so it actually handles the event variable in the background and maps it to a Flask request.

Import the flask request object, and use that in your code instead:

from flask import Flask, request

Read the Flask docs around the request but it will have all the headers etc you would expect in the lambda event

Also you are using agent User-Agent: PostmanRuntime/7.4.0 to send the request that gives the second set of headers. You literally as a developer set those headers, so I'm confused why you would expect them to match unless you set them to match.

What header are you specifically looking to check?

GWed
  • 15,167
  • 5
  • 62
  • 99
  • Hi Thx for your reply. As I mentioned I am using AWS v4 to sign the request, basically the header is more like customised header, which can you find in the first code block. However, I am actually getting the header in second block. I have changed the whole structure to use serverless framework without flask, but the header I am getting is missing the Key from the header, which is called Authorization. So it is not possible for me to read the signature(in the value of Authorization key) which is sent from the client. Sorry about any confusing explanation. Still trying to learn AWS. – Lehtia Dec 24 '18 at 03:01