| 1 | # π€ The delegated Route53 hosted zone for dev.11ch.at β the region-neutral base |
| 2 | # domain for multi-edge Phase 1 (docs/multi-edge.md). It is NS-delegated from the |
| 3 | # prod 11ch.at DNSimple zone (176940) in dns.tf, so DNSimple stays the registrar |
| 4 | # and authoritative for everything ELSE under 11ch.at; only the dev.11ch.at |
| 5 | # subtree lives here, in the dev AWS account. |
| 6 | # |
| 7 | # Why a Route53 zone at all: the dev boxes need a *.dev.11ch.at WILDCARD cert |
| 8 | # (both boxes must terminate TLS for any region-neutral host, since either may own |
| 9 | # it by home_region or proxy to the box that does β mesh.go). A wildcard cert is |
| 10 | # DNS-01 only, and Route53's per-zone IAM lets a box solve that challenge with its |
| 11 | # AWS role/user β NO DNS token on disk (route53dns.go, LCHAT_DNS_PROVIDER=route53). |
| 12 | # DNSimple's account-scoped tokens can't be confined to one zone, which is the |
| 13 | # friction this sidesteps. DNSimple remains a fully-supported provider everywhere |
| 14 | # else β this is the AWS off-ramp, additive, never a replacement. |
| 15 | |
| 16 | resource "aws_route53_zone" "dev" { |
| 17 | name = "dev.11ch.at" |
| 18 | comment = "dev mesh β region-neutral space addressing (docs/multi-edge.md)" |
| 19 | } |
| 20 | |
| 21 | # The region-neutral wildcard: new spaces mint as <sqid>.dev.11ch.at β ONE |
| 22 | # namespace, no country label (the global id ledger keeps ids fleet-unique, |
| 23 | # idalloc). Points at the Dublin (ie) box, the mesh front door: it receives any |
| 24 | # region-neutral host and either serves it (home_region == ie) or reverse-proxies |
| 25 | # to the box whose region owns it (mesh.go proxyTo). A single-label wildcard, so |
| 26 | # it never shadows the deeper two-label *.ie.dev / *.fi.dev records below. |
| 27 | resource "aws_route53_record" "dev_wildcard" { |
| 28 | zone_id = aws_route53_zone.dev.zone_id |
| 29 | name = "*.dev.11ch.at" |
| 30 | type = "A" |
| 31 | ttl = 60 |
| 32 | records = [aws_eip.ie_node.public_ip] |
| 33 | } |
| 34 | |
| 35 | # The APEX of the dev subtree β dev.11ch.at itself, with no label in front. A |
| 36 | # wildcard does NOT cover the bare name it wildcards, so without this record |
| 37 | # dev.11ch.at resolves nowhere no matter how many *.dev.11ch.at hosts exist. |
| 38 | # |
| 39 | # It exists for the short-link redirector (lchat-links.service, issue #905), |
| 40 | # which is an apex service by nature: production serves 11ch.at itself, so the |
| 41 | # dev mesh has to serve dev.11ch.at itself to rehearse it at all. Nothing else |
| 42 | # needs the apex today. |
| 43 | # |
| 44 | # This is the dev-side mirror of a real production gap: 11ch.at's own apex A |
| 45 | # record and route are what were missing, so the redirector had nowhere to be |
| 46 | # reached even after its code merged β a wildcard cert on *.11ch.at made it |
| 47 | # look configured while the apex failed the TLS handshake outright. |
| 48 | resource "aws_route53_record" "dev_apex" { |
| 49 | zone_id = aws_route53_zone.dev.zone_id |
| 50 | name = "dev.11ch.at" |
| 51 | type = "A" |
| 52 | ttl = 60 |
| 53 | records = [aws_eip.ie_node.public_ip] |
| 54 | } |
| 55 | |
| 56 | # The two per-country wildcards, MOVED here from DNSimple (they were in the old |
| 57 | # dns.tf). The delegation makes DNSimple non-authoritative for the whole |
| 58 | # dev.11ch.at subtree, so these must live in THIS zone or every existing |
| 59 | # *.ie.dev / *.fi.dev host β including each box's own one.<cc>.dev.11ch.at self |
| 60 | # URL (LCHAT_MESH_SELF) β would stop resolving. Kept so the existing per-country |
| 61 | # hosts and the mesh peer-dial addresses survive the cutover unchanged. |
| 62 | resource "aws_route53_record" "ie_wildcard" { |
| 63 | zone_id = aws_route53_zone.dev.zone_id |
| 64 | name = "*.ie.dev.11ch.at" |
| 65 | type = "A" |
| 66 | ttl = 60 |
| 67 | records = [aws_eip.ie_node.public_ip] |
| 68 | } |
| 69 | |
| 70 | resource "aws_route53_record" "fi_wildcard" { |
| 71 | zone_id = aws_route53_zone.dev.zone_id |
| 72 | name = "*.fi.dev.11ch.at" |
| 73 | type = "A" |
| 74 | ttl = 60 |
| 75 | records = [var.fi_node_ip] |
| 76 | } |
| 77 | |
| 78 | # ---- DNS-01 permissions for the *.dev.11ch.at wildcard cert -------------------- |
| 79 | # The boxes publish then delete an _acme-challenge TXT in THIS zone |
| 80 | # (route53dns.go). ListHostedZonesByName and GetChange take no resource-level |
| 81 | # permissions in AWS (they're account-wide by design), so they're granted on "*"; |
| 82 | # the one MUTATING op β ChangeResourceRecordSets β is locked to this single zone. |
| 83 | # A leaked box credential could therefore touch dev.11ch.at records and nothing |
| 84 | # else in the account: not prod DNS (it's in DNSimple), not any other zone. |
| 85 | data "aws_iam_policy_document" "route53_dns01" { |
| 86 | statement { |
| 87 | sid = "DiscoverZoneAndChange" |
| 88 | actions = ["route53:ListHostedZonesByName", "route53:GetChange"] |
| 89 | resources = ["*"] |
| 90 | } |
| 91 | statement { |
| 92 | sid = "WriteChallengeInDevZoneOnly" |
| 93 | actions = ["route53:ChangeResourceRecordSets"] |
| 94 | resources = [aws_route53_zone.dev.arn] |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | # Dublin (ie) reaches Route53 through its EC2 instance role (no keys on the box). |
| 99 | resource "aws_iam_role_policy" "ie_node_route53" { |
| 100 | name = "eleven-dev-mesh-route53-dns01" |
| 101 | role = aws_iam_role.ie_node.id |
| 102 | policy = data.aws_iam_policy_document.route53_dns01.json |
| 103 | } |
| 104 | |
| 105 | # Helsinki (fi) is Hetzner β it can't assume an EC2 role, so the same policy |
| 106 | # attaches to its scoped IAM user (the S3 credential it already carries lives in |
| 107 | # the vault; this just widens that user to the one DNS zone). |
| 108 | resource "aws_iam_user_policy" "fi_node_route53" { |
| 109 | name = "eleven-dev-mesh-route53-dns01" |
| 110 | user = aws_iam_user.fi_node.name |
| 111 | policy = data.aws_iam_policy_document.route53_dns01.json |
| 112 | } |
| 113 | |