Using Lambda@Edge to fix permalink in Jekyll

Origin Access Identity (OAI) is a secure way to access S3 buckets from CloudFront, think of it as letting CloudFront use the S3 APIs to request objects instead of H. The alternative is to make the bucket publicly available via bucket policy or ACLs, but that's not ideal.

On S3 you can configure a default index document, which is requested if the specified path doesn't resolve to anything. This is handy, since static site generators like Jekyll relies on sub-directories for generating "clean URLs". But with Open Access Identity CloudFront will request the literal object using the S3 APIs, and in this case S3 doesn't know what to respond.

sequenceDiagram
    participant Client
    participant CloudFront
    participant Lambda
    participant S3 as S3 Bucket
    Client->>CloudFront: Client Request GET /foobar/zoo/
    CloudFront->>Lambda: Invoke
    Lambda-->>CloudFront: Return
    CloudFront->>S3: S3 Object Request /foobar/zoo/index.html
    S3-->>CloudFront: S3 Object Response
    CloudFront-->>Client: Client Response GET /foobar/zoo/

In this flowchart the users request is intercepted at the origin-request, which means before CloudFront requests the object from the origin, in our case, a S3 bucket. This lets us manipulate the request header to include index.html so that CloudFront will request the correct object.

import re

def lambda_handler(event, context):
    request = event['Records'][0]['cf']['request']
    request['uri'] = re.sub(r'/$', '/index.html', request['uri'])

    return request