Skip to content

Commit 62604a2

Browse files
authored
Merge pull request #655 from aryan9600/preferred-kex
2 parents 362bc56 + 5c84ea7 commit 62604a2

File tree

5 files changed

+83
-12
lines changed

5 files changed

+83
-12
lines changed

main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646
"github.com/fluxcd/source-controller/controllers"
4747
"github.com/fluxcd/source-controller/internal/cache"
4848
"github.com/fluxcd/source-controller/internal/helm"
49+
"github.com/fluxcd/source-controller/pkg/git"
4950
"github.com/fluxcd/source-controller/pkg/git/libgit2/managed"
5051
// +kubebuilder:scaffold:imports
5152
)
@@ -90,6 +91,7 @@ func main() {
9091
helmCacheMaxSize int
9192
helmCacheTTL string
9293
helmCachePurgeInterval string
94+
kexAlgos []string
9395
)
9496

9597
flag.StringVar(&metricsAddr, "metrics-addr", envOrDefault("METRICS_ADDR", ":8080"),
@@ -120,6 +122,8 @@ func main() {
120122
"The TTL of an index in the cache. Valid time units are ns, us (or µs), ms, s, m, h.")
121123
flag.StringVar(&helmCachePurgeInterval, "helm-cache-purge-interval", "1m",
122124
"The interval at which the cache is purged. Valid time units are ns, us (or µs), ms, s, m, h.")
125+
flag.StringSliceVar(&kexAlgos, "ssh-kex-algos", []string{},
126+
"The list of key exchange algorithms to use for ssh connections, arranged from most preferred to the least.")
123127

124128
clientOptions.BindFlags(flag.CommandLine)
125129
logOptions.BindFlags(flag.CommandLine)
@@ -174,6 +178,7 @@ func main() {
174178
storageAdvAddr = determineAdvStorageAddr(storageAddr, setupLog)
175179
}
176180
storage := mustInitStorage(storagePath, storageAdvAddr, setupLog)
181+
setPreferredKexAlgos(kexAlgos)
177182

178183
if err = (&controllers.GitRepositoryReconciler{
179184
Client: mgr.GetClient(),
@@ -333,3 +338,7 @@ func envOrDefault(envName, defaultValue string) string {
333338

334339
return defaultValue
335340
}
341+
342+
func setPreferredKexAlgos(algos []string) {
343+
git.KexAlgos = algos
344+
}

pkg/git/gogit/transport.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
"github.com/fluxcd/pkg/ssh/knownhosts"
2727

2828
"github.com/fluxcd/source-controller/pkg/git"
29+
30+
gossh "golang.org/x/crypto/ssh"
2931
)
3032

3133
// transportAuth constructs the transport.AuthMethod for the git.Transport of
@@ -58,7 +60,10 @@ func transportAuth(opts *git.AuthOptions) (transport.AuthMethod, error) {
5860
}
5961
pk.HostKeyCallback = callback
6062
}
61-
return pk, nil
63+
customPK := &CustomPublicKeys{
64+
pk: pk,
65+
}
66+
return customPK, nil
6267
}
6368
case "":
6469
return nil, fmt.Errorf("no transport type set")
@@ -75,3 +80,28 @@ func caBundle(opts *git.AuthOptions) []byte {
7580
}
7681
return opts.CAFile
7782
}
83+
84+
// CustomPublicKeys is a wrapper around ssh.PublicKeys to help us
85+
// customize the ssh config. It implements ssh.AuthMethod.
86+
type CustomPublicKeys struct {
87+
pk *ssh.PublicKeys
88+
}
89+
90+
func (a *CustomPublicKeys) Name() string {
91+
return a.pk.Name()
92+
}
93+
94+
func (a *CustomPublicKeys) String() string {
95+
return a.pk.String()
96+
}
97+
98+
func (a *CustomPublicKeys) ClientConfig() (*gossh.ClientConfig, error) {
99+
config, err := a.pk.ClientConfig()
100+
if err != nil {
101+
return nil, err
102+
}
103+
if len(git.KexAlgos) > 0 {
104+
config.Config.KeyExchanges = git.KexAlgos
105+
}
106+
return config, nil
107+
}

pkg/git/gogit/transport_test.go

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222

2323
"github.com/go-git/go-git/v5/plumbing/transport"
2424
"github.com/go-git/go-git/v5/plumbing/transport/http"
25-
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
2625
. "github.com/onsi/gomega"
2726

2827
"github.com/fluxcd/source-controller/pkg/git"
@@ -72,6 +71,7 @@ func Test_transportAuth(t *testing.T) {
7271
name string
7372
opts *git.AuthOptions
7473
wantFunc func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions)
74+
kexAlgos []string
7575
wantErr error
7676
}{
7777
{
@@ -128,10 +128,10 @@ func Test_transportAuth(t *testing.T) {
128128
Identity: []byte(privateKeyFixture),
129129
},
130130
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
131-
tt, ok := t.(*ssh.PublicKeys)
131+
tt, ok := t.(*CustomPublicKeys)
132132
g.Expect(ok).To(BeTrue())
133-
g.Expect(tt.User).To(Equal(opts.Username))
134-
g.Expect(tt.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
133+
g.Expect(tt.pk.User).To(Equal(opts.Username))
134+
g.Expect(tt.pk.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
135135
},
136136
},
137137
{
@@ -143,10 +143,31 @@ func Test_transportAuth(t *testing.T) {
143143
Identity: []byte(privateKeyPassphraseFixture),
144144
},
145145
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
146-
tt, ok := t.(*ssh.PublicKeys)
146+
tt, ok := t.(*CustomPublicKeys)
147147
g.Expect(ok).To(BeTrue())
148-
g.Expect(tt.User).To(Equal(opts.Username))
149-
g.Expect(tt.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
148+
g.Expect(tt.pk.User).To(Equal(opts.Username))
149+
g.Expect(tt.pk.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
150+
},
151+
},
152+
{
153+
name: "SSH with custom key exchanges",
154+
opts: &git.AuthOptions{
155+
Transport: git.SSH,
156+
Username: "example",
157+
Identity: []byte(privateKeyFixture),
158+
KnownHosts: []byte(knownHostsFixture),
159+
},
160+
kexAlgos: []string{"curve25519-sha256", "diffie-hellman-group-exchange-sha256"},
161+
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
162+
tt, ok := t.(*CustomPublicKeys)
163+
g.Expect(ok).To(BeTrue())
164+
g.Expect(tt.pk.User).To(Equal(opts.Username))
165+
g.Expect(tt.pk.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
166+
config, err := tt.ClientConfig()
167+
g.Expect(err).ToNot(HaveOccurred())
168+
g.Expect(config.Config.KeyExchanges).To(Equal(
169+
[]string{"curve25519-sha256", "diffie-hellman-group-exchange-sha256"}),
170+
)
150171
},
151172
},
152173
{
@@ -168,11 +189,11 @@ func Test_transportAuth(t *testing.T) {
168189
KnownHosts: []byte(knownHostsFixture),
169190
},
170191
wantFunc: func(g *WithT, t transport.AuthMethod, opts *git.AuthOptions) {
171-
tt, ok := t.(*ssh.PublicKeys)
192+
tt, ok := t.(*CustomPublicKeys)
172193
g.Expect(ok).To(BeTrue())
173-
g.Expect(tt.User).To(Equal(opts.Username))
174-
g.Expect(tt.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
175-
g.Expect(tt.HostKeyCallback).ToNot(BeNil())
194+
g.Expect(tt.pk.User).To(Equal(opts.Username))
195+
g.Expect(tt.pk.Signer.PublicKey().Type()).To(Equal("ssh-rsa"))
196+
g.Expect(tt.pk.HostKeyCallback).ToNot(BeNil())
176197
},
177198
},
178199
{
@@ -202,6 +223,10 @@ func Test_transportAuth(t *testing.T) {
202223
t.Run(tt.name, func(t *testing.T) {
203224
g := NewWithT(t)
204225

226+
if len(tt.kexAlgos) > 0 {
227+
git.KexAlgos = tt.kexAlgos
228+
}
229+
205230
got, err := transportAuth(tt.opts)
206231
if tt.wantErr != nil {
207232
g.Expect(err).To(Equal(tt.wantErr))

pkg/git/libgit2/managed/ssh.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import (
5858

5959
"golang.org/x/crypto/ssh"
6060

61+
"github.com/fluxcd/source-controller/pkg/git"
6162
git2go "github.com/libgit2/git2go/v33"
6263
)
6364

@@ -344,6 +345,9 @@ func cacheKeyAndConfig(remoteAddress string, cred *git2go.Credential) (string, *
344345
Auth: []ssh.AuthMethod{ssh.PublicKeys(key)},
345346
Timeout: sshConnectionTimeOut,
346347
}
348+
if len(git.KexAlgos) > 0 {
349+
cfg.Config.KeyExchanges = git.KexAlgos
350+
}
347351

348352
return ck, cfg, nil
349353
}

pkg/git/options.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ type AuthOptions struct {
7070
CAFile []byte
7171
}
7272

73+
// List of custom key exchange algorithms to be used for ssh connections.
74+
var KexAlgos []string
75+
7376
// Validate the AuthOptions against the defined Transport.
7477
func (o AuthOptions) Validate() error {
7578
switch o.Transport {

0 commit comments

Comments
 (0)