Skip to content

Commit

Permalink
feat: adding multi-domain support
Browse files Browse the repository at this point in the history
  • Loading branch information
kiraum committed Oct 7, 2024
1 parent fe42ba8 commit 0ed5962
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 29 deletions.
6 changes: 6 additions & 0 deletions environments/prod/data.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@ data "aws_acm_certificate" "website_cert_kiraum" {
domain = "kiraum.it"
statuses = ["ISSUED"]
}

#data "aws_acm_certificate" "website_cert_xpto_it" {
# provider = aws.us_east_1
# domain = "xpto.it"
# statuses = ["ISSUED"]
#}
4 changes: 4 additions & 0 deletions environments/prod/locals.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
locals {
tlsa_hash_kiraum = base64encode(sha256(data.aws_acm_certificate.website_cert_kiraum.certificate))
}

#locals {
# tlsa_hash_xpto_it = base64encode(sha256(data.aws_acm_certificate.website_cert_xpto_it.certificate))
#}
105 changes: 103 additions & 2 deletions environments/prod/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,105 @@ module "route53" {
records = ["protonmail3.domainkey.dempd74kuxcjabpnbahdxnyoscyzm34xj6e5of6vyqwjrw64bwqoq.domains.proton.ch."]
}
]
},
"xpto_it" = {
domain_name = "xpto.it"
comment = "xpto.it hosted zone"
records = [
# A record for root domain
{
name = ""
type = "A"
alias = {
name = "dpop20p5u4112.cloudfront.net"
zone_id = "Z2FDTNDATAQYW2"
evaluate_target_health = false
}
},
# AAAA record for root domain
{
name = ""
type = "AAAA"
alias = {
name = "dpop20p5u4112.cloudfront.net"
zone_id = "Z2FDTNDATAQYW2"
evaluate_target_health = false
}
},
# A record for www domain
{
name = "www"
type = "A"
alias = {
name = "dpop20p5u4112.cloudfront.net"
zone_id = "Z2FDTNDATAQYW2"
evaluate_target_health = false
}
},
# AAAA record for www domain
{
name = "www"
type = "AAAA"
alias = {
name = "dpop20p5u4112.cloudfront.net"
zone_id = "Z2FDTNDATAQYW2"
evaluate_target_health = false
}
},
# TLSA record
#{
# name = "_443._tcp"
# type = "TXT"
# ttl = 300
# records = ["3 1 1 ${local.tlsa_hash_xpto_it}"]
#},
# MX records for email routing
{
name = ""
type = "MX"
ttl = 300
records = ["10 mail.protonmail.ch", "20 mailsec.protonmail.ch"]
},
# TXT records for various verifications and SPF
{
name = ""
type = "TXT"
ttl = 300
records = [
# xpto.it
"protonmail-verification=cc3c2c9aebe9de240703d0be5df8c25c2adc5460",
# kiraum.it
"protonmail-verification=4fd8734e27858d5bb727e0b811f506185942856d",
"v=spf1 include:_spf.protonmail.ch ~all"
]
},
# DMARC record
{
name = "_dmarc"
type = "TXT"
ttl = 300
records = ["v=DMARC1; p=quarantine"]
},
# DKIM records for ProtonMail
{
name = "protonmail._domainkey"
type = "CNAME"
ttl = 300
records = ["protonmail.domainkey.dempd74kuxcjabpnbahdxnyoscyzm34xj6e5of6vyqwjrw64bwqoq.domains.proton.ch."]
},
{
name = "protonmail2._domainkey"
type = "CNAME"
ttl = 300
records = ["protonmail2.domainkey.dempd74kuxcjabpnbahdxnyoscyzm34xj6e5of6vyqwjrw64bwqoq.domains.proton.ch."]
},
{
name = "protonmail3._domainkey"
type = "CNAME"
ttl = 300
records = ["protonmail3.domainkey.dempd74kuxcjabpnbahdxnyoscyzm34xj6e5of6vyqwjrw64bwqoq.domains.proton.ch."]
}
]
}
}

Expand All @@ -178,9 +277,11 @@ module "route53" {
module "static_website" {
source = "../../modules/static_website"

bucket_name = "xpto-static-website-bucket"
domain_name = "kiraum.it"
bucket_name = "xpto-static-website-bucket"
domain_names = ["kiraum.it"]
#domain_names = ["kiraum.it", "xpto.it"]
cloudfront_price_class = "PriceClass_100"

tags = {
Environment = var.environment
Project = var.project
Expand Down
2 changes: 2 additions & 0 deletions modules/static_website/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ module "static_website" {
- A monthly budget of $1 USD is set for CloudFront usage with an alert at 80% threshold.
- The Lambda function logs are retained for 7 days in CloudWatch.

Order to create => AWS R53 => AWS CF => TLSA

## Requirements

- Terraform >= 1.0.0
Expand Down
45 changes: 26 additions & 19 deletions modules/static_website/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ terraform {
# Get current AWS account information
data "aws_caller_identity" "current" {}

# Fetch the Route 53 zone for the domain
# Fetch the Route 53 zone for each domain
data "aws_route53_zone" "base_domain" {
name = var.domain_name
for_each = toset(var.domain_names)
name = each.value
private_zone = false
}

# Generate a random string for custom header value
Expand Down Expand Up @@ -172,14 +174,14 @@ resource "aws_s3_bucket_policy" "static_site" {
policy = data.aws_iam_policy_document.s3_policy.json
}

# Create an SSL certificate for the domain
# Create an SSL certificate for each domain
resource "aws_acm_certificate" "cert" {
provider = aws.us_east_1

domain_name = var.domain_name
validation_method = "DNS"
for_each = toset(var.domain_names)

subject_alternative_names = ["*.${var.domain_name}"]
provider = aws.us_east_1
domain_name = each.value
subject_alternative_names = ["*.${each.value}"]
validation_method = "DNS"

tags = var.tags

Expand All @@ -191,10 +193,11 @@ resource "aws_acm_certificate" "cert" {
# Set up DNS records for certificate validation
resource "aws_route53_record" "cert_validation" {
for_each = {
for dvo in aws_acm_certificate.cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
for domain in var.domain_names : domain => {
name = tolist(aws_acm_certificate.cert[domain].domain_validation_options)[0].resource_record_name
record = tolist(aws_acm_certificate.cert[domain].domain_validation_options)[0].resource_record_value
type = tolist(aws_acm_certificate.cert[domain].domain_validation_options)[0].resource_record_type
zone_id = data.aws_route53_zone.base_domain[domain].zone_id
}
}

Expand All @@ -203,16 +206,20 @@ resource "aws_route53_record" "cert_validation" {
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = data.aws_route53_zone.base_domain.zone_id
zone_id = each.value.zone_id
}

# Validate the SSL certificate

# Validate the SSL certificates
resource "aws_acm_certificate_validation" "cert" {
for_each = aws_acm_certificate.cert

provider = aws.us_east_1
certificate_arn = aws_acm_certificate.cert.arn
validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn]
certificate_arn = each.value.arn
validation_record_fqdns = [for record in aws_route53_record.cert_validation : record.fqdn if record.name == tolist(each.value.domain_validation_options)[0].resource_record_name]
}


# Create a CloudFront distribution for content delivery
resource "aws_cloudfront_distribution" "static_site" {
provider = aws.us_east_1
Expand All @@ -232,7 +239,7 @@ resource "aws_cloudfront_distribution" "static_site" {
is_ipv6_enabled = true
http_version = "http2and3"
default_root_object = "index.html"
aliases = [var.domain_name, "*.${var.domain_name}"]
aliases = flatten([for domain in var.domain_names : [domain, "*.${domain}"]])

default_cache_behavior {
allowed_methods = ["GET", "HEAD", "OPTIONS"]
Expand Down Expand Up @@ -290,7 +297,7 @@ resource "aws_cloudfront_distribution" "static_site" {
}

viewer_certificate {
acm_certificate_arn = aws_acm_certificate.cert.arn
acm_certificate_arn = aws_acm_certificate.cert[var.domain_names[0]].arn
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}
Expand All @@ -304,7 +311,7 @@ resource "aws_cloudfront_distribution" "static_site" {
resource "aws_cloudfront_origin_access_control" "static_site" {
provider = aws.us_east_1
name = "${var.bucket_name}-oac"
description = "OAC for ${var.domain_name}"
description = "OAC for ${join(", ", var.domain_names)}"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
Expand Down
6 changes: 3 additions & 3 deletions modules/static_website/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ output "cloudfront_distribution_id" {
value = aws_cloudfront_distribution.static_site.id
}

output "acm_certificate_arn" {
description = "The ARN of the ACM certificate"
value = aws_acm_certificate.cert.arn
output "acm_certificate_arns" {
description = "The ARNs of the ACM certificates"
value = { for domain, cert in aws_acm_certificate.cert : domain => cert.arn }
}
10 changes: 5 additions & 5 deletions modules/static_website/varriables.tf
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
variable "bucket_name" {
type = string
description = "The name of the S3 bucket to create"
variable "domain_names" {
type = list(string)
description = "The domain names for the static website"
}

variable "domain_name" {
variable "bucket_name" {
type = string
description = "The domain name for the static website"
description = "The name of the S3 bucket to create"
}

variable "cloudfront_price_class" {
Expand Down

0 comments on commit 0ed5962

Please sign in to comment.