Skip to content

Commit 637d156

Browse files
committed
🎉 Initial commit
1 parent d4714f0 commit 637d156

File tree

4 files changed

+208
-0
lines changed

4 files changed

+208
-0
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,23 @@
11
# terraform-aws-react_app
2+
23
Terraform private module for installing a React App using S3, CloudFront, and Route53
4+
5+
## Module Installation
6+
7+
### Setting up a provider and registering the module
8+
9+
This is outside the scope of this README. For more information, go visit [the relevant documentation](https://www.terraform.io/docs/cloud/registry/publish.html)
10+
11+
### Using the module
12+
13+
In your terraform configuration, you can then use the module this way
14+
15+
```hcl
16+
module "react_app" {
17+
source = "app.terraform.io/YOUR_ORGANIZATION/react_app/aws"
18+
version = "1.0.0"
19+
# insert required variables here
20+
}
21+
```
22+
23+
And use outputs value as you would with a normal terraform resource

main.tf

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
provider "aws" {
2+
alias = "us_east_1"
3+
region = "us-east-1"
4+
}
5+
6+
resource "aws_s3_bucket" "this" {
7+
bucket = "${var.bucket_name_prefix}-app"
8+
acl = "public-read"
9+
10+
policy = <<EOF
11+
{
12+
"Id": "${var.bucket_name_prefix}-app",
13+
"Version": "2012-10-17",
14+
"Statement": [
15+
{
16+
"Sid": "${var.bucket_name_prefix}-app-main",
17+
"Action": [
18+
"s3:GetObject"
19+
],
20+
"Effect": "Allow",
21+
"Resource": "arn:aws:s3:::${var.bucket_name_prefix}-app/*",
22+
"Principal": "*"
23+
}
24+
]
25+
}
26+
EOF
27+
28+
website {
29+
index_document = "index.html"
30+
error_document = "index.html"
31+
}
32+
33+
force_destroy = true
34+
}
35+
36+
locals {
37+
s3_origin_id = "${var.bucket_name_prefix}-origin"
38+
}
39+
40+
resource "aws_cloudfront_origin_access_identity" "this" {
41+
comment = "S3 Bucket Origin"
42+
}
43+
44+
resource "aws_cloudfront_distribution" "this" {
45+
origin {
46+
domain_name = aws_s3_bucket.this.bucket_regional_domain_name
47+
origin_id = local.s3_origin_id
48+
49+
s3_origin_config {
50+
origin_access_identity = aws_cloudfront_origin_access_identity.this.cloudfront_access_identity_path
51+
}
52+
}
53+
54+
enabled = true
55+
is_ipv6_enabled = true
56+
default_root_object = "index.html"
57+
58+
aliases = concat(
59+
["${var.service_name}.${var.zone}"],
60+
var.aliases
61+
)
62+
63+
default_cache_behavior {
64+
allowed_methods = ["GET", "HEAD", "OPTIONS"]
65+
cached_methods = ["GET", "HEAD"]
66+
target_origin_id = local.s3_origin_id
67+
68+
forwarded_values {
69+
query_string = false
70+
71+
cookies {
72+
forward = "none"
73+
}
74+
}
75+
76+
viewer_protocol_policy = "redirect-to-https"
77+
min_ttl = 0
78+
default_ttl = 3600
79+
max_ttl = 86400
80+
}
81+
82+
price_class = "PriceClass_200"
83+
84+
restrictions {
85+
geo_restriction {
86+
restriction_type = "none"
87+
}
88+
}
89+
90+
custom_error_response {
91+
error_caching_min_ttl = 10
92+
error_code = 404
93+
response_code = 200
94+
response_page_path = "/index.html"
95+
}
96+
97+
viewer_certificate {
98+
acm_certificate_arn = aws_acm_certificate_validation.this.certificate_arn
99+
ssl_support_method = "sni-only"
100+
}
101+
}
102+
103+
resource "aws_acm_certificate" "this" {
104+
provider = aws.us_east_1
105+
domain_name = "${var.service_name}.${var.zone}"
106+
validation_method = "DNS"
107+
subject_alternative_names = var.aliases
108+
109+
lifecycle {
110+
create_before_destroy = true
111+
}
112+
}
113+
114+
data "aws_route53_zone" "this" {
115+
name = var.zone
116+
private_zone = false
117+
}
118+
119+
resource "aws_route53_record" "certificate_validation" {
120+
for_each = {
121+
for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => {
122+
name = dvo.resource_record_name
123+
record = dvo.resource_record_value
124+
type = dvo.resource_record_type
125+
}
126+
}
127+
128+
allow_overwrite = true
129+
name = each.value.name
130+
records = [each.value.record]
131+
ttl = 60
132+
type = each.value.type
133+
zone_id = data.aws_route53_zone.this.zone_id
134+
}
135+
136+
resource "aws_acm_certificate_validation" "this" {
137+
provider = aws.us_east_1
138+
certificate_arn = aws_acm_certificate.this.arn
139+
validation_record_fqdns = [for record in aws_route53_record.certificate_validation : record.fqdn]
140+
}
141+
142+
resource "aws_route53_record" "this" {
143+
for_each = toset(concat(["${var.service_name}.${var.zone}"], var.aliases))
144+
145+
zone_id = data.aws_route53_zone.this.zone_id
146+
name = each.value
147+
type = "A"
148+
allow_overwrite = true
149+
150+
alias {
151+
name = aws_cloudfront_distribution.this.domain_name
152+
zone_id = aws_cloudfront_distribution.this.hosted_zone_id
153+
evaluate_target_health = false
154+
}
155+
}

outputs.tf

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
output "domain" {
2+
value = aws_s3_bucket.this.website_domain
3+
}
4+
5+
output "endpoint" {
6+
value = aws_s3_bucket.this.website_endpoint
7+
}
8+
9+
output "bucket" {
10+
value = aws_s3_bucket.this.bucket
11+
}

variables.tf

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
variable "bucket_name_prefix" {
3+
type = string
4+
description = "Prefix of the bucket used to store the react files"
5+
}
6+
7+
variable "service_name" {
8+
type = string
9+
description = "Name of the service prefixed to the zone to form the base URl"
10+
}
11+
12+
variable "zone" {
13+
type = string
14+
description = "Name of the zone appended to the service name to form the base URL"
15+
}
16+
17+
variable "aliases" {
18+
default = []
19+
type = list(string)
20+
description = "List of aliases in the zone to access the react app with"
21+
}

0 commit comments

Comments
 (0)