internal/smoke/userca.go
Ref: Size: 2.3 KiB History
package smoke
import (
"crypto/ed25519"
"crypto/rand"
"encoding/pem"
"errors"
"fmt"
"io/fs"
"os"
"path/filepath"
"golang.org/x/crypto/ssh"
)
// smokeUserCA returns the CA the smoke signs with: the persistent one at path,
// or a throwaway held in memory when no path is configured. The gate check
// needs the persistent one (its public half is registered once and reused);
// the delegation leg registers whichever it gets, so it works either way.
func smokeUserCA(path string) (ssh.Signer, error) {
if path == "" {
return generateUserCA()
}
return loadOrCreateUserCA(path)
}
// generateUserCA returns a fresh ed25519 CA that is never written down.
func generateUserCA() (ssh.Signer, error) {
_, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, fmt.Errorf("generate user CA key: %w", err)
}
signer, err := ssh.NewSignerFromSigner(priv)
if err != nil {
return nil, fmt.Errorf("build user CA signer: %w", err)
}
return signer, nil
}
// loadOrCreateUserCA loads the smoke's persistent user CA key from path,
// generating and persisting a fresh ed25519 key on first run so subsequent
// smoke runs reuse the same CA identity (the gate check registers this key's
// public half with the tenant once; a fresh key every run would mean an
// ever-growing set of trusted, never-reused CAs).
func loadOrCreateUserCA(path string) (ssh.Signer, error) {
data, err := os.ReadFile(path)
if err == nil {
signer, err := ssh.ParsePrivateKey(data)
if err != nil {
return nil, fmt.Errorf("parse user CA key %q: %w", path, err)
}
return signer, nil
}
if !errors.Is(err, fs.ErrNotExist) {
return nil, fmt.Errorf("read user CA key %q: %w", path, err)
}
_, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, fmt.Errorf("generate user CA key: %w", err)
}
block, err := ssh.MarshalPrivateKey(priv, "")
if err != nil {
return nil, fmt.Errorf("marshal user CA key: %w", err)
}
pemBytes := pem.EncodeToMemory(block)
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
return nil, fmt.Errorf("mkdir user CA key dir: %w", err)
}
if err := os.WriteFile(path, pemBytes, 0o600); err != nil {
return nil, fmt.Errorf("write user CA key %q: %w", path, err)
}
signer, err := ssh.NewSignerFromSigner(priv)
if err != nil {
return nil, fmt.Errorf("build user CA signer: %w", err)
}
return signer, nil
}