Skip to content

Commit 030738f

Browse files
committed
Enable Azure OIDC for Azure DevOps Respository
- Add a new provider field to GitRepository API spec which can be set to azure to enable passwordless authentication to Azure DevOps repositories. - API docs for new provider field and guidance to setup Azure environment with workload identity. - Controller changes to set the provider options in git authoptions to fetch credential while cloning the repository. Signed-off-by: Dipti Pai <[email protected]>
1 parent b2f08f5 commit 030738f

File tree

7 files changed

+151
-13
lines changed

7 files changed

+151
-13
lines changed

api/v1/gitrepository_types.go

+15
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ import (
2727
const (
2828
// GitRepositoryKind is the string representation of a GitRepository.
2929
GitRepositoryKind = "GitRepository"
30+
31+
// GitProviderGeneric provides support for authentication using
32+
// credentials specified in secretRef.
33+
GitProviderGeneric string = "generic"
34+
35+
// GitProviderAzure provides support for authentication to azure
36+
// repositories using Managed Identity.
37+
GitProviderAzure string = "azure"
3038
)
3139

3240
const (
@@ -80,6 +88,13 @@ type GitRepositorySpec struct {
8088
// +optional
8189
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
8290

91+
// The provider used for authentication, can be 'azure', 'generic'.
92+
// When not specified, defaults to 'generic'.
93+
// +kubebuilder:validation:Enum=generic;azure
94+
// +kubebuilder:default:=generic
95+
// +optional
96+
Provider string `json:"provider,omitempty"`
97+
8398
// Interval at which the GitRepository URL is checked for updates.
8499
// This interval is approximate and may be subject to jitter to ensure
85100
// efficient use of resources.

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

+9
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,15 @@ spec:
103103
efficient use of resources.
104104
pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
105105
type: string
106+
provider:
107+
default: generic
108+
description: |-
109+
The provider used for authentication, can be 'azure', 'generic'.
110+
When not specified, defaults to 'generic'.
111+
enum:
112+
- generic
113+
- azure
114+
type: string
106115
proxySecretRef:
107116
description: |-
108117
ProxySecretRef specifies the Secret containing the proxy configuration

docs/api/v1/source.md

+26
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,19 @@ and &lsquo;known_hosts&rsquo; fields.</p>
104104
</tr>
105105
<tr>
106106
<td>
107+
<code>provider</code><br>
108+
<em>
109+
string
110+
</em>
111+
</td>
112+
<td>
113+
<em>(Optional)</em>
114+
<p>The provider used for authentication, can be &lsquo;azure&rsquo;, &lsquo;generic&rsquo;.
115+
When not specified, defaults to &lsquo;generic&rsquo;.</p>
116+
</td>
117+
</tr>
118+
<tr>
119+
<td>
107120
<code>interval</code><br>
108121
<em>
109122
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">
@@ -1016,6 +1029,19 @@ and &lsquo;known_hosts&rsquo; fields.</p>
10161029
</tr>
10171030
<tr>
10181031
<td>
1032+
<code>provider</code><br>
1033+
<em>
1034+
string
1035+
</em>
1036+
</td>
1037+
<td>
1038+
<em>(Optional)</em>
1039+
<p>The provider used for authentication, can be &lsquo;azure&rsquo;, &lsquo;generic&rsquo;.
1040+
When not specified, defaults to &lsquo;generic&rsquo;.</p>
1041+
</td>
1042+
</tr>
1043+
<tr>
1044+
<td>
10191045
<code>interval</code><br>
10201046
<em>
10211047
<a href="https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1#Duration">

docs/spec/v1/gitrepositories.md

+66
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,72 @@ For password-protected SSH private keys, the password must be provided
212212
via an additional `password` field in the secret. Flux CLI also supports
213213
this via the `--password` flag.
214214

215+
### Provider
216+
217+
`.spec.provider` is an optional field that allows specifying an OIDC provider
218+
used for authentication purposes.
219+
220+
Supported options are:
221+
222+
- `generic`
223+
- `azure`
224+
225+
When provider is not specified, it defaults to `generic` indicating that
226+
mechanisms using `spec.secretRef` are used for authentication.
227+
228+
#### Azure
229+
230+
The `azure` provider can be used to authenticate to Azure DevOps repositories
231+
automatically using Workload Identity.
232+
233+
##### Pre-requisites
234+
235+
- Ensure that your Azure DevOps Organization is [connected to Microsoft
236+
Entra](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/connect-organization-to-azure-ad?view=azure-devops)
237+
- Ensure Workload Identity is properly set up on your cluster and the mutating
238+
webhook is installed.
239+
- Create a managed identity and federated identity between the source-controller
240+
service account and managed identity. Please take a look at this
241+
[guide](https://azure.github.io/azure-workload-identity/docs/quick-start.html#6-establish-federated-identity-credential-between-the-identity-and-the-service-account-issuer--subject)
242+
- Ensure that the managed identity has required permissions to access the Azure
243+
DevOps repository as described
244+
[here](https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity?view=azure-devops#2-add-and-manage-service-principals-in-an-azure-devops-organization)
245+
246+
Add the following patch in `flux-system/kustomization.yaml` file:
247+
248+
```yaml
249+
apiVersion: kustomize.config.k8s.io/v1beta1
250+
kind: Kustomization
251+
resources:
252+
- gotk-components.yaml
253+
- gotk-sync.yaml
254+
patches:
255+
- patch: |-
256+
apiVersion: v1
257+
kind: ServiceAccount
258+
metadata:
259+
name: source-controller
260+
namespace: flux-system
261+
annotations:
262+
azure.workload.identity/client-id: <AZURE_CLIENT_ID>
263+
labels:
264+
azure.workload.identity/use: "true"
265+
- patch: |-
266+
apiVersion: apps/v1
267+
kind: Deployment
268+
metadata:
269+
name: source-controller
270+
namespace: flux-system
271+
labels:
272+
azure.workload.identity/use: "true"
273+
spec:
274+
template:
275+
metadata:
276+
labels:
277+
azure.workload.identity/use: "true"
278+
```
279+
280+
215281
### Interval
216282

217283
`.spec.interval` is a required field that specifies the interval at which the

go.mod

+9-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ require (
2424
github.com/fluxcd/cli-utils v0.36.0-flux.9
2525
github.com/fluxcd/pkg/apis/event v0.10.0
2626
github.com/fluxcd/pkg/apis/meta v1.6.0
27+
github.com/fluxcd/pkg/auth v0.0.0-00010101000000-000000000000
2728
github.com/fluxcd/pkg/git v0.20.0
2829
github.com/fluxcd/pkg/git/gogit v0.20.0
2930
github.com/fluxcd/pkg/gittestserver v0.13.0
@@ -179,7 +180,7 @@ require (
179180
github.com/felixge/httpsnoop v1.0.4 // indirect
180181
github.com/fluxcd/gitkit v0.6.0 // indirect
181182
github.com/fluxcd/pkg/apis/acl v0.3.0 // indirect
182-
github.com/fluxcd/pkg/cache v0.0.2 // indirect
183+
github.com/fluxcd/pkg/cache v0.0.3 // indirect
183184
github.com/fsnotify/fsnotify v1.7.0 // indirect
184185
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
185186
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
@@ -372,7 +373,7 @@ require (
372373
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
373374
golang.org/x/mod v0.20.0 // indirect
374375
golang.org/x/net v0.28.0 // indirect
375-
golang.org/x/sys v0.24.0 // indirect
376+
golang.org/x/sys v0.25.0 // indirect
376377
golang.org/x/term v0.23.0 // indirect
377378
golang.org/x/text v0.17.0 // indirect
378379
golang.org/x/time v0.6.0 // indirect
@@ -405,3 +406,9 @@ require (
405406
)
406407

407408
retract v0.32.0 // Refers to incorrect ./api version.
409+
410+
replace github.com/fluxcd/pkg/auth => github.com/dipti-pai/pkg/auth v0.0.0-20240906172542-16adfc971f2e
411+
412+
replace github.com/fluxcd/pkg/git => github.com/dipti-pai/pkg/git v0.0.0-20240906172542-16adfc971f2e
413+
414+
replace github.com/fluxcd/pkg/git/gogit => github.com/dipti-pai/pkg/git/gogit v0.0.0-20240906172542-16adfc971f2e

go.sum

+10-8
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,12 @@ github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 h1:lxmTCgmHE1G
291291
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7/go.mod h1:GvWntX9qiTlOud0WkQ6ewFm0LPy5JUR1Xo0Ngbd1w6Y=
292292
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
293293
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
294+
github.com/dipti-pai/pkg/auth v0.0.0-20240906172542-16adfc971f2e h1:2nIwoRVKfcm8a5vJXtcY3hhvJrSHzJwIfZiFKS685sM=
295+
github.com/dipti-pai/pkg/auth v0.0.0-20240906172542-16adfc971f2e/go.mod h1:0VS8EHPXNoB9q84OJg+t2LlkdIvWzttUPXhSxMKavGk=
296+
github.com/dipti-pai/pkg/git v0.0.0-20240906172542-16adfc971f2e h1:fdh8qioq01d2F6TV2/KnFglyhDQ+3fU8QC/omPMHTJA=
297+
github.com/dipti-pai/pkg/git v0.0.0-20240906172542-16adfc971f2e/go.mod h1:RDOIm/0qU6akK3F7JLcNY+TxaNJQOTuz3MIc/aXXPfU=
298+
github.com/dipti-pai/pkg/git/gogit v0.0.0-20240906172542-16adfc971f2e h1:1z0CTzAuJRvb8JjzmRZ0GyndgzYOObxXIZiSI39UUP4=
299+
github.com/dipti-pai/pkg/git/gogit v0.0.0-20240906172542-16adfc971f2e/go.mod h1:pX0wDKVhNINddJ3vtUS6ripizHTqjc+kk93CLO0UDmM=
294300
github.com/distribution/distribution/v3 v3.0.0-beta.1 h1:X+ELTxPuZ1Xe5MsD3kp2wfGUhc8I+MPfRis8dZ818Ic=
295301
github.com/distribution/distribution/v3 v3.0.0-beta.1/go.mod h1:O9O8uamhHzWWQVTjuQpyYUVm/ShPHPUDgvQMpHGVBDs=
296302
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
@@ -349,12 +355,8 @@ github.com/fluxcd/pkg/apis/event v0.10.0 h1:eMYXjMnLQ9jctPkTauuiBmEI127RjCKDf1zf
349355
github.com/fluxcd/pkg/apis/event v0.10.0/go.mod h1:pG/3gbSBLNy6YGZP2eajiyVgkEQDvva789t46PY6NFE=
350356
github.com/fluxcd/pkg/apis/meta v1.6.0 h1:93TcRpiph0OCoQh+cI+PM7E35kBW9dScuas9tWc90Dw=
351357
github.com/fluxcd/pkg/apis/meta v1.6.0/go.mod h1:ZOeHcvyVdZDC5ZOGV7YuwplIvAx6LvmpeyhfTcNZCnc=
352-
github.com/fluxcd/pkg/cache v0.0.2 h1:+x1VCNDQbTQ5AbrOpMH3ps3NGek+qt52+6z7UjUP818=
353-
github.com/fluxcd/pkg/cache v0.0.2/go.mod h1:Xo09Wdo2YIiqyNrQbwvp83hIzxevznsvhcy+6xFjbcM=
354-
github.com/fluxcd/pkg/git v0.20.0 h1:byUbxLLZ9AyVYmK16mvxY/iA/ZhNwA30GHKPKNh7pik=
355-
github.com/fluxcd/pkg/git v0.20.0/go.mod h1:YnBOFhX7zzyVjg/u1Et1xBqXs30kb2sWWesIl3/glhw=
356-
github.com/fluxcd/pkg/git/gogit v0.20.0 h1:ZlWq//I465lv9aEEWaJhjJaTiTtnjcH+Td0fg1rPXWU=
357-
github.com/fluxcd/pkg/git/gogit v0.20.0/go.mod h1:ZA4WsKr28cj1yuplxOw9vHgCL4OCNJJLib1cJ77Tp9o=
358+
github.com/fluxcd/pkg/cache v0.0.3 h1:VK5joG/p+amh5Ob+r1OFOx0cCYiswEf8mX1/J1BG7Mw=
359+
github.com/fluxcd/pkg/cache v0.0.3/go.mod h1:UU6oFhV+mG0A5/RwIlvXhyuKlJwQEkk92jVB3vKMLtk=
358360
github.com/fluxcd/pkg/gittestserver v0.13.0 h1:6rvD9Z7+4zBcNT+LK0z4H0z6mDaw1Zd8ZaLh/dw8dzI=
359361
github.com/fluxcd/pkg/gittestserver v0.13.0/go.mod h1:LDw32Wo9mTmKNmJq4g7LRVBqPXlpMIWFBDOrRRh/+As=
360362
github.com/fluxcd/pkg/helmtestserver v0.19.0 h1:DbidD46we8iLp/Sxn2TO8twtlP5gxFQaP3XTNJC0bl8=
@@ -1210,8 +1212,8 @@ golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
12101212
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
12111213
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
12121214
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1213-
golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
1214-
golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1215+
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
1216+
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
12151217
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
12161218
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
12171219
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=

internal/controller/gitrepository_controller.go

+16-3
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"time"
2828

2929
securejoin "github.com/cyphar/filepath-securejoin"
30+
"github.com/fluxcd/pkg/auth/azure"
3031
"github.com/fluxcd/pkg/runtime/logger"
3132
"github.com/go-git/go-git/v5/plumbing/transport"
3233
corev1 "k8s.io/api/core/v1"
@@ -127,9 +128,8 @@ type GitRepositoryReconciler struct {
127128
kuberecorder.EventRecorder
128129
helper.Metrics
129130

130-
Storage *Storage
131-
ControllerName string
132-
131+
Storage *Storage
132+
ControllerName string
133133
requeueDependency time.Duration
134134
features map[string]bool
135135

@@ -647,6 +647,19 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
647647
if err != nil {
648648
return nil, err
649649
}
650+
651+
// Configure provider authentication if specified in spec
652+
if obj.Spec.Provider != "" && obj.Spec.Provider != sourcev1.GitProviderGeneric {
653+
if obj.Spec.Provider == sourcev1.GitProviderAzure {
654+
authOpts.ProviderOpts = &git.ProviderOptions{
655+
Name: obj.Spec.Provider,
656+
AzureOpts: []azure.OptFunc{
657+
azure.WithAzureDevOpsScope(),
658+
},
659+
}
660+
}
661+
}
662+
650663
return authOpts, nil
651664
}
652665

0 commit comments

Comments
 (0)