Achieve Basic Authentication with CloudFront Lambda @ Edge with Python 3.8

Introduction

I tried to use Lambda @ Edge to apply Basic authentication to the site, but when I search in Japanese, I usually get a lot of articles such as Node 6 and 8. However, this limitation was just after the general release of Lambda @ Edge, and I felt that the information was too old, so I checked the current support status of Lambda @ Edge again. Then, at the moment (October 08, 2020), Lambda @ Edge can be used up to Python 3.8, so I decided to use this to apply Basic authentication, which is the purpose of this time.

NOTE: A viable Lambda environment

The environment that can be executed at the time of writing the article (2020/10/08) is as follows.

Source: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-requirements-limits.html#lambda-requirements-lambda-function-configuration

It could be run in Python as well as Node.js. Looking at when this change came in, it seems that Python 3.7 was available in August 2019, and Python 3.8 and Node 12 were around March 2020.

What is Lambda @ Edge?

By executing AWS Lambda between Amazon CloudFront requests, the necessary processing can be inserted separately from the application. See below for the officially introduced use cases.

https://aws.amazon.com/jp/lambda/edge/

This time, the purpose is to perform Basic authentication independently of the original content by inserting the Basic authentication process before the user (viewer) accesses CloudFront and accesses its cache and origin. ..

Create a Lambda function for Lambda @ Edge

Create a Lambda function in the Northern Virginia (us-east-1) region

CloudFront is a global service that can be used in any region, but the resources used here (such as the certificate used by SSL Certificate Manager) must be created in the us-east-1 region. Create a Lambda function in this region as well.

The procedure for creating with the management console is shown below. As a prerequisite, it is assumed that you have the authority to create an appropriate Lambda or IAM Role, and that you have already completed the settings for CloudFront that uses Basic authentication.

--Open the Lambda page and press the "Create Function" button to start creating the function --Perform the initial settings according to the figure below. --When creating a new execution role -"Create a new role from an AWS policy template Grant "basic Lambda @ Edge permissions (for CloudFront triggers)" as " --If you already have a role with similar privileges, you can use it. --You can use any name you like

SnapCrab_NoName_2020-10-8_22-24-48_No-00.png SnapCrab_NoName_2020-10-8_22-25-11_No-00.png

--Press Create Function to create a function --Rewrite the function code as follows --Here, the user name and password are determined by the ʻauthenticate` function, so rewrite it so that you can use it yourself. --In the Lambda Function used by Lambda @ Edge, ** environment variables cannot be used **, so it is written in solid form.

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Lambda for Basic authentication@The Python version of Edge.
"""

import base64


def authenticate(user, password):
    """Authentication"""
    return user == 'cloudfront' and password == 'CL0UDFR0NT'


def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    headers = request['headers']

    error_response = {
        'status': '401',
        'statusDescription': 'Unauthorized',
        'body': 'Authentication Failed',
        'headers': {
            'www-authenticate': [
                {
                    'key': 'WWW-Authenticate',
                    'value': 'Basic realm="Basic Authentication"'
                }
            ]
        }
    }

    if 'authorization' not in headers:
        return error_response

    try:
        auth_values = headers['authorization'][0]['value'].split(" ")
        auth = base64.b64decode(auth_values[1]).decode().split(":")
        (user, password) = (auth[0], auth[1])
        return request if authenticate(user, password) else error_response
    except Exception:
        #Format error etc.
        return error_response

--Press the Deploy button to apply this code to $ LATEST --Create a "new version" from the action --Lambda @ Edge cannot use $ LATEST, so be sure to issue a fixed version --Make sure that the version is "the latest version currently created" and press the "+ Add trigger" button at the bottom left of the figure below.

SnapCrab_NoName_2020-10-8_22-39-6_No-00.png

--When you select CloudFront in the trigger settings, the item to set Lambda @ Edge for the already set CloudFront is displayed. ――You choose which distribution you want -In "Select cache behavior", it will appear in the path unit specified in Behavior of CloudFront, so select the Behavior to which Lambda @ Edge is applied. --When setting from the CloudFront side, set in Behavior in the same way. --Set "Viewer Request" because you want to insert the process between " Viewer (User) "-> CloudFront in CloudFront event. --Agree to function replication to all regions -Press "Add"

SnapCrab_NoName_2020-10-8_22-42-28_No-00.png

Once the above process is completed and applied to CloudFront, basic authentication will be required for access.

Note: Troubleshooting

What I actually did.

--Lambda @ Edge doesn't return the expected results --Because the version was not fixed. The version needs to be fixed properly --Lambda @ Edge's Lambda function doesn't show the log when I try to "View CloudWatch Log" --Recorded in CloudWatch logs for the region actually processed --This time, a log group called /aws/lambda/us-east-1.cloudfront-basic-auth was created in the ap-northeast-1 region and the log was output here. --Basic authentication does not pass no matter how many times you enter --The default setting for CloudFront events is "Origin Request", so you need to change this to "Viewer Request" correctly. --In the default Origin Request Policy, the ʻAuthorization header is set not to flow to the origin. If you put Lambda @ Edge here, the authentication token will not be passed to Lambda @ Edge in the first place, so ʻerror_response will always be returned.

Summary

In the early article, I had the impression that the initial setting was difficult due to various IAM Role settings, but at the moment I found that Lambda @ Edge can be easily realized by using the wizard without thinking difficult. It may not be used when protecting the development site from general access, applying Basic authentication to the site as a completely internal service, or adding Basic authentication to the root path of the site management screen etc. Is it?

reference

Recommended Posts

Achieve Basic Authentication with CloudFront Lambda @ Edge with Python 3.8
Setting up Basic authentication using Python @Lambda
Send HTTP with Basic authentication header in Python
Operate TwitterBot with Lambda, Python
[Python] Using OpenCV with Python (Basic)
[Python] [SQLite3] Operate SQLite with Python (Basic)
Basic authentication with an encrypted password (.htpasswd) in bottle with python
Scraping with Selenium in Python (Basic)
Face detection with Lambda (Python) + Rekognition
[Python] Using OpenCV with Python (Edge Detection)
[Python] Use Basic/Digest authentication with Flask
Basic authentication and Digest authentication with Flask
1. Statistics learned with Python 1-1. Basic statistics (Pandas)
Notify HipChat with AWS Lambda (Python)
Use PostgreSQL with Lambda (Python + psycopg2)
Basic study of OpenCV with Python
[SAM] Try using RDS Proxy with Lambda (Python) [user/pass, IAM authentication]
[AWS] Using ini files with Lambda [Python]
Getting Started with python3 # 1 Learn Basic Knowledge
Passwordless authentication with RDS and IAM (Python)
Manipulate DynamoDB data with Lambda (Node & Python)
Learn Python! Comparison with Java (basic function)
Connect to s3 with AWS Lambda Python
Try assigning or switching with Python: lambda
Addictive point when going through http proxy with basic authentication in python
Python + Selenium + Headless Chromium with aws lambda
Setting up Digest authentication using Python @Lambda
AWS-Perform web scraping regularly with Lambda + Python + Cron
Edge extraction with python + OpenCV (Sobel filter, Laplacian filter)
Play with Lambda layer (python) for about 5 minutes
LINE BOT with Python + AWS Lambda + API Gateway
Serverless application with AWS SAM! (APIGATEWAY + Lambda (Python))
Sample to send slack notification with python lambda
Achieve scraping with Python & CSS selector in 1 minute
Export RDS snapshot to S3 with Lambda (Python)
Upload files to Google Drive with Lambda (Python)
Flow to complete Slack authentication with Flask (Python)
[Introduction to Python] Basic usage of lambda expressions
FizzBuzz with Python3
Scraping with Python
RF Python Basic_01
Scraping with Python
Python with Go
Twilio with Python
Integrate with Python
Play with 2016-Python
AES256 with python
Tested with Python
Basic Python writing
python starts with ()
with syntax (Python)
Python3 basic grammar
Bingo with python
Zundokokiyoshi with python
RF Python Basic_02
Python Https Authentication
Excel with Python
Flask Basic authentication
Microcomputer with Python
Cast with python
Create Python version Lambda function (+ Lambda Layer) with Serverless Framework