Repository: kubernetes-sigs/cloud-provider-azure
Pull request #8728 (2025-03-25 03:45:10)

Upgrade azclient and set compute and network ARM client
<!--  Thanks for sending a pull request!  Here are some tips for you:

1. If this is your first time, please read our contributor guidelines: https://git.k8s.io/community/contributors/guide/first-contribution.md#your-first-contribution and developer guide https://git.k8s.io/community/contributors/devel/development.md#development-guide
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request. For reference on required PR/issue labels, read here:
https://git.k8s.io/community/contributors/devel/sig-release/release.md#issuepr-kind-label
3. Ensure you have added or ran the appropriate tests for your PR: https://git.k8s.io/community/contributors/devel/sig-testing/testing.md
4. If you want *faster* PR reviews, read how: https://git.k8s.io/community/contributors/guide/pull-requests.md#best-practices-for-faster-reviews
5. If the PR is unfinished, see how to mark it: https://git.k8s.io/community/contributors/guide/pull-requests.md#marking-unfinished-pull-requests
-->

#### What type of PR is this?

<!--
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind design

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
/kind bug

#### What this PR does / why we need it:

1. Upgrade azclient (see #8596)
2. Fix a bug where using a different network subscription within the same tenant would fallback to the compute subscription for ARM requests.

#### Which issue(s) this PR fixes:
<!--
*Automatically closes linked issue when PR is merged.
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
_If PR is about `failing-tests or flakes`, please post the related issues/tests in a comment and do not use `Fixes`_*
-->
Fixes #

#### Special notes for your reviewer:

#### Does this PR introduce a user-facing change?
<!--
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".

For more information on release notes see: https://git.k8s.io/community/contributors/guide/release-notes.md
-->
```release-note
Fix network ARM client setting in a different subscription within the same tenant.
```

#### Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.:

<!--
This section can be blank if this pull request does not require a release note.

When adding links which point to resources within git repositories, like
KEPs or supporting documentation, please reference a specific commit and avoid
linking directly to the master branch. This ensures that links reference a
specific point in time, rather than a document that may change over time.

See here for guidance on getting permanent links to files: https://help.github.com/en/articles/getting-permanent-links-to-files

Please use the following format for linking documentation:
- [KEP]: <link>
- [Usage]: <link>
- [Other doc]: <link>
-->
```docs

```


k8s-ci-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/8728#" title="Author self-approved">zarvd</a>*
**Once this PR has been reviewed and has the lgtm label**, please assign [andyzhangx](https://github.com/andyzhangx) for approval. For more information see [the Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcloud-provider-azure).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubernetes-sigs/cloud-provider-azure/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["andyzhangx"]} -->
k8s-ci-robot: Hi @zarvd. Thanks for your PR.

I'm waiting for a [kubernetes-sigs](https://github.com/orgs/kubernetes-sigs/people) member to verify that this patch is reasonable to test. If it is, they should reply with `/ok-to-test` on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should [join the org](https://git.k8s.io/community/community-membership.md#member) to skip this step.

Once the patch is verified, the new status will be reflected by the `ok-to-test` label.

I understand the commands that are listed [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcloud-provider-azure).

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository.
</details>

nilo19: /ok-to-test
k8s-ci-robot: @zarvd: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904379968545099776) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904379968545099776) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904379968545099776) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904379968457019392) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904379968545099776) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904379968457019392) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904379968683511808) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904379968545099776) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904379968457019392) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904379968683511808) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1904379968771592192) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904379968545099776) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904379968457019392) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904379968683511808) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1904379968771592192) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-capz/1904379968624791552) | true | `/test pull-cloud-provider-azure-e2e-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904379968545099776) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904379968457019392) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1904379968771592192) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-capz/1904379968624791552) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904403968566497280) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904379968457019392) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1904379968771592192) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-capz/1904379968624791552) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904403968566497280) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904403968377753600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904379968457019392) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1904379968771592192) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904403968566497280) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904403968377753600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-capz/1904403968470028288) | true | `/test pull-cloud-provider-azure-e2e-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904379968457019392) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1904379968771592192) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904403968566497280) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904403968377753600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-capz/1904403968470028288) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1904403968918818816) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904379968838701056) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1904379968771592192) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904403968566497280) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904403968377753600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-capz/1904403968470028288) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1904403968918818816) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904403968285478912) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz | d194eb38e9e8030e274717bd222de49da3a15039 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz/1904379968771592192) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-ip-lb-capz`
pull-cloud-provider-azure-e2e-ccm-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-capz/1904403968566497280) | true | `/test pull-cloud-provider-azure-e2e-ccm-capz`
pull-cloud-provider-azure-e2e-ccm-vmssflex-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmssflex-capz/1904403968377753600) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmssflex-capz`
pull-cloud-provider-azure-e2e-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-capz/1904403968470028288) | true | `/test pull-cloud-provider-azure-e2e-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz/1904403968918818816) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-shared-probe-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904403968285478912) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`
pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz | 7d51820a795a50fd6436a60eeccb27e857584312 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz/1904403968755240960) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-multi-slb-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: @zarvd: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-cloud-provider-azure-e2e-ccm-vmss-capz | e5e07a17fa95b8f6e7944c062748a11a78b252d5 | [link](https://prow.k8s.io/view/gs/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_cloud-provider-azure/8728/pull-cloud-provider-azure-e2e-ccm-vmss-capz/1904820330799566848) | true | `/test pull-cloud-provider-azure-e2e-ccm-vmss-capz`

[Full PR test history](https://prow.k8s.io/pr-history?org=kubernetes-sigs&repo=cloud-provider-azure&pr=8728). [Your PR dashboard](https://prow.k8s.io/pr?query=is%3Apr%20state%3Aopen%20author%3Azarvd). Please help us cut down on flakes by [linking to](https://git.k8s.io/community/contributors/devel/sig-testing/flaky-tests.md#filing-issues-for-flaky-tests) an [open issue](https://github.com/kubernetes-sigs/cloud-provider-azure/issues?q=is:issue+is:open) when you hit one in your PR.

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/8728#pullrequestreview-2719143610" title="Approved">feiskyer</a>*, *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/8728#" title="Author self-approved">zarvd</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubernetes-sigs%2Fcloud-provider-azure).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubernetes-sigs/cloud-provider-azure/blob/master/OWNERS)~~ [feiskyer]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/go.mod b/go.mod
index ffe4276ef..037c612ea 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module sigs.k8s.io/cloud-provider-azure
 go 1.24
 
 require (
-	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0
+	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
 	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.3.0
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6 v6.2.0
@@ -38,8 +38,8 @@ require (
 	k8s.io/controller-manager v0.32.3
 	k8s.io/klog/v2 v2.130.1
 	k8s.io/kubelet v0.32.3
-	k8s.io/utils v0.0.0-20241210054802-24370beab758
-	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.14
+	k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
+	sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.20
 	sigs.k8s.io/cloud-provider-azure/pkg/azclient/cache v0.4.3
 	sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.4.4
 	sigs.k8s.io/yaml v1.4.0
@@ -58,7 +58,7 @@ require (
 	github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.1.1 // indirect
 	github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
 	github.com/Azure/msi-dataplane v0.4.3 // indirect
-	github.com/AzureAD/microsoft-authentication-library-for-go v1.4.0 // indirect
+	github.com/AzureAD/microsoft-authentication-library-for-go v1.4.1 // indirect
 	github.com/NYTimes/gziphandler v1.1.1 // indirect
 	github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
 	github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
@@ -78,7 +78,7 @@ require (
 	github.com/go-openapi/swag v0.23.0 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
-	github.com/golang-jwt/jwt/v5 v5.2.1 // indirect
+	github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
 	github.com/golang/protobuf v1.5.4 // indirect
 	github.com/google/btree v1.0.1 // indirect
 	github.com/google/cel-go v0.22.0 // indirect
@@ -117,7 +117,7 @@ require (
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.27.0 // indirect
 	golang.org/x/crypto v0.36.0 // indirect
-	golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
+	golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 // indirect
 	golang.org/x/net v0.37.0 // indirect
 	golang.org/x/oauth2 v0.24.0 // indirect
 	golang.org/x/term v0.30.0 // indirect
diff --git a/go.sum b/go.sum
index 94780534e..287607d99 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,7 @@
 cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo=
 cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0 h1:g0EZJwz7xkXQiZAI5xi9f3WWFYBlX1CPTrR+NDToRkQ=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0/go.mod h1:XCW7KnZet0Opnr7HccfUw1PLc4CjHqpcaxW8DHklNkQ=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1 h1:DSDNVxqkoXJiko6x8a90zidoYqnYYa6c1MTzDKzKkTo=
+github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1/go.mod h1:zGqV2R4Cr/k8Uye5w+dgQ06WJtEcbQG/8J7BB6hnCr4=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2 h1:F0gBpfdPLGsw+nsgk6aqqkZS1jiixa5WwFe3fk/T3Ys=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.2/go.mod h1:SqINnQ9lVVdRlyC8cd1lCI0SdX4n2paeABd2K8ggfnE=
 github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.2 h1:yz1bePFlP5Vws5+8ez6T3HWXPmwOK7Yvq8QxDBD3SKY=
@@ -46,8 +46,8 @@ github.com/Azure/msi-dataplane v0.4.3 h1:dWPWzY4b54tLIR9T1Q014Xxd/1DxOsMIp6EjRFA
 github.com/Azure/msi-dataplane v0.4.3/go.mod h1:yAfxdJyvcnvSDfSyOFV9qm4fReEQDl+nZLGeH2ZWSmw=
 github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM=
 github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.4.0 h1:MUkXAnvvDHgvPItl0nBj0hgk0f7hnnQbGm0h0+YxbN4=
-github.com/AzureAD/microsoft-authentication-library-for-go v1.4.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.4.1 h1:8BKxhZZLX/WosEeoCvWysmKUscfa9v8LIPEEU0JjE2o=
+github.com/AzureAD/microsoft-authentication-library-for-go v1.4.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
 github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
 github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
 github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
@@ -87,6 +87,8 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/
 github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
 github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
 github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
+github.com/go-faker/faker/v4 v4.6.0 h1:6aOPzNptRiDwD14HuAnEtlTa+D1IfFuEHO8+vEFwjTs=
+github.com/go-faker/faker/v4 v4.6.0/go.mod h1:ZmrHuVtTTm2Em9e0Du6CJ9CADaLEzGXW62z1YqFH0m0=
 github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
 github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
@@ -107,8 +109,8 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
 github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
 github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk=
-github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
+github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
+github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
@@ -168,10 +170,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ=
-github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
-github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
-github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
+github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0=
+github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
+github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
+github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
 github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -274,8 +276,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
 golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
-golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
-golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
+golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
+golang.org/x/exp v0.0.0-20250305212735-054e65f0b394/go.mod h1:sIifuuw/Yco/y6yb6+bDNfyeQ/MdPUy/hKEMYQV17cM=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -310,8 +312,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
-golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
+golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
+golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
 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=
@@ -364,12 +366,12 @@ k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJ
 k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4=
 k8s.io/kubelet v0.32.3 h1:B9HzW4yB67flx8tN2FYuDwZvxnmK3v5EjxxFvOYjmc8=
 k8s.io/kubelet v0.32.3/go.mod h1:yyAQSCKC+tjSlaFw4HQG7Jein+vo+GeKBGdXdQGvL1U=
-k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
-k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
+k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0 h1:CPT0ExVicCzcpeN4baWEV2ko2Z/AsiZgEdwgcfwLgMo=
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.14 h1:81DZINoz++Qii1LJWxTJD4LvfIVxGXbJNzp8GXRolN4=
-sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.14/go.mod h1:5ZmwXbPbTYOy3GmOp9NBy3JX2fOvCf8PwefHceRuvcE=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.20 h1:aVSc4LFdBVlrhlldIzPo4NrcTQRdnAlqTB31sOcPIrM=
+sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.20/go.mod h1:OkkCYstvomfIwV4rvVIegymcgMnt7ZQ3+1Wi9WZmP1s=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/cache v0.4.3 h1:jrBGF1VJy1Dl3KSu/rDES/yl1SH/ZhU1+Ft/0pRgt5g=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/cache v0.4.3/go.mod h1:sp3NF7RKtDd3NoIVXOUOFX2jRITVLHwRblGG8Uad8e4=
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader v0.4.4 h1:iUuz6adm2lc/Kz8TqmBJFQsbh77S2t12uvZalArMOJg=
diff --git a/pkg/provider/azure.go b/pkg/provider/azure.go
index f1e821dff..3449ced3f 100644
--- a/pkg/provider/azure.go
+++ b/pkg/provider/azure.go
@@ -24,9 +24,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
-	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
-
 	v1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/types"
 	"k8s.io/apimachinery/pkg/util/wait"
@@ -44,7 +41,6 @@ import (
 	"k8s.io/klog/v2"
 
 	"sigs.k8s.io/cloud-provider-azure/pkg/azclient"
-	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/armauth"
 	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/configloader"
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
@@ -249,6 +245,13 @@ func NewCloudFromSecret(ctx context.Context, clientBuilder cloudprovider.Control
 	return az, nil
 }
 
+var (
+	// newARMClientFactory is a function that returns a new ARM client factory.
+	// It is used to mock the ARM client factory for testing.
+	// TODO: use fake options for testing
+	newARMClientFactory = azclient.NewClientFactory
+)
+
 // InitializeCloudFromConfig initializes the Cloud from config.
 func (az *Cloud) InitializeCloudFromConfig(ctx context.Context, config *config.Config, _, callFromCCM bool) error {
 	if config == nil {
@@ -402,60 +405,40 @@ func (az *Cloud) InitializeCloudFromConfig(ctx context.Context, config *config.C
 		az.ARMClientConfig.UserAgent = fmt.Sprintf("kubernetes-cloudprovider/%s", k8sVersion)
 	}
 
-	if az.ComputeClientFactory == nil {
-		var cred azcore.TokenCredential
-
-		if az.AuthProvider.IsMultiTenantModeEnabled() {
-			// It uses Service Principal as the multi-tenant credential.
-			// TODO: refactor `IsMultiTenantModeEnabled` to make it more clear.
-			multiTenantCred := az.AuthProvider.GetMultiTenantIdentity()
-			networkTenantCred := az.AuthProvider.GetNetworkAzIdentity()
-			az.NetworkClientFactory, err = azclient.NewClientFactory(&azclient.ClientFactoryConfig{
-				SubscriptionID: az.NetworkResourceSubscriptionID,
-			}, &az.ARMClientConfig, clientOps.Cloud, networkTenantCred)
-			if err != nil {
-				return err
-			}
-			cred = multiTenantCred
-		} else {
-			cred = az.AuthProvider.GetAzIdentity()
-		}
+	if az.ComputeClientFactory == nil && az.AuthProvider != nil {
+		var (
+			computeCred = az.AuthProvider.GetAzIdentity()
+			networkCred = az.AuthProvider.GetNetworkAzIdentity() // It would fallback to compute credential if network credential is not set
+		)
 
-		var opts []func(option *arm.ClientOptions)
-		if az.AzureAuthConfig.AuxiliaryTokenProvider != nil && az.AzureAuthConfig.UseManagedIdentityExtension {
-			klog.InfoS("Using auxiliary token provider for ARM network credential")
-			// Multi-tenant mode with auxiliary token provider.
-			// It uses Managed Identity as the primary credential and auxiliary token provider as the auxiliary credential.
-			opts = append(opts, func(option *arm.ClientOptions) {
-				option.PerRetryPolicies = append(option.PerRetryPolicies, armauth.NewAuxiliaryAuthPolicy(
-					[]azcore.TokenCredential{az.AuthProvider.GetNetworkAzIdentity()},
-					az.AuthProvider.DefaultTokenScope(),
-				))
-			})
-
-			az.NetworkClientFactory, err = azclient.NewClientFactory(&azclient.ClientFactoryConfig{
-				SubscriptionID: az.NetworkResourceSubscriptionID,
-			}, &az.ARMClientConfig, clientOps.Cloud, az.AuthProvider.GetNetworkAzIdentity())
-			if err != nil {
-				return err
-			}
+		networkSubscriptionID := az.getNetworkResourceSubscriptionID() // It would also fallback to compute subscription ID if network subscription ID is not set
+		az.NetworkClientFactory, err = newARMClientFactory(&azclient.ClientFactoryConfig{
+			SubscriptionID: networkSubscriptionID,
+		}, &az.ARMClientConfig, clientOps.Cloud, networkCred)
+		if err != nil {
+			return err
 		}
+		klog.InfoS("Setting up ARM client factory for network resources", "subscriptionID", networkSubscriptionID)
 
-		az.ComputeClientFactory, err = azclient.NewClientFactory(&azclient.ClientFactoryConfig{
+		az.ComputeClientFactory, err = newARMClientFactory(&azclient.ClientFactoryConfig{
 			SubscriptionID: az.SubscriptionID,
-		}, &az.ARMClientConfig, clientOps.Cloud, cred, opts...)
+		}, &az.ARMClientConfig, clientOps.Cloud, computeCred, az.AuthProvider.AdditionalComputeClientOptions...)
 		if err != nil {
 			return err
 		}
-		if az.NetworkClientFactory == nil {
-			az.NetworkClientFactory = az.ComputeClientFactory
-		}
+		klog.InfoS("Setting up ARM client factory for compute resources", "subscriptionID", az.SubscriptionID)
 	}
 
 	networkClientFactory := az.NetworkClientFactory
 
 	if az.nsgRepo == nil {
-		az.nsgRepo, err = securitygroup.NewSecurityGroupRepo(az.SecurityGroupResourceGroup, az.SecurityGroupName, az.NsgCacheTTLInSeconds, az.DisableAPICallCache, networkClientFactory.GetSecurityGroupClient())
+		az.nsgRepo, err = securitygroup.NewSecurityGroupRepo(
+			az.SecurityGroupResourceGroup,
+			az.SecurityGroupName,
+			az.NsgCacheTTLInSeconds,
+			az.DisableAPICallCache,
+			networkClientFactory.GetSecurityGroupClient(),
+		)
 		if err != nil {
 			return err
 		}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md
index cf422304e..bd9667d99 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/CHANGELOG.md
@@ -1,5 +1,12 @@
 # Release History
 
+## 1.17.1 (2025-03-20)
+
+### Other Changes
+
+* Upgraded to Go 1.23
+* Upgraded dependencies
+
 ## 1.17.0 (2025-01-07)
 
 ### Features Added
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go
index 44ab00d40..c8929e596 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azcore/internal/shared/constants.go
@@ -40,5 +40,5 @@ const (
 	Module = "azcore"
 
 	// Version is the semantic version (see http://semver.org) of this module.
-	Version = "v1.17.0"
+	Version = "v1.17.1"
 )
diff --git a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go
index 71275b32f..7bd0a8b3c 100644
--- a/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go
+++ b/vendor/github.com/AzureAD/microsoft-authentication-library-for-go/apps/internal/oauth/ops/accesstokens/accesstokens.go
@@ -68,7 +68,7 @@ type DeviceCodeResponse struct {
 
 	UserCode        string `json:"user_code"`
 	DeviceCode      string `json:"device_code"`
-	VerificationURL string `json:"verification_url"`
+	VerificationURL string `json:"verification_uri"`
 	ExpiresIn       int    `json:"expires_in"`
 	Interval        int    `json:"interval"`
 	Message         string `json:"message"`
diff --git a/vendor/github.com/golang-jwt/jwt/v5/README.md b/vendor/github.com/golang-jwt/jwt/v5/README.md
index 964598a31..0bb636f22 100644
--- a/vendor/github.com/golang-jwt/jwt/v5/README.md
+++ b/vendor/github.com/golang-jwt/jwt/v5/README.md
@@ -10,11 +10,11 @@ implementation of [JSON Web
 Tokens](https://datatracker.ietf.org/doc/html/rfc7519).
 
 Starting with [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0)
-this project adds Go module support, but maintains backwards compatibility with
+this project adds Go module support, but maintains backward compatibility with
 older `v3.x.y` tags and upstream `github.com/dgrijalva/jwt-go`. See the
 [`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information. Version
 v5.0.0 introduces major improvements to the validation of tokens, but is not
-entirely backwards compatible. 
+entirely backward compatible. 
 
 > After the original author of the library suggested migrating the maintenance
 > of `jwt-go`, a dedicated team of open source maintainers decided to clone the
@@ -24,7 +24,7 @@ entirely backwards compatible.
 
 
 **SECURITY NOTICE:** Some older versions of Go have a security issue in the
-crypto/elliptic. Recommendation is to upgrade to at least 1.15 See issue
+crypto/elliptic. The recommendation is to upgrade to at least 1.15 See issue
 [dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more
 detail.
 
@@ -32,7 +32,7 @@ detail.
 what you
 expect](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/).
 This library attempts to make it easy to do the right thing by requiring key
-types match the expected alg, but you should take the extra step to verify it in
+types to match the expected alg, but you should take the extra step to verify it in
 your usage.  See the examples provided.
 
 ### Supported Go versions
@@ -41,7 +41,7 @@ Our support of Go versions is aligned with Go's [version release
 policy](https://golang.org/doc/devel/release#policy). So we will support a major
 version of Go until there are two newer major releases. We no longer support
 building jwt-go with unsupported Go versions, as these contain security
-vulnerabilities which will not be fixed.
+vulnerabilities that will not be fixed.
 
 ## What the heck is a JWT?
 
@@ -117,7 +117,7 @@ notable differences:
 
 This library is considered production ready.  Feedback and feature requests are
 appreciated.  The API should be considered stable.  There should be very few
-backwards-incompatible changes outside of major version updates (and only with
+backward-incompatible changes outside of major version updates (and only with
 good reason).
 
 This project uses [Semantic Versioning 2.0.0](http://semver.org).  Accepted pull
@@ -125,8 +125,8 @@ requests will land on `main`.  Periodically, versions will be tagged from
 `main`.  You can find all the releases on [the project releases
 page](https://github.com/golang-jwt/jwt/releases).
 
-**BREAKING CHANGES:*** A full list of breaking changes is available in
-`VERSION_HISTORY.md`.  See `MIGRATION_GUIDE.md` for more information on updating
+**BREAKING CHANGES:** A full list of breaking changes is available in
+`VERSION_HISTORY.md`.  See [`MIGRATION_GUIDE.md`](./MIGRATION_GUIDE.md) for more information on updating
 your code.
 
 ## Extensions
diff --git a/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md b/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md
index b08402c34..2740597f1 100644
--- a/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md
+++ b/vendor/github.com/golang-jwt/jwt/v5/SECURITY.md
@@ -2,11 +2,11 @@
 
 ## Supported Versions
 
-As of February 2022 (and until this document is updated), the latest version `v4` is supported.
+As of November 2024 (and until this document is updated), the latest version `v5` is supported. In critical cases, we might supply back-ported patches for `v4`.
 
 ## Reporting a Vulnerability
 
-If you think you found a vulnerability, and even if you are not sure, please report it to jwt-go-security@googlegroups.com or one of the other [golang-jwt maintainers](https://github.com/orgs/golang-jwt/people). Please try be explicit, describe steps to reproduce the security issue with code example(s).
+If you think you found a vulnerability, and even if you are not sure, please report it a [GitHub Security Advisory](https://github.com/golang-jwt/jwt/security/advisories/new). Please try be explicit, describe steps to reproduce the security issue with code example(s).
 
 You will receive a response within a timely manner. If the issue is confirmed, we will do our best to release a patch as soon as possible given the complexity of the problem.
 
diff --git a/vendor/github.com/golang-jwt/jwt/v5/parser.go b/vendor/github.com/golang-jwt/jwt/v5/parser.go
index ecf99af78..054c7eb6f 100644
--- a/vendor/github.com/golang-jwt/jwt/v5/parser.go
+++ b/vendor/github.com/golang-jwt/jwt/v5/parser.go
@@ -8,6 +8,8 @@ import (
 	"strings"
 )
 
+const tokenDelimiter = "."
+
 type Parser struct {
 	// If populated, only these methods will be considered valid.
 	validMethods []string
@@ -136,9 +138,10 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
 // It's only ever useful in cases where you know the signature is valid (since it has already
 // been or will be checked elsewhere in the stack) and you want to extract values from it.
 func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
-	parts = strings.Split(tokenString, ".")
-	if len(parts) != 3 {
-		return nil, parts, newError("token contains an invalid number of segments", ErrTokenMalformed)
+	var ok bool
+	parts, ok = splitToken(tokenString)
+	if !ok {
+		return nil, nil, newError("token contains an invalid number of segments", ErrTokenMalformed)
 	}
 
 	token = &Token{Raw: tokenString}
@@ -196,6 +199,33 @@ func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Toke
 	return token, parts, nil
 }
 
+// splitToken splits a token string into three parts: header, claims, and signature. It will only
+// return true if the token contains exactly two delimiters and three parts. In all other cases, it
+// will return nil parts and false.
+func splitToken(token string) ([]string, bool) {
+	parts := make([]string, 3)
+	header, remain, ok := strings.Cut(token, tokenDelimiter)
+	if !ok {
+		return nil, false
+	}
+	parts[0] = header
+	claims, remain, ok := strings.Cut(remain, tokenDelimiter)
+	if !ok {
+		return nil, false
+	}
+	parts[1] = claims
+	// One more cut to ensure the signature is the last part of the token and there are no more
+	// delimiters. This avoids an issue where malicious input could contain additional delimiters
+	// causing unecessary overhead parsing tokens.
+	signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
+	if unexpected {
+		return nil, false
+	}
+	parts[2] = signature
+
+	return parts, true
+}
+
 // DecodeSegment decodes a JWT specific base64url encoding. This function will
 // take into account whether the [Parser] is configured with additional options,
 // such as [WithStrictDecoding] or [WithPaddingAllowed].
diff --git a/vendor/github.com/golang-jwt/jwt/v5/token.go b/vendor/github.com/golang-jwt/jwt/v5/token.go
index 352873a2d..9c7f4ab01 100644
--- a/vendor/github.com/golang-jwt/jwt/v5/token.go
+++ b/vendor/github.com/golang-jwt/jwt/v5/token.go
@@ -75,7 +75,7 @@ func (t *Token) SignedString(key interface{}) (string, error) {
 }
 
 // SigningString generates the signing string.  This is the most expensive part
-// of the whole deal.  Unless you need this for something special, just go
+// of the whole deal. Unless you need this for something special, just go
 // straight for the SignedString.
 func (t *Token) SigningString() (string, error) {
 	h, err := json.Marshal(t.Header)
diff --git a/vendor/golang.org/x/exp/constraints/constraints.go b/vendor/golang.org/x/exp/constraints/constraints.go
deleted file mode 100644
index 2c033dff4..000000000
--- a/vendor/golang.org/x/exp/constraints/constraints.go
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2021 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Package constraints defines a set of useful constraints to be used
-// with type parameters.
-package constraints
-
-// Signed is a constraint that permits any signed integer type.
-// If future releases of Go add new predeclared signed integer types,
-// this constraint will be modified to include them.
-type Signed interface {
-	~int | ~int8 | ~int16 | ~int32 | ~int64
-}
-
-// Unsigned is a constraint that permits any unsigned integer type.
-// If future releases of Go add new predeclared unsigned integer types,
-// this constraint will be modified to include them.
-type Unsigned interface {
-	~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
-}
-
-// Integer is a constraint that permits any integer type.
-// If future releases of Go add new predeclared integer types,
-// this constraint will be modified to include them.
-type Integer interface {
-	Signed | Unsigned
-}
-
-// Float is a constraint that permits any floating-point type.
-// If future releases of Go add new predeclared floating-point types,
-// this constraint will be modified to include them.
-type Float interface {
-	~float32 | ~float64
-}
-
-// Complex is a constraint that permits any complex numeric type.
-// If future releases of Go add new predeclared complex numeric types,
-// this constraint will be modified to include them.
-type Complex interface {
-	~complex64 | ~complex128
-}
-
-// Ordered is a constraint that permits any ordered type: any type
-// that supports the operators < <= >= >.
-// If future releases of Go add new ordered types,
-// this constraint will be modified to include them.
-type Ordered interface {
-	Integer | Float | ~string
-}
diff --git a/vendor/golang.org/x/exp/slices/cmp.go b/vendor/golang.org/x/exp/slices/cmp.go
deleted file mode 100644
index fbf1934a0..000000000
--- a/vendor/golang.org/x/exp/slices/cmp.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2023 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slices
-
-import "golang.org/x/exp/constraints"
-
-// min is a version of the predeclared function from the Go 1.21 release.
-func min[T constraints.Ordered](a, b T) T {
-	if a < b || isNaN(a) {
-		return a
-	}
-	return b
-}
-
-// max is a version of the predeclared function from the Go 1.21 release.
-func max[T constraints.Ordered](a, b T) T {
-	if a > b || isNaN(a) {
-		return a
-	}
-	return b
-}
-
-// cmpLess is a copy of cmp.Less from the Go 1.21 release.
-func cmpLess[T constraints.Ordered](x, y T) bool {
-	return (isNaN(x) && !isNaN(y)) || x < y
-}
-
-// cmpCompare is a copy of cmp.Compare from the Go 1.21 release.
-func cmpCompare[T constraints.Ordered](x, y T) int {
-	xNaN := isNaN(x)
-	yNaN := isNaN(y)
-	if xNaN && yNaN {
-		return 0
-	}
-	if xNaN || x < y {
-		return -1
-	}
-	if yNaN || x > y {
-		return +1
-	}
-	return 0
-}
diff --git a/vendor/golang.org/x/exp/slices/slices.go b/vendor/golang.org/x/exp/slices/slices.go
index 46ceac343..da0df370d 100644
--- a/vendor/golang.org/x/exp/slices/slices.go
+++ b/vendor/golang.org/x/exp/slices/slices.go
@@ -6,9 +6,8 @@
 package slices
 
 import (
-	"unsafe"
-
-	"golang.org/x/exp/constraints"
+	"cmp"
+	"slices"
 )
 
 // Equal reports whether two slices are equal: the same length and all
@@ -16,16 +15,10 @@ import (
 // Otherwise, the elements are compared in increasing index order, and the
 // comparison stops at the first unequal pair.
 // Floating point NaNs are not considered equal.
+//
+//go:fix inline
 func Equal[S ~[]E, E comparable](s1, s2 S) bool {
-	if len(s1) != len(s2) {
-		return false
-	}
-	for i := range s1 {
-		if s1[i] != s2[i] {
-			return false
-		}
-	}
-	return true
+	return slices.Equal(s1, s2)
 }
 
 // EqualFunc reports whether two slices are equal using an equality
@@ -33,17 +26,10 @@ func Equal[S ~[]E, E comparable](s1, s2 S) bool {
 // EqualFunc returns false. Otherwise, the elements are compared in
 // increasing index order, and the comparison stops at the first index
 // for which eq returns false.
+//
+//go:fix inline
 func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) bool) bool {
-	if len(s1) != len(s2) {
-		return false
-	}
-	for i, v1 := range s1 {
-		v2 := s2[i]
-		if !eq(v1, v2) {
-			return false
-		}
-	}
-	return true
+	return slices.EqualFunc(s1, s2, eq)
 }
 
 // Compare compares the elements of s1 and s2, using [cmp.Compare] on each pair
@@ -53,20 +39,10 @@ func EqualFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, eq func(E1, E2) boo
 // If both slices are equal until one of them ends, the shorter slice is
 // considered less than the longer one.
 // The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2.
-func Compare[S ~[]E, E constraints.Ordered](s1, s2 S) int {
-	for i, v1 := range s1 {
-		if i >= len(s2) {
-			return +1
-		}
-		v2 := s2[i]
-		if c := cmpCompare(v1, v2); c != 0 {
-			return c
-		}
-	}
-	if len(s1) < len(s2) {
-		return -1
-	}
-	return 0
+//
+//go:fix inline
+func Compare[S ~[]E, E cmp.Ordered](s1, s2 S) int {
+	return slices.Compare(s1, s2)
 }
 
 // CompareFunc is like [Compare] but uses a custom comparison function on each
@@ -74,53 +50,41 @@ func Compare[S ~[]E, E constraints.Ordered](s1, s2 S) int {
 // The result is the first non-zero result of cmp; if cmp always
 // returns 0 the result is 0 if len(s1) == len(s2), -1 if len(s1) < len(s2),
 // and +1 if len(s1) > len(s2).
+//
+//go:fix inline
 func CompareFunc[S1 ~[]E1, S2 ~[]E2, E1, E2 any](s1 S1, s2 S2, cmp func(E1, E2) int) int {
-	for i, v1 := range s1 {
-		if i >= len(s2) {
-			return +1
-		}
-		v2 := s2[i]
-		if c := cmp(v1, v2); c != 0 {
-			return c
-		}
-	}
-	if len(s1) < len(s2) {
-		return -1
-	}
-	return 0
+	return slices.CompareFunc(s1, s2, cmp)
 }
 
 // Index returns the index of the first occurrence of v in s,
 // or -1 if not present.
+//
+//go:fix inline
 func Index[S ~[]E, E comparable](s S, v E) int {
-	for i := range s {
-		if v == s[i] {
-			return i
-		}
-	}
-	return -1
+	return slices.Index(s, v)
 }
 
 // IndexFunc returns the first index i satisfying f(s[i]),
 // or -1 if none do.
+//
+//go:fix inline
 func IndexFunc[S ~[]E, E any](s S, f func(E) bool) int {
-	for i := range s {
-		if f(s[i]) {
-			return i
-		}
-	}
-	return -1
+	return slices.IndexFunc(s, f)
 }
 
 // Contains reports whether v is present in s.
+//
+//go:fix inline
 func Contains[S ~[]E, E comparable](s S, v E) bool {
-	return Index(s, v) >= 0
+	return slices.Contains(s, v)
 }
 
 // ContainsFunc reports whether at least one
 // element e of s satisfies f(e).
+//
+//go:fix inline
 func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
-	return IndexFunc(s, f) >= 0
+	return slices.ContainsFunc(s, f)
 }
 
 // Insert inserts the values v... into s at index i,
@@ -130,93 +94,10 @@ func ContainsFunc[S ~[]E, E any](s S, f func(E) bool) bool {
 // and r[i+len(v)] == value originally at r[i].
 // Insert panics if i is out of range.
 // This function is O(len(s) + len(v)).
+//
+//go:fix inline
 func Insert[S ~[]E, E any](s S, i int, v ...E) S {
-	m := len(v)
-	if m == 0 {
-		return s
-	}
-	n := len(s)
-	if i == n {
-		return append(s, v...)
-	}
-	if n+m > cap(s) {
-		// Use append rather than make so that we bump the size of
-		// the slice up to the next storage class.
-		// This is what Grow does but we don't call Grow because
-		// that might copy the values twice.
-		s2 := append(s[:i], make(S, n+m-i)...)
-		copy(s2[i:], v)
-		copy(s2[i+m:], s[i:])
-		return s2
-	}
-	s = s[:n+m]
-
-	// before:
-	// s: aaaaaaaabbbbccccccccdddd
-	//            ^   ^       ^   ^
-	//            i  i+m      n  n+m
-	// after:
-	// s: aaaaaaaavvvvbbbbcccccccc
-	//            ^   ^       ^   ^
-	//            i  i+m      n  n+m
-	//
-	// a are the values that don't move in s.
-	// v are the values copied in from v.
-	// b and c are the values from s that are shifted up in index.
-	// d are the values that get overwritten, never to be seen again.
-
-	if !overlaps(v, s[i+m:]) {
-		// Easy case - v does not overlap either the c or d regions.
-		// (It might be in some of a or b, or elsewhere entirely.)
-		// The data we copy up doesn't write to v at all, so just do it.
-
-		copy(s[i+m:], s[i:])
-
-		// Now we have
-		// s: aaaaaaaabbbbbbbbcccccccc
-		//            ^   ^       ^   ^
-		//            i  i+m      n  n+m
-		// Note the b values are duplicated.
-
-		copy(s[i:], v)
-
-		// Now we have
-		// s: aaaaaaaavvvvbbbbcccccccc
-		//            ^   ^       ^   ^
-		//            i  i+m      n  n+m
-		// That's the result we want.
-		return s
-	}
-
-	// The hard case - v overlaps c or d. We can't just shift up
-	// the data because we'd move or clobber the values we're trying
-	// to insert.
-	// So instead, write v on top of d, then rotate.
-	copy(s[n:], v)
-
-	// Now we have
-	// s: aaaaaaaabbbbccccccccvvvv
-	//            ^   ^       ^   ^
-	//            i  i+m      n  n+m
-
-	rotateRight(s[i:], m)
-
-	// Now we have
-	// s: aaaaaaaavvvvbbbbcccccccc
-	//            ^   ^       ^   ^
-	//            i  i+m      n  n+m
-	// That's the result we want.
-	return s
-}
-
-// clearSlice sets all elements up to the length of s to the zero value of E.
-// We may use the builtin clear func instead, and remove clearSlice, when upgrading
-// to Go 1.21+.
-func clearSlice[S ~[]E, E any](s S) {
-	var zero E
-	for i := range s {
-		s[i] = zero
-	}
+	return slices.Insert(s, i, v...)
 }
 
 // Delete removes the elements s[i:j] from s, returning the modified slice.
@@ -224,136 +105,36 @@ func clearSlice[S ~[]E, E any](s S) {
 // Delete is O(len(s)-i), so if many items must be deleted, it is better to
 // make a single call deleting them all together than to delete one at a time.
 // Delete zeroes the elements s[len(s)-(j-i):len(s)].
+//
+//go:fix inline
 func Delete[S ~[]E, E any](s S, i, j int) S {
-	_ = s[i:j:len(s)] // bounds check
-
-	if i == j {
-		return s
-	}
-
-	oldlen := len(s)
-	s = append(s[:i], s[j:]...)
-	clearSlice(s[len(s):oldlen]) // zero/nil out the obsolete elements, for GC
-	return s
+	return slices.Delete(s, i, j)
 }
 
 // DeleteFunc removes any elements from s for which del returns true,
 // returning the modified slice.
 // DeleteFunc zeroes the elements between the new length and the original length.
+//
+//go:fix inline
 func DeleteFunc[S ~[]E, E any](s S, del func(E) bool) S {
-	i := IndexFunc(s, del)
-	if i == -1 {
-		return s
-	}
-	// Don't start copying elements until we find one to delete.
-	for j := i + 1; j < len(s); j++ {
-		if v := s[j]; !del(v) {
-			s[i] = v
-			i++
-		}
-	}
-	clearSlice(s[i:]) // zero/nil out the obsolete elements, for GC
-	return s[:i]
+	return slices.DeleteFunc(s, del)
 }
 
 // Replace replaces the elements s[i:j] by the given v, and returns the
 // modified slice. Replace panics if s[i:j] is not a valid slice of s.
 // When len(v) < (j-i), Replace zeroes the elements between the new length and the original length.
+//
+//go:fix inline
 func Replace[S ~[]E, E any](s S, i, j int, v ...E) S {
-	_ = s[i:j] // verify that i:j is a valid subslice
-
-	if i == j {
-		return Insert(s, i, v...)
-	}
-	if j == len(s) {
-		return append(s[:i], v...)
-	}
-
-	tot := len(s[:i]) + len(v) + len(s[j:])
-	if tot > cap(s) {
-		// Too big to fit, allocate and copy over.
-		s2 := append(s[:i], make(S, tot-i)...) // See Insert
-		copy(s2[i:], v)
-		copy(s2[i+len(v):], s[j:])
-		return s2
-	}
-
-	r := s[:tot]
-
-	if i+len(v) <= j {
-		// Easy, as v fits in the deleted portion.
-		copy(r[i:], v)
-		if i+len(v) != j {
-			copy(r[i+len(v):], s[j:])
-		}
-		clearSlice(s[tot:]) // zero/nil out the obsolete elements, for GC
-		return r
-	}
-
-	// We are expanding (v is bigger than j-i).
-	// The situation is something like this:
-	// (example has i=4,j=8,len(s)=16,len(v)=6)
-	// s: aaaaxxxxbbbbbbbbyy
-	//        ^   ^       ^ ^
-	//        i   j  len(s) tot
-	// a: prefix of s
-	// x: deleted range
-	// b: more of s
-	// y: area to expand into
-
-	if !overlaps(r[i+len(v):], v) {
-		// Easy, as v is not clobbered by the first copy.
-		copy(r[i+len(v):], s[j:])
-		copy(r[i:], v)
-		return r
-	}
-
-	// This is a situation where we don't have a single place to which
-	// we can copy v. Parts of it need to go to two different places.
-	// We want to copy the prefix of v into y and the suffix into x, then
-	// rotate |y| spots to the right.
-	//
-	//        v[2:]      v[:2]
-	//         |           |
-	// s: aaaavvvvbbbbbbbbvv
-	//        ^   ^       ^ ^
-	//        i   j  len(s) tot
-	//
-	// If either of those two destinations don't alias v, then we're good.
-	y := len(v) - (j - i) // length of y portion
-
-	if !overlaps(r[i:j], v) {
-		copy(r[i:j], v[y:])
-		copy(r[len(s):], v[:y])
-		rotateRight(r[i:], y)
-		return r
-	}
-	if !overlaps(r[len(s):], v) {
-		copy(r[len(s):], v[:y])
-		copy(r[i:j], v[y:])
-		rotateRight(r[i:], y)
-		return r
-	}
-
-	// Now we know that v overlaps both x and y.
-	// That means that the entirety of b is *inside* v.
-	// So we don't need to preserve b at all; instead we
-	// can copy v first, then copy the b part of v out of
-	// v to the right destination.
-	k := startIdx(v, s[j:])
-	copy(r[i:], v)
-	copy(r[i+len(v):], r[i+k:])
-	return r
+	return slices.Replace(s, i, j, v...)
 }
 
 // Clone returns a copy of the slice.
 // The elements are copied using assignment, so this is a shallow clone.
+//
+//go:fix inline
 func Clone[S ~[]E, E any](s S) S {
-	// Preserve nil in case it matters.
-	if s == nil {
-		return nil
-	}
-	return append(S([]E{}), s...)
+	return slices.Clone(s)
 }
 
 // Compact replaces consecutive runs of equal elements with a single copy.
@@ -361,155 +142,41 @@ func Clone[S ~[]E, E any](s S) S {
 // Compact modifies the contents of the slice s and returns the modified slice,
 // which may have a smaller length.
 // Compact zeroes the elements between the new length and the original length.
+//
+//go:fix inline
 func Compact[S ~[]E, E comparable](s S) S {
-	if len(s) < 2 {
-		return s
-	}
-	i := 1
-	for k := 1; k < len(s); k++ {
-		if s[k] != s[k-1] {
-			if i != k {
-				s[i] = s[k]
-			}
-			i++
-		}
-	}
-	clearSlice(s[i:]) // zero/nil out the obsolete elements, for GC
-	return s[:i]
+	return slices.Compact(s)
 }
 
 // CompactFunc is like [Compact] but uses an equality function to compare elements.
 // For runs of elements that compare equal, CompactFunc keeps the first one.
 // CompactFunc zeroes the elements between the new length and the original length.
+//
+//go:fix inline
 func CompactFunc[S ~[]E, E any](s S, eq func(E, E) bool) S {
-	if len(s) < 2 {
-		return s
-	}
-	i := 1
-	for k := 1; k < len(s); k++ {
-		if !eq(s[k], s[k-1]) {
-			if i != k {
-				s[i] = s[k]
-			}
-			i++
-		}
-	}
-	clearSlice(s[i:]) // zero/nil out the obsolete elements, for GC
-	return s[:i]
+	return slices.CompactFunc(s, eq)
 }
 
 // Grow increases the slice's capacity, if necessary, to guarantee space for
 // another n elements. After Grow(n), at least n elements can be appended
 // to the slice without another allocation. If n is negative or too large to
 // allocate the memory, Grow panics.
+//
+//go:fix inline
 func Grow[S ~[]E, E any](s S, n int) S {
-	if n < 0 {
-		panic("cannot be negative")
-	}
-	if n -= cap(s) - len(s); n > 0 {
-		// TODO(https://go.dev/issue/53888): Make using []E instead of S
-		// to workaround a compiler bug where the runtime.growslice optimization
-		// does not take effect. Revert when the compiler is fixed.
-		s = append([]E(s)[:cap(s)], make([]E, n)...)[:len(s)]
-	}
-	return s
+	return slices.Grow(s, n)
 }
 
 // Clip removes unused capacity from the slice, returning s[:len(s):len(s)].
-func Clip[S ~[]E, E any](s S) S {
-	return s[:len(s):len(s)]
-}
-
-// Rotation algorithm explanation:
-//
-// rotate left by 2
-// start with
-//   0123456789
-// split up like this
-//   01 234567 89
-// swap first 2 and last 2
-//   89 234567 01
-// join first parts
-//   89234567 01
-// recursively rotate first left part by 2
-//   23456789 01
-// join at the end
-//   2345678901
 //
-// rotate left by 8
-// start with
-//   0123456789
-// split up like this
-//   01 234567 89
-// swap first 2 and last 2
-//   89 234567 01
-// join last parts
-//   89 23456701
-// recursively rotate second part left by 6
-//   89 01234567
-// join at the end
-//   8901234567
-
-// TODO: There are other rotate algorithms.
-// This algorithm has the desirable property that it moves each element exactly twice.
-// The triple-reverse algorithm is simpler and more cache friendly, but takes more writes.
-// The follow-cycles algorithm can be 1-write but it is not very cache friendly.
-
-// rotateLeft rotates b left by n spaces.
-// s_final[i] = s_orig[i+r], wrapping around.
-func rotateLeft[E any](s []E, r int) {
-	for r != 0 && r != len(s) {
-		if r*2 <= len(s) {
-			swap(s[:r], s[len(s)-r:])
-			s = s[:len(s)-r]
-		} else {
-			swap(s[:len(s)-r], s[r:])
-			s, r = s[len(s)-r:], r*2-len(s)
-		}
-	}
-}
-func rotateRight[E any](s []E, r int) {
-	rotateLeft(s, len(s)-r)
-}
-
-// swap swaps the contents of x and y. x and y must be equal length and disjoint.
-func swap[E any](x, y []E) {
-	for i := 0; i < len(x); i++ {
-		x[i], y[i] = y[i], x[i]
-	}
-}
-
-// overlaps reports whether the memory ranges a[0:len(a)] and b[0:len(b)] overlap.
-func overlaps[E any](a, b []E) bool {
-	if len(a) == 0 || len(b) == 0 {
-		return false
-	}
-	elemSize := unsafe.Sizeof(a[0])
-	if elemSize == 0 {
-		return false
-	}
-	// TODO: use a runtime/unsafe facility once one becomes available. See issue 12445.
-	// Also see crypto/internal/alias/alias.go:AnyOverlap
-	return uintptr(unsafe.Pointer(&a[0])) <= uintptr(unsafe.Pointer(&b[len(b)-1]))+(elemSize-1) &&
-		uintptr(unsafe.Pointer(&b[0])) <= uintptr(unsafe.Pointer(&a[len(a)-1]))+(elemSize-1)
-}
-
-// startIdx returns the index in haystack where the needle starts.
-// prerequisite: the needle must be aliased entirely inside the haystack.
-func startIdx[E any](haystack, needle []E) int {
-	p := &needle[0]
-	for i := range haystack {
-		if p == &haystack[i] {
-			return i
-		}
-	}
-	// TODO: what if the overlap is by a non-integral number of Es?
-	panic("needle not found")
+//go:fix inline
+func Clip[S ~[]E, E any](s S) S {
+	return slices.Clip(s)
 }
 
 // Reverse reverses the elements of the slice in place.
+//
+//go:fix inline
 func Reverse[S ~[]E, E any](s S) {
-	for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
-		s[i], s[j] = s[j], s[i]
-	}
+	slices.Reverse(s)
 }
diff --git a/vendor/golang.org/x/exp/slices/sort.go b/vendor/golang.org/x/exp/slices/sort.go
index f58bbc7ba..bd91a8d40 100644
--- a/vendor/golang.org/x/exp/slices/sort.go
+++ b/vendor/golang.org/x/exp/slices/sort.go
@@ -2,21 +2,19 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:generate go run $GOROOT/src/sort/gen_sort_variants.go -exp
-
 package slices
 
 import (
-	"math/bits"
-
-	"golang.org/x/exp/constraints"
+	"cmp"
+	"slices"
 )
 
 // Sort sorts a slice of any ordered type in ascending order.
 // When sorting floating-point numbers, NaNs are ordered before other values.
-func Sort[S ~[]E, E constraints.Ordered](x S) {
-	n := len(x)
-	pdqsortOrdered(x, 0, n, bits.Len(uint(n)))
+//
+//go:fix inline
+func Sort[S ~[]E, E cmp.Ordered](x S) {
+	slices.Sort(x)
 }
 
 // SortFunc sorts the slice x in ascending order as determined by the cmp
@@ -28,119 +26,79 @@ func Sort[S ~[]E, E constraints.Ordered](x S) {
 // SortFunc requires that cmp is a strict weak ordering.
 // See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
 // To indicate 'uncomparable', return 0 from the function.
+//
+//go:fix inline
 func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
-	n := len(x)
-	pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
+	slices.SortFunc(x, cmp)
 }
 
 // SortStableFunc sorts the slice x while keeping the original order of equal
 // elements, using cmp to compare elements in the same way as [SortFunc].
+//
+//go:fix inline
 func SortStableFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
-	stableCmpFunc(x, len(x), cmp)
+	slices.SortStableFunc(x, cmp)
 }
 
 // IsSorted reports whether x is sorted in ascending order.
-func IsSorted[S ~[]E, E constraints.Ordered](x S) bool {
-	for i := len(x) - 1; i > 0; i-- {
-		if cmpLess(x[i], x[i-1]) {
-			return false
-		}
-	}
-	return true
+//
+//go:fix inline
+func IsSorted[S ~[]E, E cmp.Ordered](x S) bool {
+	return slices.IsSorted(x)
 }
 
 // IsSortedFunc reports whether x is sorted in ascending order, with cmp as the
 // comparison function as defined by [SortFunc].
+//
+//go:fix inline
 func IsSortedFunc[S ~[]E, E any](x S, cmp func(a, b E) int) bool {
-	for i := len(x) - 1; i > 0; i-- {
-		if cmp(x[i], x[i-1]) < 0 {
-			return false
-		}
-	}
-	return true
+	return slices.IsSortedFunc(x, cmp)
 }
 
 // Min returns the minimal value in x. It panics if x is empty.
 // For floating-point numbers, Min propagates NaNs (any NaN value in x
 // forces the output to be NaN).
-func Min[S ~[]E, E constraints.Ordered](x S) E {
-	if len(x) < 1 {
-		panic("slices.Min: empty list")
-	}
-	m := x[0]
-	for i := 1; i < len(x); i++ {
-		m = min(m, x[i])
-	}
-	return m
+//
+//go:fix inline
+func Min[S ~[]E, E cmp.Ordered](x S) E {
+	return slices.Min(x)
 }
 
 // MinFunc returns the minimal value in x, using cmp to compare elements.
 // It panics if x is empty. If there is more than one minimal element
 // according to the cmp function, MinFunc returns the first one.
+//
+//go:fix inline
 func MinFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
-	if len(x) < 1 {
-		panic("slices.MinFunc: empty list")
-	}
-	m := x[0]
-	for i := 1; i < len(x); i++ {
-		if cmp(x[i], m) < 0 {
-			m = x[i]
-		}
-	}
-	return m
+	return slices.MinFunc(x, cmp)
 }
 
 // Max returns the maximal value in x. It panics if x is empty.
 // For floating-point E, Max propagates NaNs (any NaN value in x
 // forces the output to be NaN).
-func Max[S ~[]E, E constraints.Ordered](x S) E {
-	if len(x) < 1 {
-		panic("slices.Max: empty list")
-	}
-	m := x[0]
-	for i := 1; i < len(x); i++ {
-		m = max(m, x[i])
-	}
-	return m
+//
+//go:fix inline
+func Max[S ~[]E, E cmp.Ordered](x S) E {
+	return slices.Max(x)
 }
 
 // MaxFunc returns the maximal value in x, using cmp to compare elements.
 // It panics if x is empty. If there is more than one maximal element
 // according to the cmp function, MaxFunc returns the first one.
+//
+//go:fix inline
 func MaxFunc[S ~[]E, E any](x S, cmp func(a, b E) int) E {
-	if len(x) < 1 {
-		panic("slices.MaxFunc: empty list")
-	}
-	m := x[0]
-	for i := 1; i < len(x); i++ {
-		if cmp(x[i], m) > 0 {
-			m = x[i]
-		}
-	}
-	return m
+	return slices.MaxFunc(x, cmp)
 }
 
 // BinarySearch searches for target in a sorted slice and returns the position
 // where target is found, or the position where target would appear in the
 // sort order; it also returns a bool saying whether the target is really found
 // in the slice. The slice must be sorted in increasing order.
-func BinarySearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) {
-	// Inlining is faster than calling BinarySearchFunc with a lambda.
-	n := len(x)
-	// Define x[-1] < target and x[n] >= target.
-	// Invariant: x[i-1] < target, x[j] >= target.
-	i, j := 0, n
-	for i < j {
-		h := int(uint(i+j) >> 1) // avoid overflow when computing h
-		// i ≤ h < j
-		if cmpLess(x[h], target) {
-			i = h + 1 // preserves x[i-1] < target
-		} else {
-			j = h // preserves x[j] >= target
-		}
-	}
-	// i == j, x[i-1] < target, and x[j] (= x[i]) >= target  =>  answer is i.
-	return i, i < n && (x[i] == target || (isNaN(x[i]) && isNaN(target)))
+//
+//go:fix inline
+func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) {
+	return slices.BinarySearch(x, target)
 }
 
 // BinarySearchFunc works like [BinarySearch], but uses a custom comparison
@@ -150,48 +108,8 @@ func BinarySearch[S ~[]E, E constraints.Ordered](x S, target E) (int, bool) {
 // or a positive number if the slice element follows the target.
 // cmp must implement the same ordering as the slice, such that if
 // cmp(a, t) < 0 and cmp(b, t) >= 0, then a must precede b in the slice.
+//
+//go:fix inline
 func BinarySearchFunc[S ~[]E, E, T any](x S, target T, cmp func(E, T) int) (int, bool) {
-	n := len(x)
-	// Define cmp(x[-1], target) < 0 and cmp(x[n], target) >= 0 .
-	// Invariant: cmp(x[i - 1], target) < 0, cmp(x[j], target) >= 0.
-	i, j := 0, n
-	for i < j {
-		h := int(uint(i+j) >> 1) // avoid overflow when computing h
-		// i ≤ h < j
-		if cmp(x[h], target) < 0 {
-			i = h + 1 // preserves cmp(x[i - 1], target) < 0
-		} else {
-			j = h // preserves cmp(x[j], target) >= 0
-		}
-	}
-	// i == j, cmp(x[i-1], target) < 0, and cmp(x[j], target) (= cmp(x[i], target)) >= 0  =>  answer is i.
-	return i, i < n && cmp(x[i], target) == 0
-}
-
-type sortedHint int // hint for pdqsort when choosing the pivot
-
-const (
-	unknownHint sortedHint = iota
-	increasingHint
-	decreasingHint
-)
-
-// xorshift paper: https://www.jstatsoft.org/article/view/v008i14/xorshift.pdf
-type xorshift uint64
-
-func (r *xorshift) Next() uint64 {
-	*r ^= *r << 13
-	*r ^= *r >> 17
-	*r ^= *r << 5
-	return uint64(*r)
-}
-
-func nextPowerOfTwo(length int) uint {
-	return 1 << bits.Len(uint(length))
-}
-
-// isNaN reports whether x is a NaN without requiring the math package.
-// This will always return false if T is not floating-point.
-func isNaN[T constraints.Ordered](x T) bool {
-	return x != x
+	return slices.BinarySearchFunc(x, target, cmp)
 }
diff --git a/vendor/golang.org/x/exp/slices/zsortanyfunc.go b/vendor/golang.org/x/exp/slices/zsortanyfunc.go
deleted file mode 100644
index 06f2c7a24..000000000
--- a/vendor/golang.org/x/exp/slices/zsortanyfunc.go
+++ /dev/null
@@ -1,479 +0,0 @@
-// Code generated by gen_sort_variants.go; DO NOT EDIT.
-
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slices
-
-// insertionSortCmpFunc sorts data[a:b] using insertion sort.
-func insertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
-	for i := a + 1; i < b; i++ {
-		for j := i; j > a && (cmp(data[j], data[j-1]) < 0); j-- {
-			data[j], data[j-1] = data[j-1], data[j]
-		}
-	}
-}
-
-// siftDownCmpFunc implements the heap property on data[lo:hi].
-// first is an offset into the array where the root of the heap lies.
-func siftDownCmpFunc[E any](data []E, lo, hi, first int, cmp func(a, b E) int) {
-	root := lo
-	for {
-		child := 2*root + 1
-		if child >= hi {
-			break
-		}
-		if child+1 < hi && (cmp(data[first+child], data[first+child+1]) < 0) {
-			child++
-		}
-		if !(cmp(data[first+root], data[first+child]) < 0) {
-			return
-		}
-		data[first+root], data[first+child] = data[first+child], data[first+root]
-		root = child
-	}
-}
-
-func heapSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
-	first := a
-	lo := 0
-	hi := b - a
-
-	// Build heap with greatest element at top.
-	for i := (hi - 1) / 2; i >= 0; i-- {
-		siftDownCmpFunc(data, i, hi, first, cmp)
-	}
-
-	// Pop elements, largest first, into end of data.
-	for i := hi - 1; i >= 0; i-- {
-		data[first], data[first+i] = data[first+i], data[first]
-		siftDownCmpFunc(data, lo, i, first, cmp)
-	}
-}
-
-// pdqsortCmpFunc sorts data[a:b].
-// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
-// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
-// C++ implementation: https://github.com/orlp/pdqsort
-// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
-// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
-func pdqsortCmpFunc[E any](data []E, a, b, limit int, cmp func(a, b E) int) {
-	const maxInsertion = 12
-
-	var (
-		wasBalanced    = true // whether the last partitioning was reasonably balanced
-		wasPartitioned = true // whether the slice was already partitioned
-	)
-
-	for {
-		length := b - a
-
-		if length <= maxInsertion {
-			insertionSortCmpFunc(data, a, b, cmp)
-			return
-		}
-
-		// Fall back to heapsort if too many bad choices were made.
-		if limit == 0 {
-			heapSortCmpFunc(data, a, b, cmp)
-			return
-		}
-
-		// If the last partitioning was imbalanced, we need to breaking patterns.
-		if !wasBalanced {
-			breakPatternsCmpFunc(data, a, b, cmp)
-			limit--
-		}
-
-		pivot, hint := choosePivotCmpFunc(data, a, b, cmp)
-		if hint == decreasingHint {
-			reverseRangeCmpFunc(data, a, b, cmp)
-			// The chosen pivot was pivot-a elements after the start of the array.
-			// After reversing it is pivot-a elements before the end of the array.
-			// The idea came from Rust's implementation.
-			pivot = (b - 1) - (pivot - a)
-			hint = increasingHint
-		}
-
-		// The slice is likely already sorted.
-		if wasBalanced && wasPartitioned && hint == increasingHint {
-			if partialInsertionSortCmpFunc(data, a, b, cmp) {
-				return
-			}
-		}
-
-		// Probably the slice contains many duplicate elements, partition the slice into
-		// elements equal to and elements greater than the pivot.
-		if a > 0 && !(cmp(data[a-1], data[pivot]) < 0) {
-			mid := partitionEqualCmpFunc(data, a, b, pivot, cmp)
-			a = mid
-			continue
-		}
-
-		mid, alreadyPartitioned := partitionCmpFunc(data, a, b, pivot, cmp)
-		wasPartitioned = alreadyPartitioned
-
-		leftLen, rightLen := mid-a, b-mid
-		balanceThreshold := length / 8
-		if leftLen < rightLen {
-			wasBalanced = leftLen >= balanceThreshold
-			pdqsortCmpFunc(data, a, mid, limit, cmp)
-			a = mid + 1
-		} else {
-			wasBalanced = rightLen >= balanceThreshold
-			pdqsortCmpFunc(data, mid+1, b, limit, cmp)
-			b = mid
-		}
-	}
-}
-
-// partitionCmpFunc does one quicksort partition.
-// Let p = data[pivot]
-// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
-// On return, data[newpivot] = p
-func partitionCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int, alreadyPartitioned bool) {
-	data[a], data[pivot] = data[pivot], data[a]
-	i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
-
-	for i <= j && (cmp(data[i], data[a]) < 0) {
-		i++
-	}
-	for i <= j && !(cmp(data[j], data[a]) < 0) {
-		j--
-	}
-	if i > j {
-		data[j], data[a] = data[a], data[j]
-		return j, true
-	}
-	data[i], data[j] = data[j], data[i]
-	i++
-	j--
-
-	for {
-		for i <= j && (cmp(data[i], data[a]) < 0) {
-			i++
-		}
-		for i <= j && !(cmp(data[j], data[a]) < 0) {
-			j--
-		}
-		if i > j {
-			break
-		}
-		data[i], data[j] = data[j], data[i]
-		i++
-		j--
-	}
-	data[j], data[a] = data[a], data[j]
-	return j, false
-}
-
-// partitionEqualCmpFunc partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
-// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
-func partitionEqualCmpFunc[E any](data []E, a, b, pivot int, cmp func(a, b E) int) (newpivot int) {
-	data[a], data[pivot] = data[pivot], data[a]
-	i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
-
-	for {
-		for i <= j && !(cmp(data[a], data[i]) < 0) {
-			i++
-		}
-		for i <= j && (cmp(data[a], data[j]) < 0) {
-			j--
-		}
-		if i > j {
-			break
-		}
-		data[i], data[j] = data[j], data[i]
-		i++
-		j--
-	}
-	return i
-}
-
-// partialInsertionSortCmpFunc partially sorts a slice, returns true if the slice is sorted at the end.
-func partialInsertionSortCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) bool {
-	const (
-		maxSteps         = 5  // maximum number of adjacent out-of-order pairs that will get shifted
-		shortestShifting = 50 // don't shift any elements on short arrays
-	)
-	i := a + 1
-	for j := 0; j < maxSteps; j++ {
-		for i < b && !(cmp(data[i], data[i-1]) < 0) {
-			i++
-		}
-
-		if i == b {
-			return true
-		}
-
-		if b-a < shortestShifting {
-			return false
-		}
-
-		data[i], data[i-1] = data[i-1], data[i]
-
-		// Shift the smaller one to the left.
-		if i-a >= 2 {
-			for j := i - 1; j >= 1; j-- {
-				if !(cmp(data[j], data[j-1]) < 0) {
-					break
-				}
-				data[j], data[j-1] = data[j-1], data[j]
-			}
-		}
-		// Shift the greater one to the right.
-		if b-i >= 2 {
-			for j := i + 1; j < b; j++ {
-				if !(cmp(data[j], data[j-1]) < 0) {
-					break
-				}
-				data[j], data[j-1] = data[j-1], data[j]
-			}
-		}
-	}
-	return false
-}
-
-// breakPatternsCmpFunc scatters some elements around in an attempt to break some patterns
-// that might cause imbalanced partitions in quicksort.
-func breakPatternsCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
-	length := b - a
-	if length >= 8 {
-		random := xorshift(length)
-		modulus := nextPowerOfTwo(length)
-
-		for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
-			other := int(uint(random.Next()) & (modulus - 1))
-			if other >= length {
-				other -= length
-			}
-			data[idx], data[a+other] = data[a+other], data[idx]
-		}
-	}
-}
-
-// choosePivotCmpFunc chooses a pivot in data[a:b].
-//
-// [0,8): chooses a static pivot.
-// [8,shortestNinther): uses the simple median-of-three method.
-// [shortestNinther,∞): uses the Tukey ninther method.
-func choosePivotCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) (pivot int, hint sortedHint) {
-	const (
-		shortestNinther = 50
-		maxSwaps        = 4 * 3
-	)
-
-	l := b - a
-
-	var (
-		swaps int
-		i     = a + l/4*1
-		j     = a + l/4*2
-		k     = a + l/4*3
-	)
-
-	if l >= 8 {
-		if l >= shortestNinther {
-			// Tukey ninther method, the idea came from Rust's implementation.
-			i = medianAdjacentCmpFunc(data, i, &swaps, cmp)
-			j = medianAdjacentCmpFunc(data, j, &swaps, cmp)
-			k = medianAdjacentCmpFunc(data, k, &swaps, cmp)
-		}
-		// Find the median among i, j, k and stores it into j.
-		j = medianCmpFunc(data, i, j, k, &swaps, cmp)
-	}
-
-	switch swaps {
-	case 0:
-		return j, increasingHint
-	case maxSwaps:
-		return j, decreasingHint
-	default:
-		return j, unknownHint
-	}
-}
-
-// order2CmpFunc returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
-func order2CmpFunc[E any](data []E, a, b int, swaps *int, cmp func(a, b E) int) (int, int) {
-	if cmp(data[b], data[a]) < 0 {
-		*swaps++
-		return b, a
-	}
-	return a, b
-}
-
-// medianCmpFunc returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
-func medianCmpFunc[E any](data []E, a, b, c int, swaps *int, cmp func(a, b E) int) int {
-	a, b = order2CmpFunc(data, a, b, swaps, cmp)
-	b, c = order2CmpFunc(data, b, c, swaps, cmp)
-	a, b = order2CmpFunc(data, a, b, swaps, cmp)
-	return b
-}
-
-// medianAdjacentCmpFunc finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
-func medianAdjacentCmpFunc[E any](data []E, a int, swaps *int, cmp func(a, b E) int) int {
-	return medianCmpFunc(data, a-1, a, a+1, swaps, cmp)
-}
-
-func reverseRangeCmpFunc[E any](data []E, a, b int, cmp func(a, b E) int) {
-	i := a
-	j := b - 1
-	for i < j {
-		data[i], data[j] = data[j], data[i]
-		i++
-		j--
-	}
-}
-
-func swapRangeCmpFunc[E any](data []E, a, b, n int, cmp func(a, b E) int) {
-	for i := 0; i < n; i++ {
-		data[a+i], data[b+i] = data[b+i], data[a+i]
-	}
-}
-
-func stableCmpFunc[E any](data []E, n int, cmp func(a, b E) int) {
-	blockSize := 20 // must be > 0
-	a, b := 0, blockSize
-	for b <= n {
-		insertionSortCmpFunc(data, a, b, cmp)
-		a = b
-		b += blockSize
-	}
-	insertionSortCmpFunc(data, a, n, cmp)
-
-	for blockSize < n {
-		a, b = 0, 2*blockSize
-		for b <= n {
-			symMergeCmpFunc(data, a, a+blockSize, b, cmp)
-			a = b
-			b += 2 * blockSize
-		}
-		if m := a + blockSize; m < n {
-			symMergeCmpFunc(data, a, m, n, cmp)
-		}
-		blockSize *= 2
-	}
-}
-
-// symMergeCmpFunc merges the two sorted subsequences data[a:m] and data[m:b] using
-// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
-// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
-// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
-// Computer Science, pages 714-723. Springer, 2004.
-//
-// Let M = m-a and N = b-n. Wolog M < N.
-// The recursion depth is bound by ceil(log(N+M)).
-// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
-// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
-//
-// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
-// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
-// in the paper carries through for Swap operations, especially as the block
-// swapping rotate uses only O(M+N) Swaps.
-//
-// symMerge assumes non-degenerate arguments: a < m && m < b.
-// Having the caller check this condition eliminates many leaf recursion calls,
-// which improves performance.
-func symMergeCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
-	// Avoid unnecessary recursions of symMerge
-	// by direct insertion of data[a] into data[m:b]
-	// if data[a:m] only contains one element.
-	if m-a == 1 {
-		// Use binary search to find the lowest index i
-		// such that data[i] >= data[a] for m <= i < b.
-		// Exit the search loop with i == b in case no such index exists.
-		i := m
-		j := b
-		for i < j {
-			h := int(uint(i+j) >> 1)
-			if cmp(data[h], data[a]) < 0 {
-				i = h + 1
-			} else {
-				j = h
-			}
-		}
-		// Swap values until data[a] reaches the position before i.
-		for k := a; k < i-1; k++ {
-			data[k], data[k+1] = data[k+1], data[k]
-		}
-		return
-	}
-
-	// Avoid unnecessary recursions of symMerge
-	// by direct insertion of data[m] into data[a:m]
-	// if data[m:b] only contains one element.
-	if b-m == 1 {
-		// Use binary search to find the lowest index i
-		// such that data[i] > data[m] for a <= i < m.
-		// Exit the search loop with i == m in case no such index exists.
-		i := a
-		j := m
-		for i < j {
-			h := int(uint(i+j) >> 1)
-			if !(cmp(data[m], data[h]) < 0) {
-				i = h + 1
-			} else {
-				j = h
-			}
-		}
-		// Swap values until data[m] reaches the position i.
-		for k := m; k > i; k-- {
-			data[k], data[k-1] = data[k-1], data[k]
-		}
-		return
-	}
-
-	mid := int(uint(a+b) >> 1)
-	n := mid + m
-	var start, r int
-	if m > mid {
-		start = n - b
-		r = mid
-	} else {
-		start = a
-		r = m
-	}
-	p := n - 1
-
-	for start < r {
-		c := int(uint(start+r) >> 1)
-		if !(cmp(data[p-c], data[c]) < 0) {
-			start = c + 1
-		} else {
-			r = c
-		}
-	}
-
-	end := n - start
-	if start < m && m < end {
-		rotateCmpFunc(data, start, m, end, cmp)
-	}
-	if a < start && start < mid {
-		symMergeCmpFunc(data, a, start, mid, cmp)
-	}
-	if mid < end && end < b {
-		symMergeCmpFunc(data, mid, end, b, cmp)
-	}
-}
-
-// rotateCmpFunc rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
-// Data of the form 'x u v y' is changed to 'x v u y'.
-// rotate performs at most b-a many calls to data.Swap,
-// and it assumes non-degenerate arguments: a < m && m < b.
-func rotateCmpFunc[E any](data []E, a, m, b int, cmp func(a, b E) int) {
-	i := m - a
-	j := b - m
-
-	for i != j {
-		if i > j {
-			swapRangeCmpFunc(data, m-i, m, j, cmp)
-			i -= j
-		} else {
-			swapRangeCmpFunc(data, m-i, m+j-i, i, cmp)
-			j -= i
-		}
-	}
-	// i == j
-	swapRangeCmpFunc(data, m-i, m, i, cmp)
-}
diff --git a/vendor/golang.org/x/exp/slices/zsortordered.go b/vendor/golang.org/x/exp/slices/zsortordered.go
deleted file mode 100644
index 99b47c398..000000000
--- a/vendor/golang.org/x/exp/slices/zsortordered.go
+++ /dev/null
@@ -1,481 +0,0 @@
-// Code generated by gen_sort_variants.go; DO NOT EDIT.
-
-// Copyright 2022 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package slices
-
-import "golang.org/x/exp/constraints"
-
-// insertionSortOrdered sorts data[a:b] using insertion sort.
-func insertionSortOrdered[E constraints.Ordered](data []E, a, b int) {
-	for i := a + 1; i < b; i++ {
-		for j := i; j > a && cmpLess(data[j], data[j-1]); j-- {
-			data[j], data[j-1] = data[j-1], data[j]
-		}
-	}
-}
-
-// siftDownOrdered implements the heap property on data[lo:hi].
-// first is an offset into the array where the root of the heap lies.
-func siftDownOrdered[E constraints.Ordered](data []E, lo, hi, first int) {
-	root := lo
-	for {
-		child := 2*root + 1
-		if child >= hi {
-			break
-		}
-		if child+1 < hi && cmpLess(data[first+child], data[first+child+1]) {
-			child++
-		}
-		if !cmpLess(data[first+root], data[first+child]) {
-			return
-		}
-		data[first+root], data[first+child] = data[first+child], data[first+root]
-		root = child
-	}
-}
-
-func heapSortOrdered[E constraints.Ordered](data []E, a, b int) {
-	first := a
-	lo := 0
-	hi := b - a
-
-	// Build heap with greatest element at top.
-	for i := (hi - 1) / 2; i >= 0; i-- {
-		siftDownOrdered(data, i, hi, first)
-	}
-
-	// Pop elements, largest first, into end of data.
-	for i := hi - 1; i >= 0; i-- {
-		data[first], data[first+i] = data[first+i], data[first]
-		siftDownOrdered(data, lo, i, first)
-	}
-}
-
-// pdqsortOrdered sorts data[a:b].
-// The algorithm based on pattern-defeating quicksort(pdqsort), but without the optimizations from BlockQuicksort.
-// pdqsort paper: https://arxiv.org/pdf/2106.05123.pdf
-// C++ implementation: https://github.com/orlp/pdqsort
-// Rust implementation: https://docs.rs/pdqsort/latest/pdqsort/
-// limit is the number of allowed bad (very unbalanced) pivots before falling back to heapsort.
-func pdqsortOrdered[E constraints.Ordered](data []E, a, b, limit int) {
-	const maxInsertion = 12
-
-	var (
-		wasBalanced    = true // whether the last partitioning was reasonably balanced
-		wasPartitioned = true // whether the slice was already partitioned
-	)
-
-	for {
-		length := b - a
-
-		if length <= maxInsertion {
-			insertionSortOrdered(data, a, b)
-			return
-		}
-
-		// Fall back to heapsort if too many bad choices were made.
-		if limit == 0 {
-			heapSortOrdered(data, a, b)
-			return
-		}
-
-		// If the last partitioning was imbalanced, we need to breaking patterns.
-		if !wasBalanced {
-			breakPatternsOrdered(data, a, b)
-			limit--
-		}
-
-		pivot, hint := choosePivotOrdered(data, a, b)
-		if hint == decreasingHint {
-			reverseRangeOrdered(data, a, b)
-			// The chosen pivot was pivot-a elements after the start of the array.
-			// After reversing it is pivot-a elements before the end of the array.
-			// The idea came from Rust's implementation.
-			pivot = (b - 1) - (pivot - a)
-			hint = increasingHint
-		}
-
-		// The slice is likely already sorted.
-		if wasBalanced && wasPartitioned && hint == increasingHint {
-			if partialInsertionSortOrdered(data, a, b) {
-				return
-			}
-		}
-
-		// Probably the slice contains many duplicate elements, partition the slice into
-		// elements equal to and elements greater than the pivot.
-		if a > 0 && !cmpLess(data[a-1], data[pivot]) {
-			mid := partitionEqualOrdered(data, a, b, pivot)
-			a = mid
-			continue
-		}
-
-		mid, alreadyPartitioned := partitionOrdered(data, a, b, pivot)
-		wasPartitioned = alreadyPartitioned
-
-		leftLen, rightLen := mid-a, b-mid
-		balanceThreshold := length / 8
-		if leftLen < rightLen {
-			wasBalanced = leftLen >= balanceThreshold
-			pdqsortOrdered(data, a, mid, limit)
-			a = mid + 1
-		} else {
-			wasBalanced = rightLen >= balanceThreshold
-			pdqsortOrdered(data, mid+1, b, limit)
-			b = mid
-		}
-	}
-}
-
-// partitionOrdered does one quicksort partition.
-// Let p = data[pivot]
-// Moves elements in data[a:b] around, so that data[i]<p and data[j]>=p for i<newpivot and j>newpivot.
-// On return, data[newpivot] = p
-func partitionOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int, alreadyPartitioned bool) {
-	data[a], data[pivot] = data[pivot], data[a]
-	i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
-
-	for i <= j && cmpLess(data[i], data[a]) {
-		i++
-	}
-	for i <= j && !cmpLess(data[j], data[a]) {
-		j--
-	}
-	if i > j {
-		data[j], data[a] = data[a], data[j]
-		return j, true
-	}
-	data[i], data[j] = data[j], data[i]
-	i++
-	j--
-
-	for {
-		for i <= j && cmpLess(data[i], data[a]) {
-			i++
-		}
-		for i <= j && !cmpLess(data[j], data[a]) {
-			j--
-		}
-		if i > j {
-			break
-		}
-		data[i], data[j] = data[j], data[i]
-		i++
-		j--
-	}
-	data[j], data[a] = data[a], data[j]
-	return j, false
-}
-
-// partitionEqualOrdered partitions data[a:b] into elements equal to data[pivot] followed by elements greater than data[pivot].
-// It assumed that data[a:b] does not contain elements smaller than the data[pivot].
-func partitionEqualOrdered[E constraints.Ordered](data []E, a, b, pivot int) (newpivot int) {
-	data[a], data[pivot] = data[pivot], data[a]
-	i, j := a+1, b-1 // i and j are inclusive of the elements remaining to be partitioned
-
-	for {
-		for i <= j && !cmpLess(data[a], data[i]) {
-			i++
-		}
-		for i <= j && cmpLess(data[a], data[j]) {
-			j--
-		}
-		if i > j {
-			break
-		}
-		data[i], data[j] = data[j], data[i]
-		i++
-		j--
-	}
-	return i
-}
-
-// partialInsertionSortOrdered partially sorts a slice, returns true if the slice is sorted at the end.
-func partialInsertionSortOrdered[E constraints.Ordered](data []E, a, b int) bool {
-	const (
-		maxSteps         = 5  // maximum number of adjacent out-of-order pairs that will get shifted
-		shortestShifting = 50 // don't shift any elements on short arrays
-	)
-	i := a + 1
-	for j := 0; j < maxSteps; j++ {
-		for i < b && !cmpLess(data[i], data[i-1]) {
-			i++
-		}
-
-		if i == b {
-			return true
-		}
-
-		if b-a < shortestShifting {
-			return false
-		}
-
-		data[i], data[i-1] = data[i-1], data[i]
-
-		// Shift the smaller one to the left.
-		if i-a >= 2 {
-			for j := i - 1; j >= 1; j-- {
-				if !cmpLess(data[j], data[j-1]) {
-					break
-				}
-				data[j], data[j-1] = data[j-1], data[j]
-			}
-		}
-		// Shift the greater one to the right.
-		if b-i >= 2 {
-			for j := i + 1; j < b; j++ {
-				if !cmpLess(data[j], data[j-1]) {
-					break
-				}
-				data[j], data[j-1] = data[j-1], data[j]
-			}
-		}
-	}
-	return false
-}
-
-// breakPatternsOrdered scatters some elements around in an attempt to break some patterns
-// that might cause imbalanced partitions in quicksort.
-func breakPatternsOrdered[E constraints.Ordered](data []E, a, b int) {
-	length := b - a
-	if length >= 8 {
-		random := xorshift(length)
-		modulus := nextPowerOfTwo(length)
-
-		for idx := a + (length/4)*2 - 1; idx <= a+(length/4)*2+1; idx++ {
-			other := int(uint(random.Next()) & (modulus - 1))
-			if other >= length {
-				other -= length
-			}
-			data[idx], data[a+other] = data[a+other], data[idx]
-		}
-	}
-}
-
-// choosePivotOrdered chooses a pivot in data[a:b].
-//
-// [0,8): chooses a static pivot.
-// [8,shortestNinther): uses the simple median-of-three method.
-// [shortestNinther,∞): uses the Tukey ninther method.
-func choosePivotOrdered[E constraints.Ordered](data []E, a, b int) (pivot int, hint sortedHint) {
-	const (
-		shortestNinther = 50
-		maxSwaps        = 4 * 3
-	)
-
-	l := b - a
-
-	var (
-		swaps int
-		i     = a + l/4*1
-		j     = a + l/4*2
-		k     = a + l/4*3
-	)
-
-	if l >= 8 {
-		if l >= shortestNinther {
-			// Tukey ninther method, the idea came from Rust's implementation.
-			i = medianAdjacentOrdered(data, i, &swaps)
-			j = medianAdjacentOrdered(data, j, &swaps)
-			k = medianAdjacentOrdered(data, k, &swaps)
-		}
-		// Find the median among i, j, k and stores it into j.
-		j = medianOrdered(data, i, j, k, &swaps)
-	}
-
-	switch swaps {
-	case 0:
-		return j, increasingHint
-	case maxSwaps:
-		return j, decreasingHint
-	default:
-		return j, unknownHint
-	}
-}
-
-// order2Ordered returns x,y where data[x] <= data[y], where x,y=a,b or x,y=b,a.
-func order2Ordered[E constraints.Ordered](data []E, a, b int, swaps *int) (int, int) {
-	if cmpLess(data[b], data[a]) {
-		*swaps++
-		return b, a
-	}
-	return a, b
-}
-
-// medianOrdered returns x where data[x] is the median of data[a],data[b],data[c], where x is a, b, or c.
-func medianOrdered[E constraints.Ordered](data []E, a, b, c int, swaps *int) int {
-	a, b = order2Ordered(data, a, b, swaps)
-	b, c = order2Ordered(data, b, c, swaps)
-	a, b = order2Ordered(data, a, b, swaps)
-	return b
-}
-
-// medianAdjacentOrdered finds the median of data[a - 1], data[a], data[a + 1] and stores the index into a.
-func medianAdjacentOrdered[E constraints.Ordered](data []E, a int, swaps *int) int {
-	return medianOrdered(data, a-1, a, a+1, swaps)
-}
-
-func reverseRangeOrdered[E constraints.Ordered](data []E, a, b int) {
-	i := a
-	j := b - 1
-	for i < j {
-		data[i], data[j] = data[j], data[i]
-		i++
-		j--
-	}
-}
-
-func swapRangeOrdered[E constraints.Ordered](data []E, a, b, n int) {
-	for i := 0; i < n; i++ {
-		data[a+i], data[b+i] = data[b+i], data[a+i]
-	}
-}
-
-func stableOrdered[E constraints.Ordered](data []E, n int) {
-	blockSize := 20 // must be > 0
-	a, b := 0, blockSize
-	for b <= n {
-		insertionSortOrdered(data, a, b)
-		a = b
-		b += blockSize
-	}
-	insertionSortOrdered(data, a, n)
-
-	for blockSize < n {
-		a, b = 0, 2*blockSize
-		for b <= n {
-			symMergeOrdered(data, a, a+blockSize, b)
-			a = b
-			b += 2 * blockSize
-		}
-		if m := a + blockSize; m < n {
-			symMergeOrdered(data, a, m, n)
-		}
-		blockSize *= 2
-	}
-}
-
-// symMergeOrdered merges the two sorted subsequences data[a:m] and data[m:b] using
-// the SymMerge algorithm from Pok-Son Kim and Arne Kutzner, "Stable Minimum
-// Storage Merging by Symmetric Comparisons", in Susanne Albers and Tomasz
-// Radzik, editors, Algorithms - ESA 2004, volume 3221 of Lecture Notes in
-// Computer Science, pages 714-723. Springer, 2004.
-//
-// Let M = m-a and N = b-n. Wolog M < N.
-// The recursion depth is bound by ceil(log(N+M)).
-// The algorithm needs O(M*log(N/M + 1)) calls to data.Less.
-// The algorithm needs O((M+N)*log(M)) calls to data.Swap.
-//
-// The paper gives O((M+N)*log(M)) as the number of assignments assuming a
-// rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
-// in the paper carries through for Swap operations, especially as the block
-// swapping rotate uses only O(M+N) Swaps.
-//
-// symMerge assumes non-degenerate arguments: a < m && m < b.
-// Having the caller check this condition eliminates many leaf recursion calls,
-// which improves performance.
-func symMergeOrdered[E constraints.Ordered](data []E, a, m, b int) {
-	// Avoid unnecessary recursions of symMerge
-	// by direct insertion of data[a] into data[m:b]
-	// if data[a:m] only contains one element.
-	if m-a == 1 {
-		// Use binary search to find the lowest index i
-		// such that data[i] >= data[a] for m <= i < b.
-		// Exit the search loop with i == b in case no such index exists.
-		i := m
-		j := b
-		for i < j {
-			h := int(uint(i+j) >> 1)
-			if cmpLess(data[h], data[a]) {
-				i = h + 1
-			} else {
-				j = h
-			}
-		}
-		// Swap values until data[a] reaches the position before i.
-		for k := a; k < i-1; k++ {
-			data[k], data[k+1] = data[k+1], data[k]
-		}
-		return
-	}
-
-	// Avoid unnecessary recursions of symMerge
-	// by direct insertion of data[m] into data[a:m]
-	// if data[m:b] only contains one element.
-	if b-m == 1 {
-		// Use binary search to find the lowest index i
-		// such that data[i] > data[m] for a <= i < m.
-		// Exit the search loop with i == m in case no such index exists.
-		i := a
-		j := m
-		for i < j {
-			h := int(uint(i+j) >> 1)
-			if !cmpLess(data[m], data[h]) {
-				i = h + 1
-			} else {
-				j = h
-			}
-		}
-		// Swap values until data[m] reaches the position i.
-		for k := m; k > i; k-- {
-			data[k], data[k-1] = data[k-1], data[k]
-		}
-		return
-	}
-
-	mid := int(uint(a+b) >> 1)
-	n := mid + m
-	var start, r int
-	if m > mid {
-		start = n - b
-		r = mid
-	} else {
-		start = a
-		r = m
-	}
-	p := n - 1
-
-	for start < r {
-		c := int(uint(start+r) >> 1)
-		if !cmpLess(data[p-c], data[c]) {
-			start = c + 1
-		} else {
-			r = c
-		}
-	}
-
-	end := n - start
-	if start < m && m < end {
-		rotateOrdered(data, start, m, end)
-	}
-	if a < start && start < mid {
-		symMergeOrdered(data, a, start, mid)
-	}
-	if mid < end && end < b {
-		symMergeOrdered(data, mid, end, b)
-	}
-}
-
-// rotateOrdered rotates two consecutive blocks u = data[a:m] and v = data[m:b] in data:
-// Data of the form 'x u v y' is changed to 'x v u y'.
-// rotate performs at most b-a many calls to data.Swap,
-// and it assumes non-degenerate arguments: a < m && m < b.
-func rotateOrdered[E constraints.Ordered](data []E, a, m, b int) {
-	i := m - a
-	j := b - m
-
-	for i != j {
-		if i > j {
-			swapRangeOrdered(data, m-i, m, j)
-			i -= j
-		} else {
-			swapRangeOrdered(data, m-i, m+j-i, i)
-			j -= i
-		}
-	}
-	// i == j
-	swapRangeOrdered(data, m-i, m, i)
-}
diff --git a/vendor/k8s.io/utils/buffer/ring_growing.go b/vendor/k8s.io/utils/buffer/ring_growing.go
index 86965a513..77243575c 100644
--- a/vendor/k8s.io/utils/buffer/ring_growing.go
+++ b/vendor/k8s.io/utils/buffer/ring_growing.go
@@ -70,3 +70,13 @@ func (r *RingGrowing) WriteOne(data interface{}) {
 	r.data[(r.readable+r.beg)%r.n] = data
 	r.readable++
 }
+
+// Len returns the number of items in the buffer.
+func (r *RingGrowing) Len() int {
+	return r.readable
+}
+
+// Cap returns the capacity of the buffer.
+func (r *RingGrowing) Cap() int {
+	return r.n
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 7385ae347..95eaf1a7a 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1,8 +1,8 @@
 # cel.dev/expr v0.18.0
 ## explicit; go 1.21.1
 cel.dev/expr
-# github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0
-## explicit; go 1.18
+# github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.1
+## explicit; go 1.23.0
 github.com/Azure/azure-sdk-for-go/sdk/azcore
 github.com/Azure/azure-sdk-for-go/sdk/azcore/arm
 github.com/Azure/azure-sdk-for-go/sdk/azcore/arm/internal/resource
@@ -82,7 +82,7 @@ github.com/Azure/go-ansiterm/winterm
 github.com/Azure/msi-dataplane/pkg/dataplane
 github.com/Azure/msi-dataplane/pkg/dataplane/internal/challenge
 github.com/Azure/msi-dataplane/pkg/dataplane/internal/client
-# github.com/AzureAD/microsoft-authentication-library-for-go v1.4.0
+# github.com/AzureAD/microsoft-authentication-library-for-go v1.4.1
 ## explicit; go 1.18
 github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache
 github.com/AzureAD/microsoft-authentication-library-for-go/apps/confidential
@@ -178,7 +178,7 @@ github.com/gogo/protobuf/protoc-gen-gogo/descriptor
 github.com/gogo/protobuf/sortkeys
 # github.com/golang-jwt/jwt/v4 v4.5.2
 ## explicit; go 1.16
-# github.com/golang-jwt/jwt/v5 v5.2.1
+# github.com/golang-jwt/jwt/v5 v5.2.2
 ## explicit; go 1.18
 github.com/golang-jwt/jwt/v5
 # github.com/golang/protobuf v1.5.4
@@ -467,9 +467,8 @@ golang.org/x/crypto/nacl/secretbox
 golang.org/x/crypto/pkcs12
 golang.org/x/crypto/pkcs12/internal/rc2
 golang.org/x/crypto/salsa20/salsa
-# golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
-## explicit; go 1.20
-golang.org/x/exp/constraints
+# golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
+## explicit; go 1.23.0
 golang.org/x/exp/slices
 # golang.org/x/net v0.37.0
 ## explicit; go 1.23.0
@@ -1381,7 +1380,7 @@ k8s.io/kubelet/pkg/apis/credentialprovider/install
 k8s.io/kubelet/pkg/apis/credentialprovider/v1
 k8s.io/kubelet/pkg/apis/credentialprovider/v1alpha1
 k8s.io/kubelet/pkg/apis/credentialprovider/v1beta1
-# k8s.io/utils v0.0.0-20241210054802-24370beab758
+# k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
 ## explicit; go 1.18
 k8s.io/utils/buffer
 k8s.io/utils/clock
@@ -1400,7 +1399,7 @@ sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client/metrics
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/common/metrics
 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client
-# sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.14
+# sigs.k8s.io/cloud-provider-azure/pkg/azclient v0.5.20
 ## explicit; go 1.23.0
 sigs.k8s.io/cloud-provider-azure/pkg/azclient
 sigs.k8s.io/cloud-provider-azure/pkg/azclient/accountclient
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/Makefile b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/Makefile
index eb8cffc4f..76582ce67 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/Makefile
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/Makefile
@@ -145,7 +145,7 @@ GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
 .PHONY: golangci-lint
 golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
 $(GOLANGCI_LINT): $(LOCALBIN)
-	test -s $(LOCALBIN)/golangci-lint || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(LOCALBIN) latest
+	test -s $(LOCALBIN)/golangci-lint || curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(LOCALBIN) v1.64.8
 
 GOIMPORTS ?= $(LOCALBIN)/goimports
 .PHONY: goimports
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth.go
index 7acbd1d92..2271b1601 100644
--- a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth.go
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth.go
@@ -17,156 +17,61 @@ limitations under the License.
 package azclient
 
 import (
-	"context"
+	"errors"
 	"fmt"
-	"os"
 	"strings"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
-	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
-	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
-	"github.com/Azure/msi-dataplane/pkg/dataplane"
+)
 
-	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/armauth"
+var (
+	ErrNoValidAuthMethodFound = errors.New("no valid authentication method found")
 )
 
 type AuthProvider struct {
-	ComputeCredential     azcore.TokenCredential
-	NetworkCredential     azcore.TokenCredential
-	MultiTenantCredential azcore.TokenCredential
-	CloudConfig           cloud.Configuration
+	ComputeCredential              azcore.TokenCredential
+	AdditionalComputeClientOptions []func(option *arm.ClientOptions)
+	NetworkCredential              azcore.TokenCredential
+	CloudConfig                    cloud.Configuration
 }
 
-func NewAuthProvider(armConfig *ARMClientConfig, config *AzureAuthConfig, clientOptionsMutFn ...func(option *policy.ClientOptions)) (*AuthProvider, error) {
+func NewAuthProvider(
+	armConfig *ARMClientConfig,
+	config *AzureAuthConfig,
+	options ...AuthProviderOption,
+) (*AuthProvider, error) {
+	opts := defaultAuthProviderOptions()
+	for _, opt := range options {
+		opt(opts)
+	}
+
 	clientOption, _, err := GetAzCoreClientOption(armConfig)
 	if err != nil {
 		return nil, err
 	}
-	for _, fn := range clientOptionsMutFn {
+	for _, fn := range opts.ClientOptionsMutFn {
 		fn(clientOption)
 	}
-	var computeCredential azcore.TokenCredential
-	var networkTokenCredential azcore.TokenCredential
-	var multiTenantCredential azcore.TokenCredential
-
-	// federatedIdentityCredential is used for workload identity federation
-	if aadFederatedTokenFile, enabled := config.GetAzureFederatedTokenFile(); enabled {
-		computeCredential, err = azidentity.NewWorkloadIdentityCredential(&azidentity.WorkloadIdentityCredentialOptions{
-			ClientOptions: *clientOption,
-			ClientID:      config.GetAADClientID(),
-			TenantID:      armConfig.GetTenantID(),
-			TokenFilePath: aadFederatedTokenFile,
-		})
-		if err != nil {
-			return nil, err
-		}
-	}
-	// managedIdentityCredential is used for managed identity extension
-	if computeCredential == nil && config.UseManagedIdentityExtension {
-		credOptions := &azidentity.ManagedIdentityCredentialOptions{
-			ClientOptions: *clientOption,
-		}
-		if len(config.UserAssignedIdentityID) > 0 {
-			if strings.Contains(strings.ToUpper(config.UserAssignedIdentityID), "/SUBSCRIPTIONS/") {
-				credOptions.ID = azidentity.ResourceID(config.UserAssignedIdentityID)
-			} else {
-				credOptions.ID = azidentity.ClientID(config.UserAssignedIdentityID)
-			}
-		}
-		computeCredential, err = azidentity.NewManagedIdentityCredential(credOptions)
-		if err != nil {
-			return nil, err
-		}
-		if config.AuxiliaryTokenProvider != nil && IsMultiTenant(armConfig) {
-			networkTokenCredential, err = armauth.NewKeyVaultCredential(
-				computeCredential,
-				config.AuxiliaryTokenProvider.SecretResourceID(),
-			)
-			if err != nil {
-				return nil, fmt.Errorf("create KeyVaultCredential for auxiliary token provider: %w", err)
-			}
-		}
-	}
-
-	// Client secret authentication
-	if computeCredential == nil && len(config.GetAADClientSecret()) > 0 {
-		credOptions := &azidentity.ClientSecretCredentialOptions{
-			ClientOptions: *clientOption,
-		}
-		computeCredential, err = azidentity.NewClientSecretCredential(armConfig.GetTenantID(), config.GetAADClientID(), config.GetAADClientSecret(), credOptions)
-		if err != nil {
-			return nil, err
-		}
-		if IsMultiTenant(armConfig) {
-			credOptions := &azidentity.ClientSecretCredentialOptions{
-				ClientOptions: *clientOption,
-			}
-			networkTokenCredential, err = azidentity.NewClientSecretCredential(armConfig.NetworkResourceTenantID, config.GetAADClientID(), config.AADClientSecret, credOptions)
-			if err != nil {
-				return nil, err
-			}
-
-			credOptions = &azidentity.ClientSecretCredentialOptions{
-				ClientOptions:              *clientOption,
-				AdditionallyAllowedTenants: []string{armConfig.NetworkResourceTenantID},
-			}
-			multiTenantCredential, err = azidentity.NewClientSecretCredential(armConfig.GetTenantID(), config.GetAADClientID(), config.GetAADClientSecret(), credOptions)
-			if err != nil {
-				return nil, err
-			}
-
-		}
-	}
 
-	// ClientCertificateCredential is used for client certificate
-	if computeCredential == nil && len(config.AADClientCertPath) > 0 {
-		credOptions := &azidentity.ClientCertificateCredentialOptions{
-			ClientOptions:        *clientOption,
-			SendCertificateChain: true,
-		}
-		certData, err := os.ReadFile(config.AADClientCertPath)
-		if err != nil {
-			return nil, fmt.Errorf("reading the client certificate from file %s: %w", config.AADClientCertPath, err)
-		}
-		certificate, privateKey, err := azidentity.ParseCertificates(certData, []byte(config.AADClientCertPassword))
-		if err != nil {
-			return nil, fmt.Errorf("decoding the client certificate: %w", err)
-		}
-		computeCredential, err = azidentity.NewClientCertificateCredential(armConfig.GetTenantID(), config.GetAADClientID(), certificate, privateKey, credOptions)
-		if err != nil {
-			return nil, err
-		}
-		if IsMultiTenant(armConfig) {
-			networkTokenCredential, err = azidentity.NewClientCertificateCredential(armConfig.NetworkResourceTenantID, config.GetAADClientID(), certificate, privateKey, credOptions)
-			if err != nil {
-				return nil, err
-			}
-			credOptions = &azidentity.ClientCertificateCredentialOptions{
-				ClientOptions:              *clientOption,
-				AdditionallyAllowedTenants: []string{armConfig.NetworkResourceTenantID},
-			}
-			multiTenantCredential, err = azidentity.NewClientCertificateCredential(armConfig.GetTenantID(), config.GetAADClientID(), certificate, privateKey, credOptions)
-			if err != nil {
-				return nil, err
-			}
-		}
+	aadFederatedTokenFile, federatedTokenEnabled := config.GetAzureFederatedTokenFile()
+	switch {
+	case federatedTokenEnabled:
+		return newAuthProviderWithWorkloadIdentity(aadFederatedTokenFile, armConfig, config, clientOption, opts)
+	case config.UseManagedIdentityExtension:
+		return newAuthProviderWithManagedIdentity(armConfig, config, clientOption, opts)
+	case len(config.GetAADClientSecret()) > 0:
+		return newAuthProviderWithServicePrincipalClientSecret(armConfig, config, clientOption, opts)
+	case len(config.AADClientCertPath) > 0:
+		return newAuthProviderWithServicePrincipalClientCertificate(armConfig, config, clientOption, opts)
+	case len(config.AADMSIDataPlaneIdentityPath) > 0:
+		return newAuthProviderWithUserAssignedIdentity(config, clientOption, opts)
+	default:
+		return &AuthProvider{
+			CloudConfig: clientOption.Cloud,
+		}, nil
 	}
-
-	// UserAssignedIdentityCredentials authentication
-	if computeCredential == nil && len(config.AADMSIDataPlaneIdentityPath) > 0 {
-		computeCredential, err = dataplane.NewUserAssignedIdentityCredential(context.Background(), config.AADMSIDataPlaneIdentityPath, dataplane.WithClientOpts(azcore.ClientOptions{Cloud: clientOption.Cloud}))
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	return &AuthProvider{
-		ComputeCredential:     computeCredential,
-		NetworkCredential:     networkTokenCredential,
-		MultiTenantCredential: multiTenantCredential,
-		CloudConfig:           clientOption.Cloud,
-	}, nil
 }
 
 func (factory *AuthProvider) GetAzIdentity() azcore.TokenCredential {
@@ -180,18 +85,11 @@ func (factory *AuthProvider) GetNetworkAzIdentity() azcore.TokenCredential {
 	return factory.ComputeCredential
 }
 
-func (factory *AuthProvider) GetMultiTenantIdentity() azcore.TokenCredential {
-	if factory.MultiTenantCredential != nil {
-		return factory.MultiTenantCredential
-	}
-	return factory.ComputeCredential
-}
-
-func (factory *AuthProvider) IsMultiTenantModeEnabled() bool {
-	return factory.MultiTenantCredential != nil
+func (factory *AuthProvider) DefaultTokenScope() string {
+	return DefaultTokenScopeFor(factory.CloudConfig)
 }
 
-func (factory *AuthProvider) DefaultTokenScope() string {
-	audience := factory.CloudConfig.Services[cloud.ResourceManager].Audience
+func DefaultTokenScopeFor(cloudCfg cloud.Configuration) string {
+	audience := cloudCfg.Services[cloud.ResourceManager].Audience
 	return fmt.Sprintf("%s/.default", strings.TrimRight(audience, "/"))
 }
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth_func.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth_func.go
new file mode 100644
index 000000000..31e6e2c81
--- /dev/null
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth_func.go
@@ -0,0 +1,310 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package azclient
+
+import (
+	"context"
+	"errors"
+	"fmt"
+	"strings"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
+	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
+	"github.com/Azure/msi-dataplane/pkg/dataplane"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/armauth"
+)
+
+var (
+	ErrAuxiliaryTokenProviderNotSet = errors.New("auxiliary token provider is not set when multi-tenant is enabled for MSI")
+	ErrNewKeyVaultCredentialFailed  = errors.New("create KeyVaultCredential failed")
+)
+
+// newAuthProviderWithWorkloadIdentity creates a new AuthProvider with workload identity.
+// The caller is responsible for checking if workload identity is enabled.
+// NOTE: it does NOT support multi-tenant scenarios.
+func newAuthProviderWithWorkloadIdentity(
+	aadFederatedTokenFile string,
+	armConfig *ARMClientConfig,
+	config *AzureAuthConfig,
+	clientOptions *policy.ClientOptions,
+	opts *authProviderOptions,
+) (*AuthProvider, error) {
+	computeCredential, err := opts.NewWorkloadIdentityCredentialFn(&azidentity.WorkloadIdentityCredentialOptions{
+		ClientOptions: *clientOptions,
+		ClientID:      config.GetAADClientID(),
+		TenantID:      armConfig.GetTenantID(),
+		TokenFilePath: aadFederatedTokenFile,
+	})
+	if err != nil {
+		return nil, err
+	}
+
+	return &AuthProvider{
+		ComputeCredential: computeCredential,
+		CloudConfig:       clientOptions.Cloud,
+	}, nil
+}
+
+// newAuthProviderWithManagedIdentity creates a new AuthProvider with managed identity.
+// When multi-tenant is enabled, it uses the auxiliary token provider to create a network credential
+// for cross-tenant resource access. If multi-tenant is enabled but the auxiliary token provider
+// is not configured, it returns an error.
+func newAuthProviderWithManagedIdentity(
+	armConfig *ARMClientConfig,
+	config *AzureAuthConfig,
+	clientOptions *policy.ClientOptions,
+	opts *authProviderOptions,
+) (*AuthProvider, error) {
+	credOptions := &azidentity.ManagedIdentityCredentialOptions{
+		ClientOptions: *clientOptions,
+	}
+	if len(config.UserAssignedIdentityID) > 0 {
+		if strings.Contains(strings.ToUpper(config.UserAssignedIdentityID), "/SUBSCRIPTIONS/") {
+			credOptions.ID = azidentity.ResourceID(config.UserAssignedIdentityID)
+		} else {
+			credOptions.ID = azidentity.ClientID(config.UserAssignedIdentityID)
+		}
+	}
+
+	computeCredential, err := opts.NewManagedIdentityCredentialFn(credOptions)
+	if err != nil {
+		return nil, err
+	}
+
+	rv := &AuthProvider{
+		ComputeCredential: computeCredential,
+		CloudConfig:       clientOptions.Cloud,
+	}
+
+	if !IsMultiTenant(armConfig) {
+		return rv, nil
+	}
+
+	if config.AuxiliaryTokenProvider == nil {
+		return nil, ErrAuxiliaryTokenProviderNotSet
+	}
+
+	// Use AuxiliaryTokenProvider as the network credential
+	networkCredential, err := opts.NewKeyVaultCredentialFn(
+		computeCredential,
+		config.AuxiliaryTokenProvider.SecretResourceID(),
+	)
+	if err != nil {
+		return nil, fmt.Errorf("%w: %w", ErrNewKeyVaultCredentialFailed, err)
+	}
+
+	// Additionally, we need to add the auxiliary token to the HTTP header when making requests to the compute resources
+	additionalComputeClientOptions := []func(option *arm.ClientOptions){
+		func(option *arm.ClientOptions) {
+			option.PerRetryPolicies = append(option.PerRetryPolicies, armauth.NewAuxiliaryAuthPolicy(
+				[]azcore.TokenCredential{networkCredential},
+				DefaultTokenScopeFor(clientOptions.Cloud),
+			))
+		},
+	}
+	rv.NetworkCredential = networkCredential
+	rv.AdditionalComputeClientOptions = additionalComputeClientOptions
+	return rv, nil
+}
+
+// newAuthProviderWithServicePrincipalClientSecret creates a new AuthProvider with service principal client secret.
+// When multi-tenant is enabled, it creates a compute credential with additional allowed tenants for cross-tenant access.
+func newAuthProviderWithServicePrincipalClientSecret(
+	armConfig *ARMClientConfig,
+	config *AzureAuthConfig,
+	clientOptions *policy.ClientOptions,
+	opts *authProviderOptions,
+) (*AuthProvider, error) {
+	var (
+		computeCredential azcore.TokenCredential
+		networkCredential azcore.TokenCredential
+	)
+
+	if !IsMultiTenant(armConfig) {
+		// Single tenant
+		credOptions := &azidentity.ClientSecretCredentialOptions{
+			ClientOptions: *clientOptions,
+		}
+		var err error
+		computeCredential, err = opts.NewClientSecretCredentialFn(
+			armConfig.GetTenantID(),
+			config.GetAADClientID(),
+			config.GetAADClientSecret(),
+			credOptions,
+		)
+		if err != nil {
+			return nil, err
+		}
+
+		return &AuthProvider{
+			ComputeCredential: computeCredential,
+			CloudConfig:       clientOptions.Cloud,
+		}, nil
+	}
+
+	// Network credential for network resource access
+	{
+		credOptions := &azidentity.ClientSecretCredentialOptions{
+			ClientOptions: *clientOptions,
+		}
+		var err error
+		networkCredential, err = opts.NewClientSecretCredentialFn(
+			armConfig.NetworkResourceTenantID,
+			config.GetAADClientID(),
+			config.GetAADClientSecret(),
+			credOptions,
+		)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Compute credential with additional allowed tenants for cross-tenant access
+	{
+		credOptions := &azidentity.ClientSecretCredentialOptions{
+			ClientOptions:              *clientOptions,
+			AdditionallyAllowedTenants: []string{armConfig.NetworkResourceTenantID},
+		}
+		var err error
+		computeCredential, err = opts.NewClientSecretCredentialFn(
+			armConfig.GetTenantID(),
+			config.GetAADClientID(),
+			config.GetAADClientSecret(),
+			credOptions,
+		)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return &AuthProvider{
+		ComputeCredential: computeCredential,
+		NetworkCredential: networkCredential,
+		CloudConfig:       clientOptions.Cloud,
+	}, nil
+}
+
+// newAuthProviderWithServicePrincipalClientCertificate creates a new AuthProvider with service principal client certificate.
+// When multi-tenant is enabled, it creates a compute credential with additional allowed tenants for cross-tenant access.
+func newAuthProviderWithServicePrincipalClientCertificate(
+	armConfig *ARMClientConfig,
+	config *AzureAuthConfig,
+	clientOptions *policy.ClientOptions,
+	opts *authProviderOptions,
+) (*AuthProvider, error) {
+	certData, err := opts.ReadFileFn(config.AADClientCertPath)
+	if err != nil {
+		return nil, fmt.Errorf("reading the client certificate from file %s: %w", config.AADClientCertPath, err)
+	}
+	certificate, privateKey, err := opts.ParseCertificatesFn(certData, []byte(config.AADClientCertPassword))
+	if err != nil {
+		return nil, fmt.Errorf("decoding the client certificate: %w", err)
+	}
+
+	var (
+		computeCredential azcore.TokenCredential
+		networkCredential azcore.TokenCredential
+	)
+
+	if !IsMultiTenant(armConfig) {
+		// Single tenant
+		credOptions := &azidentity.ClientCertificateCredentialOptions{
+			ClientOptions:        *clientOptions,
+			SendCertificateChain: true,
+		}
+		computeCredential, err = opts.NewClientCertificateCredentialFn(
+			armConfig.GetTenantID(),
+			config.GetAADClientID(),
+			certificate,
+			privateKey,
+			credOptions,
+		)
+		if err != nil {
+			return nil, err
+		}
+		return &AuthProvider{
+			ComputeCredential: computeCredential,
+			CloudConfig:       clientOptions.Cloud,
+		}, nil
+	}
+
+	// Network credential for network resource access
+	{
+		credOptions := &azidentity.ClientCertificateCredentialOptions{
+			ClientOptions:        *clientOptions,
+			SendCertificateChain: true,
+		}
+		networkCredential, err = opts.NewClientCertificateCredentialFn(
+			armConfig.NetworkResourceTenantID,
+			config.GetAADClientID(),
+			certificate,
+			privateKey,
+			credOptions,
+		)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	// Compute credential with additional allowed tenants for cross-tenant access
+	{
+		credOptions := &azidentity.ClientCertificateCredentialOptions{
+			ClientOptions:              *clientOptions,
+			AdditionallyAllowedTenants: []string{armConfig.NetworkResourceTenantID},
+			SendCertificateChain:       true,
+		}
+		computeCredential, err = opts.NewClientCertificateCredentialFn(
+			armConfig.GetTenantID(),
+			config.GetAADClientID(),
+			certificate,
+			privateKey,
+			credOptions,
+		)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return &AuthProvider{
+		ComputeCredential: computeCredential,
+		NetworkCredential: networkCredential,
+		CloudConfig:       clientOptions.Cloud,
+	}, nil
+}
+
+func newAuthProviderWithUserAssignedIdentity(
+	config *AzureAuthConfig,
+	clientOptions *policy.ClientOptions,
+	opts *authProviderOptions,
+) (*AuthProvider, error) {
+	computeCredential, err := opts.NewUserAssignedIdentityCredentialFn(
+		context.Background(),
+		config.AADMSIDataPlaneIdentityPath,
+		dataplane.WithClientOpts(azcore.ClientOptions{Cloud: clientOptions.Cloud}),
+	)
+	if err != nil {
+		return nil, err
+	}
+
+	return &AuthProvider{
+		ComputeCredential: computeCredential,
+		CloudConfig:       clientOptions.Cloud,
+	}, nil
+}
diff --git a/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth_option.go b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth_option.go
new file mode 100644
index 000000000..2597d799c
--- /dev/null
+++ b/vendor/sigs.k8s.io/cloud-provider-azure/pkg/azclient/auth_option.go
@@ -0,0 +1,150 @@
+/*
+Copyright 2025 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package azclient
+
+import (
+	"context"
+	"crypto"
+	"crypto/x509"
+	"os"
+
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
+	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
+	"github.com/Azure/msi-dataplane/pkg/dataplane"
+
+	"sigs.k8s.io/cloud-provider-azure/pkg/azclient/armauth"
+)
+
+type (
+	NewWorkloadIdentityCredentialFn func(
+		options *azidentity.WorkloadIdentityCredentialOptions,
+	) (azcore.TokenCredential, error)
+
+	NewManagedIdentityCredentialFn func(
+		options *azidentity.ManagedIdentityCredentialOptions,
+	) (azcore.TokenCredential, error)
+
+	NewClientSecretCredentialFn func(
+		tenantID string,
+		clientID string,
+		clientSecret string,
+		options *azidentity.ClientSecretCredentialOptions,
+	) (azcore.TokenCredential, error)
+
+	NewClientCertificateCredentialFn func(
+		tenantID string,
+		clientID string,
+		certs []*x509.Certificate,
+		key crypto.PrivateKey,
+		options *azidentity.ClientCertificateCredentialOptions,
+	) (azcore.TokenCredential, error)
+
+	NewKeyVaultCredentialFn func(
+		credential azcore.TokenCredential,
+		secretResourceID armauth.SecretResourceID,
+	) (azcore.TokenCredential, error)
+
+	NewUserAssignedIdentityCredentialFn func(
+		ctx context.Context,
+		credentialPath string,
+		opts ...dataplane.Option,
+	) (azcore.TokenCredential, error)
+)
+
+func DefaultNewWorkloadIdentityCredentialFn() NewWorkloadIdentityCredentialFn {
+	return func(options *azidentity.WorkloadIdentityCredentialOptions) (azcore.TokenCredential, error) {
+		return azidentity.NewWorkloadIdentityCredential(options)
+	}
+}
+
+func DefaultNewManagedIdentityCredentialFn() NewManagedIdentityCredentialFn {
+	return func(options *azidentity.ManagedIdentityCredentialOptions) (azcore.TokenCredential, error) {
+		return azidentity.NewManagedIdentityCredential(options)
+	}
+}
+
+func DefaultNewClientSecretCredentialFn() NewClientSecretCredentialFn {
+	return func(
+		tenantID string,
+		clientID string,
+		clientSecret string,
+		options *azidentity.ClientSecretCredentialOptions,
+	) (azcore.TokenCredential, error) {
+		return azidentity.NewClientSecretCredential(tenantID, clientID, clientSecret, options)
+	}
+}
+func DefaultNewClientCertificateCredentialFn() NewClientCertificateCredentialFn {
+	return func(
+		tenantID string,
+		clientID string,
+		certs []*x509.Certificate,
+		key crypto.PrivateKey,
+		options *azidentity.ClientCertificateCredentialOptions,
+	) (azcore.TokenCredential, error) {
+		return azidentity.NewClientCertificateCredential(tenantID, clientID, certs, key, options)
+	}
+}
+
+func DefaultNewKeyVaultCredentialFn() NewKeyVaultCredentialFn {
+	return func(
+		credential azcore.TokenCredential,
+		secretResourceID armauth.SecretResourceID,
+	) (azcore.TokenCredential, error) {
+		return armauth.NewKeyVaultCredential(credential, secretResourceID)
+	}
+}
+
+func DefaultNewUserAssignedIdentityCredentialFn() NewUserAssignedIdentityCredentialFn {
+	return dataplane.NewUserAssignedIdentityCredential
+}
+
+type AuthProviderOption func(option *authProviderOptions)
+
+type authProviderOptions struct {
+	ClientOptionsMutFn []func(option *policy.ClientOptions)
+	// The following credential factory functions are for testing purposes only
+	// and should not be modified by users of this package
+	NewWorkloadIdentityCredentialFn     NewWorkloadIdentityCredentialFn
+	NewManagedIdentityCredentialFn      NewManagedIdentityCredentialFn
+	NewClientSecretCredentialFn         NewClientSecretCredentialFn
+	NewClientCertificateCredentialFn    NewClientCertificateCredentialFn
+	NewKeyVaultCredentialFn             NewKeyVaultCredentialFn
+	NewUserAssignedIdentityCredentialFn NewUserAssignedIdentityCredentialFn
+	ReadFileFn                          func(name string) ([]byte, error)
+	ParseCertificatesFn                 func(certData []byte, password []byte) ([]*x509.Certificate, crypto.PrivateKey, error)
+}
+
+func defaultAuthProviderOptions() *authProviderOptions {
+	return &authProviderOptions{
+		ClientOptionsMutFn:                  []func(option *policy.ClientOptions){},
+		NewWorkloadIdentityCredentialFn:     DefaultNewWorkloadIdentityCredentialFn(),
+		NewManagedIdentityCredentialFn:      DefaultNewManagedIdentityCredentialFn(),
+		NewClientSecretCredentialFn:         DefaultNewClientSecretCredentialFn(),
+		NewClientCertificateCredentialFn:    DefaultNewClientCertificateCredentialFn(),
+		NewKeyVaultCredentialFn:             DefaultNewKeyVaultCredentialFn(),
+		NewUserAssignedIdentityCredentialFn: DefaultNewUserAssignedIdentityCredentialFn(),
+		ReadFileFn:                          os.ReadFile,
+		ParseCertificatesFn:                 azidentity.ParseCertificates,
+	}
+}
+
+func WithClientOptionsMutFn(fn func(option *policy.ClientOptions)) AuthProviderOption {
+	return func(option *authProviderOptions) {
+		option.ClientOptionsMutFn = append(option.ClientOptionsMutFn, fn)
+	}
+}


Test patch:
diff --git a/pkg/provider/azure_test.go b/pkg/provider/azure_test.go
index 13fb9ae85..6d9c613da 100644
--- a/pkg/provider/azure_test.go
+++ b/pkg/provider/azure_test.go
@@ -27,6 +27,8 @@ import (
 	"time"
 
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
+	"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
 	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
 	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6"
 	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
@@ -2439,6 +2441,163 @@ func TestInitializeCloudFromConfig(t *testing.T) {
 		assert.NoError(t, err)
 		assert.Equal(t, az.Config.LoadBalancerBackendPoolConfigurationType, consts.LoadBalancerBackendPoolConfigurationTypeNodeIPConfiguration)
 	})
+
+	t.Run("should setup network client factory with network subscription ID - same network sub in same tenant", func(t *testing.T) {
+
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+
+		az := GetTestCloud(ctrl)
+		zoneMock := az.zoneRepo.(*zone.MockRepository)
+		zoneMock.EXPECT().ListZones(gomock.Any()).Return(map[string][]string{"eastus": {"1", "2", "3"}}, nil).AnyTimes()
+
+		const (
+			tenantID       = "tenant-id"
+			subscriptionID = "subscription-id"
+		)
+
+		az.ComputeClientFactory = nil
+		az.NetworkClientFactory = nil
+
+		azureconfig := config.Config{}
+		azureconfig.ARMClientConfig.TenantID = tenantID
+		azureconfig.SubscriptionID = subscriptionID
+
+		nCall := 0
+		newARMClientFactory = func(
+			config *azclient.ClientFactoryConfig,
+			armConfig *azclient.ARMClientConfig,
+			cloud cloud.Configuration,
+			cred azcore.TokenCredential,
+			clientOptionsMutFn ...func(option *arm.ClientOptions),
+		) (azclient.ClientFactory, error) {
+			switch nCall {
+			case 0:
+				// It should create network client factory
+				assert.Equal(t, subscriptionID, config.SubscriptionID)
+			case 1:
+				// It should create compute client factory
+				assert.Equal(t, subscriptionID, config.SubscriptionID)
+			default:
+				panic("unexpected call")
+			}
+			nCall++
+			return azclient.NewClientFactory(config, armConfig, cloud, cred, clientOptionsMutFn...)
+		}
+		defer func() {
+			newARMClientFactory = azclient.NewClientFactory
+		}()
+
+		err := az.InitializeCloudFromConfig(context.Background(), &azureconfig, false, true)
+		assert.NoError(t, err)
+	})
+
+	t.Run("should setup network client factory with network subscription ID - different network sub in same tenant", func(t *testing.T) {
+
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+
+		az := GetTestCloud(ctrl)
+		zoneMock := az.zoneRepo.(*zone.MockRepository)
+		zoneMock.EXPECT().ListZones(gomock.Any()).Return(map[string][]string{"eastus": {"1", "2", "3"}}, nil).AnyTimes()
+
+		const (
+			tenantID              = "tenant-id"
+			networkSubscriptionID = "network-subscription-id"
+			computeSubscriptionID = "compute-subscription-id"
+		)
+
+		az.ComputeClientFactory = nil
+		az.NetworkClientFactory = nil
+
+		azureconfig := config.Config{}
+		azureconfig.ARMClientConfig.TenantID = tenantID
+		azureconfig.ARMClientConfig.NetworkResourceTenantID = tenantID
+		azureconfig.NetworkResourceSubscriptionID = networkSubscriptionID
+		azureconfig.SubscriptionID = computeSubscriptionID
+
+		nCall := 0
+		newARMClientFactory = func(
+			config *azclient.ClientFactoryConfig,
+			armConfig *azclient.ARMClientConfig,
+			cloud cloud.Configuration,
+			cred azcore.TokenCredential,
+			clientOptionsMutFn ...func(option *arm.ClientOptions),
+		) (azclient.ClientFactory, error) {
+			switch nCall {
+			case 0:
+				// It should create network client factory
+				assert.Equal(t, networkSubscriptionID, config.SubscriptionID)
+			case 1:
+				// It should create compute client factory
+				assert.Equal(t, computeSubscriptionID, config.SubscriptionID)
+			default:
+				panic("unexpected call")
+			}
+			nCall++
+			return azclient.NewClientFactory(config, armConfig, cloud, cred, clientOptionsMutFn...)
+		}
+		defer func() {
+			newARMClientFactory = azclient.NewClientFactory
+		}()
+
+		err := az.InitializeCloudFromConfig(context.Background(), &azureconfig, false, true)
+		assert.NoError(t, err)
+	})
+
+	t.Run("should setup network client factory with network subscription ID - different network sub in different tenant", func(t *testing.T) {
+
+		ctrl := gomock.NewController(t)
+		defer ctrl.Finish()
+
+		az := GetTestCloud(ctrl)
+		zoneMock := az.zoneRepo.(*zone.MockRepository)
+		zoneMock.EXPECT().ListZones(gomock.Any()).Return(map[string][]string{"eastus": {"1", "2", "3"}}, nil).AnyTimes()
+
+		const (
+			tenantID              = "tenant-id"
+			networkTenantID       = "network-tenant-id"
+			networkSubscriptionID = "network-subscription-id"
+			computeSubscriptionID = "compute-subscription-id"
+		)
+
+		az.ComputeClientFactory = nil
+		az.NetworkClientFactory = nil
+
+		azureconfig := config.Config{}
+		azureconfig.ARMClientConfig.TenantID = tenantID
+		azureconfig.ARMClientConfig.NetworkResourceTenantID = networkTenantID
+		azureconfig.NetworkResourceSubscriptionID = networkSubscriptionID
+		azureconfig.SubscriptionID = computeSubscriptionID
+
+		nCall := 0
+		newARMClientFactory = func(
+			config *azclient.ClientFactoryConfig,
+			armConfig *azclient.ARMClientConfig,
+			cloud cloud.Configuration,
+			cred azcore.TokenCredential,
+			clientOptionsMutFn ...func(option *arm.ClientOptions),
+		) (azclient.ClientFactory, error) {
+			switch nCall {
+			case 0:
+				// It should create network client factory
+				assert.Equal(t, networkSubscriptionID, config.SubscriptionID)
+			case 1:
+				// It should create compute client factory
+				assert.Equal(t, computeSubscriptionID, config.SubscriptionID)
+			default:
+				panic("unexpected call")
+			}
+			nCall++
+			return azclient.NewClientFactory(config, armConfig, cloud, cred, clientOptionsMutFn...)
+		}
+		defer func() {
+			newARMClientFactory = azclient.NewClientFactory
+		}()
+
+		err := az.InitializeCloudFromConfig(context.Background(), &azureconfig, false, true)
+		assert.NoError(t, err)
+	})
 }
 
 func TestSetLBDefaults(t *testing.T) {