From 48417bdc8bd7bcff23339e7fa5807c57c812cd13 Mon Sep 17 00:00:00 2001
From: Dipti Pai
Date: Thu, 22 Aug 2024 22:41:55 -0700
Subject: [PATCH] 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.
- Add unit tests for testing provider
Signed-off-by: Dipti Pai
---
api/v1/gitrepository_types.go | 15 ++++
...rce.toolkit.fluxcd.io_gitrepositories.yaml | 9 ++
docs/api/v1/source.md | 26 ++++++
docs/spec/v1/gitrepositories.md | 85 +++++++++++++++++++
go.mod | 21 ++---
go.sum | 42 ++++-----
.../controller/gitrepository_controller.go | 14 +++
.../gitrepository_controller_test.go | 48 +++++++++++
8 files changed, 230 insertions(+), 30 deletions(-)
diff --git a/api/v1/gitrepository_types.go b/api/v1/gitrepository_types.go
index 0d3b3abea..bfe309871 100644
--- a/api/v1/gitrepository_types.go
+++ b/api/v1/gitrepository_types.go
@@ -27,6 +27,14 @@ import (
const (
// GitRepositoryKind is the string representation of a GitRepository.
GitRepositoryKind = "GitRepository"
+
+ // GitProviderGeneric provides support for authentication using
+ // credentials specified in secretRef.
+ GitProviderGeneric string = "generic"
+
+ // GitProviderAzure provides support for authentication to azure
+ // repositories using Managed Identity.
+ GitProviderAzure string = "azure"
)
const (
@@ -80,6 +88,13 @@ type GitRepositorySpec struct {
// +optional
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
+ // Provider used for authentication, can be 'azure', 'generic'.
+ // When not specified, defaults to 'generic'.
+ // +kubebuilder:validation:Enum=generic;azure
+ // +kubebuilder:default:=generic
+ // +optional
+ Provider string `json:"provider,omitempty"`
+
// Interval at which the GitRepository URL is checked for updates.
// This interval is approximate and may be subject to jitter to ensure
// efficient use of resources.
diff --git a/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml
index f12533ad6..e7a48ee25 100644
--- a/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml
+++ b/config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml
@@ -103,6 +103,15 @@ spec:
efficient use of resources.
pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$
type: string
+ provider:
+ default: generic
+ description: |-
+ Provider used for authentication, can be 'azure', 'generic'.
+ When not specified, defaults to 'generic'.
+ enum:
+ - generic
+ - azure
+ type: string
proxySecretRef:
description: |-
ProxySecretRef specifies the Secret containing the proxy configuration
diff --git a/docs/api/v1/source.md b/docs/api/v1/source.md
index 1424cdecc..521dddc14 100644
--- a/docs/api/v1/source.md
+++ b/docs/api/v1/source.md
@@ -383,6 +383,19 @@ and ‘known_hosts’ fields.
+provider
+
+string
+
+ |
+
+(Optional)
+ Provider used for authentication, can be ‘azure’, ‘generic’.
+When not specified, defaults to ‘generic’.
+ |
+
+
+
interval
@@ -1710,6 +1723,19 @@ and ‘known_hosts’ fields.
|
+provider
+
+string
+
+ |
+
+(Optional)
+ Provider used for authentication, can be ‘azure’, ‘generic’.
+When not specified, defaults to ‘generic’.
+ |
+
+
+
interval
diff --git a/docs/spec/v1/gitrepositories.md b/docs/spec/v1/gitrepositories.md
index 4170d9f1b..e78aee74a 100644
--- a/docs/spec/v1/gitrepositories.md
+++ b/docs/spec/v1/gitrepositories.md
@@ -212,6 +212,91 @@ For password-protected SSH private keys, the password must be provided
via an additional `password` field in the secret. Flux CLI also supports
this via the `--password` flag.
+### Provider
+
+`.spec.provider` is an optional field that allows specifying an OIDC provider
+used for authentication purposes.
+
+Supported options are:
+
+- `generic`
+- `azure`
+
+When provider is not specified, it defaults to `generic` indicating that
+mechanisms using `spec.secretRef` are used for authentication.
+
+#### Azure
+
+The `azure` provider can be used to authenticate to Azure DevOps repositories
+automatically using Workload Identity.
+
+##### Pre-requisites
+
+- Ensure that your Azure DevOps Organization is
+ [connected](https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/connect-organization-to-azure-ad?view=azure-devops)
+ to Microsoft Entra.
+- Ensure Workload Identity is properly [set up on your
+ cluster](https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster#create-an-aks-cluster).
+
+##### Configure Flux controller
+
+- Create a managed identity to access Azure DevOps. Establish a federated
+ identity credential between the managed identity and the source-controller
+ service account. In the default installation, the source-controller service
+ account is located in the `flux-system` namespace with name
+ `source-controller`. Ensure the federated credential uses the correct
+ namespace and name of the source-controller service account. For more details,
+ please refer to this
+ [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).
+
+- Add the managed identity to the Azure DevOps organization as a user. Ensure
+ that the managed identity has the necessary permissions to access the Azure
+ DevOps repository as described
+ [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).
+
+- Add the following patch to your bootstrap repository in
+ `flux-system/kustomization.yaml` file:
+
+
+```yaml
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+resources:
+ - gotk-components.yaml
+ - gotk-sync.yaml
+patches:
+ - patch: |-
+ apiVersion: v1
+ kind: ServiceAccount
+ metadata:
+ name: source-controller
+ namespace: flux-system
+ annotations:
+ azure.workload.identity/client-id:
+ labels:
+ azure.workload.identity/use: "true"
+ - patch: |-
+ apiVersion: apps/v1
+ kind: Deployment
+ metadata:
+ name: source-controller
+ namespace: flux-system
+ labels:
+ azure.workload.identity/use: "true"
+ spec:
+ template:
+ metadata:
+ labels:
+ azure.workload.identity/use: "true"
+```
+
+**Note:** When azure `provider` is used with `GitRepository`, the `.spec.url`
+must follow this format:
+
+```
+https://dev.azure.com/{your-organization}/{your-project}/_git/{your-repository}
+```
+
### Interval
`.spec.interval` is a required field that specifies the interval at which the
diff --git a/go.mod b/go.mod
index 1406a0b81..b52ca41d9 100644
--- a/go.mod
+++ b/go.mod
@@ -16,7 +16,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0
github.com/Masterminds/semver/v3 v3.3.0
- github.com/cyphar/filepath-securejoin v0.3.1
+ github.com/cyphar/filepath-securejoin v0.3.2
github.com/distribution/distribution/v3 v3.0.0-beta.1
github.com/docker/cli v27.2.1+incompatible
github.com/docker/go-units v0.5.0
@@ -24,19 +24,20 @@ require (
github.com/fluxcd/cli-utils v0.36.0-flux.9
github.com/fluxcd/pkg/apis/event v0.10.0
github.com/fluxcd/pkg/apis/meta v1.6.0
- github.com/fluxcd/pkg/git v0.20.0
- github.com/fluxcd/pkg/git/gogit v0.20.0
- github.com/fluxcd/pkg/gittestserver v0.13.0
+ github.com/fluxcd/pkg/auth v0.0.1
+ github.com/fluxcd/pkg/git v0.21.0
+ github.com/fluxcd/pkg/git/gogit v0.21.0
+ github.com/fluxcd/pkg/gittestserver v0.13.1
github.com/fluxcd/pkg/helmtestserver v0.19.0
github.com/fluxcd/pkg/lockedfile v0.3.0
github.com/fluxcd/pkg/masktoken v0.4.0
github.com/fluxcd/pkg/oci v0.41.0
github.com/fluxcd/pkg/runtime v0.49.0
github.com/fluxcd/pkg/sourceignore v0.8.0
- github.com/fluxcd/pkg/ssh v0.14.0
+ github.com/fluxcd/pkg/ssh v0.14.1
github.com/fluxcd/pkg/tar v0.8.0
github.com/fluxcd/pkg/testserver v0.7.0
- github.com/fluxcd/pkg/version v0.4.0
+ github.com/fluxcd/pkg/version v0.4.1
github.com/fluxcd/source-controller/api v1.3.0
github.com/foxcpp/go-mockdns v1.1.0
github.com/go-git/go-billy/v5 v5.5.0
@@ -146,7 +147,7 @@ require (
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
- github.com/cloudflare/circl v1.3.9 // indirect
+ github.com/cloudflare/circl v1.4.0 // indirect
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
github.com/containerd/containerd v1.7.20 // indirect
github.com/containerd/continuity v0.4.3 // indirect
@@ -371,13 +372,13 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
- golang.org/x/mod v0.20.0 // indirect
- golang.org/x/net v0.28.0 // indirect
+ golang.org/x/mod v0.21.0 // indirect
+ golang.org/x/net v0.29.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/term v0.24.0 // indirect
golang.org/x/text v0.18.0 // indirect
golang.org/x/time v0.6.0 // indirect
- golang.org/x/tools v0.24.0 // indirect
+ golang.org/x/tools v0.25.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect
diff --git a/go.sum b/go.sum
index 5fe9a5a41..5bd9d7ac5 100644
--- a/go.sum
+++ b/go.sum
@@ -239,8 +239,8 @@ github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyM
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
-github.com/cloudflare/circl v1.3.9 h1:QFrlgFYf2Qpi8bSpVPK1HBvWpx16v/1TZivyo7pGuBE=
-github.com/cloudflare/circl v1.3.9/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
+github.com/cloudflare/circl v1.4.0 h1:BV7h5MgrktNzytKmWjpOtdYrf0lkkbF8YMlBGPhJQrY=
+github.com/cloudflare/circl v1.4.0/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/apd/v3 v3.2.1 h1:U+8j7t0axsIgvQUqthuNm82HIrYXodOV2iWLWtEaIwg=
github.com/cockroachdb/apd/v3 v3.2.1/go.mod h1:klXJcjp+FffLTHlhIG69tezTDvdP065naDsHzKhYSqc=
@@ -271,8 +271,8 @@ github.com/creack/pty v1.1.19 h1:tUN6H7LWqNx4hQVxomd0CVsDwaDr9gaRQaI4GpSmrsA=
github.com/creack/pty v1.1.19/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 h1:2Dx4IHfC1yHWI12AxQDJM1QbRCDfk6M+blLzlZCXdrc=
github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
-github.com/cyphar/filepath-securejoin v0.3.1 h1:1V7cHiaW+C+39wEfpH6XlLBQo3j/PciWFrgfCLS8XrE=
-github.com/cyphar/filepath-securejoin v0.3.1/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzwRZm4NQsGTBdpp6mETc=
+github.com/cyphar/filepath-securejoin v0.3.2 h1:QhZu5AxQ+o1XZH0Ye05YzvJ0kAdK6VQc0z9NNMek7gc=
+github.com/cyphar/filepath-securejoin v0.3.2/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzwRZm4NQsGTBdpp6mETc=
github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs=
github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -348,14 +348,16 @@ github.com/fluxcd/pkg/apis/event v0.10.0 h1:eMYXjMnLQ9jctPkTauuiBmEI127RjCKDf1zf
github.com/fluxcd/pkg/apis/event v0.10.0/go.mod h1:pG/3gbSBLNy6YGZP2eajiyVgkEQDvva789t46PY6NFE=
github.com/fluxcd/pkg/apis/meta v1.6.0 h1:93TcRpiph0OCoQh+cI+PM7E35kBW9dScuas9tWc90Dw=
github.com/fluxcd/pkg/apis/meta v1.6.0/go.mod h1:ZOeHcvyVdZDC5ZOGV7YuwplIvAx6LvmpeyhfTcNZCnc=
+github.com/fluxcd/pkg/auth v0.0.1 h1:3fMg1EdkQdY2Rv1qHbiPPWCBa27xsNeu09y9SuZk6Co=
+github.com/fluxcd/pkg/auth v0.0.1/go.mod h1:tdCkiB3/LBg7CcxX1fhVmM5ZjDIaOduK0XX88pBXie0=
github.com/fluxcd/pkg/cache v0.0.3 h1:VK5joG/p+amh5Ob+r1OFOx0cCYiswEf8mX1/J1BG7Mw=
github.com/fluxcd/pkg/cache v0.0.3/go.mod h1:UU6oFhV+mG0A5/RwIlvXhyuKlJwQEkk92jVB3vKMLtk=
-github.com/fluxcd/pkg/git v0.20.0 h1:byUbxLLZ9AyVYmK16mvxY/iA/ZhNwA30GHKPKNh7pik=
-github.com/fluxcd/pkg/git v0.20.0/go.mod h1:YnBOFhX7zzyVjg/u1Et1xBqXs30kb2sWWesIl3/glhw=
-github.com/fluxcd/pkg/git/gogit v0.20.0 h1:ZlWq//I465lv9aEEWaJhjJaTiTtnjcH+Td0fg1rPXWU=
-github.com/fluxcd/pkg/git/gogit v0.20.0/go.mod h1:ZA4WsKr28cj1yuplxOw9vHgCL4OCNJJLib1cJ77Tp9o=
-github.com/fluxcd/pkg/gittestserver v0.13.0 h1:6rvD9Z7+4zBcNT+LK0z4H0z6mDaw1Zd8ZaLh/dw8dzI=
-github.com/fluxcd/pkg/gittestserver v0.13.0/go.mod h1:LDw32Wo9mTmKNmJq4g7LRVBqPXlpMIWFBDOrRRh/+As=
+github.com/fluxcd/pkg/git v0.21.0 h1:5FfcKj9bDVz8KwoOQUOSJABLMeSdhvLBf7yctwwuMzc=
+github.com/fluxcd/pkg/git v0.21.0/go.mod h1:iCCmUCunoFLgntySJfIDxsHGYfS97ky990gEKIDZ9lo=
+github.com/fluxcd/pkg/git/gogit v0.21.0 h1:iR2kzW1XrcBDYuC8zVIAdC/2/aeXuRkZ9jupdd54E6I=
+github.com/fluxcd/pkg/git/gogit v0.21.0/go.mod h1:gyoSlEIqzsOiTwSL0iFuEiJat+W0uGgc+WEiCVC1xk8=
+github.com/fluxcd/pkg/gittestserver v0.13.1 h1:5rXF8ANlk6wtAsvqH7tI7gaO2zhMySftf7ALh0AhfU4=
+github.com/fluxcd/pkg/gittestserver v0.13.1/go.mod h1:nPO7ibtBRgLWFHTSvxI63zZubJXU82cVMH6nViVnHsY=
github.com/fluxcd/pkg/helmtestserver v0.19.0 h1:DbidD46we8iLp/Sxn2TO8twtlP5gxFQaP3XTNJC0bl8=
github.com/fluxcd/pkg/helmtestserver v0.19.0/go.mod h1:BhP2n8VMh+HnikYg9XEpzd2+pMQKemT9pBYg3SKCOxE=
github.com/fluxcd/pkg/lockedfile v0.3.0 h1:tZkBAffcxyt4zMigHIKc54cKgN5I/kFF005gyWZdyds=
@@ -368,14 +370,14 @@ github.com/fluxcd/pkg/runtime v0.49.0 h1:XldsD4C2TsfuIgku3NEQYCXFLZWDau22YqClTGU
github.com/fluxcd/pkg/runtime v0.49.0/go.mod h1:0JYsoNhrBtBC4mKAuZdfrkfIqsVGAXKM/A234HuNSnk=
github.com/fluxcd/pkg/sourceignore v0.8.0 h1:oHQZ0Fnk88T7EQKfUshgZ4MULVKlt/AbW4C8Chmrrx4=
github.com/fluxcd/pkg/sourceignore v0.8.0/go.mod h1:6dYIHKdlaATjY/e32EDabfyx0m89ObvlYQesJQoPPOc=
-github.com/fluxcd/pkg/ssh v0.14.0 h1:rkcUwEZiwNoHq8oGOf/THV5sf9LBbXOoJgOt+6+bU34=
-github.com/fluxcd/pkg/ssh v0.14.0/go.mod h1:1USgRvaaayJfzybQaCIAUn2e8LPsLe601Rec7Y8KQQE=
+github.com/fluxcd/pkg/ssh v0.14.1 h1:C/RBDch6cxAqQtaOohcasSAeGfZznNEeZtvpfI+hXQY=
+github.com/fluxcd/pkg/ssh v0.14.1/go.mod h1:HsVzHyF7CkfTnjtLEI6XK+8tfyWqwI1TPxJ34HcMg2o=
github.com/fluxcd/pkg/tar v0.8.0 h1:YcEW7K40/XM8o+bkU23dceWtxdaKUpsKcsppLSp8QWc=
github.com/fluxcd/pkg/tar v0.8.0/go.mod h1:O0WUC+nUIw7Cnw1h/4V310kLvzW4tvacD/VZTJtGBUM=
github.com/fluxcd/pkg/testserver v0.7.0 h1:kNVAn+3bAF2rfR9cT6SxzgEz2o84i+o7zKY3XRKTXmk=
github.com/fluxcd/pkg/testserver v0.7.0/go.mod h1:Ih5IK3Y5G3+a6c77BTqFkdPDCY1Yj1A1W5cXQqkCs9s=
-github.com/fluxcd/pkg/version v0.4.0 h1:3F6oeIZ+ug/f7pALIBhcUhfURel37EPPOn7nsGfsnOg=
-github.com/fluxcd/pkg/version v0.4.0/go.mod h1:izVsSDxac81qWRmpOL9qcxZYx+zAN1ajoP5SidGP6PA=
+github.com/fluxcd/pkg/version v0.4.1 h1:xnw+cu+GRcQSBTejcGiigYpipszO4Cn5UUGpAHVN4F0=
+github.com/fluxcd/pkg/version v0.4.1/go.mod h1:hO3ul44vTFFrosekcnrpxoPaM4cLbET4Fc/LR6pz4YQ=
github.com/foxcpp/go-mockdns v1.1.0 h1:jI0rD8M0wuYAxL7r/ynTrCQQq0BVqfB99Vgk7DlmewI=
github.com/foxcpp/go-mockdns v1.1.0/go.mod h1:IhLeSFGed3mJIAXPH2aiRQB+kqz7oqu8ld2qVbOu7Wk=
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
@@ -1093,8 +1095,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
-golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
+golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1128,8 +1130,8 @@ golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
-golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
-golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
+golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
+golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
@@ -1233,8 +1235,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/tools v0.15.0/go.mod h1:hpksKq4dtpQWS1uQ61JkdqWM3LscIS6Slf+VVkm+wQk=
-golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
-golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
+golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
+golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/internal/controller/gitrepository_controller.go b/internal/controller/gitrepository_controller.go
index aadbb6267..39e43fa9d 100644
--- a/internal/controller/gitrepository_controller.go
+++ b/internal/controller/gitrepository_controller.go
@@ -27,6 +27,7 @@ import (
"time"
securejoin "github.com/cyphar/filepath-securejoin"
+ "github.com/fluxcd/pkg/auth/azure"
"github.com/fluxcd/pkg/runtime/logger"
"github.com/go-git/go-git/v5/plumbing/transport"
corev1 "k8s.io/api/core/v1"
@@ -647,6 +648,19 @@ func (r *GitRepositoryReconciler) getAuthOpts(ctx context.Context, obj *sourcev1
if err != nil {
return nil, err
}
+
+ // Configure provider authentication if specified in spec
+ if obj.Spec.Provider != "" && obj.Spec.Provider != sourcev1.GitProviderGeneric {
+ if obj.Spec.Provider == sourcev1.GitProviderAzure {
+ authOpts.ProviderOpts = &git.ProviderOptions{
+ Name: obj.Spec.Provider,
+ AzureOpts: []azure.OptFunc{
+ azure.WithAzureDevOpsScope(),
+ },
+ }
+ }
+ }
+
return authOpts, nil
}
diff --git a/internal/controller/gitrepository_controller_test.go b/internal/controller/gitrepository_controller_test.go
index 800c65577..a81235553 100644
--- a/internal/controller/gitrepository_controller_test.go
+++ b/internal/controller/gitrepository_controller_test.go
@@ -683,6 +683,54 @@ func TestGitRepositoryReconciler_reconcileSource_authStrategy(t *testing.T) {
}
}
+func TestGitRepositoryReconciler_getAuthOpts_provider(t *testing.T) {
+ tests := []struct {
+ name string
+ beforeFunc func(obj *sourcev1.GitRepository)
+ wantProviderOptsName string
+ }{
+ {
+ name: "azure provider",
+ beforeFunc: func(obj *sourcev1.GitRepository) {
+ obj.Spec.Provider = sourcev1.GitProviderAzure
+ },
+ wantProviderOptsName: sourcev1.GitProviderAzure,
+ },
+ {
+ name: "generic provider",
+ beforeFunc: func(obj *sourcev1.GitRepository) {
+ obj.Spec.Provider = sourcev1.GitProviderGeneric
+ },
+ },
+ {
+ name: "no provider",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ g := NewWithT(t)
+ obj := &sourcev1.GitRepository{}
+ r := &GitRepositoryReconciler{}
+ url, _ := url.Parse("https://dev.azure.com/foo/bar/_git/baz")
+
+ if tt.beforeFunc != nil {
+ tt.beforeFunc(obj)
+ }
+ opts, err := r.getAuthOpts(context.TODO(), obj, *url)
+
+ g.Expect(err).ToNot(HaveOccurred())
+ g.Expect(opts).ToNot(BeNil())
+ if tt.wantProviderOptsName != "" {
+ g.Expect(opts.ProviderOpts).ToNot(BeNil())
+ g.Expect(opts.ProviderOpts.Name).To(Equal(tt.wantProviderOptsName))
+ } else {
+ g.Expect(opts.ProviderOpts).To(BeNil())
+ }
+ })
+ }
+}
+
func TestGitRepositoryReconciler_reconcileSource_checkoutStrategy(t *testing.T) {
g := NewWithT(t)
|