add flag to allow configuration of SSH kex algos
Adds a flag `ssh-kex-algos` which configures the gogit and libgit2 managed clients to use the specified list of kex algos for ssh. If not used the default list in `golang/x/crypto/ssh` is used. Signed-off-by: Sanskar Jaiswal <jaiswalsanskar078@gmail.com>
This commit is contained in:
parent
362bc56bd7
commit
5c84ea7e96
9
main.go
9
main.go
|
@ -46,6 +46,7 @@ import (
|
||||||
"github.com/fluxcd/source-controller/controllers"
|
"github.com/fluxcd/source-controller/controllers"
|
||||||
"github.com/fluxcd/source-controller/internal/cache"
|
"github.com/fluxcd/source-controller/internal/cache"
|
||||||
"github.com/fluxcd/source-controller/internal/helm"
|
"github.com/fluxcd/source-controller/internal/helm"
|
||||||
|
"github.com/fluxcd/source-controller/pkg/git"
|
||||||
"github.com/fluxcd/source-controller/pkg/git/libgit2/managed"
|
"github.com/fluxcd/source-controller/pkg/git/libgit2/managed"
|
||||||
// +kubebuilder:scaffold:imports
|
// +kubebuilder:scaffold:imports
|
||||||
)
|
)
|
||||||
|
@ -90,6 +91,7 @@ func main() {
|
||||||
helmCacheMaxSize int
|
helmCacheMaxSize int
|
||||||
helmCacheTTL string
|
helmCacheTTL string
|
||||||
helmCachePurgeInterval string
|
helmCachePurgeInterval string
|
||||||
|
kexAlgos []string
|
||||||
)
|
)
|
||||||
|
|
||||||
flag.StringVar(&metricsAddr, "metrics-addr", envOrDefault("METRICS_ADDR", ":8080"),
|
flag.StringVar(&metricsAddr, "metrics-addr", envOrDefault("METRICS_ADDR", ":8080"),
|
||||||
|
@ -120,6 +122,8 @@ func main() {
|
||||||
"The TTL of an index in the cache. Valid time units are ns, us (or µs), ms, s, m, h.")
|
"The TTL of an index in the cache. Valid time units are ns, us (or µs), ms, s, m, h.")
|
||||||
flag.StringVar(&helmCachePurgeInterval, "helm-cache-purge-interval", "1m",
|
flag.StringVar(&helmCachePurgeInterval, "helm-cache-purge-interval", "1m",
|
||||||
"The interval at which the cache is purged. Valid time units are ns, us (or µs), ms, s, m, h.")
|
"The interval at which the cache is purged. Valid time units are ns, us (or µs), ms, s, m, h.")
|
||||||
|
flag.StringSliceVar(&kexAlgos, "ssh-kex-algos", []string{},
|
||||||
|
"The list of key exchange algorithms to use for ssh connections, arranged from most preferred to the least.")
|
||||||
|
|
||||||
clientOptions.BindFlags(flag.CommandLine)
|
clientOptions.BindFlags(flag.CommandLine)
|
||||||
logOptions.BindFlags(flag.CommandLine)
|
logOptions.BindFlags(flag.CommandLine)
|
||||||
|
@ -174,6 +178,7 @@ func main() {
|
||||||
storageAdvAddr = determineAdvStorageAddr(storageAddr, setupLog)
|
storageAdvAddr = determineAdvStorageAddr(storageAddr, setupLog)
|
||||||
}
|
}
|
||||||
storage := mustInitStorage(storagePath, storageAdvAddr, setupLog)
|
storage := mustInitStorage(storagePath, storageAdvAddr, setupLog)
|
||||||
|
setPreferredKexAlgos(kexAlgos)
|
||||||
|
|
||||||
if err = (&controllers.GitRepositoryReconciler{
|
if err = (&controllers.GitRepositoryReconciler{
|
||||||
Client: mgr.GetClient(),
|
Client: mgr.GetClient(),
|
||||||
|
@ -333,3 +338,7 @@ func envOrDefault(envName, defaultValue string) string {
|
||||||
|
|
||||||
return defaultValue
|
return defaultValue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setPreferredKexAlgos(algos []string) {
|
||||||
|
git.KexAlgos = algos
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,8 @@ import (
|
||||||
"github.com/fluxcd/pkg/ssh/knownhosts"
|
"github.com/fluxcd/pkg/ssh/knownhosts"
|
||||||
|
|
||||||
"github.com/fluxcd/source-controller/pkg/git"
|
"github.com/fluxcd/source-controller/pkg/git"
|
||||||
|
|
||||||
|
gossh "golang.org/x/crypto/ssh"
|
||||||
)
|
)
|
||||||
|
|
||||||
// transportAuth constructs the transport.AuthMethod for the git.Transport of
|
// transportAuth constructs the transport.AuthMethod for the git.Transport of
|
||||||
|
@ -58,7 +60,10 @@ func transportAuth(opts *git.AuthOptions) (transport.AuthMethod, error) {
|
||||||
}
|
}
|
||||||
pk.HostKeyCallback = callback
|
pk.HostKeyCallback = callback
|
||||||
}
|
}
|
||||||
return pk, nil
|
customPK := &CustomPublicKeys{
|
||||||
|
pk: pk,
|
||||||
|
}
|
||||||
|
return customPK, nil
|
||||||
}
|
}
|
||||||
case "":
|
case "":
|
||||||
return nil, fmt.Errorf("no transport type set")
|
return nil, fmt.Errorf("no transport type set")
|
||||||
|
@ -75,3 +80,28 @@ func caBundle(opts *git.AuthOptions) []byte {
|
||||||
}
|
}
|
||||||
return opts.CAFile
|
return opts.CAFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CustomPublicKeys is a wrapper around ssh.PublicKeys to help us
|
||||||
|
// customize the ssh config. It implements ssh.AuthMethod.
|
||||||
|
type CustomPublicKeys struct {
|
||||||
|
pk *ssh.PublicKeys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *CustomPublicKeys) Name() string {
|
||||||
|
return a.pk.Name()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *CustomPublicKeys) String() string {
|
||||||
|
return a.pk.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *CustomPublicKeys) ClientConfig() (*gossh.ClientConfig, error) {
|
||||||
|
config, err := a.pk.ClientConfig()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(git.KexAlgos) > 0 {
|
||||||
|
config.Config.KeyExchanges = git.KexAlgos
|
||||||
|
}
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,6 @@ import (
|
||||||
|
|
||||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||||
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
|
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
"github.com/fluxcd/source-controller/pkg/git"
|
"github.com/fluxcd/source-controller/pkg/git"
|
||||||
|
@ -72,6 +71,7 @@ func Test_transportAuth(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
opts *git.AuthOptions
|
opts *git.AuthOptions
|
||||||
wantFunc func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions)
|
wantFunc func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions)
|
||||||
|
kexAlgos []string
|
||||||
wantErr error
|
wantErr error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
@ -128,10 +128,10 @@ func Test_transportAuth(t *testing.T) {
|
||||||
Identity: []byte(privateKeyFixture),
|
Identity: []byte(privateKeyFixture),
|
||||||
},
|
},
|
||||||
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
|
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
|
||||||
tt, ok := t.(*ssh.PublicKeys)
|
tt, ok := t.(*CustomPublicKeys)
|
||||||
g.Expect(ok).To(BeTrue())
|
g.Expect(ok).To(BeTrue())
|
||||||
g.Expect(tt.User).To(Equal(opts.Username))
|
g.Expect(tt.pk.User).To(Equal(opts.Username))
|
||||||
g.Expect(tt.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
|
g.Expect(tt.pk.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -143,10 +143,31 @@ func Test_transportAuth(t *testing.T) {
|
||||||
Identity: []byte(privateKeyPassphraseFixture),
|
Identity: []byte(privateKeyPassphraseFixture),
|
||||||
},
|
},
|
||||||
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
|
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
|
||||||
tt, ok := t.(*ssh.PublicKeys)
|
tt, ok := t.(*CustomPublicKeys)
|
||||||
g.Expect(ok).To(BeTrue())
|
g.Expect(ok).To(BeTrue())
|
||||||
g.Expect(tt.User).To(Equal(opts.Username))
|
g.Expect(tt.pk.User).To(Equal(opts.Username))
|
||||||
g.Expect(tt.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
|
g.Expect(tt.pk.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SSH with custom key exchanges",
|
||||||
|
opts: &git.AuthOptions{
|
||||||
|
Transport: git.SSH,
|
||||||
|
Username: "example",
|
||||||
|
Identity: []byte(privateKeyFixture),
|
||||||
|
KnownHosts: []byte(knownHostsFixture),
|
||||||
|
},
|
||||||
|
kexAlgos: []string{"curve25519-sha256", "diffie-hellman-group-exchange-sha256"},
|
||||||
|
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
|
||||||
|
tt, ok := t.(*CustomPublicKeys)
|
||||||
|
g.Expect(ok).To(BeTrue())
|
||||||
|
g.Expect(tt.pk.User).To(Equal(opts.Username))
|
||||||
|
g.Expect(tt.pk.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
|
||||||
|
config, err := tt.ClientConfig()
|
||||||
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
g.Expect(config.Config.KeyExchanges).To(Equal(
|
||||||
|
[]string{"curve25519-sha256", "diffie-hellman-group-exchange-sha256"}),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -168,11 +189,11 @@ func Test_transportAuth(t *testing.T) {
|
||||||
KnownHosts: []byte(knownHostsFixture),
|
KnownHosts: []byte(knownHostsFixture),
|
||||||
},
|
},
|
||||||
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
|
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
|
||||||
tt, ok := t.(*ssh.PublicKeys)
|
tt, ok := t.(*CustomPublicKeys)
|
||||||
g.Expect(ok).To(BeTrue())
|
g.Expect(ok).To(BeTrue())
|
||||||
g.Expect(tt.User).To(Equal(opts.Username))
|
g.Expect(tt.pk.User).To(Equal(opts.Username))
|
||||||
g.Expect(tt.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
|
g.Expect(tt.pk.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
|
||||||
g.Expect(tt.HostKeyCallback).ToNot(BeNil())
|
g.Expect(tt.pk.HostKeyCallback).ToNot(BeNil())
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -202,6 +223,10 @@ func Test_transportAuth(t *testing.T) {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
g := NewWithT(t)
|
g := NewWithT(t)
|
||||||
|
|
||||||
|
if len(tt.kexAlgos) > 0 {
|
||||||
|
git.KexAlgos = tt.kexAlgos
|
||||||
|
}
|
||||||
|
|
||||||
got, err := transportAuth(tt.opts)
|
got, err := transportAuth(tt.opts)
|
||||||
if tt.wantErr != nil {
|
if tt.wantErr != nil {
|
||||||
g.Expect(err).To(Equal(tt.wantErr))
|
g.Expect(err).To(Equal(tt.wantErr))
|
||||||
|
|
|
@ -58,6 +58,7 @@ import (
|
||||||
|
|
||||||
"golang.org/x/crypto/ssh"
|
"golang.org/x/crypto/ssh"
|
||||||
|
|
||||||
|
"github.com/fluxcd/source-controller/pkg/git"
|
||||||
git2go "github.com/libgit2/git2go/v33"
|
git2go "github.com/libgit2/git2go/v33"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -344,6 +345,9 @@ func cacheKeyAndConfig(remoteAddress string, cred *git2go.Credential) (string, *
|
||||||
Auth: []ssh.AuthMethod{ssh.PublicKeys(key)},
|
Auth: []ssh.AuthMethod{ssh.PublicKeys(key)},
|
||||||
Timeout: sshConnectionTimeOut,
|
Timeout: sshConnectionTimeOut,
|
||||||
}
|
}
|
||||||
|
if len(git.KexAlgos) > 0 {
|
||||||
|
cfg.Config.KeyExchanges = git.KexAlgos
|
||||||
|
}
|
||||||
|
|
||||||
return ck, cfg, nil
|
return ck, cfg, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,9 @@ type AuthOptions struct {
|
||||||
CAFile []byte
|
CAFile []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List of custom key exchange algorithms to be used for ssh connections.
|
||||||
|
var KexAlgos []string
|
||||||
|
|
||||||
// Validate the AuthOptions against the defined Transport.
|
// Validate the AuthOptions against the defined Transport.
|
||||||
func (o AuthOptions) Validate() error {
|
func (o AuthOptions) Validate() error {
|
||||||
switch o.Transport {
|
switch o.Transport {
|
||||||
|
|
Loading…
Reference in New Issue