Skip to content

Commit bf843ff

Browse files
authored
Use cloudfront secure headers (#42)
* Add ResponseHeadersPolicy * Remove Lambda at Edge function * Update Readme Co-authored-by: Nick <[email protected]> * Add missing step to diagram
1 parent 3ad9a23 commit bf843ff

File tree

8 files changed

+46
-89
lines changed

8 files changed

+46
-89
lines changed

Makefile

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,4 @@ build-static:
4141

4242
package-static:
4343
make build-static
44-
cd source/witch && zip -r ../../witch.zip nodejs
45-
46-
package-function:
47-
make clean
48-
make package-static
49-
cd source/secured-headers/ && zip -r ../../s-headers.zip index.js
44+
cd source/witch && zip -r ../../witch.zip nodejs

README.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Use this solution to create a secure static website for your registered domain n
55
- Is hosted on [Amazon S3](https://aws.amazon.com/s3/)
66
- Is distributed by [Amazon CloudFront](https://aws.amazon.com/cloudfront/)
77
- Uses an SSL/TLS certificate from [AWS Certificate Manager (ACM)](https://aws.amazon.com/certificate-manager/)
8-
- Uses [Lambda@Edge](https://aws.amazon.com/lambda/edge/) to add security headers to every server response
8+
- Uses [CloudFront Response Header Policies](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-response-headers.html) to add security headers to every server response
99
- Is deployed with [AWS CloudFormation](https://aws.amazon.com/cloudformation/)
1010

1111
For more information about each of these components, see the **Solution details** section on this page.
@@ -14,30 +14,31 @@ For more information about each of these components, see the **Solution details*
1414

1515
The following diagram shows an overview of how the solution works:
1616

17-
![Architecture](./docs/images/architecture.png)
17+
![Architecture](./docs/images/cf-secure-static-site-architecture.png)
1818

1919
1. The viewer requests the website at www.example.com.
2020
2. If the requested object is cached, CloudFront returns the object from its cache to the viewer.
2121
3. If the object is not in CloudFront’s cache, CloudFront requests the object from the origin (an S3 bucket).
22-
4. S3 returns the object to CloudFront, which triggers the Lambda@Edge origin response event.
23-
5. The object, including the security headers added by the Lambda@Edge function, is added to CloudFront’s cache.
24-
6. (Not shown) The objects is returned to the viewer. Subsequent responses for the object are served from the CloudFront cache.
22+
4. S3 returns the object to CloudFront
23+
5. CloudFront caches the object.
24+
6. The object is returned to the viewer. Subsequent responses for the object are served from the CloudFront cache.
25+
2526

2627
## Solution details
2728

2829
### S3 configuration
2930
This solution creates an S3 bucket that hosts your static website’s assets. The website is only accessible via CloudFront, not directly from S3.
3031

3132
### CloudFront configuration
32-
This solution creates a CloudFront distribution to serve your website to viewers. The distribution is configured with a CloudFront [origin access identity](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html) to make sure that the website is only accessible via CloudFront, not directly from S3. The distribution is also configured with a [Lambda@Edge function](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-at-the-edge.html) that adds security headers to every response.
33+
This solution creates a CloudFront distribution to serve your website to viewers. The distribution is configured with a CloudFront [origin access identity](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html) to make sure that the website is only accessible via CloudFront, not directly from S3. The distribution is also configured with a [CloudFront Response Header Policy](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/adding-response-headers.html) that adds security headers to every response.
3334

3435
### ACM configuration
3536
This solution creates an SSL/TLS certificate in ACM, and attaches it to the CloudFront distribution. This enables the distribution to serve your domain’s website using HTTPS.
3637

37-
### Lambda@Edge configuration
38-
This solution creates a Lambda@Edge function that’s triggered on an [origin response event](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-cloudfront-trigger-events.html). The function adds security headers to every response served by CloudFront.
38+
### CloudFront Response Header Policy
39+
The CloudFront Response Header Policy adds security headers to every response served by CloudFront.
3940

40-
The security headers can help mitigate some attacks, as explained in this blog post: [Adding HTTP Security Headers Using Lambda@Edge and Amazon CloudFront](https://aws.amazon.com/blogs/networking-and-content-delivery/adding-http-security-headers-using-lambdaedge-and-amazon-cloudfront/). Security headers are a group of headers in the web server response that tell web browsers to take extra security precautions. This solution adds the following headers to each response:
41+
The security headers can help mitigate some attacks, as explained in the [Amazon CloudFront - Understanding response header policies documentation](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/understanding-response-headers-policies.html#understanding-response-headers-policies-security). Security headers are a group of headers in the web server response that tell web browsers to take extra security precautions. This solution adds the following headers to each response:
4142

4243
- [Strict-Transport-Security](https://infosec.mozilla.org/guidelines/web_security#http-strict-transport-security)
4344
- [Content-Security-Policy](https://infosec.mozilla.org/guidelines/web_security#content-security-policy)
@@ -70,7 +71,7 @@ To deploy the solution, you use [AWS CloudFormation](https://aws.amazon.com/clou
7071
following fields:
7172

7273
- **SubDomain:** The subdomain for your registered domain name. Viewers use the subdomain to access your website, for example: www.example.com. We recommend using the default value of **www** as the subdomain.
73-
- **DomainName:** Your registered domain name, such as example.com. This domain must be pointed to a Route 53 hosted zone.
74+
- **DomainName:** Your registered domain name, such as example.com. This domain must be pointed to a Route 53 hosted zone.
7475
- **CreateApex:** Optionally create an Alias to the domain apex (example.com) in your CloudFront configuration. Default is [no]
7576

7677
After entering values, choose the **Next** button.
@@ -111,7 +112,7 @@ https://s3.amazonaws.com/solution-builders-us-east-1/amazon-cloudfront-secure-st
111112
3. Run the following command to package a build artifact.
112113

113114
```shell
114-
make package-function
115+
make package-static
115116
```
116117

117118
4. Copy your website content into the **www** folder.
@@ -138,8 +139,8 @@ https://s3.amazonaws.com/solution-builders-us-east-1/amazon-cloudfront-secure-st
138139
--template-file packaged.template \
139140
--capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
140141
--parameter-overrides DomainName=<your domain name> SubDomain=<your website subdomain>
141-
```
142-
142+
```
143+
143144
8. [Optional] Run the following command to deploy the packaged CloudFormation template to a CloudFormation stack with a domain apex.
144145

145146
```shell
@@ -148,8 +149,8 @@ https://s3.amazonaws.com/solution-builders-us-east-1/amazon-cloudfront-secure-st
148149
--template-file packaged.template \
149150
--capabilities CAPABILITY_NAMED_IAM CAPABILITY_AUTO_EXPAND \
150151
--parameter-overrides DomainName=<your domain name> SubDomain=<your website subdomain> CreateApex=yes
151-
```
152-
152+
```
153+
153154

154155
### Updating the site Content Security Policy
155156

ci/include.lst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
templates
22
cfn-publish.config
3-
s-headers.zip
43
witch.zip
54
www

docs/images/architecture.png

-94.1 KB
Binary file not shown.
18.1 KB
Loading

source/secured-headers/index.js

Lines changed: 0 additions & 18 deletions
This file was deleted.

templates/cloudfront-site.yaml

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -50,44 +50,6 @@ Resources:
5050
Principal:
5151
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
5252

53-
LambdaEdgeFunction:
54-
DeletionPolicy: Retain
55-
Type: AWS::Serverless::Function
56-
Properties:
57-
Handler: index.handler
58-
Role: !GetAtt LambdaEdgeFunctionRole.Arn
59-
CodeUri: ../s-headers.zip
60-
Runtime: 'nodejs12.x'
61-
Timeout: 25
62-
63-
Lambdaversion:
64-
Type: AWS::Lambda::Version
65-
Properties:
66-
FunctionName: !Ref LambdaEdgeFunction
67-
Description: v1
68-
69-
LambdaEdgeFunctionRole:
70-
Type: AWS::IAM::Role
71-
Properties:
72-
Path: '/'
73-
ManagedPolicyArns:
74-
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
75-
AssumeRolePolicyDocument:
76-
Version: '2012-10-17'
77-
Statement:
78-
-
79-
Sid: 'AllowLambdaServiceToAssumeRole'
80-
Effect: 'Allow'
81-
Action:
82-
- 'sts:AssumeRole'
83-
Principal:
84-
Service:
85-
- 'lambda.amazonaws.com'
86-
- 'edgelambda.amazonaws.com'
87-
Tags:
88-
- Key: Solution
89-
Value: ACFS3
90-
9153
CloudFrontDistribution:
9254
Type: AWS::CloudFront::Distribution
9355
Properties:
@@ -102,11 +64,8 @@ Resources:
10264
QueryString: true
10365
MaxTTL: 31536000
10466
TargetOriginId: !Sub 'S3-${AWS::StackName}-root'
105-
LambdaFunctionAssociations:
106-
-
107-
EventType: origin-response
108-
LambdaFunctionARN: !Ref Lambdaversion
10967
ViewerProtocolPolicy: 'redirect-to-https'
68+
ResponseHeadersPolicyId: !Ref ResponseHeadersPolicy
11069
CustomErrorResponses:
11170
- ErrorCachingMinTTL: 60
11271
ErrorCode: 404
@@ -172,11 +131,35 @@ Resources:
172131
# The following HosteZoneId is always used for alias records pointing to CF.
173132
HostedZoneId: 'Z2FDTNDATAQYW2'
174133

175-
Outputs:
176-
LambdaEdgeFunctionVersion:
177-
Description: Security Lambda version
178-
Value: !Ref Lambdaversion
134+
ResponseHeadersPolicy:
135+
Type: AWS::CloudFront::ResponseHeadersPolicy
136+
Properties:
137+
ResponseHeadersPolicyConfig:
138+
Comment: "practera-security-headers-for-${env:APPV2S3BUCKET}"
139+
Name: "practera-security-headers-for-GlobalAPPv2"
140+
SecurityHeadersConfig:
141+
StrictTransportSecurity:
142+
AccessControlMaxAgeSec: 63072000
143+
IncludeSubdomains: true
144+
Override: true
145+
Preload: true
146+
ContentSecurityPolicy:
147+
ContentSecurityPolicy: "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; object-src 'none'"
148+
Override: true
149+
ContentTypeOptions:
150+
Override: true
151+
FrameOptions:
152+
FrameOption: DENY
153+
Override: true
154+
ReferrerPolicy:
155+
ReferrerPolicy: "same-origin"
156+
Override: true
157+
XSSProtection:
158+
ModeBlock: true
159+
Override: true
160+
Protection: true
179161

162+
Outputs:
180163
CloudFrontDistribution:
181164
Description: CloudFront distribution
182165
Value: !GetAtt CloudFrontDistribution.DomainName

templates/main.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,6 @@ Outputs:
9898
CFDistributionName:
9999
Description: CloudFront distribution
100100
Value: !GetAtt CloudFrontStack.Outputs.CloudFrontDistribution
101-
LambdaEdgeFunctionVersion:
102-
Description: Security Lambda version
103-
Value: !GetAtt CloudFrontStack.Outputs.LambdaEdgeFunctionVersion
104101
CloudFrontDomainName:
105102
Description: Website address
106103
Value: !GetAtt CloudFrontStack.Outputs.CloudFrontDomainName

0 commit comments

Comments
 (0)