Skip to content

Commit 5000fd3

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): update target URL for TLSConfigFromSecret this commit ensures that the target URL for runtime/secrets.TLSConfigFromSecret has the scheme and host Signed-off-by: abhijith-darshan <[email protected]> (chore): adds test scenarios this commit adds test scenarios for mTLS GitHub app in reconcile source auth strategy Signed-off-by: abhijith-darshan <[email protected]> (chore): use runtime/secrets authMethods this commit ensures that GitHubApp secret resolution happens via pkg/runtime/secrets Signed-off-by: abhijith-darshan <[email protected]> (chore): update docs Signed-off-by: abhijith-darshan <[email protected]> (chore): adds github app data check this commit ensures that when provider is github and no github app data is present in the secret, it will error out with invalid configuration Signed-off-by: abhijith-darshan <[email protected]> (chore): removes getProxyOpts helper func this commit removes the helper method getProxyOpts and uses the standardized pkg/runtime/secrets APIs to get proxy options. Signed-off-by: abhijith-darshan <[email protected]> (chore): removes getProxyOpts test Signed-off-by: abhijith-darshan <[email protected]>
1 parent c2b572b commit 5000fd3

File tree

5 files changed

+142
-141
lines changed

5 files changed

+142
-141
lines changed

docs/spec/v1/gitrepositories.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ same pattern.
357357
- The private key that was generated in the pre-requisites.
358358
- (Optional) GitHub Enterprise Server users can set the base URL to
359359
`http(s)://HOSTNAME/api/v3`.
360+
- (Optional) If GitHub Enterprise Server uses a private CA, include its bundle (root and any intermediates) in `ca.crt`.
361+
If the `ca.crt` is specified, then it will be used for TLS verification for all API / Git over `HTTPS` requests to the GitHub Enterprise Server.
360362

361363
```yaml
362364
apiVersion: v1
@@ -372,6 +374,10 @@ stringData:
372374
...
373375
-----END RSA PRIVATE KEY-----
374376
githubAppBaseURL: "<github-enterprise-api-url>" #optional, required only for GitHub Enterprise Server users
377+
ca.crt: | #optional, for GitHub Enterprise Server users
378+
-----BEGIN CERTIFICATE-----
379+
...
380+
-----END CERTIFICATE-----
375381
```
376382

377383
Alternatively, the Flux CLI can be used to automatically create the secret with

go.mod

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ require (
3030
github.com/fluxcd/pkg/apis/meta v1.18.0
3131
github.com/fluxcd/pkg/auth v0.21.0
3232
github.com/fluxcd/pkg/cache v0.10.0
33-
github.com/fluxcd/pkg/git v0.34.0
34-
github.com/fluxcd/pkg/git/gogit v0.37.0
33+
github.com/fluxcd/pkg/git v0.35.0
34+
github.com/fluxcd/pkg/git/gogit v0.38.0
3535
github.com/fluxcd/pkg/gittestserver v0.18.0
3636
github.com/fluxcd/pkg/helmtestserver v0.26.0
3737
github.com/fluxcd/pkg/http/transport v0.6.0
3838
github.com/fluxcd/pkg/lockedfile v0.6.0
3939
github.com/fluxcd/pkg/masktoken v0.7.0
4040
github.com/fluxcd/pkg/oci v0.51.0
41-
github.com/fluxcd/pkg/runtime v0.78.0
41+
github.com/fluxcd/pkg/runtime v0.79.0
4242
github.com/fluxcd/pkg/sourceignore v0.13.0
4343
github.com/fluxcd/pkg/ssh v0.20.0
4444
github.com/fluxcd/pkg/tar v0.13.0

go.sum

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -382,10 +382,10 @@ github.com/fluxcd/pkg/auth v0.21.0 h1:ckAQqP12wuptXEkMY18SQKWEY09m9e6yI0mEMsDV15
382382
github.com/fluxcd/pkg/auth v0.21.0/go.mod h1:MXmpsXT97c874HCw5hnfqFUP7TsG8/Ss1vFrk8JccfM=
383383
github.com/fluxcd/pkg/cache v0.10.0 h1:M+OGDM4da1cnz7q+sZSBtkBJHpiJsLnKVmR9OdMWxEY=
384384
github.com/fluxcd/pkg/cache v0.10.0/go.mod h1:pPXRzQUDQagsCniuOolqVhnAkbNgYOg8d2cTliPs7ME=
385-
github.com/fluxcd/pkg/git v0.34.0 h1:qTViWkfpEDnjzySyKRKliqUeGj/DznqlkmPhaDNIsFY=
386-
github.com/fluxcd/pkg/git v0.34.0/go.mod h1:F9Asm3MlLW4uZx3FF92+bqho+oktdMdnTn/QmXe56NE=
387-
github.com/fluxcd/pkg/git/gogit v0.37.0 h1:JINylFYpwrxS3MCu5Ei+g6XPgxbs5lv9PppIYYr07KY=
388-
github.com/fluxcd/pkg/git/gogit v0.37.0/go.mod h1:X7YzW5mb4srA05h4SpL2OEGEHq02tbXQF5DPJen9hlc=
385+
github.com/fluxcd/pkg/git v0.35.0 h1:mAauhsdfxNW4yQdXviVlvcN/uCGGG0+6p5D1+HFZI9w=
386+
github.com/fluxcd/pkg/git v0.35.0/go.mod h1:F9Asm3MlLW4uZx3FF92+bqho+oktdMdnTn/QmXe56NE=
387+
github.com/fluxcd/pkg/git/gogit v0.38.0 h1:222KmjpKf9pxqi8rAtm1omDcpGTY4JkahLrAwZ3AcwU=
388+
github.com/fluxcd/pkg/git/gogit v0.38.0/go.mod h1:kHStdfd/AtkH5ED0UEWP2tmMGnfxg1GG92D29M+lRJ0=
389389
github.com/fluxcd/pkg/gittestserver v0.18.0 h1:jkuLmzWFfq+v1ziI0LspZrUzc5WzCO98BaWb8OVRPtk=
390390
github.com/fluxcd/pkg/gittestserver v0.18.0/go.mod h1:2wDLqUkPuixk/8pGQdef9ewaGJXf7Z+xHDVq8PIFG4E=
391391
github.com/fluxcd/pkg/helmtestserver v0.26.0 h1:gKw1MGqWwN94nzs2yg3WKgMxi1RqqlDZXlGziaNCcv4=
@@ -398,8 +398,8 @@ github.com/fluxcd/pkg/masktoken v0.7.0 h1:pitmyOg2pUVdW+nn2Lk/xqm2TaA08uxvOC0ns3
398398
github.com/fluxcd/pkg/masktoken v0.7.0/go.mod h1:Lc1uoDjO1GY6+YdkK+ZqqBIBWquyV58nlSJ5S1N1IYU=
399399
github.com/fluxcd/pkg/oci v0.51.0 h1:9oYnm+T4SCVSBif9gn80ALJkMGSERabVMDJiaMIdr7Y=
400400
github.com/fluxcd/pkg/oci v0.51.0/go.mod h1:5J6IhHoDVYCVeBEC+4E3nPeKh7d0kjJ8IEL6NVCiTx4=
401-
github.com/fluxcd/pkg/runtime v0.78.0 h1:xwNZqnazmgURGuLiHDbzST6BI5K9fvZuNS4eMVY35Es=
402-
github.com/fluxcd/pkg/runtime v0.78.0/go.mod h1:iGhdaEq+lMJQTJNAFEPOU4gUJ7kt3yeDcJPZy7O9IUw=
401+
github.com/fluxcd/pkg/runtime v0.79.0 h1:9tv79EiQDx/QJH9mYDd9kZ9WybCVWBUGoiBHij+eKkc=
402+
github.com/fluxcd/pkg/runtime v0.79.0/go.mod h1:iGhdaEq+lMJQTJNAFEPOU4gUJ7kt3yeDcJPZy7O9IUw=
403403
github.com/fluxcd/pkg/sourceignore v0.13.0 h1:ZvkzX2WsmyZK9cjlqOFFW1onHVzhPZIqDbCh96rPqbU=
404404
github.com/fluxcd/pkg/sourceignore v0.13.0/go.mod h1:Z9H1GoBx0ljOhptnzoV0PL6Nd/UzwKcSphP27lqb4xI=
405405
github.com/fluxcd/pkg/ssh v0.20.0 h1:Ak0laIYIc/L8lEfqls/LDWRW8wYPESGaravQsCRGLb8=

internal/controller/gitrepository_controller.go

Lines changed: 37 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131
authutils "github.com/fluxcd/pkg/auth/utils"
3232
"github.com/fluxcd/pkg/git/github"
3333
"github.com/fluxcd/pkg/runtime/logger"
34+
"github.com/fluxcd/pkg/runtime/secrets"
3435
"github.com/go-git/go-git/v5/plumbing/transport"
3536
corev1 "k8s.io/api/core/v1"
3637
"k8s.io/apimachinery/pkg/runtime"
@@ -485,7 +486,11 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
485486
var proxyURL *url.URL
486487
if obj.Spec.ProxySecretRef != nil {
487488
var err error
488-
proxyOpts, proxyURL, err = r.getProxyOpts(ctx, obj.Spec.ProxySecretRef.Name, obj.GetNamespace())
489+
secretRef := types.NamespacedName{
490+
Name: obj.Spec.ProxySecretRef.Name,
491+
Namespace: obj.GetNamespace(),
492+
}
493+
proxyURL, err = secrets.ProxyURLFromSecretRef(ctx, r.Client, secretRef)
489494
if err != nil {
490495
e := serror.NewGeneric(
491496
fmt.Errorf("failed to configure proxy options: %w", err),
@@ -495,6 +500,7 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
495500
// Return error as the world as observed may change
496501
return sreconcile.ResultEmpty, e
497502
}
503+
proxyOpts = &transport.ProxyOptions{URL: proxyURL.String()}
498504
}
499505

500506
u, err := url.Parse(obj.Spec.URL)
@@ -617,52 +623,16 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
617623
return sreconcile.ResultSuccess, nil
618624
}
619625

620-
// getProxyOpts fetches the secret containing the proxy settings, constructs a
621-
// transport.ProxyOptions object using those settings and then returns it.
622-
func (r *GitRepositoryReconciler) getProxyOpts(ctx context.Context, proxySecretName,
623-
proxySecretNamespace string) (*transport.ProxyOptions, *url.URL, error) {
624-
proxyData, err := r.getSecretData(ctx, proxySecretName, proxySecretNamespace)
625-
if err != nil {
626-
return nil, nil, fmt.Errorf("failed to get proxy secret '%s/%s': %w", proxySecretNamespace, proxySecretName, err)
627-
}
628-
b, ok := proxyData["address"]
629-
if !ok {
630-
return nil, nil, fmt.Errorf("invalid proxy secret '%s/%s': key 'address' is missing", proxySecretNamespace, proxySecretName)
631-
}
632-
633-
address := string(b)
634-
username := string(proxyData["username"])
635-
password := string(proxyData["password"])
636-
637-
proxyOpts := &transport.ProxyOptions{
638-
URL: address,
639-
Username: username,
640-
Password: password,
641-
}
642-
643-
proxyURL, err := url.Parse(string(address))
644-
if err != nil {
645-
return nil, nil, fmt.Errorf("invalid address in proxy secret '%s/%s': %w", proxySecretNamespace, proxySecretName, err)
646-
}
647-
switch {
648-
case username != "" && password == "":
649-
proxyURL.User = url.User(username)
650-
case username != "" && password != "":
651-
proxyURL.User = url.UserPassword(username, password)
652-
}
653-
654-
return proxyOpts, proxyURL, nil
655-
}
656-
657626
// getAuthOpts fetches the secret containing the auth options (if specified),
658627
// constructs a git.AuthOptions object using those options along with the provided
659628
// URL and returns it.
660629
func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1.GitRepository,
661630
u url.URL, proxyURL *url.URL) (*git.AuthOptions, error) {
631+
var secret *corev1.Secret
662632
var authData map[string][]byte
663633
if obj.Spec.SecretRef != nil {
664634
var err error
665-
authData, err = r.getSecretData(ctx, obj.Spec.SecretRef.Name, obj.GetNamespace())
635+
secret, err = r.getSecret(ctx, obj.Spec.SecretRef.Name, obj.GetNamespace())
666636
if err != nil {
667637
e := serror.NewGeneric(
668638
fmt.Errorf("failed to get secret '%s/%s': %w", obj.GetNamespace(), obj.Spec.SecretRef.Name, err),
@@ -671,6 +641,7 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
671641
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
672642
return nil, e
673643
}
644+
authData = secret.Data
674645
}
675646

676647
// Configure authentication strategy to access the source
@@ -717,24 +688,38 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
717688
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
718689
return nil, e
719690
}
720-
691+
targetURL := fmt.Sprintf("%s://%s", u.Scheme, u.Host)
692+
authMethods, err := secrets.AuthMethodsFromSecret(ctx, secret, secrets.WithTargetURL(targetURL), secrets.WithTLSSystemCertPool())
693+
if err != nil {
694+
return nil, err
695+
}
696+
if !authMethods.HasGitHubAppData() {
697+
e := serror.NewStalling(
698+
fmt.Errorf("secretRef with github app data must be specified when provider is set to github"),
699+
sourcev1.InvalidProviderConfigurationReason,
700+
)
701+
conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e)
702+
return nil, e
703+
}
721704
getCreds = func() (*authutils.GitCredentials, error) {
722-
var opts []github.OptFunc
705+
var appOpts []github.OptFunc
723706

724-
if len(authData) > 0 {
725-
opts = append(opts, github.WithAppData(authData))
726-
}
707+
appOpts = append(appOpts, github.WithAppData(authMethods.GitHubAppData))
727708

728709
if proxyURL != nil {
729-
opts = append(opts, github.WithProxyURL(proxyURL))
710+
appOpts = append(appOpts, github.WithProxyURL(proxyURL))
730711
}
731712

732713
if r.TokenCache != nil {
733-
opts = append(opts, github.WithCache(r.TokenCache, sourcev1.GitRepositoryKind,
714+
appOpts = append(appOpts, github.WithCache(r.TokenCache, sourcev1.GitRepositoryKind,
734715
obj.GetName(), obj.GetNamespace(), cache.OperationReconcile))
735716
}
736717

737-
username, password, err := github.GetCredentials(ctx, opts...)
718+
if authMethods.HasTLS() {
719+
appOpts = append(appOpts, github.WithTLSConfig(authMethods.TLS))
720+
}
721+
722+
username, password, err := github.GetCredentials(ctx, appOpts...)
738723
if err != nil {
739724
return nil, err
740725
}
@@ -771,16 +756,16 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
771756
return opts, nil
772757
}
773758

774-
func (r *GitRepositoryReconciler) getSecretData(ctx context.Context, name, namespace string) (map[string][]byte, error) {
759+
func (r *GitRepositoryReconciler) getSecret(ctx context.Context, name, namespace string) (*corev1.Secret, error) {
775760
key := types.NamespacedName{
776761
Namespace: namespace,
777762
Name: name,
778763
}
779-
var secret corev1.Secret
780-
if err := r.Client.Get(ctx, key, &secret); err != nil {
781-
return nil, err
764+
secret := &corev1.Secret{}
765+
if err := r.Client.Get(ctx, key, secret); err != nil {
766+
return nil, fmt.Errorf("failed to get secret '%s/%s': %w", namespace, name, err)
782767
}
783-
return secret.Data, nil
768+
return secret, nil
784769
}
785770

786771
// reconcileArtifact archives a new Artifact to the Storage, if the current

0 commit comments

Comments
 (0)