internal/server/syncsvc/hostcert.go
Ref: Size: 2.3 KiB History
package syncsvc
import (
"fmt"
"log/slog"
"github.com/a73x/eitri/internal/pb"
"golang.org/x/crypto/ssh"
)
// hostCertSigner signs a guest's public host key for the principal the control
// plane chose.
type hostCertSigner interface {
SignHostCert(pub ssh.PublicKey, principal string) (certLine string, err error)
}
// SetHostCertSigner wires the guest host-cert signer. Called once at startup
// when the jump gate is enabled, alongside the other seams the API hands this
// service (SetConsoleDialer, SetAgentUpgrader).
func (s *Service) SetHostCertSigner(c hostCertSigner) { s.certs = c }
// signAndRecordHostCert certifies one guest's host key.
func (s *Service) signAndRecordHostCert(hostID, vmID, pubLine string) error {
vm, err := s.st.GetVM(vmID)
if err != nil {
return fmt.Errorf("read vm: %w", err)
}
if vm.HostID != hostID {
return fmt.Errorf("vm %s is not on host %s", vmID, hostID)
}
if vm.DeletedAt != nil {
return fmt.Errorf("vm %s is tombstoned", vmID)
}
pub, _, _, _, err := ssh.ParseAuthorizedKey([]byte(pubLine))
if err != nil {
return fmt.Errorf("parse reported host key: %w", err)
}
cert, err := s.certs.SignHostCert(pub, vm.Tenant+"."+vm.Name)
if err != nil {
return fmt.Errorf("sign host cert: %w", err)
}
if err := s.st.RecordVMHostKey(vmID, hostID, pubLine, cert); err != nil {
return fmt.Errorf("record host cert: %w", err)
}
s.hub.Poke(hostID)
return nil
}
// certifyReportedHostKeys signs every newly-reported guest host key in one
// report. It runs ahead of — and outside — the status write-through loop,
// which only looks at VMs in phase ready or failed: a VM waiting for its
// certificate reports `creating`, and is exactly the VM that needs one.
//
// A failure is logged and dropped, like every other per-VM failure in a report:
// the key rides every later report too, so the next tick tries again.
func (s *Service) certifyReportedHostKeys(hostID string, vms []*pb.VMStatus) {
if s.certs == nil {
return
}
for _, v := range vms {
pub := v.GetSshHostPubkey()
if pub == "" {
continue
}
vmID := v.GetVmId()
if err := s.certTrack.writeThrough(vmID, pub, func() error {
return s.signAndRecordHostCert(hostID, vmID, pub)
}); err != nil {
slog.Warn("sign guest host cert", "vm", vmID, "host", hostID, "err", err)
}
}
}