Merge pull request #655 from aryan9600/preferred-kex

This commit is contained in:
Hidde Beydals 2022-04-07 13:56:46 +02:00 committed by GitHub
commit 62604a2206
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 83 additions and 12 deletions

View File

@ -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
}

View File

@ -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
}

View File

@ -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))

View File

@ -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
} }

View File

@ -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 {