From d446b60b7edc2c03361e4717f05522d05cd93b41 Mon Sep 17 00:00:00 2001 From: Hidde Beydals Date: Fri, 29 May 2026 22:11:26 +0200 Subject: [PATCH] Wire SSH signing into provider bootstrap commands Adds the same explicit-path SSH-signing wiring to flux bootstrap github / gitlab / gitea / bitbucket-server, consulting the new effectiveSshSigningPassword helper for the resolved passphrase. The reuse-path wiring applies only to gitlab and bitbucket-server (which consume --private-key-file as the SSH transport key). github and gitea generate the transport key in-process, so they reject --ssh-signing-reuse-private-key explicitly with a message explaining why. The reject check fires immediately after each subcommand's bootstrapOpts slice literal closes, before any conditional appends, so the failure semantics match the reading order of the code. Signed-off-by: Hidde Beydals --- cmd/flux/bootstrap_bitbucket_server.go | 26 ++++++++++++++++++++++++++ cmd/flux/bootstrap_gitea.go | 19 +++++++++++++++++++ cmd/flux/bootstrap_github.go | 19 +++++++++++++++++++ cmd/flux/bootstrap_gitlab.go | 26 ++++++++++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/cmd/flux/bootstrap_bitbucket_server.go b/cmd/flux/bootstrap_bitbucket_server.go index 3490ffbe..c595b482 100644 --- a/cmd/flux/bootstrap_bitbucket_server.go +++ b/cmd/flux/bootstrap_bitbucket_server.go @@ -24,6 +24,7 @@ import ( "github.com/fluxcd/pkg/git" "github.com/fluxcd/pkg/git/gogit" + "github.com/fluxcd/pkg/git/signature" "github.com/spf13/cobra" "github.com/fluxcd/flux2/v2/internal/flags" @@ -287,6 +288,31 @@ func bootstrapBServerCmdRun(cmd *cobra.Command, args []string) error { bootstrapOpts = append(bootstrapOpts, bootstrap.WithReconcile()) } + if bootstrapArgs.sshSigningKeyFile != "" { + pemBytes, err := os.ReadFile(bootstrapArgs.sshSigningKeyFile) + if err != nil { + return fmt.Errorf("failed to read SSH signing key file: %w", err) + } + pwd, err := effectiveSshSigningPassword() + if err != nil { + return err + } + bootstrapOpts = append(bootstrapOpts, + bootstrap.WithSSHCommitSigning(pemBytes, []byte(pwd))) + } + + if bootstrapArgs.sshSigningReusePrivateKey { + pemBytes, err := os.ReadFile(bootstrapArgs.privateKeyFile) + if err != nil { + return fmt.Errorf("failed to read transport private key for signing: %w", err) + } + if _, err := signature.NewSSHSigner(pemBytes, []byte(gitArgs.password)); err != nil { + return fmt.Errorf("invalid signing key (reused from --private-key-file): %w", err) + } + bootstrapOpts = append(bootstrapOpts, + bootstrap.WithSSHCommitSigning(pemBytes, []byte(gitArgs.password))) + } + // Setup bootstrapper with constructed configs b, err := bootstrap.NewGitProviderBootstrapper(gitClient, providerClient, kubeClient, bootstrapOpts...) if err != nil { diff --git a/cmd/flux/bootstrap_gitea.go b/cmd/flux/bootstrap_gitea.go index c6db27f8..20628f6f 100644 --- a/cmd/flux/bootstrap_gitea.go +++ b/cmd/flux/bootstrap_gitea.go @@ -252,6 +252,12 @@ func bootstrapGiteaCmdRun(cmd *cobra.Command, args []string) error { bootstrap.WithLogger(logger), bootstrap.WithGitCommitSigning(entityList, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID), } + + if bootstrapArgs.sshSigningReusePrivateKey { + return fmt.Errorf("--ssh-signing-reuse-private-key is not supported by 'bootstrap gitea'; " + + "that subcommand generates the SSH transport key in-process and has no operator-supplied key to reuse") + } + if bootstrapArgs.sshHostname != "" { bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname)) } @@ -265,6 +271,19 @@ func bootstrapGiteaCmdRun(cmd *cobra.Command, args []string) error { bootstrapOpts = append(bootstrapOpts, bootstrap.WithReconcile()) } + if bootstrapArgs.sshSigningKeyFile != "" { + pemBytes, err := os.ReadFile(bootstrapArgs.sshSigningKeyFile) + if err != nil { + return fmt.Errorf("failed to read SSH signing key file: %w", err) + } + pwd, err := effectiveSshSigningPassword() + if err != nil { + return err + } + bootstrapOpts = append(bootstrapOpts, + bootstrap.WithSSHCommitSigning(pemBytes, []byte(pwd))) + } + // Setup bootstrapper with constructed configs b, err := bootstrap.NewGitProviderBootstrapper(gitClient, providerClient, kubeClient, bootstrapOpts...) if err != nil { diff --git a/cmd/flux/bootstrap_github.go b/cmd/flux/bootstrap_github.go index 9c5ca2a2..e78ebc60 100644 --- a/cmd/flux/bootstrap_github.go +++ b/cmd/flux/bootstrap_github.go @@ -259,6 +259,12 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error { bootstrap.WithLogger(logger), bootstrap.WithGitCommitSigning(entityList, bootstrapArgs.gpgPassphrase, bootstrapArgs.gpgKeyID), } + + if bootstrapArgs.sshSigningReusePrivateKey { + return fmt.Errorf("--ssh-signing-reuse-private-key is not supported by 'bootstrap github'; " + + "that subcommand generates the SSH transport key in-process and has no operator-supplied key to reuse") + } + if bootstrapArgs.sshHostname != "" { bootstrapOpts = append(bootstrapOpts, bootstrap.WithSSHHostname(bootstrapArgs.sshHostname)) } @@ -272,6 +278,19 @@ func bootstrapGitHubCmdRun(cmd *cobra.Command, args []string) error { bootstrapOpts = append(bootstrapOpts, bootstrap.WithReconcile()) } + if bootstrapArgs.sshSigningKeyFile != "" { + pemBytes, err := os.ReadFile(bootstrapArgs.sshSigningKeyFile) + if err != nil { + return fmt.Errorf("failed to read SSH signing key file: %w", err) + } + pwd, err := effectiveSshSigningPassword() + if err != nil { + return err + } + bootstrapOpts = append(bootstrapOpts, + bootstrap.WithSSHCommitSigning(pemBytes, []byte(pwd))) + } + // Setup bootstrapper with constructed configs b, err := bootstrap.NewGitProviderBootstrapper(gitClient, providerClient, kubeClient, bootstrapOpts...) if err != nil { diff --git a/cmd/flux/bootstrap_gitlab.go b/cmd/flux/bootstrap_gitlab.go index 9f4510ca..2e08bff6 100644 --- a/cmd/flux/bootstrap_gitlab.go +++ b/cmd/flux/bootstrap_gitlab.go @@ -27,6 +27,7 @@ import ( "github.com/fluxcd/go-git-providers/gitprovider" "github.com/fluxcd/pkg/git" "github.com/fluxcd/pkg/git/gogit" + "github.com/fluxcd/pkg/git/signature" "github.com/spf13/cobra" "github.com/fluxcd/flux2/v2/internal/flags" @@ -321,6 +322,31 @@ func bootstrapGitLabCmdRun(cmd *cobra.Command, args []string) error { bootstrapOpts = append(bootstrapOpts, bootstrap.WithReconcile()) } + if bootstrapArgs.sshSigningKeyFile != "" { + pemBytes, err := os.ReadFile(bootstrapArgs.sshSigningKeyFile) + if err != nil { + return fmt.Errorf("failed to read SSH signing key file: %w", err) + } + pwd, err := effectiveSshSigningPassword() + if err != nil { + return err + } + bootstrapOpts = append(bootstrapOpts, + bootstrap.WithSSHCommitSigning(pemBytes, []byte(pwd))) + } + + if bootstrapArgs.sshSigningReusePrivateKey { + pemBytes, err := os.ReadFile(bootstrapArgs.privateKeyFile) + if err != nil { + return fmt.Errorf("failed to read transport private key for signing: %w", err) + } + if _, err := signature.NewSSHSigner(pemBytes, []byte(gitArgs.password)); err != nil { + return fmt.Errorf("invalid signing key (reused from --private-key-file): %w", err) + } + bootstrapOpts = append(bootstrapOpts, + bootstrap.WithSSHCommitSigning(pemBytes, []byte(gitArgs.password))) + } + // Setup bootstrapper with constructed configs b, err := bootstrap.NewGitProviderBootstrapper(gitClient, providerClient, kubeClient, bootstrapOpts...) if err != nil {