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)