Skip to content

Origin Access Identity Support #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 46 additions & 28 deletions serverless.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
service: 'sveltekit-app'
service: "sveltekit-app"

frameworkVersion: "3"

plugins:
- '@silvermine/serverless-plugin-cloudfront-lambda-edge'
- "@silvermine/serverless-plugin-cloudfront-lambda-edge"
- serverless-s3-deploy

provider:
Expand All @@ -25,23 +25,22 @@ custom:
assets:
auto: true
targets:
- bucket:
- bucket:
Ref: StaticAssets
files:
- source: ./build/assets/
globs:
- '**'
globs:
- "**"
empty: true
headers:
CacheControl: max-age=31104000
- source: ./build/prerendered/
globs:
- '**'
globs:
- "**"
empty: true
headers:
CacheControl: max-age=60


functions:
#SSR Function
svelte:
Expand All @@ -56,7 +55,7 @@ functions:
memorySize: 128
timeout: 1
lambdaAtEdge:
distribution: 'WebsiteDistribution'
distribution: "WebsiteDistribution"
eventType: origin-request

resources:
Expand All @@ -65,14 +64,14 @@ resources:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:provider.stage}-${self:service}-static-assets
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
OwnershipControls:
Rules:
- ObjectOwnership: BucketOwnerPreferred
PublicAccessBlockConfiguration:
BlockPublicAcls: false
BlockPublicPolicy: false
IgnorePublicAcls: false
RestrictPublicBuckets: false

StaticAssetsS3BucketPolicy:
Type: AWS::S3::BucketPolicy
Expand All @@ -81,35 +80,54 @@ resources:
Ref: StaticAssets
PolicyDocument:
Statement:
- Sid: PublicReadGetObject
- Sid: PolicyForCloudFrontPrivateContent
Effect: Allow
Principal: "*"
Principal:
AWS:
Fn::Join:
[
"",
["arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ", { "Ref": "StaticAssetsOAI" }],
]
Action:
- s3:GetObject
Resource:
Fn::Join: ["", ["arn:aws:s3:::", { "Ref": "StaticAssets" }, "/*"]]

StaticAssetsOAI:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: "Access Identity for ${self:service} (${self:provider.stage})"

WebsiteDistribution:
Type: 'AWS::CloudFront::Distribution'
Type: "AWS::CloudFront::Distribution"
Properties:
DistributionConfig:
Origins:
-
DomainName: !Select [2, !Split ["/", !GetAtt ["SvelteLambdaFunctionUrl", "FunctionUrl"]]]
Id: default
OriginCustomHeaders:
- DomainName: !Select [2, !Split ["/", !GetAtt ["SvelteLambdaFunctionUrl", "FunctionUrl"]]]
Id: svelte-server
OriginCustomHeaders:
#Lambda@edge does not support ENV vars, so instead we have to pass in a customHeaders.
-
HeaderName: 's3-host'
HeaderValue: '${self:provider.stage}-${self:service}-static-assets.s3.amazonaws.com'
- HeaderName: "s3-host"
HeaderValue: "${self:provider.stage}-${self:service}-static-assets.s3.amazonaws.com"
CustomOriginConfig:
HTTPPort: 80
HTTPSPort: 443
OriginProtocolPolicy: 'https-only'
OriginProtocolPolicy: "https-only"
- DomainName: !GetAtt ["StaticAssets", "DomainName"]
Id: static-assets
OriginCustomHeaders:
#Lambda@edge does not support ENV vars, so instead we have to pass in a customHeaders.
- HeaderName: "lambda-domain"
HeaderValue: !Select [2, !Split ["/", !GetAtt ["SvelteLambdaFunctionUrl", "FunctionUrl"]]]
S3OriginConfig:
OriginAccessIdentity:
Fn::Join: ["", ["origin-access-identity/cloudfront/", { "Ref": "StaticAssetsOAI" }]]
Enabled: true
Comment: '${self:service}_${self:provider.stage}'
Comment: "${self:service}_${self:provider.stage}"
DefaultCacheBehavior:
TargetOriginId: default
TargetOriginId: static-assets
Compress: true
AllowedMethods:
- DELETE
Expand Down Expand Up @@ -146,4 +164,4 @@ resources:
}
FunctionConfig:
Comment: 'Add x-forwarded-host'
Runtime: cloudfront-js-1.0
Runtime: cloudfront-js-1.0
56 changes: 22 additions & 34 deletions src/router.js
Original file line number Diff line number Diff line change
@@ -1,47 +1,35 @@
'use strict';
"use strict";

import staticFiles from './static.js'
import staticFiles from "./static.js";

exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;

//Only send GET request to S3
if (request.method !== 'GET') {
callback(null, request);
return;
}

let uri = request.uri;
//If our path matches a static file, perfrom an origin re-write to S3;
if (staticFiles.includes(uri)) {
callback(null, performReWrite(uri, request));
return;
if (!uri.includes(".") && uri.slice(-1) !== "/") {
uri += "/";
}

//Remove the leading slash (if any) to normalise the path
if (uri.slice(-1) === "/") {
uri = uri.substring(0, uri.length - 1);
uri += "index.html";
}

//Pre-rendered pages could be named `/index.html` or `route/name.html` lets try looking for those as well
if (staticFiles.includes(uri + '/index.html')) {
callback(null, performReWrite(uri + '/index.html', request));
return;
}
if (staticFiles.includes(uri + '.html')) {
callback(null, performReWrite(uri + '.html', request));
return;
if (staticFiles.includes(uri)) {
request.uri = uri;
} else {
const domainName = request.origin.s3.customHeaders["lambda-domain"][0].value;
request.headers["host"] = [{ key: "Host", value: domainName }];
request.origin.custom = {
domainName: domainName,
keepaliveTimeout: 5,
path: "",
port: 443,
protocol: "https",
readTimeout: 30,
sslProtocols: ["TLSv1", "SSLv3"],
};

// Cleanup request origin to only have custom configuration
delete request.origin.s3;
}

callback(null, request);
};

function performReWrite(uri, request) {
request.uri = uri;
//Lambda@edge does not support ENV vars, so instead we have to pass in a customHeaders.
const domainName = request.origin.custom.customHeaders["s3-host"][0].value;
request.origin.custom.domainName = domainName;
request.origin.custom.path = "";
request.headers["host"] = [{ key: "host", value: domainName }];
return request;
}