feat(cluster): PG Logical Replication setup + Master-Key-Sync + Firewall-Ports
cluster-init-replication: - listen_addresses = '*' damit Cluster-Peers PG auf :5432 erreichen können - max_replication_slots = 20 / max_wal_senders = 10 (verhindert Slot-Erschöpfung bei initaler Tabellen-Synchronisation mit vielen gleichzeitigen Sync-Workern) - pg-replication-secret: Ownership an edgeguard-User (API-Lesezugriff) - detectPGConfig() statt hardcoded PG 16 (System läuft PG 17) cluster-setup-standby: - syncMasterKey(): holt /var/lib/edgeguard/.master_key via mTLS vom Primary — ohne identischen Master-Key können replizierte WireGuard-Keys nicht entschlüsselt werden - render-config: sudo -u edgeguard statt als root (DB-Zugriff) nftables Template: - Port 5432 (PG) + 6379 (KeyDB) für Cluster-Peers (@peer_ipv4/@peer_ipv6) freigegeben handlers/cluster.go: - GET /agent/cluster/master-key: gibt .master_key via mTLS zurück (hex-kodiert) v1.2.15 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,11 @@ table inet edgeguard {
|
||||
# Cluster-internal: peers reach edgeguard-api over mTLS on :8443
|
||||
tcp dport 8443 ip saddr @peer_ipv4 accept
|
||||
tcp dport 8443 ip6 saddr @peer_ipv6 accept
|
||||
# Cluster-internal: PG Logical Replication (:5432) + KeyDB Active-Active (:6379)
|
||||
tcp dport 5432 ip saddr @peer_ipv4 accept
|
||||
tcp dport 5432 ip6 saddr @peer_ipv6 accept
|
||||
tcp dport 6379 ip saddr @peer_ipv4 accept
|
||||
tcp dport 6379 ip6 saddr @peer_ipv6 accept
|
||||
|
||||
# ── Service-Auto-Rules (DNS/Squid/WG/...) ──
|
||||
# Aus dem laufenden Service-State abgeleitet — Operator
|
||||
|
||||
@@ -215,6 +215,7 @@ func (h *ClusterHandler) RegisterAgent(rg *gin.RouterGroup) {
|
||||
g.POST("/peers", h.AgentRegisterPeer)
|
||||
g.GET("/identity", h.AgentIdentity)
|
||||
g.GET("/pg-replication-info", h.AgentPGReplicationInfo)
|
||||
g.GET("/master-key", h.AgentMasterKey)
|
||||
g.GET("/version", h.AgentVersion)
|
||||
g.POST("/trigger-update", h.AgentTriggerUpdate)
|
||||
}
|
||||
@@ -270,6 +271,20 @@ func (h *ClusterHandler) AgentPGReplicationInfo(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// AgentMasterKey gibt den Secrets-Master-Key zurück, damit cluster-setup-standby
|
||||
// ihn auf dem Secondary synchronisieren kann. Nur über den mTLS-Agent-Listener
|
||||
// erreichbar. Ohne gemeinsamen Master-Key können replizierte verschlüsselte
|
||||
// Felder (WireGuard private keys, PSKs) auf dem Secondary nicht entschlüsselt werden.
|
||||
func (h *ClusterHandler) AgentMasterKey(c *gin.Context) {
|
||||
const keyPath = "/var/lib/edgeguard/.master_key"
|
||||
data, err := os.ReadFile(keyPath)
|
||||
if err != nil {
|
||||
response.NotFound(c, simpleError("master key nicht gefunden"))
|
||||
return
|
||||
}
|
||||
response.OK(c, gin.H{"key_hex": fmt.Sprintf("%x", data)})
|
||||
}
|
||||
|
||||
func readFileString(path string) (string, error) {
|
||||
b, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
@@ -719,7 +734,7 @@ rm -f /var/lib/edgeguard/upgrade.sh
|
||||
_ = exec.Command("sudo", "-n", "/usr/bin/systemctl", "reset-failed", unitName).Run()
|
||||
cmd := exec.Command("sudo", "-n", "/usr/bin/systemd-run",
|
||||
"--unit="+unitName,
|
||||
"--description=EdgeGuard rolling-update (triggered by primary)",
|
||||
"--description=EdgeGuard self-upgrade",
|
||||
"--collect",
|
||||
"bash", scriptPath)
|
||||
if err := cmd.Run(); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user