eleven / messenger Public

infra: status.elevenmessenger.com β€” CloudFront + ACM front for the status bucket (#695)

Deliberately not the router box: a status page must not be served by the
infrastructure it reports on. DNS via the dnsimple provider (product acct,
token from env, never in state). Applied.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell d9947f0e28682c648bfe6b8afba3b0ecf62bf646 parent 510086f
2 files changed, +119 −0
  • infra/prod/main.tf +4 −0
  • infra/prod/status-domain.tf +115 −0
diff --git a/infra/prod/main.tf b/infra/prod/main.tf
index dca4fef..fe246ed 100644
--- a/infra/prod/main.tf
+++ b/infra/prod/main.tf
@@ -12,6 +12,10 @@ terraform {
source = "hashicorp/aws"
version = "~> 6.0"
}
+ dnsimple = {
+ source = "dnsimple/dnsimple"
+ version = "~> 1.0"
+ }
}
backend "s3" {
diff --git a/infra/prod/status-domain.tf b/infra/prod/status-domain.tf
new file mode 100644
index 0000000..7a048ad
--- /dev/null
+++ b/infra/prod/status-domain.tf
@@ -0,0 +1,115 @@
+# πŸ€– status.elevenmessenger.com β€” the friendly front for the status bucket.
+# CloudFront + ACM rather than the router box on purpose: a status page must
+# not be served by the infrastructure it reports on, or it goes dark exactly
+# when it matters. DNS rides the DNSimple provider (product account 176940,
+# token via env DNSIMPLE_TOKEN/DNSIMPLE_ACCOUNT β€” never in state or files).
+
+# ACM certs used by CloudFront must live in us-east-1, wherever the viewer is.
+provider "aws" {
+ alias = "us_east_1"
+ region = "us-east-1"
+
+ default_tags {
+ tags = {
+ project = "eleven"
+ env = "prod"
+ managed = "opentofu"
+ }
+ }
+}
+
+provider "dnsimple" {}
+
+locals {
+ status_host = "status.elevenmessenger.com"
+}
+
+resource "aws_acm_certificate" "status" {
+ provider = aws.us_east_1
+ domain_name = local.status_host
+ validation_method = "DNS"
+
+ lifecycle {
+ create_before_destroy = true
+ }
+}
+
+# One validation record per domain (here: one). trimsuffix strips the zone +
+# trailing dot ACM includes, because DNSimple wants the relative name.
+resource "dnsimple_zone_record" "status_validation" {
+ for_each = {
+ for dvo in aws_acm_certificate.status.domain_validation_options : dvo.domain_name => {
+ name = trimsuffix(dvo.resource_record_name, ".elevenmessenger.com.")
+ type = dvo.resource_record_type
+ value = trimsuffix(dvo.resource_record_value, ".")
+ }
+ }
+
+ zone_name = "elevenmessenger.com"
+ name = each.value.name
+ type = each.value.type
+ value = each.value.value
+ ttl = 300
+}
+
+resource "aws_acm_certificate_validation" "status" {
+ provider = aws.us_east_1
+ certificate_arn = aws_acm_certificate.status.arn
+ validation_record_fqdns = [
+ for dvo in aws_acm_certificate.status.domain_validation_options : trimsuffix(dvo.resource_record_name, ".")
+ ]
+
+ depends_on = [dnsimple_zone_record.status_validation]
+}
+
+resource "aws_cloudfront_distribution" "status" {
+ enabled = true
+ comment = "eleven public status dashboards"
+ aliases = [local.status_host]
+ default_root_object = "index.html"
+ price_class = "PriceClass_100" # EU+NA edges β€” where members are
+
+ origin {
+ # The bucket's REST endpoint: objects are public-read by design, so no
+ # origin access control is needed β€” CloudFront is here for the name and
+ # the cert, not for access mediation.
+ domain_name = "${aws_s3_bucket.status.bucket}.s3.eu-west-1.amazonaws.com"
+ origin_id = "status-bucket"
+ }
+
+ default_cache_behavior {
+ target_origin_id = "status-bucket"
+ viewer_protocol_policy = "redirect-to-https"
+ allowed_methods = ["GET", "HEAD"]
+ cached_methods = ["GET", "HEAD"]
+ compress = true
+ # AWS managed CachingOptimized policy: honors the origin's Cache-Control,
+ # which the publisher sets deliberately (JSON 60s, pages 300s) β€” the edge
+ # inherits the freshness contract instead of inventing its own.
+ cache_policy_id = "658327ea-f89d-4fab-a63d-7e88639e58f6"
+ }
+
+ restrictions {
+ geo_restriction {
+ restriction_type = "none"
+ }
+ }
+
+ viewer_certificate {
+ acm_certificate_arn = aws_acm_certificate_validation.status.certificate_arn
+ ssl_support_method = "sni-only"
+ minimum_protocol_version = "TLSv1.2_2021"
+ }
+}
+
+resource "dnsimple_zone_record" "status" {
+ zone_name = "elevenmessenger.com"
+ name = "status"
+ type = "CNAME"
+ value = aws_cloudfront_distribution.status.domain_name
+ ttl = 300
+}
+
+output "status_domain_url" {
+ value = "https://${local.status_host}/"
+}