Skip to content

Commit 57516b1

Browse files
(chore): adds tls config for GitHub App auth
this commit ensures that if ca.crt or caFile is available in the github app secret, a tls config with user provided certs is appended to system cert pool and passed to the underlying http transport Signed-off-by: abhijith-darshan <[email protected]> (chore): keeps implementation in-sync with source-controller Signed-off-by: abhijith-darshan <[email protected]> (chore): inline proxy detection This commit removes getProxyOpts(...) helper func and uses pkg/runtime/secrets to retrieve proxy information from secret reference Signed-off-by: abhijith-darshan <[email protected]> (chore): remove err formatting for secrets.ProxyURLFromSecretRef Signed-off-by: abhijith-darshan <[email protected]>
1 parent f584731 commit 57516b1

File tree

4 files changed

+85
-159
lines changed

4 files changed

+85
-159
lines changed

go.mod

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,13 @@ require (
1919
github.com/fluxcd/image-reflector-controller/api v0.35.2
2020
github.com/fluxcd/pkg/apis/acl v0.8.0
2121
github.com/fluxcd/pkg/apis/event v0.18.0
22-
github.com/fluxcd/pkg/apis/meta v1.17.0
22+
github.com/fluxcd/pkg/apis/meta v1.18.0
2323
github.com/fluxcd/pkg/auth v0.21.0
2424
github.com/fluxcd/pkg/cache v0.10.0
25-
github.com/fluxcd/pkg/git v0.34.0
26-
github.com/fluxcd/pkg/git/gogit v0.37.0
25+
github.com/fluxcd/pkg/git v0.35.0
26+
github.com/fluxcd/pkg/git/gogit v0.38.0
2727
github.com/fluxcd/pkg/gittestserver v0.18.0
28-
github.com/fluxcd/pkg/runtime v0.69.0
28+
github.com/fluxcd/pkg/runtime v0.79.0
2929
github.com/fluxcd/pkg/ssh v0.20.0
3030
github.com/fluxcd/source-controller/api v1.6.1
3131
github.com/go-git/go-billy/v5 v5.6.2

go.sum

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,20 +132,20 @@ github.com/fluxcd/pkg/apis/acl v0.8.0 h1:mZNl4mOQQf5/cdMCYgKcrZTZRndCtMtkI0BDfNO
132132
github.com/fluxcd/pkg/apis/acl v0.8.0/go.mod h1:uv7pXXR/gydiX4MUwlQa7vS8JONEDztynnjTvY3JxKQ=
133133
github.com/fluxcd/pkg/apis/event v0.18.0 h1:PNbWk9gvX8gMIi6VsJapnuDO+giLEeY+6olLVXvXFkk=
134134
github.com/fluxcd/pkg/apis/event v0.18.0/go.mod h1:7S/DGboLolfbZ6stO6dcDhG1SfkPWQ9foCULvbiYpiA=
135-
github.com/fluxcd/pkg/apis/meta v1.17.0 h1:KVMDyJQj1NYCsppsFUkbJGMnKxsqJVpnKBFolHf/q8E=
136-
github.com/fluxcd/pkg/apis/meta v1.17.0/go.mod h1:97l3hTwBpJbXBY+wetNbqrUsvES8B1jGioKcBUxmqd8=
135+
github.com/fluxcd/pkg/apis/meta v1.18.0 h1:ACHrMIjlcioE9GKS7NGk62KX4NshqNewr8sBwMcXABs=
136+
github.com/fluxcd/pkg/apis/meta v1.18.0/go.mod h1:97l3hTwBpJbXBY+wetNbqrUsvES8B1jGioKcBUxmqd8=
137137
github.com/fluxcd/pkg/auth v0.21.0 h1:ckAQqP12wuptXEkMY18SQKWEY09m9e6yI0mEMsDV15M=
138138
github.com/fluxcd/pkg/auth v0.21.0/go.mod h1:MXmpsXT97c874HCw5hnfqFUP7TsG8/Ss1vFrk8JccfM=
139139
github.com/fluxcd/pkg/cache v0.10.0 h1:M+OGDM4da1cnz7q+sZSBtkBJHpiJsLnKVmR9OdMWxEY=
140140
github.com/fluxcd/pkg/cache v0.10.0/go.mod h1:pPXRzQUDQagsCniuOolqVhnAkbNgYOg8d2cTliPs7ME=
141-
github.com/fluxcd/pkg/git v0.34.0 h1:qTViWkfpEDnjzySyKRKliqUeGj/DznqlkmPhaDNIsFY=
142-
github.com/fluxcd/pkg/git v0.34.0/go.mod h1:F9Asm3MlLW4uZx3FF92+bqho+oktdMdnTn/QmXe56NE=
143-
github.com/fluxcd/pkg/git/gogit v0.37.0 h1:JINylFYpwrxS3MCu5Ei+g6XPgxbs5lv9PppIYYr07KY=
144-
github.com/fluxcd/pkg/git/gogit v0.37.0/go.mod h1:X7YzW5mb4srA05h4SpL2OEGEHq02tbXQF5DPJen9hlc=
141+
github.com/fluxcd/pkg/git v0.35.0 h1:mAauhsdfxNW4yQdXviVlvcN/uCGGG0+6p5D1+HFZI9w=
142+
github.com/fluxcd/pkg/git v0.35.0/go.mod h1:F9Asm3MlLW4uZx3FF92+bqho+oktdMdnTn/QmXe56NE=
143+
github.com/fluxcd/pkg/git/gogit v0.38.0 h1:222KmjpKf9pxqi8rAtm1omDcpGTY4JkahLrAwZ3AcwU=
144+
github.com/fluxcd/pkg/git/gogit v0.38.0/go.mod h1:kHStdfd/AtkH5ED0UEWP2tmMGnfxg1GG92D29M+lRJ0=
145145
github.com/fluxcd/pkg/gittestserver v0.18.0 h1:jkuLmzWFfq+v1ziI0LspZrUzc5WzCO98BaWb8OVRPtk=
146146
github.com/fluxcd/pkg/gittestserver v0.18.0/go.mod h1:2wDLqUkPuixk/8pGQdef9ewaGJXf7Z+xHDVq8PIFG4E=
147-
github.com/fluxcd/pkg/runtime v0.69.0 h1:5gPY95NSFI34GlQTj0+NHjOFpirSwviCUb9bM09b5nA=
148-
github.com/fluxcd/pkg/runtime v0.69.0/go.mod h1:ug+pat+I4wfOBuCy2E/pLmBNd3kOOo4cP2jxnxefPwY=
147+
github.com/fluxcd/pkg/runtime v0.79.0 h1:9tv79EiQDx/QJH9mYDd9kZ9WybCVWBUGoiBHij+eKkc=
148+
github.com/fluxcd/pkg/runtime v0.79.0/go.mod h1:iGhdaEq+lMJQTJNAFEPOU4gUJ7kt3yeDcJPZy7O9IUw=
149149
github.com/fluxcd/pkg/ssh v0.20.0 h1:Ak0laIYIc/L8lEfqls/LDWRW8wYPESGaravQsCRGLb8=
150150
github.com/fluxcd/pkg/ssh v0.20.0/go.mod h1:sRfAAkxx1GwCGjYirKPnTKdNkNrJRo9kqzWLVFXKv7E=
151151
github.com/fluxcd/pkg/version v0.9.0 h1:pQBHMt9TbnnTUzj3EoMhRi5JUkNBqrTBSAaoLG1ovUA=

internal/source/git.go

Lines changed: 50 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"time"
2626

2727
"github.com/ProtonMail/go-crypto/openpgp"
28+
"github.com/fluxcd/pkg/runtime/secrets"
2829
"github.com/go-git/go-git/v5/plumbing/transport"
2930
corev1 "k8s.io/api/core/v1"
3031
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -62,13 +63,14 @@ type gitSrcCfg struct {
6263
}
6364

6465
func buildGitConfig(ctx context.Context, c client.Client, originKey, srcKey types.NamespacedName, gitSpec *imagev1.GitSpec, opts SourceOptions) (*gitSrcCfg, error) {
66+
var err error
6567
cfg := &gitSrcCfg{
6668
srcKey: srcKey,
6769
}
6870

6971
// Get the repo.
7072
repo := &sourcev1.GitRepository{}
71-
if err := c.Get(ctx, srcKey, repo); err != nil {
73+
if err = c.Get(ctx, srcKey, repo); err != nil {
7274
if client.IgnoreNotFound(err) == nil {
7375
return nil, fmt.Errorf("referenced git repository does not exist: %w", err)
7476
}
@@ -94,14 +96,26 @@ func buildGitConfig(ctx context.Context, c client.Client, originKey, srcKey type
9496

9597
// Configure push first as the client options below depend on the push
9698
// configuration.
97-
if err := configurePush(cfg, gitSpec, cfg.checkoutRef); err != nil {
99+
if err = configurePush(cfg, gitSpec, cfg.checkoutRef); err != nil {
98100
return nil, err
99101
}
100102

101-
proxyOpts, proxyURL, err := getProxyOpts(ctx, c, repo)
102-
if err != nil {
103-
return nil, err
103+
var proxyURL *url.URL
104+
var proxyOpts *transport.ProxyOptions
105+
// Check if a proxy secret reference is provided in the GitRepository spec.
106+
if repo.Spec.ProxySecretRef != nil {
107+
secretRef := types.NamespacedName{
108+
Name: repo.Spec.ProxySecretRef.Name,
109+
Namespace: repo.GetNamespace(),
110+
}
111+
// Get the proxy URL from runtime/secret
112+
proxyURL, err = secrets.ProxyURLFromSecretRef(ctx, c, secretRef)
113+
if err != nil {
114+
return nil, err
115+
}
116+
proxyOpts = &transport.ProxyOptions{URL: proxyURL.String()}
104117
}
118+
105119
cfg.authOpts, err = getAuthOpts(ctx, c, repo, opts, proxyURL)
106120
if err != nil {
107121
return nil, err
@@ -165,13 +179,15 @@ func configurePush(cfg *gitSrcCfg, gitSpec *imagev1.GitSpec, checkoutRef *source
165179

166180
func getAuthOpts(ctx context.Context, c client.Client, repo *sourcev1.GitRepository,
167181
srcOpts SourceOptions, proxyURL *url.URL) (*git.AuthOptions, error) {
182+
var secret *corev1.Secret
168183
var data map[string][]byte
169184
var err error
170185
if repo.Spec.SecretRef != nil {
171-
data, err = getSecretData(ctx, c, repo.Spec.SecretRef.Name, repo.GetNamespace())
186+
secret, err = getSecret(ctx, c, repo.Spec.SecretRef.Name, repo.GetNamespace())
172187
if err != nil {
173188
return nil, fmt.Errorf("failed to get auth secret '%s/%s': %w", repo.GetNamespace(), repo.Spec.SecretRef.Name, err)
174189
}
190+
data = secret.Data
175191
}
176192

177193
u, err := url.Parse(repo.Spec.URL)
@@ -211,24 +227,34 @@ func getAuthOpts(ctx context.Context, c client.Client, repo *sourcev1.GitReposit
211227
if repo.Spec.SecretRef == nil {
212228
return nil, fmt.Errorf("secretRef with github app data must be specified when provider is set to github: %w", ErrInvalidSourceConfiguration)
213229
}
230+
targetURL := fmt.Sprintf("%s://%s", u.Scheme, u.Host)
231+
authMethods, err := secrets.AuthMethodsFromSecret(ctx, secret, secrets.WithTargetURL(targetURL), secrets.WithTLSSystemCertPool())
232+
if err != nil {
233+
return nil, err
234+
}
235+
if !authMethods.HasGitHubAppData() {
236+
return nil, fmt.Errorf("secretRef with github app data must be specified when provider is set to github: %w", ErrInvalidSourceConfiguration)
237+
}
214238

215239
getCreds = func() (*authutils.GitCredentials, error) {
216-
var opts []github.OptFunc
240+
var appOpts []github.OptFunc
217241

218-
if len(data) > 0 {
219-
opts = append(opts, github.WithAppData(data))
220-
}
242+
appOpts = append(appOpts, github.WithAppData(authMethods.GitHubAppData))
221243

222244
if proxyURL != nil {
223-
opts = append(opts, github.WithProxyURL(proxyURL))
245+
appOpts = append(appOpts, github.WithProxyURL(proxyURL))
224246
}
225247

226248
if srcOpts.tokenCache != nil {
227-
opts = append(opts, github.WithCache(srcOpts.tokenCache, imagev1.ImageUpdateAutomationKind,
249+
appOpts = append(appOpts, github.WithCache(srcOpts.tokenCache, imagev1.ImageUpdateAutomationKind,
228250
srcOpts.objName, srcOpts.objNamespace, cache.OperationReconcile))
229251
}
230252

231-
username, password, err := github.GetCredentials(ctx, opts...)
253+
if authMethods.HasTLS() {
254+
appOpts = append(appOpts, github.WithTLSConfig(authMethods.TLS))
255+
}
256+
257+
username, password, err := github.GetCredentials(ctx, appOpts...)
232258
if err != nil {
233259
return nil, err
234260
}
@@ -255,45 +281,6 @@ func getAuthOpts(ctx context.Context, c client.Client, repo *sourcev1.GitReposit
255281
return opts, nil
256282
}
257283

258-
func getProxyOpts(ctx context.Context, c client.Client, repo *sourcev1.GitRepository) (*transport.ProxyOptions, *url.URL, error) {
259-
if repo.Spec.ProxySecretRef == nil {
260-
return nil, nil, nil
261-
}
262-
name := repo.Spec.ProxySecretRef.Name
263-
namespace := repo.GetNamespace()
264-
proxyData, err := getSecretData(ctx, c, name, namespace)
265-
if err != nil {
266-
return nil, nil, fmt.Errorf("failed to get proxy secret '%s/%s': %w", namespace, name, err)
267-
}
268-
b, ok := proxyData["address"]
269-
if !ok {
270-
return nil, nil, fmt.Errorf("invalid proxy secret '%s/%s': key 'address' is missing", namespace, name)
271-
}
272-
273-
address := string(b)
274-
username := string(proxyData["username"])
275-
password := string(proxyData["password"])
276-
277-
proxyOpts := &transport.ProxyOptions{
278-
URL: address,
279-
Username: username,
280-
Password: password,
281-
}
282-
283-
proxyURL, err := url.Parse(string(address))
284-
if err != nil {
285-
return nil, nil, fmt.Errorf("invalid address in proxy secret '%s/%s': %w", namespace, name, err)
286-
}
287-
switch {
288-
case username != "" && password == "":
289-
proxyURL.User = url.User(username)
290-
case username != "" && password != "":
291-
proxyURL.User = url.UserPassword(username, password)
292-
}
293-
294-
return proxyOpts, proxyURL, nil
295-
}
296-
297284
func getSigningEntity(ctx context.Context, c client.Client, namespace string, gitSpec *imagev1.GitSpec) (*openpgp.Entity, error) {
298285
secretName := gitSpec.Commit.SigningKey.SecretRef.Name
299286
secretData, err := getSecretData(ctx, c, secretName, namespace)
@@ -330,13 +317,21 @@ func getSigningEntity(ctx context.Context, c client.Client, namespace string, gi
330317
}
331318

332319
func getSecretData(ctx context.Context, c client.Client, name, namespace string) (map[string][]byte, error) {
320+
secret, err := getSecret(ctx, c, name, namespace)
321+
if err != nil {
322+
return nil, err
323+
}
324+
return secret.Data, nil
325+
}
326+
327+
func getSecret(ctx context.Context, c client.Client, name, namespace string) (*corev1.Secret, error) {
333328
key := types.NamespacedName{
334329
Namespace: namespace,
335330
Name: name,
336331
}
337-
var secret corev1.Secret
338-
if err := c.Get(ctx, key, &secret); err != nil {
332+
secret := &corev1.Secret{}
333+
if err := c.Get(ctx, key, secret); err != nil {
339334
return nil, err
340335
}
341-
return secret.Data, nil
336+
return secret, nil
342337
}

internal/source/git_test.go

Lines changed: 23 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,9 @@ package source
1919
import (
2020
"context"
2121
"fmt"
22-
"net/url"
2322
"testing"
2423
"time"
2524

26-
"github.com/go-git/go-git/v5/plumbing/transport"
2725
. "github.com/onsi/gomega"
2826
corev1 "k8s.io/api/core/v1"
2927
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -32,12 +30,13 @@ import (
3230
"sigs.k8s.io/controller-runtime/pkg/client"
3331
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
3432

35-
imagev1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
36-
"github.com/fluxcd/image-automation-controller/internal/testutil"
3733
"github.com/fluxcd/pkg/apis/meta"
3834
"github.com/fluxcd/pkg/git"
3935
"github.com/fluxcd/pkg/git/github"
4036
sourcev1 "github.com/fluxcd/source-controller/api/v1"
37+
38+
imagev1 "github.com/fluxcd/image-automation-controller/api/v1beta2"
39+
"github.com/fluxcd/image-automation-controller/internal/testutil"
4140
)
4241

4342
func Test_getAuthOpts(t *testing.T) {
@@ -196,6 +195,26 @@ func Test_getAuthOpts_providerAuth(t *testing.T) {
196195
},
197196
wantErr: "Key must be a PEM encoded PKCS1 or PKCS8 key",
198197
},
198+
{
199+
name: "github provider with basic auth in secret",
200+
url: "https://example.com/org/repo",
201+
secret: &corev1.Secret{
202+
ObjectMeta: metav1.ObjectMeta{
203+
Name: "basic-auth-secret",
204+
},
205+
Data: map[string][]byte{
206+
"username": []byte("abc"),
207+
"password": []byte(""),
208+
},
209+
},
210+
beforeFunc: func(obj *sourcev1.GitRepository) {
211+
obj.Spec.Provider = sourcev1.GitProviderGitHub
212+
obj.Spec.SecretRef = &meta.LocalObjectReference{
213+
Name: "basic-auth-secret",
214+
}
215+
},
216+
wantErr: "secretRef with github app data must be specified when provider is set to github",
217+
},
199218
{
200219
name: "generic provider with github app data in secret",
201220
url: "https://example.com/org/repo",
@@ -266,94 +285,6 @@ func Test_getAuthOpts_providerAuth(t *testing.T) {
266285
}
267286
}
268287

269-
func Test_getProxyOpts(t *testing.T) {
270-
namespace := "default"
271-
invalidProxy := &corev1.Secret{
272-
ObjectMeta: metav1.ObjectMeta{
273-
Name: "invalid-proxy",
274-
Namespace: namespace,
275-
},
276-
Data: map[string][]byte{
277-
"url": []byte("https://example.com"),
278-
},
279-
}
280-
validProxy := &corev1.Secret{
281-
ObjectMeta: metav1.ObjectMeta{
282-
Name: "valid-proxy",
283-
Namespace: namespace,
284-
},
285-
Data: map[string][]byte{
286-
"address": []byte("https://example.com"),
287-
"username": []byte("user"),
288-
"password": []byte("pass"),
289-
},
290-
}
291-
292-
tests := []struct {
293-
name string
294-
secretName string
295-
want *transport.ProxyOptions
296-
wantProxyURL *url.URL
297-
wantErr bool
298-
}{
299-
{
300-
name: "non-existing secret",
301-
secretName: "non-existing",
302-
want: nil,
303-
wantProxyURL: nil,
304-
wantErr: true,
305-
},
306-
{
307-
name: "invalid proxy secret",
308-
secretName: "invalid-proxy",
309-
want: nil,
310-
wantProxyURL: nil,
311-
wantErr: true,
312-
},
313-
{
314-
name: "valid proxy secret",
315-
secretName: "valid-proxy",
316-
want: &transport.ProxyOptions{
317-
URL: "https://example.com",
318-
Username: "user",
319-
Password: "pass",
320-
},
321-
wantProxyURL: &url.URL{
322-
Scheme: "https",
323-
Host: "example.com",
324-
User: url.UserPassword("user", "pass"),
325-
},
326-
wantErr: false,
327-
},
328-
}
329-
for _, tt := range tests {
330-
t.Run(tt.name, func(t *testing.T) {
331-
g := NewWithT(t)
332-
333-
clientBuilder := fakeclient.NewClientBuilder().
334-
WithScheme(scheme.Scheme).
335-
WithObjects(invalidProxy, validProxy)
336-
c := clientBuilder.Build()
337-
338-
gitRepo := &sourcev1.GitRepository{}
339-
gitRepo.Namespace = namespace
340-
if tt.secretName != "" {
341-
gitRepo.Spec = sourcev1.GitRepositorySpec{
342-
ProxySecretRef: &meta.LocalObjectReference{Name: tt.secretName},
343-
}
344-
}
345-
346-
got, gotProxyURL, err := getProxyOpts(context.TODO(), c, gitRepo)
347-
if (err != nil) != tt.wantErr {
348-
g.Fail(fmt.Sprintf("unexpected error: %v", err))
349-
return
350-
}
351-
g.Expect(got).To(Equal(tt.want))
352-
g.Expect(gotProxyURL).To(Equal(tt.wantProxyURL))
353-
})
354-
}
355-
}
356-
357288
func Test_getSigningEntity(t *testing.T) {
358289
g := NewWithT(t)
359290

0 commit comments

Comments
 (0)