feat: deploy all machine keys (mesh)
When deploying keys to a machine, upload ALL private keys from ALL other machines (not just sync pair peers). Also populate known_hosts with all other machine hosts. Creates a full mesh where any machine can SSH to any other. - sshmanager/deploy.go: change knownHostsHost string parameter to knownHostsHosts []string for multi-host ssh-keyscan - handlers_machines.go: replace sync-pair-based key detection with loop over all machines, deduplicating by local key path
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
@@ -367,22 +368,28 @@ func (h *MachineHandler) DeployKeys(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pairRepo := models.NewSyncPairRepository(h.db)
|
allMachines, err := repo.GetAll()
|
||||||
allPairs, err := pairRepo.GetAll()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Warn("failed to fetch sync pairs for auto-detect", "error", err)
|
slog.Warn("failed to fetch machines for auto-detect", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var keys []sshmanager.DeployKey
|
var keys []sshmanager.DeployKey
|
||||||
|
seenKeys := make(map[string]bool)
|
||||||
|
knownHostsHosts := []string{}
|
||||||
|
|
||||||
for _, pair := range allPairs {
|
for _, other := range allMachines {
|
||||||
if pair.SourceMachineID != nil && *pair.SourceMachineID == m.ID {
|
if other.ID == m.ID {
|
||||||
if pair.DestMachineID != nil {
|
continue
|
||||||
destMachine, err := repo.GetByID(*pair.DestMachineID)
|
}
|
||||||
if err == nil && destMachine.SSHKeyID != nil {
|
knownHostsHosts = append(knownHostsHosts, fmt.Sprintf("%s:%d", other.Host, other.Port))
|
||||||
|
if other.SSHKeyID != nil {
|
||||||
skRepo := models.NewSSHKeyRepository(h.db)
|
skRepo := models.NewSSHKeyRepository(h.db)
|
||||||
sk, err := skRepo.GetByID(*destMachine.SSHKeyID)
|
sk, err := skRepo.GetByID(*other.SSHKeyID)
|
||||||
if err == nil && sk.PrivateKeyPath != "" {
|
if err == nil && sk.PrivateKeyPath != "" {
|
||||||
|
if seenKeys[sk.PrivateKeyPath] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seenKeys[sk.PrivateKeyPath] = true
|
||||||
keys = append(keys, sshmanager.DeployKey{
|
keys = append(keys, sshmanager.DeployKey{
|
||||||
LocalPath: sk.PrivateKeyPath,
|
LocalPath: sk.PrivateKeyPath,
|
||||||
RemotePath: "/var/lib/syncserver/ssh/keys/" + filepath.Base(sk.PrivateKeyPath),
|
RemotePath: "/var/lib/syncserver/ssh/keys/" + filepath.Base(sk.PrivateKeyPath),
|
||||||
@@ -391,24 +398,6 @@ func (h *MachineHandler) DeployKeys(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if pair.DestMachineID != nil && *pair.DestMachineID == m.ID {
|
|
||||||
if pair.SourceMachineID != nil {
|
|
||||||
srcMachine, err := repo.GetByID(*pair.SourceMachineID)
|
|
||||||
if err == nil && srcMachine.SSHKeyID != nil {
|
|
||||||
skRepo := models.NewSSHKeyRepository(h.db)
|
|
||||||
sk, err := skRepo.GetByID(*srcMachine.SSHKeyID)
|
|
||||||
if err == nil && sk.PrivateKeyPath != "" {
|
|
||||||
keys = append(keys, sshmanager.DeployKey{
|
|
||||||
LocalPath: sk.PrivateKeyPath,
|
|
||||||
RemotePath: "/var/lib/syncserver/ssh/keys/" + filepath.Base(sk.PrivateKeyPath),
|
|
||||||
Mode: 0600,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(keys) == 0 {
|
if len(keys) == 0 {
|
||||||
slog.Info("no keys auto-detected for machine, using empty key list", "machine", m.Name)
|
slog.Info("no keys auto-detected for machine, using empty key list", "machine", m.Name)
|
||||||
@@ -422,7 +411,7 @@ func (h *MachineHandler) DeployKeys(w http.ResponseWriter, r *http.Request) {
|
|||||||
m.Port,
|
m.Port,
|
||||||
m.SSHUser,
|
m.SSHUser,
|
||||||
keys,
|
keys,
|
||||||
req.KnownHostsHost,
|
knownHostsHosts,
|
||||||
req.IncludeServerKey,
|
req.IncludeServerKey,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ type DeployResult struct {
|
|||||||
Errors []string
|
Errors []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeployKeysToMachine(ctx context.Context, serverKeyPath, serverPubKey string, host string, port int, user string, keys []DeployKey, knownHostsHost string, addServerPubKey bool) (*DeployResult, error) {
|
func DeployKeysToMachine(ctx context.Context, serverKeyPath, serverPubKey string, host string, port int, user string, keys []DeployKey, knownHostsHosts []string, addServerPubKey bool) (*DeployResult, error) {
|
||||||
result := &DeployResult{Success: true, Messages: []string{}, Errors: []string{}}
|
result := &DeployResult{Success: true, Messages: []string{}, Errors: []string{}}
|
||||||
|
|
||||||
addr := fmt.Sprintf("%s:%d", host, port)
|
addr := fmt.Sprintf("%s:%d", host, port)
|
||||||
@@ -141,22 +141,24 @@ func DeployKeysToMachine(ctx context.Context, serverKeyPath, serverPubKey string
|
|||||||
result.Messages = append(result.Messages, fmt.Sprintf("Uploaded %s to %s:%s", filepath.Base(k.LocalPath), host, k.RemotePath))
|
result.Messages = append(result.Messages, fmt.Sprintf("Uploaded %s to %s:%s", filepath.Base(k.LocalPath), host, k.RemotePath))
|
||||||
}
|
}
|
||||||
|
|
||||||
if knownHostsHost != "" {
|
if len(knownHostsHosts) > 0 {
|
||||||
|
for _, khHost := range knownHostsHosts {
|
||||||
session2, err := conn.NewSession()
|
session2, err := conn.NewSession()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result.Errors = append(result.Errors, fmt.Sprintf("session for ssh-keyscan: %v", err))
|
result.Errors = append(result.Errors, fmt.Sprintf("session for ssh-keyscan %s: %v", khHost, err))
|
||||||
result.Success = false
|
result.Success = false
|
||||||
} else {
|
continue
|
||||||
|
}
|
||||||
session2.Stdout = &stdout
|
session2.Stdout = &stdout
|
||||||
session2.Stderr = &stderr
|
session2.Stderr = &stderr
|
||||||
err := session2.Run(fmt.Sprintf("ssh-keyscan -H -p %d %s 2>/dev/null >> %s/known_hosts", port, knownHostsHost, remoteSSHDir))
|
err = session2.Run(fmt.Sprintf("ssh-keyscan -H -p %s 2>/dev/null >> %s/known_hosts", khHost, remoteSSHDir))
|
||||||
session2.Close()
|
session2.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Warn("deploy: ssh-keyscan failed", "host", knownHostsHost, "port", port, "error", err)
|
slog.Warn("deploy: ssh-keyscan failed", "host", khHost, "error", err)
|
||||||
result.Errors = append(result.Errors, fmt.Sprintf("ssh-keyscan %s: %v (stderr: %s)", knownHostsHost, err, stderr.String()))
|
result.Errors = append(result.Errors, fmt.Sprintf("ssh-keyscan %s: %v (stderr: %s)", khHost, err, stderr.String()))
|
||||||
result.Success = false
|
result.Success = false
|
||||||
} else {
|
} else {
|
||||||
result.Messages = append(result.Messages, fmt.Sprintf("Populated known_hosts with %s:%d", knownHostsHost, port))
|
result.Messages = append(result.Messages, fmt.Sprintf("Populated known_hosts with %s", khHost))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user