Skip to content

Commit 0e437a3

Browse files
committed
[RFC-007] Implement GitHub app authentication for git repositories.
- API change to add new `github` provider field in `GitRepository` spec. - Controller change to use the GitHub authentication information specified in `.spec.secretRef` to create the auth options to authenticate to git repositories when the `provider` field is set to `github`, - Tests for new `github` provider field - Updated docs to use GitHub Apps for authentication in source-controller. Signed-off-by: Dipti Pai <[email protected]>
1 parent 53868f7 commit 0e437a3

File tree

8 files changed

+99
-14
lines changed

8 files changed

+99
-14
lines changed

api/v1/gitrepository_types.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ const (
3535
// GitProviderAzure provides support for authentication to azure
3636
// repositories using Managed Identity.
3737
GitProviderAzure string = "azure"
38+
39+
// GitProviderGitHub provides support for authentication to git
40+
// repositories using GitHub App authentication
41+
GitProviderGitHub string = "github"
3842
)
3943

4044
const (
@@ -88,9 +92,9 @@ type GitRepositorySpec struct {
8892
// +optional
8993
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
9094

91-
// Provider used for authentication, can be 'azure', 'generic'.
95+
// Provider used for authentication, can be 'azure', 'github', 'generic'.
9296
// When not specified, defaults to 'generic'.
93-
// +kubebuilder:validation:Enum=generic;azure
97+
// +kubebuilder:validation:Enum=generic;azure;github
9498
// +optional
9599
Provider string `json:"provider,omitempty"`
96100

config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,12 @@ spec:
105105
type: string
106106
provider:
107107
description: |-
108-
Provider used for authentication, can be 'azure', 'generic'.
108+
Provider used for authentication, can be 'azure', 'github', 'generic'.
109109
When not specified, defaults to 'generic'.
110110
enum:
111111
- generic
112112
- azure
113+
- github
113114
type: string
114115
proxySecretRef:
115116
description: |-

docs/api/v1/source.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ string
390390
</td>
391391
<td>
392392
<em>(Optional)</em>
393-
<p>Provider used for authentication, can be &lsquo;azure&rsquo;, &lsquo;generic&rsquo;.
393+
<p>Provider used for authentication, can be &lsquo;azure&rsquo;, &lsquo;github&rsquo;, &lsquo;generic&rsquo;.
394394
When not specified, defaults to &lsquo;generic&rsquo;.</p>
395395
</td>
396396
</tr>
@@ -1730,7 +1730,7 @@ string
17301730
</td>
17311731
<td>
17321732
<em>(Optional)</em>
1733-
<p>Provider used for authentication, can be &lsquo;azure&rsquo;, &lsquo;generic&rsquo;.
1733+
<p>Provider used for authentication, can be &lsquo;azure&rsquo;, &lsquo;github&rsquo;, &lsquo;generic&rsquo;.
17341734
When not specified, defaults to &lsquo;generic&rsquo;.</p>
17351735
</td>
17361736
</tr>

docs/spec/v1/gitrepositories.md

+46
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ Supported options are:
221221

222222
- `generic`
223223
- `azure`
224+
- `github`
224225

225226
When provider is not specified, it defaults to `generic` indicating that
226227
mechanisms using `spec.secretRef` are used for authentication.
@@ -296,6 +297,51 @@ must follow this format:
296297
```
297298
https://dev.azure.com/{your-organization}/{your-project}/_git/{your-repository}
298299
```
300+
#### GitHub
301+
302+
The `github` provider can be used to authenticate to git repositories using
303+
[GitHub Apps](https://docs.github.com/en/apps/overview).
304+
305+
##### Pre-requisites
306+
307+
- [Register]((https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app))
308+
the GitHub App with the necessary permissions and [generate a private
309+
key](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps)
310+
for the app.
311+
312+
- [Install](https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app)
313+
the app in the organization/account configuring access to the necessary
314+
repositories.
315+
316+
##### Configure GitHub App secret
317+
318+
The GitHub App information is specified in `.spec.secretRef` in the format
319+
specified below:
320+
321+
* Get the App ID from the app settings page at
322+
`https://github.com/settings/apps/<app-name>`.
323+
* Get the App Installation ID from the app installations page at
324+
`https://github.com/settings/installations`. Click the installed app, the URL
325+
will contain the installation ID
326+
`https://github.com/settings/installations/<installation-id>`. For
327+
organizations, the first part of the URL may be different, but it follows the
328+
same pattern.
329+
* The private key that was generated in the pre-requisites.
330+
331+
```yaml
332+
apiVersion: v1
333+
kind: Secret
334+
metadata:
335+
name: github-sa
336+
type: Opaque
337+
stringData:
338+
githubAppID: <app-id>
339+
githubAppInstallationID: <app-installation-id>
340+
githubAppPrivateKey: |
341+
-----BEGIN RSA PRIVATE KEY-----
342+
...
343+
-----END RSA PRIVATE KEY-----
344+
```
299345

300346
### Interval
301347

go.mod

+8
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ require (
137137
github.com/beorn7/perks v1.0.1 // indirect
138138
github.com/blang/semver v3.5.1+incompatible // indirect
139139
github.com/blang/semver/v4 v4.0.0 // indirect
140+
github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 // indirect
140141
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 // indirect
141142
github.com/buildkite/agent/v3 v3.76.2 // indirect
142143
github.com/buildkite/go-pipeline v0.10.0 // indirect
@@ -221,6 +222,7 @@ require (
221222
github.com/google/go-cmp v0.6.0 // indirect
222223
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20230516205744-dbecb1de8cfa // indirect
223224
github.com/google/go-github/v55 v55.0.0 // indirect
225+
github.com/google/go-github/v62 v62.0.0 // indirect
224226
github.com/google/go-querystring v1.1.0 // indirect
225227
github.com/google/gofuzz v1.2.0 // indirect
226228
github.com/google/s2a-go v0.1.8 // indirect
@@ -407,3 +409,9 @@ require (
407409
)
408410

409411
retract v0.32.0 // Refers to incorrect ./api version.
412+
413+
replace github.com/fluxcd/pkg/auth => github.com/dipti-pai/pkg/auth v0.0.0-20241112210126-09c286242cc8
414+
415+
replace github.com/fluxcd/pkg/git/gogit => github.com/dipti-pai/pkg/git/gogit v0.0.0-20241112210126-09c286242cc8
416+
417+
replace github.com/fluxcd/pkg/git => github.com/dipti-pai/pkg/git v0.0.0-20241112210126-09c286242cc8

go.sum

+10-6
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn
202202
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
203203
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
204204
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
205+
github.com/bradleyfalzon/ghinstallation/v2 v2.11.0 h1:R9d0v+iobRHSaE4wKUnXFiZp53AL4ED5MzgEMwGTZag=
206+
github.com/bradleyfalzon/ghinstallation/v2 v2.11.0/go.mod h1:0LWKQwOHewXO/1acI6TtyE0Xc4ObDb2rFN7eHBAG71M=
205207
github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70=
206208
github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
207209
github.com/bsm/ginkgo/v2 v2.7.0/go.mod h1:AiKlXPm7ItEHNc/2+OkrNG4E0ITzojb9/xWzvQ9XZ9w=
@@ -290,6 +292,12 @@ github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1G
290292
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y=
291293
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
292294
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
295+
github.com/dipti-pai/pkg/auth v0.0.0-20241112210126-09c286242cc8 h1:FlhPrNBTBXmrqkauOIEa2jyZD4lEzX6/dN6E8XxaJEE=
296+
github.com/dipti-pai/pkg/auth v0.0.0-20241112210126-09c286242cc8/go.mod h1:hBf1c8e7+5utvTIB38NDRpaciDIf9A63okkIEtH3zhA=
297+
github.com/dipti-pai/pkg/git v0.0.0-20241112210126-09c286242cc8 h1:XeByD9Qq8X0CmzKNnPtr0lSTSV//Yl0WfKs6i6Bz7QQ=
298+
github.com/dipti-pai/pkg/git v0.0.0-20241112210126-09c286242cc8/go.mod h1:LUbu8ljvEk+ACKSRUM3Jeb9dpME63+Qjn0mgbQS5xBI=
299+
github.com/dipti-pai/pkg/git/gogit v0.0.0-20241112210126-09c286242cc8 h1:ltsT6WuqvNudJtMClCVRwAVYWBb/uG5xCQJeaQQgtjs=
300+
github.com/dipti-pai/pkg/git/gogit v0.0.0-20241112210126-09c286242cc8/go.mod h1:olbXMpeNBlL2IL665+X9WpdIKDaVgUKuBbnBGbPN3K8=
293301
github.com/distribution/distribution/v3 v3.0.0-beta.1 h1:X+ELTxPuZ1Xe5MsD3kp2wfGUhc8I+MPfRis8dZ818Ic=
294302
github.com/distribution/distribution/v3 v3.0.0-beta.1/go.mod h1:O9O8uamhHzWWQVTjuQpyYUVm/ShPHPUDgvQMpHGVBDs=
295303
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
@@ -348,14 +356,8 @@ github.com/fluxcd/pkg/apis/event v0.10.1 h1:3PIAWOtEWblw7R2NUiEMFahRLs3cyYWXQpsM
348356
github.com/fluxcd/pkg/apis/event v0.10.1/go.mod h1:MuOoVHW27i0KOoEEerSOg49VdUy4etKc3thbQIeXAmg=
349357
github.com/fluxcd/pkg/apis/meta v1.6.1 h1:maLhcRJ3P/70ArLCY/LF/YovkxXbX+6sTWZwZQBeNq0=
350358
github.com/fluxcd/pkg/apis/meta v1.6.1/go.mod h1:YndB/gxgGZmKfqpAfFxyCDNFJFP0ikpeJzs66jwq280=
351-
github.com/fluxcd/pkg/auth v0.0.1 h1:3fMg1EdkQdY2Rv1qHbiPPWCBa27xsNeu09y9SuZk6Co=
352-
github.com/fluxcd/pkg/auth v0.0.1/go.mod h1:tdCkiB3/LBg7CcxX1fhVmM5ZjDIaOduK0XX88pBXie0=
353359
github.com/fluxcd/pkg/cache v0.0.4 h1:TM733caGoj58GFCOKQN3GajdSVmFx8yNx0HY6l5wV+M=
354360
github.com/fluxcd/pkg/cache v0.0.4/go.mod h1:jE7QdMvS9SZcdQaDhUYUm2/fV/KORA362iCNMLdH4pw=
355-
github.com/fluxcd/pkg/git v0.21.0 h1:5FfcKj9bDVz8KwoOQUOSJABLMeSdhvLBf7yctwwuMzc=
356-
github.com/fluxcd/pkg/git v0.21.0/go.mod h1:iCCmUCunoFLgntySJfIDxsHGYfS97ky990gEKIDZ9lo=
357-
github.com/fluxcd/pkg/git/gogit v0.21.0 h1:iR2kzW1XrcBDYuC8zVIAdC/2/aeXuRkZ9jupdd54E6I=
358-
github.com/fluxcd/pkg/git/gogit v0.21.0/go.mod h1:gyoSlEIqzsOiTwSL0iFuEiJat+W0uGgc+WEiCVC1xk8=
359361
github.com/fluxcd/pkg/gittestserver v0.13.1 h1:5rXF8ANlk6wtAsvqH7tI7gaO2zhMySftf7ALh0AhfU4=
360362
github.com/fluxcd/pkg/gittestserver v0.13.1/go.mod h1:nPO7ibtBRgLWFHTSvxI63zZubJXU82cVMH6nViVnHsY=
361363
github.com/fluxcd/pkg/helmtestserver v0.20.0 h1:eNeon7D92DYkTnBShGBS1l5blpjW7IQ21U0gTpArbiE=
@@ -526,6 +528,8 @@ github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-2023051620574
526528
github.com/google/go-containerregistry/pkg/authn/kubernetes v0.0.0-20230516205744-dbecb1de8cfa/go.mod h1:KdL98/Va8Dy1irB6lTxIRIQ7bQj4lbrlvqUzKEQ+ZBU=
527529
github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg=
528530
github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA=
531+
github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4=
532+
github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4=
529533
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
530534
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
531535
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=

internal/controller/gitrepository_controller.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828

2929
securejoin "github.com/cyphar/filepath-securejoin"
3030
"github.com/fluxcd/pkg/auth/azure"
31+
"github.com/fluxcd/pkg/auth/github"
3132
"github.com/fluxcd/pkg/runtime/logger"
3233
"github.com/go-git/go-git/v5/plumbing/transport"
3334
corev1 "k8s.io/api/core/v1"
@@ -650,13 +651,21 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
650651
}
651652

652653
// Configure provider authentication if specified in spec
653-
if obj.GetProvider() == sourcev1.GitProviderAzure {
654+
switch obj.GetProvider() {
655+
case sourcev1.GitProviderAzure:
654656
authOpts.ProviderOpts = &git.ProviderOptions{
655-
Name: obj.GetProvider(),
657+
Name: sourcev1.GitProviderAzure,
656658
AzureOpts: []azure.OptFunc{
657659
azure.WithAzureDevOpsScope(),
658660
},
659661
}
662+
case sourcev1.GitProviderGitHub:
663+
authOpts.ProviderOpts = &git.ProviderOptions{
664+
Name: sourcev1.GitProviderGitHub,
665+
GitHubOpts: []github.OptFunc{
666+
github.WithAppData(authData),
667+
},
668+
}
660669
}
661670

662671
return authOpts, nil

internal/controller/gitrepository_controller_test.go

+14-1
Original file line numberDiff line numberDiff line change
@@ -686,23 +686,35 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
686686
func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
687687
tests := []struct {
688688
name string
689+
url string
689690
beforeFunc func(obj *sourcev1.GitRepository)
690691
wantProviderOptsName string
691692
}{
692693
{
693694
name: "azure provider",
695+
url: "https://dev.azure.com/foo/bar/_git/baz",
694696
beforeFunc: func(obj *sourcev1.GitRepository) {
695697
obj.Spec.Provider = sourcev1.GitProviderAzure
696698
},
697699
wantProviderOptsName: sourcev1.GitProviderAzure,
698700
},
701+
{
702+
name: "github provider",
703+
url: "https://github.com/org/repo.git",
704+
beforeFunc: func(obj *sourcev1.GitRepository) {
705+
obj.Spec.Provider = sourcev1.GitProviderGitHub
706+
},
707+
wantProviderOptsName: sourcev1.GitProviderGitHub,
708+
},
699709
{
700710
name: "generic provider",
711+
url: "https://example.com/org/repo",
701712
beforeFunc: func(obj *sourcev1.GitRepository) {
702713
obj.Spec.Provider = sourcev1.GitProviderGeneric
703714
},
704715
},
705716
{
717+
url: "https://example.com/org/repo",
706718
name: "no provider",
707719
},
708720
}
@@ -712,7 +724,8 @@ func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
712724
g := NewWithT(t)
713725
obj := &sourcev1.GitRepository{}
714726
r := &GitRepositoryReconciler{}
715-
url, _ := url.Parse("https://dev.azure.com/foo/bar/_git/baz")
727+
url, err := url.Parse(tt.url)
728+
g.Expect(err).ToNot(HaveOccurred())
716729

717730
if tt.beforeFunc != nil {
718731
tt.beforeFunc(obj)

0 commit comments

Comments
 (0)