Tags: #aws #lambda #makefile #python #cognito
The AWS Python SDK (Boto) is pre-installed with AWS Lambda, so if all we need is the requests
library, then we can use the following trick to avoid needing to package up our lambda script and its dependencies…
from botocore.vendored import requests
Note: the following instructions require you to be using Pipenv for handling you Python dev environment.
To generate your dependencies and zip them (+ your lambda script) up for upload to AWS:
pipenv run pip install -r <(pipenv lock -r) --target ./
zip -r lambda.zip ./
You need to ensure the dependencies are in the same directory as the lambda script. For example…
requests/
urllib3/
lambda_function.py
You can (if you’re not using pipenv) use --target
flag to install dependencies to the current directory: pip install requests --target .
unzip -vl lambda.zip
to check contents of zip
SHELL := /bin/bash
build: clean
pipenv run pip install -r <(pipenv lock -r) --target ./
zip -r lambda.zip ./
# We use `@` to prevent Make from displaying the line that was just executed (it's just noise)
# We also use `&> /dev/null || true` to ensure errors are silenced
# e.g. trying to remove files that don't exist, would normally trigger an error in Bash
clean:
@# use double $$ to avoid conflict with builtin $() syntax
@rm -r $$(ls | egrep -v 'Makefile|Pipfile|lambda_function.py') &> /dev/null || true
run:
@# env vars can be set in the AWS Lambda console
FOO=123 BAR=456 python lambda_function.py
import os
import requests
def get_host():
tld = 'stage.example.com'
host = f'https://{tld}'
webapp_stage_user = os.environ["STAGE_USN"]
webapp_stage_pass = os.environ["STAGE_PSW"]
creds = f'{webapp_stage_user}:{webapp_stage_pass}'
host = f'https://{creds}@{tld}'
return host
def authn_webapp(event):
data = {'username': event['userName'],
'password': event['request']['password']}
uri = f'{get_host()}/api/login'
return requests.post(uri, data=data)
def lambda_handler(event, context):
"""
There are two states:
1. authentication (but before user created in cognito)
2. forgotten password
For authentication we log the user into our webapp and then extract their
details and modify the user account that is about to be created in cognito.
This allows us to handle migrating users from our data store to cognito.
"""
if event['triggerSource'] == "UserMigration_Authentication":
login_response = authn_webapp(event)
if login_response.status_code == 200:
d = login_response.json()
user_attr = {'username': d['username'],
'name': d['display_name'],
'email': d['email'],
'email_verified': 'true',
'custom:webapp_id': d['userid']}
event['response']['userAttributes'] = user_attr
event['response']['finalUserStatus'] = "CONFIRMED"
event['response']['messageAction'] = "SUPPRESS"
return event
else:
return None
else:
return None
if __name__ == "__main__":
event = {'triggerSource': 'UserMigration_Authentication',
'userName': 'beep',
'request': {'password': 'boop'},
'response': {}}
result = lambda_handler(event, {})
print(f'result: {result}')
# Build package:
# make build
# pipenv run pip install -r <(pipenv lock -r) --target ./
# zip -r lambda.zip ./
#
# Test locally:
# make run
# STAGE_USN=123 STAGE_PSW=456 python lambda_function.py