package store import ( "context" "crypto/ed25519" "crypto/x509" "errors" "fmt" ) // LoadOrCreateIdentity returns the master's private key, creating and // storing one with generate on first start. Keeping it in Postgres means it // survives container recreation and is covered by database backups; losing // it would force every agent to be reconfigured with a new MASTER_KEY. func (s *Store) LoadOrCreateIdentity(ctx context.Context, generate func() (ed25519.PrivateKey, error)) (ed25519.PrivateKey, error) { fresh, err := generate() if err != nil { return nil, err } der, err := x509.MarshalPKCS8PrivateKey(fresh) if err != nil { return nil, fmt.Errorf("marshal master key: %w", err) } if _, err := s.pool.Exec(ctx, `INSERT INTO master_identity (id, private_key) VALUES (1, $1) ON CONFLICT (id) DO NOTHING`, der, ); err != nil { return nil, fmt.Errorf("store master key: %w", err) } var stored []byte if err := s.pool.QueryRow(ctx, `SELECT private_key FROM master_identity WHERE id = 1`).Scan(&stored); err != nil { return nil, fmt.Errorf("load master key: %w", err) } parsed, err := x509.ParsePKCS8PrivateKey(stored) if err != nil { return nil, fmt.Errorf("parse master key: %w", err) } key, ok := parsed.(ed25519.PrivateKey) if !ok { return nil, errors.New("stored master key is not ed25519") } return key, nil }