diff options
-rw-r--r-- | jinwei.me/infra/.terraform.lock.hcl | 2 | ||||
-rw-r--r-- | jinwei.me/infra/acm.tf | 41 | ||||
-rw-r--r-- | jinwei.me/infra/cloudflare.tf | 3 | ||||
-rw-r--r-- | jinwei.me/infra/cloudfront.tf | 76 | ||||
-rw-r--r-- | jinwei.me/infra/s3.tf | 8 | ||||
-rw-r--r-- | jinwei.me/infra/variables.tf | 6 | ||||
-rw-r--r-- | jinwei.me/infra/versions.tf | 5 |
7 files changed, 134 insertions, 7 deletions
diff --git a/jinwei.me/infra/.terraform.lock.hcl b/jinwei.me/infra/.terraform.lock.hcl index 9fdb71e..e16e9bd 100644 --- a/jinwei.me/infra/.terraform.lock.hcl +++ b/jinwei.me/infra/.terraform.lock.hcl | |||
@@ -23,7 +23,7 @@ provider "registry.terraform.io/cloudflare/cloudflare" { | |||
23 | 23 | ||
24 | provider "registry.terraform.io/hashicorp/aws" { | 24 | provider "registry.terraform.io/hashicorp/aws" { |
25 | version = "4.46.0" | 25 | version = "4.46.0" |
26 | constraints = "~> 4.46" | 26 | constraints = ">= 3.73.0, ~> 4.46" |
27 | hashes = [ | 27 | hashes = [ |
28 | "h1:EZB4OgvytV38JpWyye9zoMQ0bfT9yB9xSXM5NY3Lrws=", | 28 | "h1:EZB4OgvytV38JpWyye9zoMQ0bfT9yB9xSXM5NY3Lrws=", |
29 | "zh:1678e6a4bdb3d81a6713adc62ca0fdb8250c584e10c10d1daca72316e9db8df2", | 29 | "zh:1678e6a4bdb3d81a6713adc62ca0fdb8250c584e10c10d1daca72316e9db8df2", |
diff --git a/jinwei.me/infra/acm.tf b/jinwei.me/infra/acm.tf new file mode 100644 index 0000000..c6900cd --- /dev/null +++ b/jinwei.me/infra/acm.tf | |||
@@ -0,0 +1,41 @@ | |||
1 | resource "aws_acm_certificate" "main" { | ||
2 | domain_name = "static.jinwei.me" | ||
3 | validation_method = "DNS" | ||
4 | |||
5 | subject_alternative_names = [ | ||
6 | "*.static.jinwei.me", | ||
7 | ] | ||
8 | } | ||
9 | |||
10 | resource "aws_acm_certificate_validation" "main" { | ||
11 | certificate_arn = aws_acm_certificate.main.arn | ||
12 | validation_record_fqdns = [cloudflare_record.acm.hostname] | ||
13 | } | ||
14 | |||
15 | |||
16 | # CloudFront requires ACM to be in us-east-1, so duplicate the resources. | ||
17 | resource "aws_acm_certificate" "us-east-1" { | ||
18 | provider = aws.us-east-1 | ||
19 | |||
20 | domain_name = "static.jinwei.me" | ||
21 | validation_method = "DNS" | ||
22 | |||
23 | subject_alternative_names = [ | ||
24 | "*.static.jinwei.me", | ||
25 | ] | ||
26 | } | ||
27 | |||
28 | resource "aws_acm_certificate_validation" "us-east-1" { | ||
29 | provider = aws.us-east-1 | ||
30 | |||
31 | certificate_arn = aws_acm_certificate.us-east-1.arn | ||
32 | validation_record_fqdns = [cloudflare_record.acm.hostname] | ||
33 | } | ||
34 | |||
35 | # Cloudflare validation record | ||
36 | resource "cloudflare_record" "acm" { | ||
37 | zone_id = data.cloudflare_zones.domain.zones[0].id | ||
38 | name = tolist(aws_acm_certificate.main.domain_validation_options)[0].resource_record_name | ||
39 | type = tolist(aws_acm_certificate.main.domain_validation_options)[0].resource_record_type | ||
40 | value = tolist(aws_acm_certificate.main.domain_validation_options)[0].resource_record_value | ||
41 | } | ||
diff --git a/jinwei.me/infra/cloudflare.tf b/jinwei.me/infra/cloudflare.tf index 5c79607..a6ca299 100644 --- a/jinwei.me/infra/cloudflare.tf +++ b/jinwei.me/infra/cloudflare.tf | |||
@@ -7,9 +7,10 @@ data "cloudflare_zones" "domain" { | |||
7 | } | 7 | } |
8 | 8 | ||
9 | resource "cloudflare_record" "s3_bucket" { | 9 | resource "cloudflare_record" "s3_bucket" { |
10 | # Point CNAME record in Cloudflare to Cloudfront | ||
10 | zone_id = data.cloudflare_zones.domain.zones[0].id | 11 | zone_id = data.cloudflare_zones.domain.zones[0].id |
11 | name = var.s3_cdn_name | 12 | name = var.s3_cdn_name |
12 | value = aws_s3_bucket.main.bucket_regional_domain_name | 13 | value = aws_cloudfront_distribution.main.domain_name |
13 | type = "CNAME" | 14 | type = "CNAME" |
14 | 15 | ||
15 | ttl = 1 | 16 | ttl = 1 |
diff --git a/jinwei.me/infra/cloudfront.tf b/jinwei.me/infra/cloudfront.tf new file mode 100644 index 0000000..2566584 --- /dev/null +++ b/jinwei.me/infra/cloudfront.tf | |||
@@ -0,0 +1,76 @@ | |||
1 | resource "aws_cloudfront_distribution" "main" { | ||
2 | aliases = [var.s3_cloudfront_name] | ||
3 | enabled = true | ||
4 | http_version = "http2and3" | ||
5 | is_ipv6_enabled = true | ||
6 | price_class = "PriceClass_All" | ||
7 | retain_on_delete = true | ||
8 | wait_for_deployment = false | ||
9 | |||
10 | default_cache_behavior { | ||
11 | target_origin_id = aws_s3_bucket.main.bucket_regional_domain_name | ||
12 | |||
13 | compress = true | ||
14 | viewer_protocol_policy = "redirect-to-https" | ||
15 | allowed_methods = ["GET", "HEAD"] | ||
16 | cached_methods = ["GET", "HEAD"] | ||
17 | cache_policy_id = data.aws_cloudfront_cache_policy.managed["CachingOptimized"].id | ||
18 | origin_request_policy_id = data.aws_cloudfront_origin_request_policy.managed["CORS-S3Origin"].id | ||
19 | } | ||
20 | |||
21 | origin { | ||
22 | origin_id = aws_s3_bucket.main.bucket_regional_domain_name | ||
23 | domain_name = aws_s3_bucket.main.bucket_regional_domain_name | ||
24 | origin_access_control_id = aws_cloudfront_origin_access_control.main.id | ||
25 | } | ||
26 | |||
27 | restrictions { | ||
28 | geo_restriction { | ||
29 | restriction_type = "none" | ||
30 | } | ||
31 | } | ||
32 | |||
33 | viewer_certificate { | ||
34 | acm_certificate_arn = aws_acm_certificate_validation.us-east-1.certificate_arn | ||
35 | minimum_protocol_version = "TLSv1.2_2021" | ||
36 | ssl_support_method = "sni-only" | ||
37 | } | ||
38 | } | ||
39 | |||
40 | resource "aws_cloudfront_origin_access_control" "main" { | ||
41 | name = var.s3_cloudfront_name | ||
42 | description = var.s3_cloudfront_name | ||
43 | origin_access_control_origin_type = "s3" | ||
44 | signing_behavior = "always" | ||
45 | signing_protocol = "sigv4" | ||
46 | } | ||
47 | |||
48 | # Managed policies | ||
49 | locals { | ||
50 | managed_cache_policies = [ | ||
51 | "Amplify", | ||
52 | "CachingDisabled", | ||
53 | "CachingOptimized", | ||
54 | "CachingOptimizedForUncompressedObjects", | ||
55 | "Elemental-MediaPackage", | ||
56 | ] | ||
57 | managed_origin_request_policies = [ | ||
58 | "AllViewer", | ||
59 | "CORS-CustomOrigin", | ||
60 | "CORS-S3Origin", | ||
61 | "Elemental-MediaTailor-PersonalizedManifests", | ||
62 | "UserAgentRefererHeaders", | ||
63 | ] | ||
64 | } | ||
65 | |||
66 | data "aws_cloudfront_cache_policy" "managed" { | ||
67 | for_each = toset(local.managed_cache_policies) | ||
68 | |||
69 | name = "Managed-${each.key}" | ||
70 | } | ||
71 | |||
72 | data "aws_cloudfront_origin_request_policy" "managed" { | ||
73 | for_each = toset(local.managed_origin_request_policies) | ||
74 | |||
75 | name = "Managed-${each.key}" | ||
76 | } | ||
diff --git a/jinwei.me/infra/s3.tf b/jinwei.me/infra/s3.tf index 58e0502..49f8e10 100644 --- a/jinwei.me/infra/s3.tf +++ b/jinwei.me/infra/s3.tf | |||
@@ -22,7 +22,7 @@ resource "aws_s3_bucket_policy" "main" { | |||
22 | } | 22 | } |
23 | 23 | ||
24 | data "aws_iam_policy_document" "bucket_policy" { | 24 | data "aws_iam_policy_document" "bucket_policy" { |
25 | # Allow Cloudflare to read from the bucket | 25 | # Allow Cloudfront to read from the bucket |
26 | statement { | 26 | statement { |
27 | principals { | 27 | principals { |
28 | type = "AWS" | 28 | type = "AWS" |
@@ -37,9 +37,9 @@ data "aws_iam_policy_document" "bucket_policy" { | |||
37 | "${aws_s3_bucket.main.arn}/*", | 37 | "${aws_s3_bucket.main.arn}/*", |
38 | ] | 38 | ] |
39 | condition { | 39 | condition { |
40 | test = "IpAddress" | 40 | test = "StringEquals" |
41 | variable = "AWS:SourceIp" | 41 | variable = "AWS:SourceArn" |
42 | values = data.cloudflare_ip_ranges.cloudflare.cidr_blocks | 42 | values = [aws_cloudfront_distribution.main.arn] |
43 | } | 43 | } |
44 | } | 44 | } |
45 | } | 45 | } |
diff --git a/jinwei.me/infra/variables.tf b/jinwei.me/infra/variables.tf index 9145176..2ae72ed 100644 --- a/jinwei.me/infra/variables.tf +++ b/jinwei.me/infra/variables.tf | |||
@@ -12,7 +12,6 @@ variable "region" { | |||
12 | description = "AWS region" | 12 | description = "AWS region" |
13 | } | 13 | } |
14 | 14 | ||
15 | |||
16 | # RDS | 15 | # RDS |
17 | variable "rds_initial_db_name" { | 16 | variable "rds_initial_db_name" { |
18 | default = "wordpress" | 17 | default = "wordpress" |
@@ -60,3 +59,8 @@ variable "s3_cdn_name" { | |||
60 | type = string | 59 | type = string |
61 | default = "static" | 60 | default = "static" |
62 | } | 61 | } |
62 | |||
63 | variable "s3_cloudfront_name" { | ||
64 | type = string | ||
65 | default = "static.jinwei.me" | ||
66 | } | ||
diff --git a/jinwei.me/infra/versions.tf b/jinwei.me/infra/versions.tf index 9d28904..3200530 100644 --- a/jinwei.me/infra/versions.tf +++ b/jinwei.me/infra/versions.tf | |||
@@ -10,3 +10,8 @@ terraform { | |||
10 | } | 10 | } |
11 | } | 11 | } |
12 | } | 12 | } |
13 | |||
14 | provider "aws" { | ||
15 | alias = "us-east-1" | ||
16 | region = "us-east-1" | ||
17 | } | ||