Hexo Serverless (part quatre)

This document is a continuation of Putting the Hexo CMS into a Serverless world, part 2 and part 3.


To properly secure and serve our website, we will update the ACL for Bucket Policy.

Edit s3.tf and change the two resources for the domain named S3 buckets to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
resource "aws_s3_bucket" "serverless_hexo" {
bucket = "${var.domain_name}"
acl = "private"
tags = "${merge(var.tags, map("Name", "Serverless Hexo Demo Website"))}"

website {
index_document = "index.html"
error_document = "error.html"
}
versioning {
enabled = true
}
logging {
target_bucket = "${aws_s3_bucket.bucket_logging.id}"
target_prefix = "${var.domain_name}"
}
server_side_encryption_configuration {
rule {
apply_server_side_encryption_by_default {
# using a CMK via SSE-KMS, you must sign requests
# using default AES256 via SSE-S3, you do not
sse_algorithm = "AES256"
}
}
}
policy = <<EOF
{
"Version":"2012-10-17",
"Statement":[
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::${var.domain_name}"
]
},
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::${var.domain_name}/*"
]
}
]
}
EOF
}

resource "aws_s3_bucket" "serverless_hexo_www" {
bucket = "www.${var.domain_name}"
acl = "public-read"
tags = "${merge(var.tags, map("Name", "Serverless Hexo Demo WWW Redirect"))}"

website {
redirect_all_requests_to = "${var.domain_name}"
}

policy = <<EOF
{
"Version": "2012-10-17",
"Statement":[
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action":[
"s3:GetObject"
],
"Resource":[
"arn:aws:s3:::www.${var.domain_name}/*"
]
}
]
}
EOF
}

Create cloudfront.tf and add the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
locals {
s3_origin_id = "s3orgin"
}

resource "aws_cloudfront_origin_access_identity" "origin_access_identity" {
comment = "Created for ${var.domain_name}"
}
resource "aws_cloudfront_distribution" "serverless_hexo" {
enabled = true
is_ipv6_enabled = true
comment = "CloudFront Distribution for the Hexo Serverless Demo"
default_root_object = "index.html"

tags = "${var.tags}"

aliases = ["${var.domain_name}"]

origin {
domain_name = "${aws_s3_bucket.serverless_hexo.bucket_regional_domain_name}"
origin_id = "${local.s3_origin_id}"
s3_origin_config {
origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}"
}
}

default_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "${local.s3_origin_id}"

forwarded_values {
query_string = false

cookies {
forward = "none"
}
}

lambda_function_association {
event_type = "origin-request"
lambda_arn = "${aws_lambda_function.cloudfront_rewrite.qualified_arn}"
include_body = false
}

viewer_protocol_policy = "allow-all"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}

restrictions {
geo_restriction {
restriction_type = "none"
}
}

logging_config {
include_cookies = false
bucket = "${aws_s3_bucket.bucket_logging.bucket_domain_name}"
prefix = "cloudfront-${var.domain_name}"
}

viewer_certificate {
acm_certificate_arn = "${aws_acm_certificate.domain.arn}"
ssl_support_method = "sni-only"
}

}

We will also need to adjust AWS Route53 to point to CloudFront as opposed to AWS S3. Update route53.tf with the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
resource "aws_route53_zone" "domain" {
name = "${var.domain_name}"
}

resource "aws_route53_record" "at" {
zone_id = "${aws_route53_zone.domain.zone_id}"
name = "@"
type = "CNAME"

alias {
name = "${aws_cloudfront_distribution.serverless_hexo.domain_name}"
zone_id = "${aws_cloudfront_distribution.serverless_hexo.hosted_zone_id}"
evaluate_target_health = true
}
}

resource "aws_route53_record" "www" {
zone_id = "${aws_route53_zone.domain.zone_id}"
name = "www"
type = "CNAME"

alias {
name = "${aws_s3_bucket.serverless_hexo.website_endpoint}"
zone_id = "${aws_s3_bucket.serverless_hexo.hosted_zone_id}"
evaluate_target_health = true
}
}

After running a terraform apply and grabbing a coffee, visit https:// for your domain and you should see the same content as before but now served securely via HTTPS. If you click any of the links, they are broken …

We need to fix that, obviously. We will resolve this in part 5.