terraforming Hetzner, dynamische IPs

kubernetes–API in der Firewall beschränken

Auf den kubernetes–Nodes lauscht auf Port 6443/tcp die kube–api, über die beispielsweise unser kubectl von zuhaus mit dem Cluster kommuniziert.

In den bisheringen Beispielen für die Firewall haben wir Ports immer fürs gesamte Internet geöffnet (0.0.0.0/0 & ::/0 als Quellen).

Ist für die kube–api natürlich nicht wirklich notwendig, zumindest in meinem Setup will erstmal nur ich von zuhause aus kubectl nutzen.

Da der Cluster dank rke nur per legacy IPv4 erreichbar ist ändert sich meine Adresse alle paar Monate, denn mein ISP weist mir leider keine statische zu. Ich habe aber einen DNS-Eintrag der immer auf die aktuelle IPv4 zeigt, über afraid.org.

Die Hetzner-Firewall kann (natürlich) nichts mit Hostnames anfangen, sondern verlangt nach IPs, der hcloud–Provider will sogar zwingend ein Netzbereich.

Ich muss also per terraform zum einen die IPv4 zu meinem Hostname herausfinden, zum anderen das in ein Netz wandeln, und das dann der Firewall übergeben.

DNS–Auflösung in terraform

Um die IP(s) zu einem Hostname herauszufinden gibt es — einen terraform–Provider! Und zwar nutze ich hashicorp/dns in Version 3.2.3. Diesen in terraform.tf wie gewohnt definiert lädt `terraform init ihn wie gewohnt herunter.

Mit dem installierten Provider erweitere ich dann den Plan für die Firewall:

firewall.tf

data "dns_a_record_set" "kubectl" {
  host = "zknt-hh3.trantuete.net"
}

So ein data–Block (statt wie üblich resource) steht für Operationen in denen wir etwas nachschlagen, aber nichts verändern. terraform löst hier also den Hostname auf und speichert die Liste der IPs. Die Antwort ist immer eine Liste, auch wenn ich weiß das ich nur eine IPv4 habe…

Nun möchte der hcloud–Provider ja Netze, nicht IPs, es muss also "/32" dahinter stehen. Dazu gehe ich einfach die Liste durch und hänge den String hinter jeden Eintrag:

locals {
  host_cidr = flatten([
    for ip in data.dns_a_record_set.ctl.addrs :
      "${ip}/32"
  ])
}

Damit steckt die gewünschte Liste von Netzen in der Variable host_cidr die ich in der Firewall–Rule direkt nutzen kann:

rule {
  direction = "in"
  protocol  = "tcp"
  port      = "6443"
  source_ips = local.host_cidr
}

Und damit ist die API nach dem nächsten plan && apply nur noch von mir aus nutzbar. Ändert mein ISP mal wieder meine IPv4 muss ich terraform halt nochmal ausführen…