Skip to content

Commit db9d7a0

Browse files
committed
Add codebase
1 parent 43fb3a7 commit db9d7a0

File tree

5 files changed

+301
-2
lines changed

5 files changed

+301
-2
lines changed

.editorconfig

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# EditorConfig is awesome: http://EditorConfig.org
2+
# Uses editorconfig to maintain consistent coding styles
3+
4+
# top-most EditorConfig file
5+
root = true
6+
7+
# Unix-style newlines with a newline ending every file
8+
[*]
9+
charset = utf-8
10+
end_of_line = lf
11+
indent_size = 2
12+
indent_style = space
13+
insert_final_newline = true
14+
max_line_length = 80
15+
trim_trailing_whitespace = true
16+
17+
[*.{tf,tfvars}]
18+
indent_size = 2
19+
indent_style = space
20+
21+
[*.md]
22+
max_line_length = 0
23+
trim_trailing_whitespace = false
24+
25+
[Makefile]
26+
tab_width = 2
27+
indent_style = tab
28+
29+
[COMMIT_EDITMSG]
30+
max_line_length = 0

README.md

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,35 @@
1-
# terraform-aws-s3-static-website
2-
Terraform Module for an S3 Static Website
1+
# AWS S3 Static Website
2+
3+
Terraform Module for an Amazon S3 Static Website.
4+
5+
## Features
6+
7+
TK
8+
9+
## Usage
10+
11+
```HCL
12+
module "static_website" {
13+
source = "[email protected]:conortm/terraform-aws-s3-static-website.git"
14+
15+
domain_name = "www.my-aws-s3-static-website.com"
16+
redirects = ["my-aws-s3-static-website.com"]
17+
secret = "SOME_SECRET_MANAGED_OUTSIDE_OF_VERSION_CONTROL"
18+
cert_arn = "ARN_OF_SSL_CERTIFICATE"
19+
zone_id = "HOSTED_ZONE_ID"
20+
21+
tags = {
22+
Foo = "Bar"
23+
}
24+
}
25+
```
26+
27+
## Inputs
28+
29+
TK
30+
31+
## TODO
32+
33+
- [ ] Expose more configuration of resources, esp. Cloudfront dist.
34+
- [ ] Better way to pass in SSL cert, Hosted Zone ID, etc.
35+
- [ ] Better way to implement Cloudfront-to-S3 access than secret?

main.tf

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
resource "aws_s3_bucket" "static_website" {
2+
bucket = "${var.domain_name}"
3+
4+
website {
5+
index_document = "index.html"
6+
error_document = "error.html"
7+
}
8+
9+
tags = "${merge(map("Name", "${var.domain_name}-static_website"), var.tags)}"
10+
}
11+
12+
data "aws_iam_policy_document" "static_website_read_with_secret" {
13+
statement {
14+
sid = "1"
15+
actions = ["s3:GetObject"]
16+
resources = ["${aws_s3_bucket.static_website.arn}${var.public_dir}/*"]
17+
18+
principals {
19+
type = "AWS"
20+
identifiers = ["*"]
21+
}
22+
23+
condition {
24+
test = "StringEquals"
25+
variable = "aws:UserAgent"
26+
values = ["${var.secret}"]
27+
}
28+
}
29+
}
30+
31+
resource "aws_s3_bucket_policy" "static_website_read_with_secret" {
32+
bucket = "${aws_s3_bucket.static_website.id}"
33+
policy = "${data.aws_iam_policy_document.static_website_read_with_secret.json}"
34+
}
35+
36+
locals {
37+
s3_origin_id = "cloudfront-distribution-origin-${var.domain_name}.s3.amazonaws.com${var.public_dir}"
38+
}
39+
40+
resource "aws_cloudfront_distribution" "cdn" {
41+
origin {
42+
domain_name = "${aws_s3_bucket.static_website.website_endpoint}"
43+
origin_path = "${var.public_dir}"
44+
origin_id = "${local.s3_origin_id}"
45+
46+
custom_origin_config {
47+
http_port = 80
48+
https_port = 443
49+
origin_protocol_policy = "http-only"
50+
origin_ssl_protocols = ["TLSv1.2", "TLSv1.1", "TLSv1"]
51+
}
52+
53+
custom_header {
54+
name = "User-Agent"
55+
value = "${var.secret}"
56+
}
57+
}
58+
59+
comment = "CDN for ${var.domain_name} S3 Bucket"
60+
enabled = true
61+
is_ipv6_enabled = true
62+
default_root_object = "index.html"
63+
aliases = ["${var.domain_name}"]
64+
65+
custom_error_response {
66+
error_code = 403
67+
response_page_path = "/error.html"
68+
response_code = 404
69+
}
70+
71+
custom_error_response {
72+
error_code = 404
73+
response_page_path = "/error.html"
74+
response_code = 404
75+
}
76+
77+
default_cache_behavior {
78+
target_origin_id = "${local.s3_origin_id}"
79+
allowed_methods = ["GET", "HEAD"]
80+
cached_methods = ["GET", "HEAD"]
81+
82+
forwarded_values {
83+
query_string = false
84+
85+
cookies {
86+
forward = "none"
87+
}
88+
}
89+
90+
viewer_protocol_policy = "redirect-to-https"
91+
}
92+
93+
restrictions {
94+
geo_restriction {
95+
restriction_type = "none"
96+
}
97+
}
98+
99+
viewer_certificate {
100+
acm_certificate_arn = "${var.cert_arn}"
101+
ssl_support_method = "sni-only"
102+
minimum_protocol_version = "TLSv1.1_2016"
103+
}
104+
105+
tags = "${merge(map("Name", "${var.domain_name}-cdn"), var.tags)}"
106+
}
107+
108+
resource "aws_route53_record" "alias" {
109+
count = "${length(var.zone_id) > 0 ? 1 : 0}"
110+
111+
zone_id = "${var.zone_id}"
112+
name = "${var.domain_name}"
113+
type = "A"
114+
115+
alias {
116+
name = "${aws_cloudfront_distribution.cdn.domain_name}"
117+
zone_id = "${aws_cloudfront_distribution.cdn.hosted_zone_id}"
118+
evaluate_target_health = false
119+
}
120+
}
121+
122+
resource "aws_s3_bucket" "redirect" {
123+
count = "${length(var.redirects)}"
124+
125+
bucket = "${element(var.redirects, count.index)}"
126+
127+
website {
128+
redirect_all_requests_to = "https://${var.domain_name}"
129+
}
130+
131+
tags = "${merge(map("Name", "${element(var.redirects, count.index)}-redirect"), var.tags)}"
132+
}
133+
134+
resource "aws_cloudfront_distribution" "redirect" {
135+
count = "${length(var.redirects)}"
136+
137+
origin {
138+
domain_name = "${element(aws_s3_bucket.redirect.*.website_endpoint, count.index)}"
139+
origin_id = "cloudfront-distribution-origin-${element(var.redirects, count.index)}.s3.amazonaws.com"
140+
141+
custom_origin_config {
142+
http_port = 80
143+
https_port = 443
144+
origin_protocol_policy = "http-only"
145+
origin_ssl_protocols = ["TLSv1.2", "TLSv1.1", "TLSv1"]
146+
}
147+
}
148+
149+
comment = "CDN for ${element(var.redirects, count.index)} S3 Bucket (redirect)"
150+
enabled = true
151+
is_ipv6_enabled = true
152+
aliases = ["${element(var.redirects, count.index)}"]
153+
154+
default_cache_behavior {
155+
target_origin_id = "cloudfront-distribution-origin-${element(var.redirects, count.index)}.s3.amazonaws.com"
156+
allowed_methods = ["GET", "HEAD"]
157+
cached_methods = ["GET", "HEAD"]
158+
159+
forwarded_values {
160+
query_string = false
161+
162+
cookies {
163+
forward = "none"
164+
}
165+
}
166+
167+
viewer_protocol_policy = "redirect-to-https"
168+
}
169+
170+
restrictions {
171+
geo_restriction {
172+
restriction_type = "none"
173+
}
174+
}
175+
176+
viewer_certificate {
177+
acm_certificate_arn = "${var.cert_arn}"
178+
ssl_support_method = "sni-only"
179+
minimum_protocol_version = "TLSv1.1_2016"
180+
}
181+
182+
tags = "${merge(map("Name", "${element(var.redirects, count.index)}-cdn_redirect"), var.tags)}"
183+
}
184+
185+
resource "aws_route53_record" "redirect" {
186+
count = "${length(var.zone_id) > 0 ? length(var.redirects) : 0}"
187+
188+
zone_id = "${var.zone_id}"
189+
# Work-around (see: https://github.com/hashicorp/terraform/issues/11210)
190+
name = "${length(var.redirects) > 0 ? element(concat(var.redirects, list("")), count.index): ""}"
191+
type = "A"
192+
193+
alias {
194+
name = "${element(aws_cloudfront_distribution.redirect.*.domain_name, count.index)}"
195+
zone_id = "${element(aws_cloudfront_distribution.redirect.*.hosted_zone_id, count.index)}"
196+
evaluate_target_health = false
197+
}
198+
}

outputs.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
output "cdn_domain_name" {
2+
description = "Domain name of the Cloudfront Distribution"
3+
value = "${aws_cloudfront_distribution.cdn.domain_name}"
4+
}

variables.tf

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
variable "domain_name" {
2+
description = "Domain name for the website (i.e. www.example.com)"
3+
type = "string"
4+
}
5+
6+
variable "redirects" {
7+
description = "A list of domain names which redirect to domain_name"
8+
default = []
9+
}
10+
11+
variable "public_dir" {
12+
description = "Directory from which to serve public files (default: /public)"
13+
default = "/public"
14+
}
15+
16+
variable "secret" {
17+
description = "A secret string between CloudFront and S3 to control access"
18+
type = "string"
19+
}
20+
21+
variable "cert_arn" {
22+
description = "ARN of the SSL Certificate to use for the Cloudfront Distribution"
23+
type = "string"
24+
}
25+
26+
variable "zone_id" {
27+
description = "ID of the Route 53 Hosted Zone in which to create an alias record"
28+
type = "string"
29+
}
30+
31+
variable "tags" {
32+
description = "A map of tags to add to all resources"
33+
default = {}
34+
}

0 commit comments

Comments
 (0)