Consul datacenter federation mit service mesh

Wir hatten uns ja schon einmal in Consul Datacenter Federation mit dem Thema befaßt. Dabei kommt ein Konstrukt wie im folgenden Diagramm zu Stande:

Consul datacenter federation without mesh-gateways

Alle Consul Server müssen mit allen anderen Consul Servern reden können. Insbesondere wenn nicht nur zwei sondern mehrere Datacenter miteinander föderiert werden sollen, kann das ein wenig unübersichtlich werden.

Deshalb kann Datacenter Föderation auch über Gateways des Consul Service-Mesh eingerichtet werden. Hintergrund ist natürlich, dass auch die Service-Meshes (sofern sie den existieren) der einzelnen Datacenter miteinander verbunden werden sollen. Und da ist es natürlich sinnvoll auch die Kommunikation der Server über diese Gateways laufen zu lassen. Idealerweise kommt dabei dann ein Konstrukt wie im folgenden Diagramm heraus:

consul datacenter federation with mesh-gateways

Die Vorteile liegen auf der Hand, insbesondere (auf dem Diagramm hier nicht zu sehen) weil die Gatewayverbindung mit Hilfe mehrerer Gateways auf beiden Seiten auch redundant ausgelegt werden kann.

Das Service-Mesh selbst ist am Besten mit dem folgenden Diagramm beschrieben:

Damit ist es möglich Anwendungen, die in VMs, auf physikalischen Servern oder auch in Kubernetes Clustern laufen, in eine Umgebung zusammenzufassen. Mit datacenter federation auch über verschiedene Datacenter hinweg.

Neben der datacenter federation hat Hashicorp sich auch noch das Cluster Peering für die Verbindung von Consul Datacentern ausgedacht:

Damit sollen auch Datacenter verbunden werden können, die von verschiedenen Teams betreut werden und damit verschiedene Verantwortungsbereiche verbinden. In diesem Blog wird erstmal nur um das Thema "WAN Federation" betrachtet.

Der Weg zu so einem Setup soll im Folgenden beschrieben werden. Teile davon sind auch Thema in der sehr guten Video-Reihe "Getting into Consul". Die folgende Episode, beschäftigt sich damit:

Das Video dokumentiert, dass es auch für Leute, die sich mit Hashicorp Consul auskennen, nicht trivial ist, dieses Setup hinzubekommen. Es hilft insbesondere auch das zugehörige GitHub Repo - und dort der Branch "part-11".

Grob beschrieben, sieht der Prozess so aus:

  • Das erste Consul Cluster aufsetzen
  • Im ersten Consul Cluster ACLs bootstrappen
  • Im ersten Consul Cluster Policies und Tokens für den ersten Cluster erzeugen und einrichten.
  • Die Mesh-Gateways im ersten Consul Cluster aufsetzen und aktivieren
  • Den zweiten Consul Cluster aufsetzen
  • Im zweiten Consul Cluster ACLs bootstrappen
  • Im zweiten Consul Cluster ACL Replication aktivieren consul join -wan <ip> nicht vergessen (überschreibt alle Token und Policies im zweiten Consul Cluster, soweit vorhanden)
  • Fehlende Policies und Token für den zweiten Consul Cluster einrichten
  • Die Mesh-Gateways für den zweiten Consul Cluster aufsetzen
  • Dann die Cluster verbinden, in dem connect aktiviert, die primary_gateways konfiguriert und die config_entries auskommentiert werden.

Beim "iterativen" Aufsetzen der Consul Cluster mit Hilfe meiner Terraform-Repos war mir aufgefallen, dass ein Eintrag im SAN-Zertifikat für consul-${count.index}.server.${var.config.domain_name}.consul fehlte. Den musste ich also noch hinzufügen damit mTLS funktionieren kann:

dns_names = [
    "consul",
    "consul.local",
    "server.${var.config.datacenter_name}.consul",
    "consul.service.${var.config.domain_name}",
    "consul-${count.index}.server.${var.config.domain_name}.consul",
]

Ein weiterer wichtiger Punkt – besonders im Kontext von OpenStack mit Floating-IPs – ist auch die "IP-Adress Akrobatik", die sicherstellen soll, dass sowohl die Kommunikation innerhalb des Clusters als auch außerhalb des Clusters funktioniert. Dazu habe ich die Konfiguration noch wie folgt angepasst

bind_addr           = "0.0.0.0"
advertise_addr      = "{{ GetInterfaceIP \"ens3\" }}"
advertise_addr_wan  = "${floatingip}"    
client_addr         = "0.0.0.0"
translate_wan_addrs = true

und die entsprechenden Optionen aus dem Unitfile für systemd entfernt. Wichtig ist das insbesondere auch bei den Consul-Clients, die auf den Gateway-Nodes laufen, weil die sich sonst falsch im Consul KV Store registrieren. Interessanterweise wird trotzdem unter wan_ipv4 doch die private Adresse gelistet:

Das Debug-Log, welches envoy ins syslog schreibt, kann da sehr aufschlußreich sein.

Für das Anlegen der Policies und der zugehörigen Token habe ich ein neues Verzeichnis /etc/consul/policies angelegt, in dem sich alle Policy-Files und ein Skript policies-tokens.sh befindet (das muß noch finalisiert werden).

Generell ist es sinnvoll, schrittweise vorzugehen. Also zuerst den Cluster zu kreiren, dann ACLs einzuschalten und zu konfigurieren und danach das Service-Mesh zu aktivieren.

Die ACL-Replikation funktioniert auch ohne dass bereits eine Verbindung über die Mesh-Gateways besteht. Offenbar ist es ausreichend, dass primary_datacenter gesetzt ist, dass enable_token_replication auf true steht, dass es ein replication token gibt, dass enable_mesh_gateway_wan_federation auf true steht und das unter primary_gatewaysein oder mehrere Mesh-Gateways konfiguriert sind. Sobald die ACL-Replikation läuft, wird auch das Master-Token des zweiten Consul-Clusters überschrieben und es gilt nur noch das Master-Token aus dem Primary-Datacenter.

Bei "den fehlenden Policies und Tokens" für das zweite Datacenter handelt es sich i. W. um die Node-Identity Token für die Mesh-Gateways. Die Mesh-Gateway Policy (und das zugehörige Token) für die Gateways wird in allen Datacentern verwendet. Deswegen wird sie auch mit

consul acl policy create -name "meshgateway" -description "Policy for mesh gateways" \
    -rules @policies/meshgateway-policy.hcl \
    -valid-datacenter prod2 -valid-datacenter prod3

angelegt. Policies und Token können übrigens mit consul acl policy update resp. consul acl token update aktualisiert werden.

Übrigens funktioniert der Prozess bei allen hinzuzufügenden Datacentern dann gleich. Es gibt nur ein Primary-Datacenter - alle anderen sind Secondaries.

Beim einschalten des Service-Mesh nicht vergessen, die zugehörigen config_entries ebenfalls zu aktivieren:

#   connect {
#     enabled = true
#     enable_mesh_gateway_wan_federation = true
#   }

#    config_entries {
#      bootstrap = [
#        {
#          kind = "proxy-defaults"
#          name = "global"
#          config {
#            protocol                   = "http"
#            envoy_prometheus_bind_addr = "0.0.0.0:9102"
#          }
#          mesh_gateway = {
#          mode = "local"
#          }
#        }
#      ]
#    } 

Beim aktivieren des Serivce-Mesh generiert Consul automatisch die CA, mit der die mTLS-Verbindungen im Verbund abgesichert werden.

Weiterhin ist es sinnvoll, die ACL default_policy zunächst auf allow stehen zu lassen und diese erst nachdem die Einrichtung abgeschlossen ist, auf deny zu ändern.

Das "zurückdrehen" der Kommunikationsmöglichkeiten (über externe IPs der Consul Cluster Nodes) und über die anonymous Policy, muss ich noch ausprobieren.

Die Diagramme habe nicht ich gemalt sondern die Profis der Hashicorp, Inc.