Skip to content

Commit

Permalink
Merge pull request #1298 from aligent/chore/static-hosting-documentation
Browse files Browse the repository at this point in the history
chore: update readme and add parameter comments
  • Loading branch information
TheOrangePuff authored Feb 1, 2024
2 parents 2173f8e + 410d2a8 commit 19fe886
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 26 deletions.
14 changes: 11 additions & 3 deletions packages/static-hosting/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,17 @@
## Overview

This repository defines a CDK construct for hosting a static website on AWS using S3 and CloudFront.
It can be imported and used within CDK applications.

It can be imported and used within CDK applications. By default this construct will create a CloudFront distribution with an S3 bucket as the origin. It will also create an IAM user and group that have permission to create files in the S3 bucket.

It has the following features that can optionally be enabled:

- Create a DNS record in an existing hosted zone
- Store CloudFront logs in an S3 bucket
- Add a custom backend origin
- Remap static files to the the S3 or backend origin

![static hosting diagram](docs/static_hosting.png)

## Example

Expand All @@ -21,8 +31,6 @@ const HostingStackProps : StaticHostingProps = {
domainName: 'domain.tld',
certificateArn: 'arn:aws:acm:us-east-1:123456789:certificate/some-arn-id',
createDnsRecord: false,
createPublisherGroup: true,
createPublisherUser: true,
enableErrorConfig: true
};
Expand Down
Binary file added packages/static-hosting/docs/static_hosting.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
202 changes: 179 additions & 23 deletions packages/static-hosting/lib/static-hosting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,57 +45,206 @@ import { CSP } from "../types/csp";
import { PathRemapFunction } from "./path-remap";

export interface StaticHostingProps {
exportPrefix?: string;
/**
* Domain name for the stack. Combined with the subDomainName it is used as
* the name for the S3 origin and an alternative domain name for the
* CloudFront distribution
*/
domainName: string;

/**
* Subdomain name for the stack. Combined with the domainName it is used as
* the name for the S3 origin and an alternative domain name for the
* CloudFront distribution
*/
subDomainName: string;

/**
* An array of additional Cloudfront alternative domain names.
*
* @default undefined
*/
extraDistributionCnames?: ReadonlyArray<string>;

/**
* The arn of the certificate to attach to the CloudFront distribution.
* Must be created in us-east-1
*/
certificateArn: string;
createDnsRecord?: boolean;

/**
* Custom backend host to add as a second origin to the CloudFront distribution
*
* @default undefined
*/
backendHost?: string;

/**
* The hosted zone name to create a DNS record in.
* If not supplied a DNS record will not be created
*
* @default undefined
*/
zoneName?: string;

/**
* Whether to create a group with permissions to publish to the S3 bucket.
*
* @default true
*/
createPublisherGroup?: boolean;

/**
* Whether to create a user with permissions to publish to the S3 bucket.
* The user will not have permissions unless the publisher group is also created
*
* @default true
*/
createPublisherUser?: boolean;
extraDistributionCnames?: ReadonlyArray<string>;

/**
* Enable CloudFront access logs
*
* @default false
*/
enableCloudFrontAccessLogging?: boolean;

/**
* Enable S3 access logging
*
* @default false
*/
enableS3AccessLogging?: boolean;
zoneName?: string;

/**
* Enable returning the errorResponsePagePath on a 404.
* Not required when using Prerender or Feature environment Lambda@Edge functions
*
* @default false
*/
enableErrorConfig?: boolean;

/**
* Custom error response page path
*
* @default index.html
*/
errorResponsePagePath?: string;

/**
* Create behaviours for the following file extensions to route straight to the S3 origin
* js, css, json, svg, jpg, jpeg, png, gif, ico, woff, woff2, otf
*
* @default true
*/
enableStaticFileRemap?: boolean;

/**
* Paths to remap on the default behaviour. For example you might remap deployed_sitemap.xml -> sitemap.xml
* Created a behaviour in CloudFront to handle the remap. If the paths are different
* it will also deploy a Lambda@Edge function to perform the required remap.
*
* @default undefined
*/
remapPaths?: remapPath[];
backendHost?: string;

/**
* Functions the same as remapPaths but uses the backendHost as the origin.
* Requires a valid backendHost to be configured
*
* @see remapPaths
* @default undefined
*/
remapBackendPaths?: remapPath[];

/**
* Override the default root object
*
* @default index.html
*/
defaultRootObject?: string;

/**
* Enforce ssl on bucket requests
*
* @default true
*/
enforceSSL?: boolean;
comment?: string;

/**
* Disable the use of the CSP header. Default value is false.
* Disable the use of the CSP header
*
* @default false
*/
disableCSP?: boolean;

/**
* Adds custom CSP directives and URLs to the header.
*
* AWS limits the max header size to 1kb, this is too small for complex csp headers.
* The main purpose of this csp header is to provide a method of setting a report-uri.
*
* @default undefined
*/
csp?: CSP;

/**
* This will generate a csp based *purely* on the provided csp object.
* Therefore disabling the automatic adding of common use-case properties.
*
* @default false
*/
explicitCSP?: boolean;

/**
* Extend the default props for S3 bucket
*
* @default undefined
*/
s3ExtendedProps?: BucketProps;

/**
* Optional WAF ARN
* Add an external WAF via an arn
*
* @default undefined
*/
webAclArn?: string;

/**
* Add response headers policies to the default behaviour
*
* @default undefined
*/
responseHeadersPolicies?: ResponseHeaderMappings;

/**
* Additional behaviours
*
* @default undefined
*/
additionalBehaviors?: Record<string, BehaviorOptions>;
errorResponsePagePath?: string;

/**
* Lambda@Edge functions to add to the default behaviour
*
* @default undefined
*/
defaultBehaviorEdgeLambdas?: EdgeLambda[];

/**
* A request policy used on the default behavior
*
* @default undefined
*/
defaultBehaviorRequestPolicy?: OriginRequestPolicy;

/**
* A cache policy used on the default behavior
*
* @default undefined
*/
defaultBehaviorCachePolicy?: CachePolicy;

/**
* After switching constructs, you need to maintain the same logical ID
* for the underlying CfnDistribution if you wish to avoid the deletion
Expand All @@ -105,19 +254,24 @@ export interface StaticHostingProps {
* the new Distribution construct with the logical ID created by the
* old construct
*
* https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront-readme.html#migrating-from-the-original-cloudfrontwebdistribution-to-the-newer-distribution-construct.
* @see https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_cloudfront-readme.html#migrating-from-the-original-cloudfrontwebdistribution-to-the-newer-distribution-construct.
* @default undefined
*/
overrideLogicalId?: string;

/**
* A Request policy used on the default behavior
* A string to prefix CloudFormation outputs with
*
* @default undefined
*/
defaultBehaviorRequestPolicy?: OriginRequestPolicy;
exportPrefix?: string;

/**
* A Cache policy used on the default behavior
* Add a comment to the CloudFront distribution
*
* @default undefined
*/
defaultBehaviorCachePolicy?: CachePolicy;
comment?: string;
}

interface remapPath {
Expand Down Expand Up @@ -211,11 +365,12 @@ export class StaticHosting extends Construct {
exportName: `${exportPrefix}BucketName`,
});

const publisherUser = props.createPublisherUser
? new User(this, "PublisherUser", {
userName: `publisher-${siteName}`,
})
: undefined;
const publisherUser =
props.createPublisherUser !== false
? new User(this, "PublisherUser", {
userName: `publisher-${siteName}`,
})
: undefined;

if (publisherUser) {
new CfnOutput(this, "PublisherUserName", {
Expand All @@ -225,9 +380,10 @@ export class StaticHosting extends Construct {
});
}

const publisherGroup = props.createPublisherGroup
? new Group(this, "PublisherGroup")
: undefined;
const publisherGroup =
props.createPublisherGroup !== false
? new Group(this, "PublisherGroup")
: undefined;

if (publisherGroup) {
this.bucket.grantReadWrite(publisherGroup);
Expand Down Expand Up @@ -434,7 +590,7 @@ export class StaticHosting extends Construct {
exportName: `${exportPrefix}DistributionName`,
});

if (props.createDnsRecord && props.zoneName) {
if (props.zoneName) {
const zone = HostedZone.fromLookup(this, "Zone", {
domainName: props.zoneName,
});
Expand Down

0 comments on commit 19fe886

Please sign in to comment.