Skip to content

Commit 0b90a45

Browse files
nutgoodzackpollard
andauthored
feat(net): reverse dns (#1763)
Co-authored-by: Zack <zack@futo.org>
1 parent c497a2c commit 0b90a45

10 files changed

Lines changed: 242 additions & 0 deletions

File tree

tf/deployment/modules/shared/bunny/futo-account/.terraform.lock.hcl

Lines changed: 57 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# FUTO bunny.net DNS
2+
3+
Reverse DNS for the FUTO `69.48.224.0/22` range, on **bunny.net** (they support
4+
`PTR` records and `arpa` zones). Reads its API key from the FUTO **`shared_tf`**
5+
1Password vault (`BUNNY_API_KEY`, seeded via `1password/futo-account`) using the
6+
futo service-account token, the same way the other futo modules do.
7+
8+
## Zones
9+
10+
- `{224,225,226,227}.48.69.in-addr.arpa` — the four reverse zones + PTR records
11+
for all 1024 IPs.
12+
- `rdns.as402421.net` — the forward FCrDNS names (`ip-69-48-<octet>-<host>`).
13+
`as402421.net` itself stays in Cloudflare; the `rdns` subdomain is delegated
14+
here via `NS` records in `cloudflare/futo-account` (`kiki.bunny.net` /
15+
`coco.bunny.net`).
16+
17+
By default each IP gets a matching PTR + A pair (FCrDNS). To point a single IP's
18+
PTR elsewhere, add it to `reverse_ptr_overrides` in `dns-reverse.tf` — that IP
19+
then gets no forward A record here.
20+
21+
## Delegation not managed here
22+
23+
The `in-addr.arpa` zones need their **upstream** delegation (the RIR / provider
24+
that assigned `69.48.224.0/22`) repointed to `kiki.bunny.net` / `coco.bunny.net`.
25+
That's set at the RIR/upstream, not in Terraform. The `rdns.as402421.net`
26+
delegation *is* managed here (the Cloudflare `NS` records).
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
terraform {
2+
backend "pg" {
3+
schema_name = "prod_bunny_futo_account"
4+
}
5+
required_version = "~> 1.7"
6+
7+
required_providers {
8+
bunnynet = {
9+
source = "BunnyWay/bunnynet"
10+
version = "~> 0.15"
11+
}
12+
onepassword = {
13+
source = "1Password/onepassword"
14+
version = "~> 2.0"
15+
}
16+
}
17+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
data "onepassword_vault" "shared_tf" {
2+
name = "shared_tf"
3+
}
4+
5+
data "onepassword_item" "bunny_api_key" {
6+
vault = data.onepassword_vault.shared_tf.uuid
7+
title = "BUNNY_API_KEY"
8+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Reverse DNS for the four /24s we own (69.48.224.0/24 – 69.48.227.0/24).
2+
#
3+
# For every IP 69.48.<octet>.<host> we manage, by default a pair:
4+
# - PTR <host> in <octet>.48.69.in-addr.arpa -> ip-69-48-<octet>-<host>.rdns.as402421.net
5+
# - A ip-69-48-<octet>-<host> in rdns.as402421.net -> 69.48.<octet>.<host>
6+
# so reverse and forward agree (FCrDNS). The zones live in zones.tf.
7+
#
8+
# Overrides: list an IP in reverse_ptr_overrides to point its PTR at a name that
9+
# is managed somewhere else (any domain). An overridden IP gets NO A record here
10+
# (that forward record is managed elsewhere).
11+
locals {
12+
reverse_zone_ids = {
13+
"224" = bunnynet_dns_zone.reverse_69_48_224.id
14+
"225" = bunnynet_dns_zone.reverse_69_48_225.id
15+
"226" = bunnynet_dns_zone.reverse_69_48_226.id
16+
"227" = bunnynet_dns_zone.reverse_69_48_227.id
17+
}
18+
19+
# Per-IP PTR target overrides. Key = full IPv4 address, value = target FQDN.
20+
# Example:
21+
# "69.48.224.254" = "bob.something.something"
22+
reverse_ptr_overrides = {
23+
}
24+
25+
# Every IP in the four /24s (1024), keyed "<octet>-<host>".
26+
reverse_ips = merge([
27+
for octet, zone_id in local.reverse_zone_ids : {
28+
for host in range(256) :
29+
"${octet}-${host}" => {
30+
zone_id = zone_id
31+
ip = "69.48.${octet}.${host}"
32+
ptr_name = tostring(host) # relative to <octet>.48.69.in-addr.arpa
33+
fwd_name = "ip-69-48-${octet}-${host}" # relative to rdns.as402421.net
34+
default_fwd = "ip-69-48-${octet}-${host}.rdns.as402421.net"
35+
}
36+
}
37+
]...)
38+
39+
# PTR for every IP: override target if listed, else the default forward name.
40+
reverse_ptr_records = {
41+
for key, v in local.reverse_ips :
42+
key => {
43+
zone = v.zone_id
44+
name = v.ptr_name
45+
value = lookup(local.reverse_ptr_overrides, v.ip, v.default_fwd)
46+
}
47+
}
48+
49+
# Forward A records in rdns.as402421.net, only for IPs that are NOT overridden.
50+
forward_a_records = {
51+
for key, v in local.reverse_ips :
52+
key => {
53+
name = v.fwd_name
54+
value = v.ip
55+
}
56+
if !contains(keys(local.reverse_ptr_overrides), v.ip)
57+
}
58+
}
59+
60+
resource "bunnynet_dns_record" "reverse_ptr" {
61+
for_each = local.reverse_ptr_records
62+
63+
zone = each.value.zone
64+
name = each.value.name
65+
type = "PTR"
66+
value = each.value.value
67+
ttl = 3600
68+
}
69+
70+
resource "bunnynet_dns_record" "reverse_forward_a" {
71+
for_each = local.forward_a_records
72+
73+
zone = bunnynet_dns_zone.rdns_as402421_net.id
74+
name = each.value.name
75+
type = "A"
76+
value = each.value.value
77+
ttl = 3600
78+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
provider "bunnynet" {
2+
api_key = data.onepassword_item.bunny_api_key.password
3+
}
4+
5+
provider "onepassword" {
6+
service_account_token = var.futo_op_service_account_token
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
terraform {
2+
source = "."
3+
4+
extra_arguments custom_vars {
5+
commands = get_terraform_commands_that_need_vars()
6+
}
7+
}
8+
9+
include "root" {
10+
path = find_in_parent_folders("root.hcl")
11+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
variable "futo_op_service_account_token" {
2+
description = "1Password service-account token for the FUTO account, used to read the bunny.net API key from the shared_tf vault"
3+
sensitive = true
4+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
resource "bunnynet_dns_zone" "reverse_69_48_224" {
2+
domain = "224.48.69.in-addr.arpa"
3+
}
4+
5+
resource "bunnynet_dns_zone" "reverse_69_48_225" {
6+
domain = "225.48.69.in-addr.arpa"
7+
}
8+
9+
resource "bunnynet_dns_zone" "reverse_69_48_226" {
10+
domain = "226.48.69.in-addr.arpa"
11+
}
12+
13+
resource "bunnynet_dns_zone" "reverse_69_48_227" {
14+
domain = "227.48.69.in-addr.arpa"
15+
}
16+
17+
# Forward (FCrDNS) names live here; delegated to bunny from the Cloudflare
18+
# as402421.net zone via NS records.
19+
resource "bunnynet_dns_zone" "rdns_as402421_net" {
20+
domain = "rdns.as402421.net"
21+
}

tf/deployment/modules/shared/cloudflare/futo-account/dns-as402421-net.tf

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,16 @@ resource "cloudflare_dns_record" "as402421_net_txt_dmarc" {
6262
ttl = 1
6363
proxied = false
6464
}
65+
66+
# Delegate rdns.as402421.net to bunny.net, where the reverse-DNS forward (FCrDNS)
67+
# names are managed (see bunny/futo-account).
68+
resource "cloudflare_dns_record" "as402421_net_ns_rdns" {
69+
for_each = toset(["kiki.bunny.net", "coco.bunny.net"])
70+
71+
zone_id = cloudflare_zone.as402421_net.id
72+
name = "rdns.as402421.net"
73+
type = "NS"
74+
content = each.value
75+
ttl = 1
76+
proxied = false
77+
}

0 commit comments

Comments
 (0)