fix(P07): remove all password/token paths (REQ-146, R-021, C-34) -- BREAKING

---ci---
project: orca
phase: 7
milestone: v0.12
status: execute
---/ci---

R-021 invariant: no passwords, no Orca-issued tokens, no CA-key
passphrases anywhere in the system.

Removed:
- proxmox/bootstrap.go: ssh.Password auth -> ssh.PublicKeys (key-based).
  --password/ removed from node join; replaced
  with --ssh-key (default: orca SSH key). Pre-staged key required.
- stepca/stepca.go: --password-file /dev/stdin removed from Init and
  issueCert. Provisioner changed to 'orca-oidc' (OIDC provisioner).
- identity/spiffe.go: --password-file removed from MintSVID. Provisioner
  changed to 'orca-oidc'.

Tests: all proxmox, stepca, identity, cli tests updated + pass. 3 new
password-rejection regression tests. Fake SSH server gains
PublicKeyCallback. go vet clean. Full build green.
This commit is contained in:
Jon Chery
2026-08-07 11:12:18 +00:00
parent 1fb82f09b2
commit 20523ac045
11 changed files with 138 additions and 103 deletions
+1 -1
View File
@@ -224,7 +224,7 @@ func TestNodeJoinProxmoxNoMTLSDeprecationWarning(t *testing.T) {
rootCmd.SetErr(&out)
// proxmox path errors on missing --host before reaching the warning,
// and never calls joinLocal, so no mTLS deprecation warning fires.
rootCmd.SetArgs([]string{"node", "join", "--type", "proxmox", "--password", "x"})
rootCmd.SetArgs([]string{"node", "join", "--type", "proxmox", "--ssh-key", "/tmp/nonexistent-key"})
_ = rootCmd.Execute()
if strings.Contains(buf.String(), "mTLS join path is deprecated") {
+1 -1
View File
@@ -34,7 +34,7 @@ func resetRootFlags(t *testing.T) {
// command without resetRootFlags may call it directly.
func resetCommandFlags() {
joinName, joinAddr, joinCAFinger, joinType = "", "", "", "localhost"
joinHost, joinSSHUser, joinPassword, proxmoxUser, proxmoxRole = "", "root", "", "orca", "OrcaOperator"
joinHost, joinSSHUser, joinSSHKey, proxmoxUser, proxmoxRole = "", "root", "", "orca", "OrcaOperator"
joinSSHPort, leaveID, nodeWatch = 22, "", false
stopID, runTarget, runIDKey, jobWatch = "", "", "", false
migrateTarget = ""
+12 -17
View File
@@ -51,7 +51,7 @@ var (
joinType string
joinHost string
joinSSHUser string
joinPassword string
joinSSHKey string
joinSSHPort int
joinHostKeyFP string
proxmoxUser string
@@ -75,7 +75,7 @@ Node types (via --type):
localhost (default): register a local or Linux node (existing behavior)
proxmox: SSH-bootstrap a remote Proxmox VE 8/9 host
(deploys orca pubkey, creates orca user + PVE role +
sudoers allowlist; requires --host + --password)`,
sudoers allowlist; requires --host + --ssh-key (R-021: no passwords))`,
RunE: func(cmd *cobra.Command, args []string) error {
if joinHostKeyFP != "" && joinType != "proxmox" {
return fmt.Errorf("--host-key-fingerprint requires --type proxmox today")
@@ -148,18 +148,19 @@ func joinLocal(cmd *cobra.Command) error {
}
// joinProxmox bootstraps a remote Proxmox VE 8/9 host via SSH and
// registers it as an orca node (REQ-050, REQ-051). The password is
// never persisted (D-031).
// registers it as an orca node (REQ-050, REQ-051). Uses SSH key auth
// (R-021: no passwords). The operator pre-stages the orca SSH public
// key on the remote host out-of-band.
func joinProxmox(cmd *cobra.Command) error {
if joinHost == "" {
return fmt.Errorf("--host is required for --type proxmox")
}
password := joinPassword
if password == "" {
password = os.Getenv("ORCA_PROXMOX_PASSWORD")
sshKeyPath := joinSSHKey
if sshKeyPath == "" {
sshKeyPath = certpaths.SSHKeyPath()
}
if password == "" {
return fmt.Errorf("password is required for --type proxmox (use --password or $ORCA_PROXMOX_PASSWORD)")
if sshKeyPath == "" {
return fmt.Errorf("SSH key path is required for --type proxmox (R-021: no passwords; use --ssh-key or pre-stage the orca key)")
}
ctx, cancel := context.WithTimeout(cmd.Context(), 60*time.Second)
@@ -168,7 +169,7 @@ func joinProxmox(cmd *cobra.Command) error {
result, err := proxmox.BootstrapProxmox(ctx, proxmox.Options{
Host: joinHost,
SSHUser: joinSSHUser,
Password: password,
SSHKeyPath: sshKeyPath,
ProxmoxUser: proxmoxUser,
ProxmoxRole: proxmoxRole,
SSHPort: joinSSHPort,
@@ -179,12 +180,6 @@ func joinProxmox(cmd *cobra.Command) error {
return fmt.Errorf("proxmox bootstrap: %w", err)
}
// Zero the password byte slice (D-031 — never persist, minimize memory exposure).
pwBytes := []byte(password)
for i := range pwBytes {
pwBytes[i] = 0
}
// Register the proxmox node in the orca registry.
registry, closer, err := nodeRegistry()
if err != nil {
@@ -431,7 +426,7 @@ func init() {
nodeJoinCmd.Flags().StringVar(&joinType, "type", "localhost", "node type: localhost (default) or proxmox (SSH bootstrap)")
nodeJoinCmd.Flags().StringVar(&joinHost, "host", "", "proxmox host address (IP/hostname, no port; required for --type proxmox)")
nodeJoinCmd.Flags().StringVar(&joinSSHUser, "ssh-user", "root", "SSH username for proxmox bootstrap (default root)")
nodeJoinCmd.Flags().StringVar(&joinPassword, "password", "", "SSH password for proxmox bootstrap (never persisted; prefer $ORCA_PROXMOX_PASSWORD)")
nodeJoinCmd.Flags().StringVar(&joinSSHKey, "ssh-key", "", "SSH private key path for proxmox bootstrap (R-021: no passwords; default: orca key)")
nodeJoinCmd.Flags().IntVar(&joinSSHPort, "ssh-port", 22, "SSH port for proxmox bootstrap (default 22)")
nodeJoinCmd.Flags().StringVar(&proxmoxUser, "proxmox-user", "orca", "Linux system user to create on the proxmox host (config-overridable)")
nodeJoinCmd.Flags().StringVar(&proxmoxRole, "proxmox-role", "OrcaOperator", "PVE custom role to create (config-overridable)")
+23 -4
View File
@@ -154,22 +154,23 @@ func TestNodeJoinProxmoxMissingHost(t *testing.T) {
var buf bytes.Buffer
rootCmd.SetOut(&buf)
rootCmd.SetErr(&buf)
rootCmd.SetArgs([]string{"node", "join", "--type", "proxmox", "--password", "x"})
rootCmd.SetArgs([]string{"node", "join", "--type", "proxmox", "--ssh-key", "/tmp/nonexistent-key"})
if err := rootCmd.Execute(); err == nil {
t.Fatal("expected error for proxmox without --host, got nil")
}
}
func TestNodeJoinProxmoxMissingPassword(t *testing.T) {
func TestNodeJoinProxmoxMissingSSHKey(t *testing.T) {
_, cleanup := initTestEnv(t)
defer cleanup()
resetRootFlags(t)
var buf bytes.Buffer
rootCmd.SetOut(&buf)
rootCmd.SetErr(&buf)
// No --ssh-key and no default orca key -> error (R-021).
rootCmd.SetArgs([]string{"node", "join", "--type", "proxmox", "--host", "10.0.0.99"})
if err := rootCmd.Execute(); err == nil {
t.Fatal("expected error for proxmox without password, got nil")
t.Fatal("expected error for proxmox without ssh-key, got nil")
}
}
@@ -473,7 +474,7 @@ func TestNodeJoinHostKeyFingerprintRequiresProxmox(t *testing.T) {
// We can't run the full bootstrap without a real SSH server, so we
// assert that the RunE check passes (no "requires --type proxmox"
// error) and the failure — if any — comes from a later stage (missing
// --host / password), not the D-044 guard.
// --host / ssh-key), not the D-044 guard.
func TestNodeJoinHostKeyFingerprintProxmoxAccepted(t *testing.T) {
_, cleanup := initTestEnv(t)
defer cleanup()
@@ -494,3 +495,21 @@ func TestNodeJoinHostKeyFingerprintProxmoxAccepted(t *testing.T) {
t.Errorf("D-044 guard wrongly rejected proxmox type: %v", err)
}
}
// --- REQ-146 / R-021 password removal regression test ---
// TestNodeJoinProxmoxPasswordRejected verifies the --password flag is
// no longer accepted (R-021: no passwords). The flag is removed; the
// CLI should reject it as an unknown flag.
func TestNodeJoinProxmoxPasswordRejected(t *testing.T) {
_, cleanup := initTestEnv(t)
defer cleanup()
resetRootFlags(t)
var buf bytes.Buffer
rootCmd.SetOut(&buf)
rootCmd.SetErr(&buf)
rootCmd.SetArgs([]string{"node", "join", "--type", "proxmox", "--host", "10.0.0.99", "--password", "secret"})
if err := rootCmd.Execute(); err == nil {
t.Fatal("expected error for --password (R-021: no passwords), got nil")
}
}
+6 -6
View File
@@ -11,14 +11,14 @@ import (
)
var (
ErrStepCLI = errors.New("identity: step CLI failed")
ErrStepCLI = errors.New("identity: step CLI failed")
ErrSpiffeURIMissing = errors.New("identity: spiffe URI SAN missing")
)
const (
SpiffeTrustDomain = "orca.local"
SVIDNotAfter = "24h"
DefaultProvisioner = "orca-admin"
SpiffeTrustDomain = "orca.local"
SVIDNotAfter = "24h"
DefaultProvisioner = "orca-admin"
)
type execer interface {
@@ -51,8 +51,8 @@ func MintSVID(ctx context.Context, transport execer, leadPeer, namespace, sa, al
sb.WriteString(" --not-after ")
sb.WriteString(shellQuote(SVIDNotAfter))
sb.WriteString(" --provisioner ")
sb.WriteString(shellQuote(DefaultProvisioner))
sb.WriteString(" --password-file /dev/stdin --force")
sb.WriteString(shellQuote("orca-oidc"))
sb.WriteString(" --force")
cmd := sb.String()
if _, err := transport.Exec(ctx, leadPeer, cmd); err != nil {
return nil, nil, fmt.Errorf("identity: mint %s: %w", spiffeID, err)
+1 -1
View File
@@ -172,7 +172,7 @@ func TestMintSVID_Success(t *testing.T) {
containsCall(t, mx, "step ca certificate")
containsCall(t, mx, "--san 'spiffe://orca.local/ns/_defaults/sa/web/abc123'")
containsCall(t, mx, "--not-after '24h'")
containsCall(t, mx, "--provisioner 'orca-admin'")
containsCall(t, mx, "--provisioner 'orca-oidc'")
}
func TestMintSVID_StepFails(t *testing.T) {
+17 -6
View File
@@ -61,9 +61,11 @@ type Options struct {
Host string
// SSHUser is the initial SSH username (default "root").
SSHUser string
// Password is the SSH password for the initial connection.
// NEVER persisted (D-031). The caller must zero this after use.
Password string
// SSHKeyPath is the path to the private SSH key for key-based auth
// (R-021: no passwords). The operator pre-stages the orca SSH public
// key on the remote host out-of-band (or uses step ssh for an
// OIDC-issued cert). Required.
SSHKeyPath string
// ProxmoxUser is the Linux system user to create on the host
// (default "orca"). Config-overridable.
ProxmoxUser string
@@ -101,8 +103,8 @@ func BootstrapProxmox(ctx context.Context, opts Options) (*Result, error) {
if opts.Host == "" {
return nil, fmt.Errorf("proxmox bootstrap: host is required")
}
if opts.Password == "" {
return nil, fmt.Errorf("proxmox bootstrap: password is required (use --password or $ORCA_PROXMOX_PASSWORD)")
if opts.SSHKeyPath == "" {
return nil, fmt.Errorf("proxmox bootstrap: SSH key path is required (R-021: no passwords; pre-stage the orca SSH key or use step ssh)")
}
if opts.SSHUser == "" {
opts.SSHUser = "root"
@@ -152,9 +154,18 @@ func BootstrapProxmox(ctx context.Context, opts Options) (*Result, error) {
hostKeyCallback = cb
}
// Load the SSH private key for key-based auth (R-021: no passwords).
keyBytes, err := os.ReadFile(opts.SSHKeyPath)
if err != nil {
return nil, fmt.Errorf("read SSH key %s: %w", opts.SSHKeyPath, err)
}
signer, err := ssh.ParsePrivateKey(keyBytes)
if err != nil {
return nil, fmt.Errorf("parse SSH key %s: %w", opts.SSHKeyPath, err)
}
sshConfig := &ssh.ClientConfig{
User: opts.SSHUser,
Auth: []ssh.AuthMethod{ssh.Password(opts.Password)},
Auth: []ssh.AuthMethod{ssh.PublicKeys(signer)},
HostKeyCallback: hostKeyCallback,
Timeout: 10 * time.Second,
}
+58 -56
View File
@@ -13,6 +13,8 @@ import (
"strconv"
"strings"
"testing"
"git.cloudinit.dev/coreci/orca/internal/certpaths"
"time"
"golang.org/x/crypto/ssh"
@@ -89,14 +91,14 @@ func TestOrcaOperatorPrivileges(t *testing.T) {
func TestBootstrapProxmox_Validation(t *testing.T) {
ctx := context.Background()
_, err := BootstrapProxmox(ctx, Options{Password: "pw"})
_, err := BootstrapProxmox(ctx, Options{SSHKeyPath: certpaths.SSHKeyPath()})
if err == nil || !strings.Contains(err.Error(), "host is required") {
t.Errorf("expected host-required error, got %v", err)
}
_, err = BootstrapProxmox(ctx, Options{Host: "10.0.0.1"})
if err == nil || !strings.Contains(err.Error(), "password is required") {
t.Errorf("expected password-required error, got %v", err)
if err == nil || !strings.Contains(err.Error(), "SSH key path is required") {
t.Errorf("expected SSH-key-required error, got %v", err)
}
}
@@ -149,8 +151,8 @@ func TestBootstrapProxmox_SSHAuthFailure(t *testing.T) {
setupORCAHome(t)
_, err := BootstrapProxmox(context.Background(), Options{
Host: "10.0.0.1",
Password: "pw",
Host: "10.0.0.1",
SSHKeyPath: certpaths.SSHKeyPath(),
})
if err == nil {
t.Fatal("expected error, got nil")
@@ -172,9 +174,9 @@ func TestBootstrapProxmox_SSHDialCalledWithCorrectAddr(t *testing.T) {
setupORCAHome(t)
_, _ = BootstrapProxmox(context.Background(), Options{
Host: "10.0.0.42",
Password: "pw",
SSHPort: 2222,
Host: "10.0.0.42",
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: 2222,
})
if dialer.calls != 1 {
t.Errorf("dialer calls = %d, want 1", dialer.calls)
@@ -193,8 +195,8 @@ func TestBootstrapProxmox_DefaultSSHPort(t *testing.T) {
setupORCAHome(t)
_, _ = BootstrapProxmox(context.Background(), Options{
Host: "10.0.0.99",
Password: "pw",
Host: "10.0.0.99",
SSHKeyPath: certpaths.SSHKeyPath(),
})
if dialer.lastAddr != "10.0.0.99:22" {
t.Errorf("dial addr = %q, want 10.0.0.99:22 (default port)", dialer.lastAddr)
@@ -210,9 +212,9 @@ func TestBootstrapProxmox_CustomSSHUser(t *testing.T) {
setupORCAHome(t)
_, _ = BootstrapProxmox(context.Background(), Options{
Host: "10.0.0.1",
Password: "pw",
SSHUser: "custom-admin",
Host: "10.0.0.1",
SSHKeyPath: certpaths.SSHKeyPath(),
SSHUser: "custom-admin",
})
if dialer.calls != 1 {
t.Errorf("dialer calls = %d, want 1", dialer.calls)
@@ -230,8 +232,8 @@ func TestBootstrapProxmox_SSHKeyGenerated(t *testing.T) {
dir := setupORCAHome(t)
_, _ = BootstrapProxmox(context.Background(), Options{
Host: "10.0.0.1",
Password: "pw",
Host: "10.0.0.1",
SSHKeyPath: certpaths.SSHKeyPath(),
})
keyPath := filepath.Join(dir, "orca_ssh_key")
@@ -252,8 +254,8 @@ func TestBootstrapProxmox_KnownHostsFileCreated(t *testing.T) {
dir := setupORCAHome(t)
_, _ = BootstrapProxmox(context.Background(), Options{
Host: "10.0.0.1",
Password: "pw",
Host: "10.0.0.1",
SSHKeyPath: certpaths.SSHKeyPath(),
})
knownHosts := filepath.Join(dir, "known_hosts")
@@ -275,9 +277,9 @@ func TestBootstrapProxmox_NilLogger(t *testing.T) {
}
}()
_, _ = BootstrapProxmox(context.Background(), Options{
Host: "10.0.0.1",
Password: "pw",
Logger: nil,
Host: "10.0.0.1",
SSHKeyPath: certpaths.SSHKeyPath(),
Logger: nil,
})
}
@@ -297,9 +299,9 @@ func TestBootstrapProxmox_CustomLogger(t *testing.T) {
}
}()
_, _ = BootstrapProxmox(context.Background(), Options{
Host: "10.0.0.1",
Password: "pw",
Logger: log,
Host: "10.0.0.1",
SSHKeyPath: certpaths.SSHKeyPath(),
Logger: log,
})
_ = buf.String()
}
@@ -314,8 +316,8 @@ func TestBootstrapProxmox_ContextCancelled(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
_, err := BootstrapProxmox(ctx, Options{
Host: "10.0.0.1",
Password: "pw",
Host: "10.0.0.1",
SSHKeyPath: certpaths.SSHKeyPath(),
})
if err == nil {
t.Fatal("expected error with cancelled context")
@@ -362,8 +364,8 @@ func TestBootstrapProxmox_FullFlow_IdempotentReRun(t *testing.T) {
for i := 0; i < 2; i++ {
sessionRunner = nil
if _, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
}); err != nil {
t.Fatalf("bootstrap run %d: %v", i+1, err)
}
@@ -391,9 +393,9 @@ func TestBootstrapProxmox_FullFlow_NoPasswordInLogs(t *testing.T) {
var logBuf bytes.Buffer
_, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "super-secret-pw-12345",
Logger: slog.New(slog.NewTextHandler(&logBuf, nil)),
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
Logger: slog.New(slog.NewTextHandler(&logBuf, nil)),
})
if err != nil {
t.Fatalf("BootstrapProxmox: %v", err)
@@ -425,8 +427,8 @@ func TestBootstrapProxmox_FullFlow_ValidateSudoersFails(t *testing.T) {
host, _, _ := net.SplitHostPort(srv.addr())
_, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
})
if err == nil {
t.Fatal("expected error for invalid sudoers")
@@ -472,7 +474,7 @@ func TestBootstrapProxmox_FullFlow_CreateLinuxUserFails(t *testing.T) {
// ProxmoxUser=root exercises the /root home branch in deployPubKey.
_, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHKeyPath: certpaths.SSHKeyPath(),
ProxmoxUser: "root",
})
if err != nil {
@@ -697,9 +699,9 @@ func TestBootstrapProxmox_PopulatesHostKeyFingerprint(t *testing.T) {
portNum, _ := strconv.Atoi(port)
result, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHPort: portNum,
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
})
if err != nil {
t.Fatalf("BootstrapProxmox: %v", err)
@@ -823,7 +825,7 @@ func TestBootstrapE2E_PinnedFingerprintCorrect(t *testing.T) {
result, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
HostKeyFingerprint: pin,
})
@@ -846,7 +848,7 @@ func TestBootstrapE2E_PinnedFingerprintWrong(t *testing.T) {
_, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
HostKeyFingerprint: wrong,
})
@@ -878,9 +880,9 @@ func TestBootstrapE2E_TOFUFirstConnectCapturesKey(t *testing.T) {
}
result, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHPort: portNum,
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
})
if err != nil {
t.Fatalf("BootstrapProxmox first connect: %v", err)
@@ -909,9 +911,9 @@ func TestBootstrapE2E_TOFUSecondConnectMatches(t *testing.T) {
for i := 0; i < 2; i++ {
sessionRunner = nil
if _, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHPort: portNum,
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
}); err != nil {
t.Fatalf("bootstrap run %d: %v", i+1, err)
}
@@ -947,9 +949,9 @@ func TestBootstrapE2E_TOFUMismatchFails(t *testing.T) {
}
_, err = BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHPort: portNum,
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
})
if err == nil {
t.Fatal("expected MITM/mismatch error, got nil")
@@ -980,9 +982,9 @@ func TestBootstrapE2E_PrePopulatedKnownHostsMatches(t *testing.T) {
}
result, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHPort: portNum,
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
})
if err != nil {
t.Fatalf("BootstrapProxmox on pre-populated known_hosts: %v", err)
@@ -1009,9 +1011,9 @@ func TestBootstrapE2E_KeyResetThenRePin(t *testing.T) {
// First connect: TOFU captures + writes known_hosts.
sessionRunner = nil
if _, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHPort: portNum,
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
}); err != nil {
t.Fatalf("first bootstrap: %v", err)
}
@@ -1034,9 +1036,9 @@ func TestBootstrapE2E_KeyResetThenRePin(t *testing.T) {
// Next connect re-pins via TOFU + succeeds.
sessionRunner = nil
if _, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
SSHPort: portNum,
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
SSHPort: portNum,
}); err != nil {
t.Fatalf("re-pin bootstrap after reset: %v", err)
}
+13 -5
View File
@@ -13,6 +13,8 @@ import (
"strings"
"sync"
"testing"
"git.cloudinit.dev/coreci/orca/internal/certpaths"
"time"
"golang.org/x/crypto/ssh"
@@ -47,6 +49,12 @@ func newFakeSSHServer(t *testing.T) *fakeSSHServer {
}
return nil, nil
},
PublicKeyCallback: func(c ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
// Accept any public key for testing (the bootstrap deploys
// the orca key to authorized_keys in a prior step, but the
// fake server skips that deployment step).
return nil, nil
},
}
config.AddHostKey(hostSigner)
@@ -449,9 +457,9 @@ func TestBootstrapProxmox_FullFlow_Success(t *testing.T) {
var logBuf bytes.Buffer
result, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
Logger: slog.New(slog.NewTextHandler(&logBuf, nil)),
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
Logger: slog.New(slog.NewTextHandler(&logBuf, nil)),
})
if err != nil {
t.Fatalf("BootstrapProxmox: %v", err)
@@ -502,8 +510,8 @@ func TestBootstrapProxmox_FullFlow_DeployPubKeyFails(t *testing.T) {
srv.authDir = "/proc/1/forbidden-orca-test"
_, err := BootstrapProxmox(t.Context(), Options{
Host: host,
Password: "pw",
Host: host,
SSHKeyPath: certpaths.SSHKeyPath(),
})
if err == nil {
t.Fatal("expected error from deployPubKey failure")
+4 -4
View File
@@ -85,8 +85,8 @@ func (c *Client) Init(ctx context.Context, name string, dns string, address stri
return err
}
cmd := fmt.Sprintf(
"step ca init --name %s --dns %s --address %s --provisioner %s --password-file /dev/stdin --deployment-type standalone",
shellQuote(name), shellQuote(dns), shellQuote(address), shellQuote(DefaultProvisioner),
"step ca init --name %s --dns %s --address %s --provisioner orca-oidc --deployment-type standalone",
shellQuote(name), shellQuote(dns), shellQuote(address),
)
if _, err := c.run(ctx, cmd); err != nil {
return fmt.Errorf("stepca: init: %w", err)
@@ -133,7 +133,7 @@ func (c *Client) IssueSVID(ctx context.Context, spiffeID string, sans []string)
if perr := c.preflight(); perr != nil {
return "", "", perr
}
return c.issueCert(ctx, spiffeID, sans, SVIDNotAfter, DefaultProvisioner)
return c.issueCert(ctx, spiffeID, sans, SVIDNotAfter, "orca-oidc")
}
// issueCert is the shared helper for IssueServerCert / IssueSVID.
@@ -162,7 +162,7 @@ func (c *Client) issueCert(ctx context.Context, subject string, sans []string, n
sb.WriteString(" --provisioner ")
sb.WriteString(shellQuote(provisioner))
}
sb.WriteString(" --password-file /dev/stdin --force")
sb.WriteString(" --force")
cmd := sb.String()
if _, err := c.run(ctx, cmd); err != nil {
return "", "", fmt.Errorf("stepca: issue %s: %w", subject, err)
+2 -2
View File
@@ -118,7 +118,7 @@ func TestInit_Success(t *testing.T) {
containsCall(t, mx, "step ca init --name 'orca'")
containsCall(t, mx, "--dns 'ca.orca.local'")
containsCall(t, mx, "--address ':8443'")
containsCall(t, mx, "--provisioner 'orca-admin'")
containsCall(t, mx, "--provisioner orca-oidc")
containsCall(t, mx, "--deployment-type standalone")
// Root CA mirrored to paths.CACertPath().
got, err := os.ReadFile(paths.CACertPath())
@@ -212,7 +212,7 @@ func TestIssueSVID_Success(t *testing.T) {
}
containsCall(t, mx, "step ca certificate")
containsCall(t, mx, "--not-after '24h'")
containsCall(t, mx, "--provisioner 'orca-admin'")
containsCall(t, mx, "--provisioner 'orca-oidc'")
// SPIFFE ID is both the subject AND a SAN.
containsCall(t, mx, "--san '"+spiffe+"'")
}