Repository: kubernetes-sigs/cloud-provider-azure
Pull request #7247 (2024-10-09 17:14:53)

build(deps): bump github.com/Azure/azure-sdk-for-go/sdk/azidentity from 1.7.0 to 1.8.0
Bumps [github.com/Azure/azure-sdk-for-go/sdk/azidentity](https://github.com/Azure/azure-sdk-for-go) from 1.7.0 to 1.8.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/Azure/azure-sdk-for-go/releases">github.com/Azure/azure-sdk-for-go/sdk/azidentity's releases</a>.</em></p>
<blockquote>
<h2>sdk/azidentity/v1.8.0</h2>
<h2>1.8.0 (2024-10-08)</h2>
<h3>Other Changes</h3>
<ul>
<li><code>AzurePipelinesCredential</code> sets an additional OIDC request header so that it
receives a 401 instead of a 302 after presenting an invalid system access token</li>
<li>Allow logging of debugging headers for <code>AzurePipelinesCredential</code> and include
them in error messages</li>
</ul>
<h2>sdk/azidentity/v1.8.0-beta.3</h2>
<h2>1.8.0-beta.3 (2024-09-17)</h2>
<h3>Features Added</h3>
<ul>
<li>Added <code>ObjectID</code> type for <code>ManagedIdentityCredentialOptions.ID</code></li>
</ul>
<h3>Other Changes</h3>
<ul>
<li>Removed redundant content from error messages</li>
</ul>
<h2>sdk/azidentity/v1.8.0-beta.2</h2>
<h2>1.8.0-beta.2 (2024-08-06)</h2>
<h3>Breaking Changes</h3>
<ul>
<li><code>NewManagedIdentityCredential</code> now returns an error when a user-assigned identity
is specified on a platform whose managed identity API doesn't support that.
<code>ManagedIdentityCredential.GetToken()</code> formerly logged a warning in these cases.
Returning an error instead prevents the credential authenticating an unexpected
identity, causing a client to act with unexpected privileges. The affected
platforms are:
<ul>
<li>Azure Arc</li>
<li>Azure ML (when a resource ID is specified; client IDs are supported)</li>
<li>Cloud Shell</li>
<li>Service Fabric</li>
</ul>
</li>
</ul>
<h3>Other Changes</h3>
<ul>
<li>If <code>DefaultAzureCredential</code> receives a non-JSON response when probing IMDS before
attempting to authenticate a managed identity, it continues to the next credential
in the chain instead of immediately returning an error.</li>
</ul>
<h2>sdk/azidentity/v1.8.0-beta.1</h2>
<h2>1.8.0-beta.1 (2024-07-17)</h2>
<h3>Features Added</h3>
<ul>
<li>Restored persistent token caching feature</li>
</ul>
<h3>Breaking Changes</h3>
<blockquote>
<p>These changes affect only code written against a beta version such as v1.7.0-beta.1</p>
</blockquote>
<ul>
<li>Redesigned the persistent caching API. Encryption is now required in all cases
and persistent cache construction is separate from credential construction.
The <code>PersistentUserAuthentication</code> example in the package docs has been updated
to demonstrate the new API.</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/Azure/azure-sdk-for-go/commit/42def9729bc158e5e19bbde1f8f55ba0e1fbb0b3"><code>42def97</code></a> Add breaking changes to release notes (<a href="https://redirect.github.com/Azure/azure-sdk-for-go/issues/21696">#21696</a>)</li>
<li><a href="https://github.com/Azure/azure-sdk-for-go/commit/112db838ac4e672302ea2b1b4c81f1e4958d4d00"><code>112db83</code></a> Azcore v1.8.0 (<a href="https://redirect.github.com/Azure/azure-sdk-for-go/issues/21694">#21694</a>)</li>
<li><a href="https://github.com/Azure/azure-sdk-for-go/commit/204a3c4df9818a998c508369b15e664f3bce8e01"><code>204a3c4</code></a> Prep azcore v1.7.2 for release (<a href="https://redirect.github.com/Azure/azure-sdk-for-go/issues/21506">#21506</a>)</li>
<li><a href="https://github.com/Azure/azure-sdk-for-go/commit/89497f58c204f2af8a7101dbb7929fac4c1c7a09"><code>89497f5</code></a> Add changelog entry for WASM fix (<a href="https://redirect.github.com/Azure/azure-sdk-for-go/issues/21493">#21493</a>)</li>
<li><a href="https://github.com/Azure/azure-sdk-for-go/commit/0414a4b6976fbabd85f82da5a64b358a52858867"><code>0414a4b</code></a> Transport dialer: setting nil for wasm build (<a href="https://redirect.github.com/Azure/azure-sdk-for-go/issues/21451">#21451</a>)</li>
<li><a href="https://github.com/Azure/azure-sdk-for-go/commit/b1db0bec367062563a8991ee4ef1b2e2bfc02e32"><code>b1db0be</code></a> Enable TLS renegotiation (<a href="https://redirect.github.com/Azure/azure-sdk-for-go/issues/21182">#21182</a>)</li>
<li>See full diff in <a href="https://github.com/Azure/azure-sdk-for-go/compare/sdk/azcore/v1.7.0...sdk/azcore/v1.8.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/Azure/azure-sdk-for-go/sdk/azidentity&package-manager=go_modules&previous-version=1.7.0&new-version=1.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

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

Approval requirements bypassed by manually added approval.

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/7247#" title="Author self-approved">dependabot[bot]</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/release-1.29/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":["feiskyer"]} -->
k8s-ci-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

Approval requirements bypassed by manually added approval.

This pull-request has been approved by: *<a href="https://github.com/kubernetes-sigs/cloud-provider-azure/pull/7247#" title="Author self-approved">dependabot[bot]</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/release-1.29/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":["feiskyer"]} -->

Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 952a8794f..78c9b283d 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -38,7 +38,7 @@ jobs:
           rm -rf ./bin
           ARCH=${{ matrix.arch }} make bin/azure-cloud-controller-manager
           mv bin/azure-cloud-controller-manager bin/azure-cloud-controller-manager-${{ matrix.os }}-${{ matrix.arch }}
-      - uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2
+      - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
         with:
           name: cloud-controller-manager-${{ matrix.os }}-${{ matrix.arch }}
           path: bin/azure-cloud-controller-manager-${{ matrix.os }}-${{ matrix.arch }}
@@ -84,13 +84,13 @@ jobs:
           mv bin/azure-cloud-node-manager-${{ matrix.arch }}.exe bin/azure-cloud-node-manager-${{ matrix.os }}-${{ matrix.arch }}.exe
       - name: Upload artifact for linux
         if: matrix.os == 'linux'
-        uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2
+        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
         with:
           name: cloud-node-manager-${{ matrix.os }}-${{ matrix.arch }}
           path: bin/azure-cloud-node-manager-${{ matrix.os }}-${{ matrix.arch }}
       - name: Upload artifact for windows
         if: matrix.os == 'windows'
-        uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2
+        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
         with:
           name: cloud-node-manager-${{ matrix.os }}-${{ matrix.arch }}
           path: bin/azure-cloud-node-manager-${{ matrix.os }}-${{ matrix.arch }}.exe
@@ -135,13 +135,13 @@ jobs:
           mv bin/azure-acr-credential-provider.exe bin/azure-acr-credential-provider-${{ matrix.os }}-${{ matrix.arch }}.exe
       - name: Upload artifact for linux
         if: matrix.os == 'linux'
-        uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2
+        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
         with:
           name: acr-credential-provider-${{ matrix.os }}-${{ matrix.arch }}
           path: bin/azure-acr-credential-provider-${{ matrix.os }}-${{ matrix.arch }}
       - name: Upload artifact for windows
         if: matrix.os == 'windows'
-        uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2
+        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
         with:
           name: acr-credential-provider-${{ matrix.os }}-${{ matrix.arch }}
           path: bin/azure-acr-credential-provider-${{ matrix.os }}-${{ matrix.arch }}.exe
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index dd35d19ec..b6842ad7d 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -64,7 +64,7 @@ jobs:
       # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
       # format to the repository Actions tab.
       - name: "Upload artifact"
-        uses: actions/upload-artifact@84480863f228bb9747b473957fcc9e309aa96097 # v4.4.2
+        uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3
         with:
           name: SARIF file
           path: results.sarif
diff --git a/.github/workflows/trivy.yaml b/.github/workflows/trivy.yaml
index 1ee827d1d..22f5be173 100644
--- a/.github/workflows/trivy.yaml
+++ b/.github/workflows/trivy.yaml
@@ -58,7 +58,7 @@ jobs:
           cd health-probe-proxy && make build-health-probe-proxy-image && cd ..
 
       - name: Run Trivy scanner CCM
-        uses: aquasecurity/trivy-action@f781cce5aab226378ee181d764ab90ea0be3cdd8 # master
+        uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # master
         with:
           image-ref: 'local/azure-cloud-controller-manager:${{ github.sha }}'
           format: 'sarif'
@@ -72,7 +72,7 @@ jobs:
           sarif_file: 'trivy-ccm-results.sarif'
           category: azure-cloud-controller-manager-image
       - name: Run Trivy scanner CNM
-        uses: aquasecurity/trivy-action@f781cce5aab226378ee181d764ab90ea0be3cdd8 # master
+        uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # master
         with:
           image-ref: 'local/azure-cloud-node-manager:${{ github.sha }}-linux-amd64'
           format: 'sarif'
@@ -86,7 +86,7 @@ jobs:
           sarif_file: 'trivy-cnm-linux-results.sarif'
           category: azure-cloud-node-manager-linux-image
       - name: Run Trivy scanner health-probe-proxy
-        uses: aquasecurity/trivy-action@f781cce5aab226378ee181d764ab90ea0be3cdd8 # master
+        uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # master
         with:
           image-ref: 'local/health-probe-proxy:${{ github.sha }}'
           format: 'sarif'
@@ -101,7 +101,7 @@ jobs:
           category: health-probe-proxy-linux-image
 
       - name: Run Trivy vulnerability scanner in repo mode
-        uses: aquasecurity/trivy-action@f781cce5aab226378ee181d764ab90ea0be3cdd8 # master
+        uses: aquasecurity/trivy-action@5681af892cd0f4997658e2bacc62bd0a894cf564 # master
         with:
           scan-type: 'fs'
           ignore-unfixed: true
diff --git a/go.mod b/go.mod
index 1549edb7e..26c07baf5 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/Azure/azure-kusto-go v0.16.1
 	github.com/Azure/azure-sdk-for-go v68.0.0+incompatible
 	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0
-	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0
+	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
 	github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v6 v6.1.0
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerregistry/armcontainerregistry v1.2.0
diff --git a/go.sum b/go.sum
index 3bf04d847..53593583a 100644
--- a/go.sum
+++ b/go.sum
@@ -7,8 +7,10 @@ github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0
 github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc=
-github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw=
+github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ=
 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2 h1:wBx10efdJcl8FSewgc41kAW4AvHPgmJZmN7fpNxn8rc=
 github.com/Azure/azure-sdk-for-go/sdk/containers/azcontainerregistry v0.2.2/go.mod h1:zzmu18cpAinSbhC86oWd47nmgbb91Fl+Yac2PE8NdYk=
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY=
@@ -71,6 +73,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z
 github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
 github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
 github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+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.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
 github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
 github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I=
@@ -99,6 +103,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
+github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
 github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
 github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -177,6 +183,8 @@ github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8Hm
 github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
+github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs=
+github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw=
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
@@ -223,6 +231,8 @@ github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJ
 github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0=
 github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
 github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
+github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4=
+github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
diff --git a/pkg/provider/azure_loadbalancer.go b/pkg/provider/azure_loadbalancer.go
index 7625e4f55..ad0983649 100644
--- a/pkg/provider/azure_loadbalancer.go
+++ b/pkg/provider/azure_loadbalancer.go
@@ -40,7 +40,6 @@ import (
 	"k8s.io/klog/v2"
 	"k8s.io/utils/pointer"
 	"k8s.io/utils/ptr"
-	"k8s.io/utils/strings/slices"
 
 	azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"
 	"sigs.k8s.io/cloud-provider-azure/pkg/consts"
@@ -3053,12 +3052,15 @@ func (az *Cloud) shouldUpdateLoadBalancer(ctx context.Context, clusterName strin
 	return existsLb && service.ObjectMeta.DeletionTimestamp == nil && service.Spec.Type == v1.ServiceTypeLoadBalancer, nil
 }
 
-func allowsConsolidation(rule network.SecurityRule) bool {
-	return strings.HasPrefix(pointer.StringDeref(rule.Name, ""), "shared")
-}
-
 // Determine if we should release existing owned public IPs
-func shouldReleaseExistingOwnedPublicIP(existingPip *network.PublicIPAddress, lbShouldExist, lbIsInternal, isUserAssignedPIP bool, desiredPipName string, ipTagRequest serviceIPTagRequest) bool {
+// FIXME: This function is a bit of a mess, and could use some refactoring.
+func shouldReleaseExistingOwnedPublicIP(
+	existingPip *network.PublicIPAddress,
+	serviceReferences []string,
+	lbShouldExist, lbIsInternal, isUserAssignedPIP bool,
+	desiredPipName string,
+	ipTagRequest serviceIPTagRequest,
+) bool {
 	// skip deleting user created pip
 	if isUserAssignedPIP {
 		return false
@@ -3076,16 +3078,14 @@ func shouldReleaseExistingOwnedPublicIP(existingPip *network.PublicIPAddress, lb
 
 	// Check whether the public IP is being referenced by other service.
 	// The owned public IP can be released only when there is not other service using it.
-	if serviceTag := getServiceFromPIPServiceTags(existingPip.Tags); serviceTag != "" {
-		// case 1: there is at least one reference when deleting the PIP
-		if !lbShouldExist && len(parsePIPServiceTag(&serviceTag)) > 0 {
-			return false
-		}
+	// case 1: there is at least one reference when deleting the PIP
+	if !lbShouldExist && len(serviceReferences) > 0 {
+		return false
+	}
 
-		// case 2: there is at least one reference from other service
-		if lbShouldExist && len(parsePIPServiceTag(&serviceTag)) > 1 {
-			return false
-		}
+	// case 2: there is at least one reference from other service
+	if lbShouldExist && len(serviceReferences) > 1 {
+		return false
 	}
 
 	// Release the ip under the following criteria -
@@ -3301,21 +3301,23 @@ func (az *Cloud) getPublicIPUpdates(
 		// We can only let them go if (a) they are owned by this service and (b) they meet the criteria for deletion.
 		owns, isUserAssignedPIP := serviceOwnsPublicIP(service, &pip, clusterName)
 		if owns {
-			var dirtyPIP, toBeDeleted bool
+			var (
+				serviceReferences     = parsePIPServiceTag(ptr.To(getServiceFromPIPServiceTags(pip.Tags)))
+				dirtyPIP, toBeDeleted bool
+			)
 			if !wantLb && !isUserAssignedPIP {
 				klog.V(2).Infof("reconcilePublicIP for service(%s): unbinding the service from pip %s", serviceName, *pip.Name)
-				if err = unbindServiceFromPIP(&pip, service, serviceName, clusterName, isUserAssignedPIP); err != nil {
+				if serviceReferences, err = unbindServiceFromPIP(&pip, serviceName, isUserAssignedPIP); err != nil {
 					return false, nil, false, nil, err
 				}
 				dirtyPIP = true
 			}
 			if !isUserAssignedPIP {
-				changed := az.ensurePIPTagged(service, &pip)
-				if changed {
+				if az.ensurePIPTagged(service, &pip) {
 					dirtyPIP = true
 				}
 			}
-			if shouldReleaseExistingOwnedPublicIP(&pip, wantLb, isInternal, isUserAssignedPIP, desiredPipName, serviceIPTagRequest) {
+			if shouldReleaseExistingOwnedPublicIP(&pip, serviceReferences, wantLb, isInternal, isUserAssignedPIP, desiredPipName, serviceIPTagRequest) {
 				// Then, release the public ip
 				pipsToBeDeleted = append(pipsToBeDeleted, &pip)
 
@@ -3485,46 +3487,6 @@ func equalSubResource(s *network.SubResource, t *network.SubResource) bool {
 	return strings.EqualFold(pointer.StringDeref(s.ID, ""), pointer.StringDeref(t.ID, ""))
 }
 
-// This compares rule's Name, Protocol, SourcePortRange, DestinationPortRange, SourceAddressPrefix, Access, and Direction.
-// Note that it compares rule's DestinationAddressPrefix only when it's not consolidated rule as such rule does not have DestinationAddressPrefix defined.
-// We intentionally do not compare DestinationAddressPrefixes in consolidated case because reconcileSecurityRule has to consider the two rules equal,
-// despite different DestinationAddressPrefixes, in order to give it a chance to consolidate the two rules.
-func findSecurityRule(rules []network.SecurityRule, rule network.SecurityRule) bool {
-	for _, existingRule := range rules {
-		if !strings.EqualFold(pointer.StringDeref(existingRule.Name, ""), pointer.StringDeref(rule.Name, "")) {
-			continue
-		}
-		if !strings.EqualFold(string(existingRule.Protocol), string(rule.Protocol)) {
-			continue
-		}
-		if !strings.EqualFold(pointer.StringDeref(existingRule.SourcePortRange, ""), pointer.StringDeref(rule.SourcePortRange, "")) {
-			continue
-		}
-		if !strings.EqualFold(pointer.StringDeref(existingRule.DestinationPortRange, ""), pointer.StringDeref(rule.DestinationPortRange, "")) {
-			continue
-		}
-		if !strings.EqualFold(pointer.StringDeref(existingRule.SourceAddressPrefix, ""), pointer.StringDeref(rule.SourceAddressPrefix, "")) {
-			continue
-		}
-		if !allowsConsolidation(existingRule) && !allowsConsolidation(rule) {
-			if !strings.EqualFold(pointer.StringDeref(existingRule.DestinationAddressPrefix, ""), pointer.StringDeref(rule.DestinationAddressPrefix, "")) {
-				continue
-			}
-			if !slices.Equal(stringSlice(existingRule.DestinationAddressPrefixes), stringSlice(rule.DestinationAddressPrefixes)) {
-				continue
-			}
-		}
-		if !strings.EqualFold(string(existingRule.Access), string(rule.Access)) {
-			continue
-		}
-		if !strings.EqualFold(string(existingRule.Direction), string(rule.Direction)) {
-			continue
-		}
-		return true
-	}
-	return false
-}
-
 func (az *Cloud) getPublicIPAddressResourceGroup(service *v1.Service) string {
 	if resourceGroup, found := service.Annotations[consts.ServiceAnnotationLoadBalancerResourceGroup]; found {
 		resourceGroupName := strings.TrimSpace(resourceGroup)
@@ -3765,17 +3727,22 @@ func bindServicesToPIP(pip *network.PublicIPAddress, incomingServiceNames []stri
 	return addedNew, nil
 }
 
-func unbindServiceFromPIP(pip *network.PublicIPAddress, _ *v1.Service,
-	serviceName, _ string, isUserAssignedPIP bool) error {
+// unbindServiceFromPIP removes the service name from the PIP's tag.
+// And returns the updated service names.
+func unbindServiceFromPIP(
+	pip *network.PublicIPAddress,
+	serviceName string,
+	isUserAssignedPIP bool,
+) ([]string, error) {
 	if pip == nil || pip.Tags == nil {
-		return fmt.Errorf("nil public IP or tags")
+		return nil, fmt.Errorf("nil public IP or tags")
 	}
 
 	if existingServiceName := getServiceFromPIPDNSTags(pip.Tags); existingServiceName != "" && strings.EqualFold(existingServiceName, serviceName) {
 		deleteServicePIPDNSTags(&pip.Tags)
 	}
 	if isUserAssignedPIP {
-		return nil
+		return nil, nil
 	}
 
 	// skip removing tags for user assigned pips
@@ -3794,7 +3761,7 @@ func unbindServiceFromPIP(pip *network.PublicIPAddress, _ *v1.Service,
 	}
 
 	_, err := bindServicesToPIP(pip, existingServiceNames, true)
-	return err
+	return existingServiceNames, err
 }
 
 // ensureLoadBalancerTagged ensures every load balancer in the resource group is tagged as configured
diff --git a/pkg/provider/azure_utils.go b/pkg/provider/azure_utils.go
index 3d1649492..c53fd7614 100644
--- a/pkg/provider/azure_utils.go
+++ b/pkg/provider/azure_utils.go
@@ -97,6 +97,20 @@ func convertMapToMapPointer(origin map[string]string) map[string]*string {
 	return newly
 }
 
+// parseTags processes and combines tags from a string and a map into a single map of string pointers.
+// It handles tag parsing, trimming, and case-insensitive key conflicts.
+//
+// Parameters:
+//   - tags: A string containing tags in the format "key1=value1,key2=value2"
+//   - tagsMap: A map of string key-value pairs representing additional tags
+//
+// Returns:
+//   - A map[string]*string where keys are tag names and values are pointers to tag values
+//
+// The function prioritizes tags from tagsMap over those from the tags string in case of conflicts.
+// It logs warnings for parsing errors and empty keys, and info messages for case-insensitive key replacements.
+//
+// XXX: return error instead of logging; decouple tag parsing and tag application
 func parseTags(tags string, tagsMap map[string]string) map[string]*string {
 	formatted := make(map[string]*string)
 
@@ -485,15 +499,6 @@ func StringInSlice(s string, list []string) bool {
 	return false
 }
 
-// stringSlice returns a string slice value for the passed string slice pointer. It returns a nil
-// slice if the pointer is nil.
-func stringSlice(s *[]string) []string {
-	if s != nil {
-		return *s
-	}
-	return nil
-}
-
 // IntInSlice checks if an int is in a list
 func IntInSlice(i int, list []int) bool {
 	for _, item := range list {
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/BREAKING_CHANGES.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/BREAKING_CHANGES.md
new file mode 100644
index 000000000..ea267e4f4
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/BREAKING_CHANGES.md
@@ -0,0 +1,10 @@
+# Breaking Changes
+
+## v1.6.0
+
+### Behavioral change to `DefaultAzureCredential` in IMDS managed identity scenarios
+
+As of `azidentity` v1.6.0, `DefaultAzureCredential` makes a minor behavioral change when it uses IMDS managed
+identity. It sends its first request to IMDS without the "Metadata" header, to expedite validating whether the endpoint
+is available. This precedes the credential's first token request and is guaranteed to fail with a 400 error. This error
+response can appear in logs but doesn't indicate authentication failed.
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md
index a8c2feb6d..e35f5ad93 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/CHANGELOG.md
@@ -1,5 +1,52 @@
 # Release History
 
+## 1.8.0 (2024-10-08)
+
+### Other Changes
+* `AzurePipelinesCredential` sets an additional OIDC request header so that it
+  receives a 401 instead of a 302 after presenting an invalid system access token
+* Allow logging of debugging headers for `AzurePipelinesCredential` and include
+  them in error messages
+
+## 1.8.0-beta.3 (2024-09-17)
+
+### Features Added
+* Added `ObjectID` type for `ManagedIdentityCredentialOptions.ID`
+
+### Other Changes
+* Removed redundant content from error messages
+
+## 1.8.0-beta.2 (2024-08-06)
+
+### Breaking Changes
+* `NewManagedIdentityCredential` now returns an error when a user-assigned identity
+  is specified on a platform whose managed identity API doesn't support that.
+  `ManagedIdentityCredential.GetToken()` formerly logged a warning in these cases.
+  Returning an error instead prevents the credential authenticating an unexpected
+  identity, causing a client to act with unexpected privileges. The affected
+  platforms are:
+  * Azure Arc
+  * Azure ML (when a resource ID is specified; client IDs are supported)
+  * Cloud Shell
+  * Service Fabric
+
+### Other Changes
+* If `DefaultAzureCredential` receives a non-JSON response when probing IMDS before
+  attempting to authenticate a managed identity, it continues to the next credential
+  in the chain instead of immediately returning an error.
+
+## 1.8.0-beta.1 (2024-07-17)
+
+### Features Added
+* Restored persistent token caching feature
+
+### Breaking Changes
+> These changes affect only code written against a beta version such as v1.7.0-beta.1
+* Redesigned the persistent caching API. Encryption is now required in all cases
+  and persistent cache construction is separate from credential construction.
+  The `PersistentUserAuthentication` example in the package docs has been updated
+  to demonstrate the new API.
+
 ## 1.7.0 (2024-06-20)
 
 ### Features Added
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md
index 7e201ea2f..96f30b25c 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/README.md
@@ -54,7 +54,7 @@ The `azidentity` module focuses on OAuth authentication with Microsoft Entra ID.
 
 ### DefaultAzureCredential
 
-`DefaultAzureCredential` is appropriate for most apps that will be deployed to Azure. It combines common production credentials with development credentials. It attempts to authenticate via the following mechanisms in this order, stopping when one succeeds:
+`DefaultAzureCredential` simplifies authentication while developing applications that deploy to Azure by combining credentials used in Azure hosting environments and credentials used in local development. In production, it's better to use a specific credential type so authentication is more predictable and easier to debug. `DefaultAzureCredential` attempts to authenticate via the following mechanisms in this order, stopping when one succeeds:
 
 ![DefaultAzureCredential authentication flow](img/mermaidjs/DefaultAzureCredentialAuthFlow.svg)
 
@@ -126,12 +126,17 @@ client := armresources.NewResourceGroupsClient("subscription ID", chain, nil)
 
 ## Credential Types
 
-### Authenticating Azure Hosted Applications
+### Credential chains
 
 |Credential|Usage
 |-|-
 |[DefaultAzureCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#DefaultAzureCredential)|Simplified authentication experience for getting started developing Azure apps
 |[ChainedTokenCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ChainedTokenCredential)|Define custom authentication flows, composing multiple credentials
+
+### Authenticating Azure-Hosted Applications
+
+|Credential|Usage
+|-|-
 |[EnvironmentCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#EnvironmentCredential)|Authenticate a service principal or user configured by environment variables
 |[ManagedIdentityCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#ManagedIdentityCredential)|Authenticate the managed identity of an Azure resource
 |[WorkloadIdentityCredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#WorkloadIdentityCredential)|Authenticate a workload identity on Kubernetes
@@ -158,7 +163,7 @@ client := armresources.NewResourceGroupsClient("subscription ID", chain, nil)
 |Credential|Usage
 |-|-
 |[AzureCLICredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureCLICredential)|Authenticate as the user signed in to the Azure CLI
-|[`AzureDeveloperCLICredential`](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureDeveloperCLICredential)|Authenticates as the user signed in to the Azure Developer CLI
+|[AzureDeveloperCLICredential](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#AzureDeveloperCLICredential)|Authenticates as the user signed in to the Azure Developer CLI
 
 ## Environment Variables
 
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD
index fbaa29220..e0bd09c63 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TOKEN_CACHING.MD
@@ -1,57 +1,40 @@
 ## Token caching in the Azure Identity client module
 
-*Token caching* is a feature provided by the Azure Identity library that allows apps to:
+Token caching helps apps:
 
 - Improve their resilience and performance.
-- Reduce the number of requests made to Microsoft Entra ID to obtain access tokens.
-- Reduce the number of times the user is prompted to authenticate.
+- Reduce the number of requests sent to Microsoft Entra ID to obtain access tokens.
+- Reduce the number of times users are prompted to authenticate.
 
-When an app needs to access a protected Azure resource, it typically needs to obtain an access token from Entra ID. Obtaining that token involves sending a request to Entra ID and may also involve prompting the user. Entra ID then validates the credentials provided in the request and issues an access token.
+When an app needs to access a protected Azure resource, it typically needs to obtain an access token from Entra ID by sending an HTTP request and sometimes prompting a user to authenticate interactively. Credentials with caches (see [the below table](#credentials-supporting-token-caching) for a list) store access tokens either [in memory](#in-memory-token-caching) or, optionally, [on disk](#persistent-token-caching). These credentials return cached tokens whenever possible, to avoid unnecessary token requests or user interaction. Both cache implementations are safe for concurrent use.
 
-Token caching, via the Azure Identity library, allows the app to store this access token [in memory](#in-memory-token-caching), where it's accessible to the current process, or [on disk](#persistent-token-caching) where it can be accessed across application or process invocations. The token can then be retrieved quickly and easily the next time the app needs to access the same resource. The app can avoid making another request to Entra ID, which reduces network traffic and improves resilience. Additionally, in scenarios where the app is authenticating users, token caching also avoids prompting the user each time new tokens are requested.
+#### Caching can't be disabled
 
-### In-memory token caching
-
-*In-memory token caching* is the default option provided by the Azure Identity library. This caching approach allows apps to store access tokens in memory. With in-memory token caching, the library first determines if a valid access token for the requested resource is already stored in memory. If a valid token is found, it's returned to the app without the need to make another request to Entra ID. If a valid token isn't found, the library will automatically acquire a token by sending a request to Entra ID. The in-memory token cache provided by the Azure Identity library is thread-safe.
-
-**Note:** When Azure Identity library credentials are used with Azure service libraries (for example, Azure Blob Storage), the in-memory token caching is active in the `Pipeline` layer as well. All `TokenCredential` implementations are supported there, including custom implementations external to the Azure Identity library.
+Whether a credential caches tokens isn't configurable. If a credential has a cache of either kind, it requests a new token only when it can't provide one from its cache. Azure SDK service clients have an additional, independent layer of in-memory token caching, to prevent redundant token requests. This cache works with any credential type, even a custom implementation defined outside the Azure SDK, and can't be disabled. Disabling token caching is therefore impossible when using Azure SDK clients or most `azidentity` credential types. However, in-memory caches can be cleared by constructing new credential and client instances.
 
-#### Caching cannot be disabled
+### In-memory token caching
 
-As there are many levels of caching, it's not possible disable in-memory caching. However, the in-memory cache may be cleared by creating a new credential instance.
+Credential types that support caching store tokens in memory by default and require no configuration to do so. Each instance of these types has its own cache, and two credential instances never share an in-memory cache.
 
 ### Persistent token caching
 
-> Only azidentity v1.5.0-beta versions support persistent token caching
+Some credential types support opt-in persistent token caching (see [the below table](#credentials-supporting-token-caching) for a list). This feature enables credentials to store and retrieve tokens across process executions, so an application doesn't need to authenticate every time it runs.
 
-*Persistent disk token caching* is an opt-in feature in the Azure Identity library. The feature allows apps to cache access tokens in an encrypted, persistent storage mechanism. As indicated in the following table, the storage mechanism differs across operating systems.
+Persistent caches are encrypted at rest using a mechanism that depends on the operating system:
 
-| Operating system | Storage mechanism                     |
+| Operating system | Encryption facility                   |
 |------------------|---------------------------------------|
 | Linux            | kernel key retention service (keyctl) |
 | macOS            | Keychain                              |
-| Windows          | DPAPI                                 |
-
-By default the token cache will protect any data which is persisted using the user data protection APIs available on the current platform.
-However, there are cases where no data protection is available, and applications may choose to allow storing the token cache in an unencrypted state by setting `TokenCachePersistenceOptions.AllowUnencryptedStorage` to `true`. This allows a credential to fall back to unencrypted storage if it can't encrypt the cache. However, we do not recommend using this storage method due to its significantly lower security measures. In addition, tokens are not encrypted solely to the current user, which could potentially allow unauthorized access to the cache by individuals with machine access.
+| Windows          | Data Protection API (DPAPI)           |
 
-With persistent disk token caching enabled, the library first determines if a valid access token for the requested resource is already stored in the persistent cache. If a valid token is found, it's returned to the app without the need to make another request to Entra ID. Additionally, the tokens are preserved across app runs, which:
-
-- Makes the app more resilient to failures.
-- Ensures the app can continue to function during an Entra ID outage or disruption.
-- Avoids having to prompt users to authenticate each time the process is restarted.
-
->IMPORTANT! The token cache contains sensitive data and **MUST** be protected to prevent compromising accounts. All application decisions regarding the persistence of the token cache must consider that a breach of its content will fully compromise all the accounts it contains.
-
-#### Example code
-
-See the [package documentation](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity@v1.6.0-beta.2#pkg-overview) for example code demonstrating how to configure persistent caching and access cached data.
+Persistent caching requires encryption. When the required encryption facility is unuseable, or the application is running on an unsupported OS, the persistent cache constructor returns an error. This doesn't mean that authentication is impossible, only that credentials can't persist authentication data and the application will need to reauthenticate the next time it runs. See the [package documentation][example] for example code showing how to configure persistent caching and access cached data.
 
 ### Credentials supporting token caching
 
 The following table indicates the state of in-memory and persistent caching in each credential type.
 
-**Note:** In-memory caching is activated by default. Persistent token caching needs to be enabled as shown in [this example](https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity@v1.5.0-beta.1#example-package-PersistentCache).
+**Note:** in-memory caching is enabled by default for every type supporting it. Persistent token caching must be enabled explicitly. See the [package documentation][user_example] for an example showing how to do this for credential types authenticating users. For types that authenticate service principals, set the `Cache` field on the constructor's options as shown in [this example][sp_example].
 
 | Credential                     | In-memory token caching                                             | Persistent token caching |
 |--------------------------------|---------------------------------------------------------------------|--------------------------|
@@ -66,6 +49,9 @@ The following table indicates the state of in-memory and persistent caching in e
 | `EnvironmentCredential`        | Supported                                                           | Not Supported            |
 | `InteractiveBrowserCredential` | Supported                                                           | Supported                |
 | `ManagedIdentityCredential`    | Supported                                                           | Not Supported            |
-| `OnBehalfOfCredential`         | Supported                                                           | Supported                |
+| `OnBehalfOfCredential`         | Supported                                                           | Not Supported            |
 | `UsernamePasswordCredential`   | Supported                                                           | Supported                |
 | `WorkloadIdentityCredential`   | Supported                                                           | Supported                |
+
+[sp_example]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#example-package-PersistentServicePrincipalAuthentication
+[user_example]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#example-package-PersistentUserAuthentication
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md
index 54016a070..c24f67e84 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/TROUBLESHOOTING.md
@@ -234,7 +234,7 @@ azd auth token --output json --scope https://management.core.windows.net/.defaul
 |---|---|---|
 | AADSTS900023: Specified tenant identifier 'some tenant ID' is neither a valid DNS name, nor a valid external domain.|The `tenantID` argument to `NewAzurePipelinesCredential` is incorrect| Verify the tenant ID. It must identify the tenant of the user-assigned managed identity or service principal configured for the service connection.|
 | No service connection found with identifier |The `serviceConnectionID` argument to `NewAzurePipelinesCredential` is incorrect| Verify the service connection ID. This parameter refers to the `resourceId` of the Azure Service Connection. It can also be found in the query string of the service connection's configuration in Azure DevOps. [Azure Pipelines documentation](https://learn.microsoft.com/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml) has more information about service connections.|
-|302 (Found) response from OIDC endpoint|The `systemAccessToken` argument to `NewAzurePipelinesCredential` is incorrect|Check pipeline configuration. This value comes from the predefined variable `System.AccessToken` [as described in Azure Pipelines documentation](https://learn.microsoft.com/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken).|
+|401 (Unauthorized) response from OIDC endpoint|The `systemAccessToken` argument to `NewAzurePipelinesCredential` is incorrect|Check pipeline configuration. This value comes from the predefined variable `System.AccessToken` [as described in Azure Pipelines documentation](https://learn.microsoft.com/azure/devops/pipelines/build/variables?view=azure-devops&tabs=yaml#systemaccesstoken).|
 
 ## Get additional help
 
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/assets.json b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/assets.json
index bff0c44da..045f87acd 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/assets.json
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/assets.json
@@ -2,5 +2,5 @@
   "AssetsRepo": "Azure/azure-sdk-assets",
   "AssetsRepoPrefixPath": "go",
   "TagPrefix": "go/azidentity",
-  "Tag": "go/azidentity_087379b475"
+  "Tag": "go/azidentity_c55452bbf6"
 }
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/authentication_record.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/authentication_record.go
index ada4d6501..840a71469 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/authentication_record.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/authentication_record.go
@@ -18,10 +18,10 @@ import (
 
 var supportedAuthRecordVersions = []string{"1.0"}
 
-// authenticationRecord is non-secret account information about an authenticated user that user credentials such as
+// AuthenticationRecord is non-secret account information about an authenticated user that user credentials such as
 // [DeviceCodeCredential] and [InteractiveBrowserCredential] can use to access previously cached authentication
-// data. Call these credentials' Authenticate method to get an authenticationRecord for a user.
-type authenticationRecord struct {
+// data. Call these credentials' Authenticate method to get an AuthenticationRecord for a user.
+type AuthenticationRecord struct {
 	// Authority is the URL of the authority that issued the token.
 	Authority string `json:"authority"`
 
@@ -42,11 +42,11 @@ type authenticationRecord struct {
 }
 
 // UnmarshalJSON implements json.Unmarshaler for AuthenticationRecord
-func (a *authenticationRecord) UnmarshalJSON(b []byte) error {
+func (a *AuthenticationRecord) UnmarshalJSON(b []byte) error {
 	// Default unmarshaling is fine but we want to return an error if the record's version isn't supported i.e., we
 	// want to inspect the unmarshalled values before deciding whether to return an error. Unmarshaling a formally
 	// different type enables this by assigning all the fields without recursing into this method.
-	type r authenticationRecord
+	type r AuthenticationRecord
 	err := json.Unmarshal(b, (*r)(a))
 	if err != nil {
 		return err
@@ -63,7 +63,7 @@ func (a *authenticationRecord) UnmarshalJSON(b []byte) error {
 }
 
 // account returns the AuthenticationRecord as an MSAL Account. The account is zero-valued when the AuthenticationRecord is zero-valued.
-func (a *authenticationRecord) account() public.Account {
+func (a *AuthenticationRecord) account() public.Account {
 	return public.Account{
 		Environment:       a.Authority,
 		HomeAccountID:     a.HomeAccountID,
@@ -71,10 +71,10 @@ func (a *authenticationRecord) account() public.Account {
 	}
 }
 
-func newAuthenticationRecord(ar public.AuthResult) (authenticationRecord, error) {
+func newAuthenticationRecord(ar public.AuthResult) (AuthenticationRecord, error) {
 	u, err := url.Parse(ar.IDToken.Issuer)
 	if err != nil {
-		return authenticationRecord{}, fmt.Errorf("Authenticate expected a URL issuer but got %q", ar.IDToken.Issuer)
+		return AuthenticationRecord{}, fmt.Errorf("Authenticate expected a URL issuer but got %q", ar.IDToken.Issuer)
 	}
 	tenant := ar.IDToken.TenantID
 	if tenant == "" {
@@ -84,7 +84,7 @@ func newAuthenticationRecord(ar public.AuthResult) (authenticationRecord, error)
 	if username == "" {
 		username = ar.IDToken.UPN
 	}
-	return authenticationRecord{
+	return AuthenticationRecord{
 		Authority:     fmt.Sprintf("%s://%s", u.Scheme, u.Host),
 		ClientID:      ar.IDToken.Audience,
 		HomeAccountID: ar.Account.HomeAccountID,
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azidentity.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azidentity.go
index b0965036b..ce55dc658 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azidentity.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azidentity.go
@@ -53,8 +53,14 @@ var (
 	errInvalidTenantID = errors.New("invalid tenantID. You can locate your tenantID by following the instructions listed here: https://learn.microsoft.com/partner-center/find-ids-and-domain-names")
 )
 
-// tokenCachePersistenceOptions contains options for persistent token caching
-type tokenCachePersistenceOptions = internal.TokenCachePersistenceOptions
+// Cache represents a persistent cache that makes authentication data available across processes.
+// Construct one with [github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache.New]. This package's
+// [persistent user authentication example] shows how to use a persistent cache to reuse user
+// logins across application runs. For service principal credential types such as
+// [ClientCertificateCredential], simply set the Cache field on the credential options.
+//
+// [persistent user authentication example]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#example-package-PersistentUserAuthentication
+type Cache = internal.Cache
 
 // setAuthorityHost initializes the authority host for credentials. Precedence is:
 //  1. cloud.Configuration.ActiveDirectoryAuthorityHost value set by user
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_pipelines_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_pipelines_credential.go
index 80c1806bb..a4b8ab6f4 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_pipelines_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/azure_pipelines_credential.go
@@ -20,6 +20,8 @@ const (
 	credNameAzurePipelines = "AzurePipelinesCredential"
 	oidcAPIVersion         = "7.1"
 	systemOIDCRequestURI   = "SYSTEM_OIDCREQUESTURI"
+	xMsEdgeRef             = "x-msedge-ref"
+	xVssE2eId              = "x-vss-e2eid"
 )
 
 // AzurePipelinesCredential authenticates with workload identity federation in an Azure Pipeline. See
@@ -40,6 +42,11 @@ type AzurePipelinesCredentialOptions struct {
 	// application is registered.
 	AdditionallyAllowedTenants []string
 
+	// Cache is a persistent cache the credential will use to store the tokens it acquires, making
+	// them available to other processes and credential instances. The default, zero value means the
+	// credential will store tokens in memory and not share them with any other credential instance.
+	Cache Cache
+
 	// DisableInstanceDiscovery should be set true only by applications authenticating in disconnected clouds, or
 	// private clouds such as Azure Stack. It determines whether the credential requests Microsoft Entra instance metadata
 	// from https://login.microsoft.com before authenticating. Setting this to true will skip this request, making
@@ -81,8 +88,11 @@ func NewAzurePipelinesCredential(tenantID, clientID, serviceConnectionID, system
 	if options == nil {
 		options = &AzurePipelinesCredentialOptions{}
 	}
+	// these headers are useful to the DevOps team when debugging OIDC error responses
+	options.ClientOptions.Logging.AllowedHeaders = append(options.ClientOptions.Logging.AllowedHeaders, xMsEdgeRef, xVssE2eId)
 	caco := ClientAssertionCredentialOptions{
 		AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
+		Cache:                      options.Cache,
 		ClientOptions:              options.ClientOptions,
 		DisableInstanceDiscovery:   options.DisableInstanceDiscovery,
 	}
@@ -108,33 +118,40 @@ func (a *AzurePipelinesCredential) getAssertion(ctx context.Context) (string, er
 	url := a.oidcURI + "?api-version=" + oidcAPIVersion + "&serviceConnectionId=" + a.connectionID
 	url, err := runtime.EncodeQueryParams(url)
 	if err != nil {
-		return "", newAuthenticationFailedError(credNameAzurePipelines, "couldn't encode OIDC URL: "+err.Error(), nil, nil)
+		return "", newAuthenticationFailedError(credNameAzurePipelines, "couldn't encode OIDC URL: "+err.Error(), nil)
 	}
 	req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, nil)
 	if err != nil {
-		return "", newAuthenticationFailedError(credNameAzurePipelines, "couldn't create OIDC token request: "+err.Error(), nil, nil)
+		return "", newAuthenticationFailedError(credNameAzurePipelines, "couldn't create OIDC token request: "+err.Error(), nil)
 	}
 	req.Header.Set("Authorization", "Bearer "+a.systemAccessToken)
+	// instruct endpoint to return 401 instead of 302, if the system access token is invalid
+	req.Header.Set("X-TFS-FedAuthRedirect", "Suppress")
 	res, err := doForClient(a.cred.client.azClient, req)
 	if err != nil {
-		return "", newAuthenticationFailedError(credNameAzurePipelines, "couldn't send OIDC token request: "+err.Error(), nil, nil)
+		return "", newAuthenticationFailedError(credNameAzurePipelines, "couldn't send OIDC token request: "+err.Error(), nil)
 	}
 	if res.StatusCode != http.StatusOK {
-		msg := res.Status + " response from the OIDC endpoint. Check service connection ID and Pipeline configuration"
+		msg := res.Status + " response from the OIDC endpoint. Check service connection ID and Pipeline configuration."
+		for _, h := range []string{xMsEdgeRef, xVssE2eId} {
+			if v := res.Header.Get(h); v != "" {
+				msg += fmt.Sprintf("\n%s: %s", h, v)
+			}
+		}
 		// include the response because its body, if any, probably contains an error message.
 		// OK responses aren't included with errors because they probably contain secrets
-		return "", newAuthenticationFailedError(credNameAzurePipelines, msg, res, nil)
+		return "", newAuthenticationFailedError(credNameAzurePipelines, msg, res)
 	}
 	b, err := runtime.Payload(res)
 	if err != nil {
-		return "", newAuthenticationFailedError(credNameAzurePipelines, "couldn't read OIDC response content: "+err.Error(), nil, nil)
+		return "", newAuthenticationFailedError(credNameAzurePipelines, "couldn't read OIDC response content: "+err.Error(), nil)
 	}
 	var r struct {
 		OIDCToken string `json:"oidcToken"`
 	}
 	err = json.Unmarshal(b, &r)
 	if err != nil {
-		return "", newAuthenticationFailedError(credNameAzurePipelines, "unexpected response from OIDC endpoint", nil, nil)
+		return "", newAuthenticationFailedError(credNameAzurePipelines, "unexpected response from OIDC endpoint", nil)
 	}
 	return r.OIDCToken, nil
 }
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/chained_token_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/chained_token_credential.go
index 6c35a941b..2460f66ec 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/chained_token_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/chained_token_credential.go
@@ -113,11 +113,19 @@ func (c *ChainedTokenCredential) GetToken(ctx context.Context, opts policy.Token
 	if err != nil {
 		// return credentialUnavailableError iff all sources did so; return AuthenticationFailedError otherwise
 		msg := createChainedErrorMessage(errs)
-		if errors.As(err, &unavailableErr) {
+		var authFailedErr *AuthenticationFailedError
+		switch {
+		case errors.As(err, &authFailedErr):
+			err = newAuthenticationFailedError(c.name, msg, authFailedErr.RawResponse)
+			if af, ok := err.(*AuthenticationFailedError); ok {
+				// stop Error() printing the response again; it's already in msg
+				af.omitResponse = true
+			}
+		case errors.As(err, &unavailableErr):
 			err = newCredentialUnavailableError(c.name, msg)
-		} else {
+		default:
 			res := getResponseFromError(err)
-			err = newAuthenticationFailedError(c.name, msg, res, err)
+			err = newAuthenticationFailedError(c.name, msg, res)
 		}
 	}
 	return token, err
@@ -126,7 +134,7 @@ func (c *ChainedTokenCredential) GetToken(ctx context.Context, opts policy.Token
 func createChainedErrorMessage(errs []error) string {
 	msg := "failed to acquire a token.\nAttempted credentials:"
 	for _, err := range errs {
-		msg += fmt.Sprintf("\n\t%s", err.Error())
+		msg += fmt.Sprintf("\n\t%s", strings.ReplaceAll(err.Error(), "\n", "\n\t\t"))
 	}
 	return msg
 }
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/ci.yml b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/ci.yml
index 4cd8c5144..62c12b546 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/ci.yml
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/ci.yml
@@ -26,16 +26,27 @@ extends:
     parameters:
       CloudConfig:
         Public:
+          ServiceConnection: azure-sdk-tests
+          SubscriptionConfigurationFilePaths:
+            - eng/common/TestResources/sub-config/AzurePublicMsft.json
           SubscriptionConfigurations:
             - $(sub-config-azure-cloud-test-resources)
             - $(sub-config-identity-test-resources)
-      EnvVars:
-        SYSTEM_ACCESSTOKEN: $(System.AccessToken)
+      EnableRaceDetector: true
       RunLiveTests: true
       ServiceDirectory: azidentity
       UsePipelineProxy: false
 
       ${{ if endsWith(variables['Build.DefinitionName'], 'weekly') }}:
+        PreSteps:
+        - task: AzureCLI@2
+          displayName: Set OIDC token
+          inputs:
+            addSpnToEnvironment: true
+            azureSubscription: azure-sdk-tests
+            inlineScript: Write-Host "##vso[task.setvariable variable=OIDC_TOKEN;]$($env:idToken)"
+            scriptLocation: inlineScript
+            scriptType: pscore
         MatrixConfigs:
           - Name: managed_identity_matrix
             GenerateVMJobs: true
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_assertion_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_assertion_credential.go
index b588750ef..2307da86f 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_assertion_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_assertion_credential.go
@@ -37,14 +37,16 @@ type ClientAssertionCredentialOptions struct {
 	// application is registered.
 	AdditionallyAllowedTenants []string
 
+	// Cache is a persistent cache the credential will use to store the tokens it acquires, making
+	// them available to other processes and credential instances. The default, zero value means the
+	// credential will store tokens in memory and not share them with any other credential instance.
+	Cache Cache
+
 	// DisableInstanceDiscovery should be set true only by applications authenticating in disconnected clouds, or
 	// private clouds such as Azure Stack. It determines whether the credential requests Microsoft Entra instance metadata
 	// from https://login.microsoft.com before authenticating. Setting this to true will skip this request, making
 	// the application responsible for ensuring the configured authority is valid and trustworthy.
 	DisableInstanceDiscovery bool
-
-	// tokenCachePersistenceOptions enables persistent token caching when not nil.
-	tokenCachePersistenceOptions *tokenCachePersistenceOptions
 }
 
 // NewClientAssertionCredential constructs a ClientAssertionCredential. The getAssertion function must be thread safe. Pass nil for options to accept defaults.
@@ -61,10 +63,10 @@ func NewClientAssertionCredential(tenantID, clientID string, getAssertion func(c
 		},
 	)
 	msalOpts := confidentialClientOptions{
-		AdditionallyAllowedTenants:   options.AdditionallyAllowedTenants,
-		ClientOptions:                options.ClientOptions,
-		DisableInstanceDiscovery:     options.DisableInstanceDiscovery,
-		tokenCachePersistenceOptions: options.tokenCachePersistenceOptions,
+		AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
+		Cache:                      options.Cache,
+		ClientOptions:              options.ClientOptions,
+		DisableInstanceDiscovery:   options.DisableInstanceDiscovery,
 	}
 	c, err := newConfidentialClient(tenantID, clientID, credNameAssertion, cred, msalOpts)
 	if err != nil {
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_certificate_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_certificate_credential.go
index 80cd96b56..9e6bca1c9 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_certificate_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_certificate_credential.go
@@ -31,6 +31,11 @@ type ClientCertificateCredentialOptions struct {
 	// application is registered.
 	AdditionallyAllowedTenants []string
 
+	// Cache is a persistent cache the credential will use to store the tokens it acquires, making
+	// them available to other processes and credential instances. The default, zero value means the
+	// credential will store tokens in memory and not share them with any other credential instance.
+	Cache Cache
+
 	// DisableInstanceDiscovery should be set true only by applications authenticating in disconnected clouds, or
 	// private clouds such as Azure Stack. It determines whether the credential requests Microsoft Entra instance metadata
 	// from https://login.microsoft.com before authenticating. Setting this to true will skip this request, making
@@ -41,9 +46,6 @@ type ClientCertificateCredentialOptions struct {
 	// header of each token request's JWT. This is required for Subject Name/Issuer (SNI) authentication.
 	// Defaults to False.
 	SendCertificateChain bool
-
-	// tokenCachePersistenceOptions enables persistent token caching when not nil.
-	tokenCachePersistenceOptions *tokenCachePersistenceOptions
 }
 
 // ClientCertificateCredential authenticates a service principal with a certificate.
@@ -65,11 +67,11 @@ func NewClientCertificateCredential(tenantID string, clientID string, certs []*x
 		return nil, err
 	}
 	msalOpts := confidentialClientOptions{
-		AdditionallyAllowedTenants:   options.AdditionallyAllowedTenants,
-		ClientOptions:                options.ClientOptions,
-		DisableInstanceDiscovery:     options.DisableInstanceDiscovery,
-		SendX5C:                      options.SendCertificateChain,
-		tokenCachePersistenceOptions: options.tokenCachePersistenceOptions,
+		AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
+		Cache:                      options.Cache,
+		ClientOptions:              options.ClientOptions,
+		DisableInstanceDiscovery:   options.DisableInstanceDiscovery,
+		SendX5C:                    options.SendCertificateChain,
 	}
 	c, err := newConfidentialClient(tenantID, clientID, credNameCert, cred, msalOpts)
 	if err != nil {
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_secret_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_secret_credential.go
index 9e6772e9b..f0890fe1e 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_secret_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/client_secret_credential.go
@@ -32,8 +32,10 @@ type ClientSecretCredentialOptions struct {
 	// the application responsible for ensuring the configured authority is valid and trustworthy.
 	DisableInstanceDiscovery bool
 
-	// tokenCachePersistenceOptions enables persistent token caching when not nil.
-	tokenCachePersistenceOptions *tokenCachePersistenceOptions
+	// Cache is a persistent cache the credential will use to store the tokens it acquires, making
+	// them available to other processes and credential instances. The default, zero value means the
+	// credential will store tokens in memory and not share them with any other credential instance.
+	Cache Cache
 }
 
 // ClientSecretCredential authenticates an application with a client secret.
@@ -51,10 +53,10 @@ func NewClientSecretCredential(tenantID string, clientID string, clientSecret st
 		return nil, err
 	}
 	msalOpts := confidentialClientOptions{
-		AdditionallyAllowedTenants:   options.AdditionallyAllowedTenants,
-		ClientOptions:                options.ClientOptions,
-		DisableInstanceDiscovery:     options.DisableInstanceDiscovery,
-		tokenCachePersistenceOptions: options.tokenCachePersistenceOptions,
+		AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
+		Cache:                      options.Cache,
+		ClientOptions:              options.ClientOptions,
+		DisableInstanceDiscovery:   options.DisableInstanceDiscovery,
 	}
 	c, err := newConfidentialClient(tenantID, clientID, credNameSecret, cred, msalOpts)
 	if err != nil {
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/confidential_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/confidential_client.go
index 3bd08c685..7059a510c 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/confidential_client.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/confidential_client.go
@@ -29,8 +29,8 @@ type confidentialClientOptions struct {
 	AdditionallyAllowedTenants []string
 	// Assertion for on-behalf-of authentication
 	Assertion                         string
+	Cache                             Cache
 	DisableInstanceDiscovery, SendX5C bool
-	tokenCachePersistenceOptions      *tokenCachePersistenceOptions
 }
 
 // confidentialClient wraps the MSAL confidential client
@@ -107,12 +107,12 @@ func (c *confidentialClient) GetToken(ctx context.Context, tro policy.TokenReque
 		}
 	}
 	if err != nil {
-		// We could get a credentialUnavailableError from managed identity authentication because in that case the error comes from our code.
-		// We return it directly because it affects the behavior of credential chains. Otherwise, we return AuthenticationFailedError.
-		var unavailableErr credentialUnavailable
-		if !errors.As(err, &unavailableErr) {
-			res := getResponseFromError(err)
-			err = newAuthenticationFailedError(c.name, err.Error(), res, err)
+		var (
+			authFailedErr  *AuthenticationFailedError
+			unavailableErr credentialUnavailable
+		)
+		if !(errors.As(err, &unavailableErr) || errors.As(err, &authFailedErr)) {
+			err = newAuthenticationFailedErrorFromMSAL(c.name, err)
 		}
 	} else {
 		msg := fmt.Sprintf("%s.GetToken() acquired a token for scope %q", c.name, strings.Join(ar.GrantedScopes, ", "))
@@ -145,7 +145,7 @@ func (c *confidentialClient) client(tro policy.TokenRequestOptions) (msalConfide
 }
 
 func (c *confidentialClient) newMSALClient(enableCAE bool) (msalConfidentialClient, error) {
-	cache, err := internal.NewCache(c.opts.tokenCachePersistenceOptions, enableCAE)
+	cache, err := internal.ExportReplace(c.opts.Cache, enableCAE)
 	if err != nil {
 		return nil, err
 	}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go
index 551d31994..3cfc0f7bf 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/default_azure_credential.go
@@ -36,10 +36,13 @@ type DefaultAzureCredentialOptions struct {
 	TenantID string
 }
 
-// DefaultAzureCredential is a default credential chain for applications that will deploy to Azure.
-// It combines credentials suitable for deployment with credentials suitable for local development.
-// It attempts to authenticate with each of these credential types, in the following order, stopping
-// when one provides a token:
+// DefaultAzureCredential simplifies authentication while developing applications that deploy to Azure by
+// combining credentials used in Azure hosting environments and credentials used in local development. In
+// production, it's better to use a specific credential type so authentication is more predictable and easier
+// to debug.
+//
+// DefaultAzureCredential attempts to authenticate with each of these credential types, in the following order,
+// stopping when one provides a token:
 //
 //   - [EnvironmentCredential]
 //   - [WorkloadIdentityCredential], if environment variable configuration is set by the Azure workload
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/device_code_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/device_code_credential.go
index cd30bedd5..53c4c7287 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/device_code_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/device_code_credential.go
@@ -25,18 +25,26 @@ type DeviceCodeCredentialOptions struct {
 	// tokens. Add the wildcard value "*" to allow the credential to acquire tokens for any tenant.
 	AdditionallyAllowedTenants []string
 
-	// authenticationRecord returned by a call to a credential's Authenticate method. Set this option
+	// AuthenticationRecord returned by a call to a credential's Authenticate method. Set this option
 	// to enable the credential to use data from a previous authentication.
-	authenticationRecord authenticationRecord
-
-	// ClientID is the ID of the application users will authenticate to.
-	// Defaults to the ID of an Azure development application.
+	AuthenticationRecord AuthenticationRecord
+
+	// Cache is a persistent cache the credential will use to store the tokens it acquires, making
+	// them available to other processes and credential instances. The default, zero value means the
+	// credential will store tokens in memory and not share them with any other credential instance.
+	Cache Cache
+
+	// ClientID is the ID of the application to which users will authenticate. When not set, users
+	// will authenticate to an Azure development application, which isn't recommended for production
+	// scenarios. In production, developers should instead register their applications and assign
+	// appropriate roles. See https://aka.ms/azsdk/identity/AppRegistrationAndRoleAssignment for more
+	// information.
 	ClientID string
 
-	// disableAutomaticAuthentication prevents the credential from automatically prompting the user to authenticate.
-	// When this option is true, GetToken will return authenticationRequiredError when user interaction is necessary
+	// DisableAutomaticAuthentication prevents the credential from automatically prompting the user to authenticate.
+	// When this option is true, GetToken will return AuthenticationRequiredError when user interaction is necessary
 	// to acquire a token.
-	disableAutomaticAuthentication bool
+	DisableAutomaticAuthentication bool
 
 	// DisableInstanceDiscovery should be set true only by applications authenticating in disconnected clouds, or
 	// private clouds such as Azure Stack. It determines whether the credential requests Microsoft Entra instance metadata
@@ -49,9 +57,6 @@ type DeviceCodeCredentialOptions struct {
 	// applications.
 	TenantID string
 
-	// tokenCachePersistenceOptions enables persistent token caching when not nil.
-	tokenCachePersistenceOptions *tokenCachePersistenceOptions
-
 	// UserPrompt controls how the credential presents authentication instructions. The credential calls
 	// this function with authentication details when it receives a device code. By default, the credential
 	// prints these details to stdout.
@@ -101,12 +106,12 @@ func NewDeviceCodeCredential(options *DeviceCodeCredentialOptions) (*DeviceCodeC
 	cp.init()
 	msalOpts := publicClientOptions{
 		AdditionallyAllowedTenants:     cp.AdditionallyAllowedTenants,
+		Cache:                          cp.Cache,
 		ClientOptions:                  cp.ClientOptions,
 		DeviceCodePrompt:               cp.UserPrompt,
-		DisableAutomaticAuthentication: cp.disableAutomaticAuthentication,
+		DisableAutomaticAuthentication: cp.DisableAutomaticAuthentication,
 		DisableInstanceDiscovery:       cp.DisableInstanceDiscovery,
-		Record:                         cp.authenticationRecord,
-		TokenCachePersistenceOptions:   cp.tokenCachePersistenceOptions,
+		Record:                         cp.AuthenticationRecord,
 	}
 	c, err := newPublicClient(cp.TenantID, cp.ClientID, credNameDeviceCode, msalOpts)
 	if err != nil {
@@ -116,8 +121,9 @@ func NewDeviceCodeCredential(options *DeviceCodeCredentialOptions) (*DeviceCodeC
 	return &DeviceCodeCredential{client: c}, nil
 }
 
-// Authenticate a user via the device code flow. Subsequent calls to GetToken will automatically use the returned AuthenticationRecord.
-func (c *DeviceCodeCredential) authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (authenticationRecord, error) {
+// Authenticate prompts a user to log in via the device code flow. Subsequent
+// GetToken calls will automatically use the returned AuthenticationRecord.
+func (c *DeviceCodeCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (AuthenticationRecord, error) {
 	var err error
 	ctx, endSpan := runtime.StartSpan(ctx, credNameDeviceCode+"."+traceOpAuthenticate, c.client.azClient.Tracer(), nil)
 	defer func() { endSpan(err) }()
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go
index 35fa01d13..b05cb035a 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/errors.go
@@ -38,18 +38,30 @@ type AuthenticationFailedError struct {
 	// RawResponse is the HTTP response motivating the error, if available.
 	RawResponse *http.Response
 
-	credType string
-	message  string
-	err      error
+	credType, message string
+	omitResponse      bool
 }
 
-func newAuthenticationFailedError(credType string, message string, resp *http.Response, err error) error {
-	return &AuthenticationFailedError{credType: credType, message: message, RawResponse: resp, err: err}
+func newAuthenticationFailedError(credType, message string, resp *http.Response) error {
+	return &AuthenticationFailedError{credType: credType, message: message, RawResponse: resp}
+}
+
+// newAuthenticationFailedErrorFromMSAL creates an AuthenticationFailedError from an MSAL error.
+// If the error is an MSAL CallErr, the new error includes an HTTP response and not the MSAL error
+// message, because that message is redundant given the response. If the original error isn't a
+// CallErr, the returned error incorporates its message.
+func newAuthenticationFailedErrorFromMSAL(credType string, err error) error {
+	msg := ""
+	res := getResponseFromError(err)
+	if res == nil {
+		msg = err.Error()
+	}
+	return newAuthenticationFailedError(credType, msg, res)
 }
 
 // Error implements the error interface. Note that the message contents are not contractual and can change over time.
 func (e *AuthenticationFailedError) Error() string {
-	if e.RawResponse == nil {
+	if e.RawResponse == nil || e.omitResponse {
 		return e.credType + ": " + e.message
 	}
 	msg := &bytes.Buffer{}
@@ -62,7 +74,7 @@ func (e *AuthenticationFailedError) Error() string {
 		fmt.Fprintln(msg, "Request information not available")
 	}
 	fmt.Fprintln(msg, "--------------------------------------------------------------------------------")
-	fmt.Fprintf(msg, "RESPONSE %s\n", e.RawResponse.Status)
+	fmt.Fprintf(msg, "RESPONSE %d: %s\n", e.RawResponse.StatusCode, e.RawResponse.Status)
 	fmt.Fprintln(msg, "--------------------------------------------------------------------------------")
 	body, err := runtime.Payload(e.RawResponse)
 	switch {
@@ -109,17 +121,17 @@ func (*AuthenticationFailedError) NonRetriable() {
 
 var _ errorinfo.NonRetriable = (*AuthenticationFailedError)(nil)
 
-// authenticationRequiredError indicates a credential's Authenticate method must be called to acquire a token
+// AuthenticationRequiredError indicates a credential's Authenticate method must be called to acquire a token
 // because the credential requires user interaction and is configured not to request it automatically.
-type authenticationRequiredError struct {
+type AuthenticationRequiredError struct {
 	credentialUnavailableError
 
 	// TokenRequestOptions for the required token. Pass this to the credential's Authenticate method.
 	TokenRequestOptions policy.TokenRequestOptions
 }
 
-func newauthenticationRequiredError(credType string, tro policy.TokenRequestOptions) error {
-	return &authenticationRequiredError{
+func newAuthenticationRequiredError(credType string, tro policy.TokenRequestOptions) error {
+	return &AuthenticationRequiredError{
 		credentialUnavailableError: credentialUnavailableError{
 			credType + " can't acquire a token without user interaction. Call Authenticate to authenticate a user interactively",
 		},
@@ -128,8 +140,8 @@ func newauthenticationRequiredError(credType string, tro policy.TokenRequestOpti
 }
 
 var (
-	_ credentialUnavailable  = (*authenticationRequiredError)(nil)
-	_ errorinfo.NonRetriable = (*authenticationRequiredError)(nil)
+	_ credentialUnavailable  = (*AuthenticationRequiredError)(nil)
+	_ errorinfo.NonRetriable = (*AuthenticationRequiredError)(nil)
 )
 
 type credentialUnavailable interface {
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/go.work.sum b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/go.work.sum
deleted file mode 100644
index c592f283b..000000000
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/go.work.sum
+++ /dev/null
@@ -1,60 +0,0 @@
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0-beta.1 h1:ODs3brnqQM99Tq1PffODpAViYv3Bf8zOg464MU7p5ew=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0-beta.1/go.mod h1:3Ug6Qzto9anB6mGlEdgYMDF5zHQ+wwhEaYR4s17PHMw=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0 h1:fb8kj/Dh4CSwgsOzHeZY4Xh68cFVbzXx+ONXGMY//4w=
-github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.0/go.mod h1:uReU2sSxZExRPBAg3qKzmAucSi51+SP1OhohieR821Q=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0/go.mod h1:okt5dMMTOFjX/aovMlrjvvXoPMBVSPzk9185BT0+eZM=
-github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
-github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/keybase/dbus v0.0.0-20220506165403-5aa21ea2c23a/go.mod h1:YPNKjjE7Ubp9dTbnWvsP3HT+hYnY6TfXzubYTBeUxc8=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
-github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
-golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
-golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
-golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
-golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
-golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
-golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
-golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
-golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
-golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
-golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
-golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
-golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
-golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
-golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
-golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
-golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
-golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
-gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/interactive_browser_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/interactive_browser_credential.go
index 056785a8a..848db16e4 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/interactive_browser_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/interactive_browser_credential.go
@@ -24,18 +24,26 @@ type InteractiveBrowserCredentialOptions struct {
 	// tokens. Add the wildcard value "*" to allow the credential to acquire tokens for any tenant.
 	AdditionallyAllowedTenants []string
 
-	// authenticationRecord returned by a call to a credential's Authenticate method. Set this option
+	// AuthenticationRecord returned by a call to a credential's Authenticate method. Set this option
 	// to enable the credential to use data from a previous authentication.
-	authenticationRecord authenticationRecord
-
-	// ClientID is the ID of the application users will authenticate to.
-	// Defaults to the ID of an Azure development application.
+	AuthenticationRecord AuthenticationRecord
+
+	// Cache is a persistent cache the credential will use to store the tokens it acquires, making
+	// them available to other processes and credential instances. The default, zero value means the
+	// credential will store tokens in memory and not share them with any other credential instance.
+	Cache Cache
+
+	// ClientID is the ID of the application to which users will authenticate. When not set, users
+	// will authenticate to an Azure development application, which isn't recommended for production
+	// scenarios. In production, developers should instead register their applications and assign
+	// appropriate roles. See https://aka.ms/azsdk/identity/AppRegistrationAndRoleAssignment for more
+	// information.
 	ClientID string
 
-	// disableAutomaticAuthentication prevents the credential from automatically prompting the user to authenticate.
-	// When this option is true, GetToken will return authenticationRequiredError when user interaction is necessary
+	// DisableAutomaticAuthentication prevents the credential from automatically prompting the user to authenticate.
+	// When this option is true, GetToken will return AuthenticationRequiredError when user interaction is necessary
 	// to acquire a token.
-	disableAutomaticAuthentication bool
+	DisableAutomaticAuthentication bool
 
 	// DisableInstanceDiscovery should be set true only by applications authenticating in disconnected clouds, or
 	// private clouds such as Azure Stack. It determines whether the credential requests Microsoft Entra instance metadata
@@ -54,9 +62,6 @@ type InteractiveBrowserCredentialOptions struct {
 	// TenantID is the Microsoft Entra tenant the credential authenticates in. Defaults to the
 	// "organizations" tenant, which can authenticate work and school accounts.
 	TenantID string
-
-	// tokenCachePersistenceOptions enables persistent token caching when not nil.
-	tokenCachePersistenceOptions *tokenCachePersistenceOptions
 }
 
 func (o *InteractiveBrowserCredentialOptions) init() {
@@ -82,13 +87,13 @@ func NewInteractiveBrowserCredential(options *InteractiveBrowserCredentialOption
 	cp.init()
 	msalOpts := publicClientOptions{
 		AdditionallyAllowedTenants:     cp.AdditionallyAllowedTenants,
+		Cache:                          cp.Cache,
 		ClientOptions:                  cp.ClientOptions,
-		DisableAutomaticAuthentication: cp.disableAutomaticAuthentication,
+		DisableAutomaticAuthentication: cp.DisableAutomaticAuthentication,
 		DisableInstanceDiscovery:       cp.DisableInstanceDiscovery,
 		LoginHint:                      cp.LoginHint,
-		Record:                         cp.authenticationRecord,
+		Record:                         cp.AuthenticationRecord,
 		RedirectURL:                    cp.RedirectURL,
-		TokenCachePersistenceOptions:   cp.tokenCachePersistenceOptions,
 	}
 	c, err := newPublicClient(cp.TenantID, cp.ClientID, credNameBrowser, msalOpts)
 	if err != nil {
@@ -97,8 +102,9 @@ func NewInteractiveBrowserCredential(options *InteractiveBrowserCredentialOption
 	return &InteractiveBrowserCredential{client: c}, nil
 }
 
-// Authenticate a user via the default browser. Subsequent calls to GetToken will automatically use the returned AuthenticationRecord.
-func (c *InteractiveBrowserCredential) authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (authenticationRecord, error) {
+// Authenticate opens the default browser so a user can log in. Subsequent
+// GetToken calls will automatically use the returned AuthenticationRecord.
+func (c *InteractiveBrowserCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (AuthenticationRecord, error) {
 	var err error
 	ctx, endSpan := runtime.StartSpan(ctx, credNameBrowser+"."+traceOpAuthenticate, c.client.azClient.Tracer(), nil)
 	defer func() { endSpan(err) }()
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/cache.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/cache.go
new file mode 100644
index 000000000..c0cfe7606
--- /dev/null
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/cache.go
@@ -0,0 +1,86 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package internal
+
+import (
+	"sync"
+
+	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache"
+)
+
+// Cache represents a persistent cache that makes authentication data available across processes.
+// Construct one with [github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache.New]. This package's
+// [persistent user authentication example] shows how to use a persistent cache to reuse user
+// logins across application runs. For service principal credential types such as
+// [ClientCertificateCredential], simply set the Cache field on the credential options.
+//
+// [persistent user authentication example]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity#example-package-PersistentUserAuthentication
+type Cache struct {
+	// impl is a pointer so a Cache can carry persistent state across copies
+	impl *impl
+}
+
+// impl is a Cache's private implementation
+type impl struct {
+	// factory constructs storage implementations
+	factory func(bool) (cache.ExportReplace, error)
+	// cae and noCAE are previously constructed storage implementations. CAE
+	// and non-CAE tokens must be stored separately because MSAL's cache doesn't
+	// observe token claims. If a single storage implementation held both kinds
+	// of tokens, it could create a reauthentication or error loop by returning
+	// a non-CAE token lacking a required claim.
+	cae, noCAE cache.ExportReplace
+	// mu synchronizes around cae and noCAE
+	mu *sync.RWMutex
+}
+
+func (i *impl) exportReplace(cae bool) (cache.ExportReplace, error) {
+	if i == nil {
+		// zero-value Cache: return a nil ExportReplace and MSAL will cache in memory
+		return nil, nil
+	}
+	var (
+		err error
+		xr  cache.ExportReplace
+	)
+	i.mu.RLock()
+	xr = i.cae
+	if !cae {
+		xr = i.noCAE
+	}
+	i.mu.RUnlock()
+	if xr != nil {
+		return xr, nil
+	}
+	i.mu.Lock()
+	defer i.mu.Unlock()
+	if cae {
+		if i.cae == nil {
+			if xr, err = i.factory(cae); err == nil {
+				i.cae = xr
+			}
+		}
+		return i.cae, err
+	}
+	if i.noCAE == nil {
+		if xr, err = i.factory(cae); err == nil {
+			i.noCAE = xr
+		}
+	}
+	return i.noCAE, err
+}
+
+// NewCache is the constructor for Cache. It takes a factory instead of an instance
+// because it doesn't know whether the Cache will store both CAE and non-CAE tokens.
+func NewCache(factory func(cae bool) (cache.ExportReplace, error)) Cache {
+	return Cache{&impl{factory: factory, mu: &sync.RWMutex{}}}
+}
+
+// ExportReplace returns an implementation satisfying MSAL's ExportReplace interface.
+// It's a function instead of a method on Cache so packages in azidentity and
+// azidentity/cache can call it while applications can't. "cae" declares whether the
+// caller intends this implementation to store CAE tokens.
+func ExportReplace(c Cache, cae bool) (cache.ExportReplace, error) {
+	return c.impl.exportReplace(cae)
+}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/exported.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/exported.go
deleted file mode 100644
index b1b4d5c8b..000000000
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/exported.go
+++ /dev/null
@@ -1,18 +0,0 @@
-//go:build go1.18
-// +build go1.18
-
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-package internal
-
-// TokenCachePersistenceOptions contains options for persistent token caching
-type TokenCachePersistenceOptions struct {
-	// AllowUnencryptedStorage controls whether the cache should fall back to storing its data in plain text
-	// when encryption isn't possible. Setting this true doesn't disable encryption. The cache always attempts
-	// encryption before falling back to plaintext storage.
-	AllowUnencryptedStorage bool
-
-	// Name identifies the cache. Set this to isolate data from other applications.
-	Name string
-}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/internal.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/internal.go
deleted file mode 100644
index c1498b464..000000000
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal/internal.go
+++ /dev/null
@@ -1,31 +0,0 @@
-//go:build go1.18
-// +build go1.18
-
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-package internal
-
-import (
-	"errors"
-
-	"github.com/AzureAD/microsoft-authentication-library-for-go/apps/cache"
-)
-
-var errMissingImport = errors.New("import github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache to enable persistent caching")
-
-// NewCache constructs a persistent token cache when "o" isn't nil. Applications that intend to
-// use a persistent cache must first import the cache module, which will replace this function
-// with a platform-specific implementation.
-var NewCache = func(o *TokenCachePersistenceOptions, enableCAE bool) (cache.ExportReplace, error) {
-	if o == nil {
-		return nil, nil
-	}
-	return nil, errMissingImport
-}
-
-// CacheFilePath returns the path to the cache file for the given name.
-// Defining it in this package makes it available to azidentity tests.
-var CacheFilePath = func(name string) (string, error) {
-	return "", errMissingImport
-}
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go
index 6122cc700..4c657a92e 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_client.go
@@ -143,6 +143,9 @@ func newManagedIdentityClient(options *ManagedIdentityCredentialOptions) (*manag
 	if endpoint, ok := os.LookupEnv(identityEndpoint); ok {
 		if _, ok := os.LookupEnv(identityHeader); ok {
 			if _, ok := os.LookupEnv(identityServerThumbprint); ok {
+				if options.ID != nil {
+					return nil, errors.New("the Service Fabric API doesn't support specifying a user-assigned managed identity at runtime")
+				}
 				env = "Service Fabric"
 				c.endpoint = endpoint
 				c.msiType = msiTypeServiceFabric
@@ -152,6 +155,9 @@ func newManagedIdentityClient(options *ManagedIdentityCredentialOptions) (*manag
 				c.msiType = msiTypeAppService
 			}
 		} else if _, ok := os.LookupEnv(arcIMDSEndpoint); ok {
+			if options.ID != nil {
+				return nil, errors.New("the Azure Arc API doesn't support specifying a user-assigned managed identity at runtime")
+			}
 			env = "Azure Arc"
 			c.endpoint = endpoint
 			c.msiType = msiTypeAzureArc
@@ -159,9 +165,15 @@ func newManagedIdentityClient(options *ManagedIdentityCredentialOptions) (*manag
 	} else if endpoint, ok := os.LookupEnv(msiEndpoint); ok {
 		c.endpoint = endpoint
 		if _, ok := os.LookupEnv(msiSecret); ok {
+			if options.ID != nil && options.ID.idKind() != miClientID {
+				return nil, errors.New("the Azure ML API supports specifying a user-assigned managed identity by client ID only")
+			}
 			env = "Azure ML"
 			c.msiType = msiTypeAzureML
 		} else {
+			if options.ID != nil {
+				return nil, errors.New("the Cloud Shell API doesn't support user-assigned managed identities")
+			}
 			env = "Cloud Shell"
 			c.msiType = msiTypeCloudShell
 		}
@@ -207,9 +219,10 @@ func (c *managedIdentityClient) authenticate(ctx context.Context, id ManagedIDKi
 		defer cancel()
 		cx = policy.WithRetryOptions(cx, policy.RetryOptions{MaxRetries: -1})
 		req, err := azruntime.NewRequest(cx, http.MethodGet, c.endpoint)
-		if err == nil {
-			_, err = c.azClient.Pipeline().Do(req)
+		if err != nil {
+			return azcore.AccessToken{}, fmt.Errorf("failed to create IMDS probe request: %s", err)
 		}
+		res, err := c.azClient.Pipeline().Do(req)
 		if err != nil {
 			msg := err.Error()
 			if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
@@ -217,7 +230,16 @@ func (c *managedIdentityClient) authenticate(ctx context.Context, id ManagedIDKi
 			}
 			return azcore.AccessToken{}, newCredentialUnavailableError(credNameManagedIdentity, msg)
 		}
-		// send normal token requests from now on because something responded
+		// because IMDS always responds with JSON, assume a non-JSON response is from something else, such
+		// as a proxy, and return credentialUnavailableError so DefaultAzureCredential continues iterating
+		b, err := azruntime.Payload(res)
+		if err != nil {
+			return azcore.AccessToken{}, newCredentialUnavailableError(credNameManagedIdentity, fmt.Sprintf("failed to read IMDS probe response: %s", err))
+		}
+		if !json.Valid(b) {
+			return azcore.AccessToken{}, newCredentialUnavailableError(credNameManagedIdentity, "unexpected response to IMDS probe")
+		}
+		// send normal token requests from now on because IMDS responded
 		c.probeIMDS = false
 	}
 
@@ -228,7 +250,7 @@ func (c *managedIdentityClient) authenticate(ctx context.Context, id ManagedIDKi
 
 	resp, err := c.azClient.Pipeline().Do(msg)
 	if err != nil {
-		return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, err.Error(), nil, err)
+		return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, err.Error(), nil)
 	}
 
 	if azruntime.HasStatusCode(resp, http.StatusOK, http.StatusCreated) {
@@ -239,7 +261,7 @@ func (c *managedIdentityClient) authenticate(ctx context.Context, id ManagedIDKi
 		switch resp.StatusCode {
 		case http.StatusBadRequest:
 			if id != nil {
-				return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "the requested identity isn't assigned to this resource", resp, nil)
+				return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "the requested identity isn't assigned to this resource", resp)
 			}
 			msg := "failed to authenticate a system assigned identity"
 			if body, err := azruntime.Payload(resp); err == nil && len(body) > 0 {
@@ -256,7 +278,7 @@ func (c *managedIdentityClient) authenticate(ctx context.Context, id ManagedIDKi
 		}
 	}
 
-	return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "authentication failed", resp, nil)
+	return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "", resp)
 }
 
 func (c *managedIdentityClient) createAccessToken(res *http.Response) (azcore.AccessToken, error) {
@@ -284,10 +306,10 @@ func (c *managedIdentityClient) createAccessToken(res *http.Response) (azcore.Ac
 		if expiresOn, err := strconv.Atoi(v); err == nil {
 			return azcore.AccessToken{Token: value.Token, ExpiresOn: time.Unix(int64(expiresOn), 0).UTC()}, nil
 		}
-		return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "unexpected expires_on value: "+v, res, nil)
+		return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, "unexpected expires_on value: "+v, res)
 	default:
 		msg := fmt.Sprintf("unsupported type received in expires_on: %T, %v", v, v)
-		return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, msg, res, nil)
+		return azcore.AccessToken{}, newAuthenticationFailedError(credNameManagedIdentity, msg, res)
 	}
 }
 
@@ -302,15 +324,15 @@ func (c *managedIdentityClient) createAuthRequest(ctx context.Context, id Manage
 		key, err := c.getAzureArcSecretKey(ctx, scopes)
 		if err != nil {
 			msg := fmt.Sprintf("failed to retreive secret key from the identity endpoint: %v", err)
-			return nil, newAuthenticationFailedError(credNameManagedIdentity, msg, nil, err)
+			return nil, newAuthenticationFailedError(credNameManagedIdentity, msg, nil)
 		}
-		return c.createAzureArcAuthRequest(ctx, id, scopes, key)
+		return c.createAzureArcAuthRequest(ctx, scopes, key)
 	case msiTypeAzureML:
 		return c.createAzureMLAuthRequest(ctx, id, scopes)
 	case msiTypeServiceFabric:
-		return c.createServiceFabricAuthRequest(ctx, id, scopes)
+		return c.createServiceFabricAuthRequest(ctx, scopes)
 	case msiTypeCloudShell:
-		return c.createCloudShellAuthRequest(ctx, id, scopes)
+		return c.createCloudShellAuthRequest(ctx, scopes)
 	default:
 		return nil, newCredentialUnavailableError(credNameManagedIdentity, "managed identity isn't supported in this environment")
 	}
@@ -323,13 +345,16 @@ func (c *managedIdentityClient) createIMDSAuthRequest(ctx context.Context, id Ma
 	}
 	request.Raw().Header.Set(headerMetadata, "true")
 	q := request.Raw().URL.Query()
-	q.Add("api-version", imdsAPIVersion)
-	q.Add("resource", strings.Join(scopes, " "))
+	q.Set("api-version", imdsAPIVersion)
+	q.Set("resource", strings.Join(scopes, " "))
 	if id != nil {
-		if id.idKind() == miResourceID {
-			q.Add(msiResID, id.String())
-		} else {
-			q.Add(qpClientID, id.String())
+		switch id.idKind() {
+		case miClientID:
+			q.Set(qpClientID, id.String())
+		case miObjectID:
+			q.Set("object_id", id.String())
+		case miResourceID:
+			q.Set(msiResID, id.String())
 		}
 	}
 	request.Raw().URL.RawQuery = q.Encode()
@@ -343,13 +368,16 @@ func (c *managedIdentityClient) createAppServiceAuthRequest(ctx context.Context,
 	}
 	request.Raw().Header.Set("X-IDENTITY-HEADER", os.Getenv(identityHeader))
 	q := request.Raw().URL.Query()
-	q.Add("api-version", "2019-08-01")
-	q.Add("resource", scopes[0])
+	q.Set("api-version", "2019-08-01")
+	q.Set("resource", scopes[0])
 	if id != nil {
-		if id.idKind() == miResourceID {
-			q.Add(miResID, id.String())
-		} else {
-			q.Add(qpClientID, id.String())
+		switch id.idKind() {
+		case miClientID:
+			q.Set(qpClientID, id.String())
+		case miObjectID:
+			q.Set("principal_id", id.String())
+		case miResourceID:
+			q.Set(miResID, id.String())
 		}
 	}
 	request.Raw().URL.RawQuery = q.Encode()
@@ -363,23 +391,24 @@ func (c *managedIdentityClient) createAzureMLAuthRequest(ctx context.Context, id
 	}
 	request.Raw().Header.Set("secret", os.Getenv(msiSecret))
 	q := request.Raw().URL.Query()
-	q.Add("api-version", "2017-09-01")
-	q.Add("resource", strings.Join(scopes, " "))
-	q.Add("clientid", os.Getenv(defaultIdentityClientID))
+	q.Set("api-version", "2017-09-01")
+	q.Set("resource", strings.Join(scopes, " "))
+	q.Set("clientid", os.Getenv(defaultIdentityClientID))
 	if id != nil {
-		if id.idKind() == miResourceID {
-			log.Write(EventAuthentication, "WARNING: Azure ML doesn't support specifying a managed identity by resource ID")
-			q.Set("clientid", "")
-			q.Set(miResID, id.String())
-		} else {
+		switch id.idKind() {
+		case miClientID:
 			q.Set("clientid", id.String())
+		case miObjectID:
+			return nil, newAuthenticationFailedError(credNameManagedIdentity, "Azure ML doesn't support specifying a managed identity by object ID", nil)
+		case miResourceID:
+			return nil, newAuthenticationFailedError(credNameManagedIdentity, "Azure ML doesn't support specifying a managed identity by resource ID", nil)
 		}
 	}
 	request.Raw().URL.RawQuery = q.Encode()
 	return request, nil
 }
 
-func (c *managedIdentityClient) createServiceFabricAuthRequest(ctx context.Context, id ManagedIDKind, scopes []string) (*policy.Request, error) {
+func (c *managedIdentityClient) createServiceFabricAuthRequest(ctx context.Context, scopes []string) (*policy.Request, error) {
 	request, err := azruntime.NewRequest(ctx, http.MethodGet, c.endpoint)
 	if err != nil {
 		return nil, err
@@ -387,16 +416,8 @@ func (c *managedIdentityClient) createServiceFabricAuthRequest(ctx context.Conte
 	q := request.Raw().URL.Query()
 	request.Raw().Header.Set("Accept", "application/json")
 	request.Raw().Header.Set("Secret", os.Getenv(identityHeader))
-	q.Add("api-version", serviceFabricAPIVersion)
-	q.Add("resource", strings.Join(scopes, " "))
-	if id != nil {
-		log.Write(EventAuthentication, "WARNING: Service Fabric doesn't support selecting a user-assigned identity at runtime")
-		if id.idKind() == miResourceID {
-			q.Add(miResID, id.String())
-		} else {
-			q.Add(qpClientID, id.String())
-		}
-	}
+	q.Set("api-version", serviceFabricAPIVersion)
+	q.Set("resource", strings.Join(scopes, " "))
 	request.Raw().URL.RawQuery = q.Encode()
 	return request, nil
 }
@@ -409,8 +430,8 @@ func (c *managedIdentityClient) getAzureArcSecretKey(ctx context.Context, resour
 	}
 	request.Raw().Header.Set(headerMetadata, "true")
 	q := request.Raw().URL.Query()
-	q.Add("api-version", azureArcAPIVersion)
-	q.Add("resource", strings.Join(resources, " "))
+	q.Set("api-version", azureArcAPIVersion)
+	q.Set("resource", strings.Join(resources, " "))
 	request.Raw().URL.RawQuery = q.Encode()
 	// send the initial request to get the short-lived secret key
 	response, err := c.azClient.Pipeline().Do(request)
@@ -421,39 +442,39 @@ func (c *managedIdentityClient) getAzureArcSecretKey(ctx context.Context, resour
 	// of the secret key file. Any other status code indicates an error in the request.
 	if response.StatusCode != 401 {
 		msg := fmt.Sprintf("expected a 401 response, received %d", response.StatusCode)
-		return "", newAuthenticationFailedError(credNameManagedIdentity, msg, response, nil)
+		return "", newAuthenticationFailedError(credNameManagedIdentity, msg, response)
 	}
 	header := response.Header.Get("WWW-Authenticate")
 	if len(header) == 0 {
-		return "", newAuthenticationFailedError(credNameManagedIdentity, "HIMDS response has no WWW-Authenticate header", nil, nil)
+		return "", newAuthenticationFailedError(credNameManagedIdentity, "HIMDS response has no WWW-Authenticate header", nil)
 	}
 	// the WWW-Authenticate header is expected in the following format: Basic realm=/some/file/path.key
 	_, p, found := strings.Cut(header, "=")
 	if !found {
-		return "", newAuthenticationFailedError(credNameManagedIdentity, "unexpected WWW-Authenticate header from HIMDS: "+header, nil, nil)
+		return "", newAuthenticationFailedError(credNameManagedIdentity, "unexpected WWW-Authenticate header from HIMDS: "+header, nil)
 	}
 	expected, err := arcKeyDirectory()
 	if err != nil {
 		return "", err
 	}
 	if filepath.Dir(p) != expected || !strings.HasSuffix(p, ".key") {
-		return "", newAuthenticationFailedError(credNameManagedIdentity, "unexpected file path from HIMDS service: "+p, nil, nil)
+		return "", newAuthenticationFailedError(credNameManagedIdentity, "unexpected file path from HIMDS service: "+p, nil)
 	}
 	f, err := os.Stat(p)
 	if err != nil {
-		return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("could not stat %q: %v", p, err), nil, nil)
+		return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("could not stat %q: %v", p, err), nil)
 	}
 	if s := f.Size(); s > 4096 {
-		return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("key is too large (%d bytes)", s), nil, nil)
+		return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("key is too large (%d bytes)", s), nil)
 	}
 	key, err := os.ReadFile(p)
 	if err != nil {
-		return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("could not read %q: %v", p, err), nil, nil)
+		return "", newAuthenticationFailedError(credNameManagedIdentity, fmt.Sprintf("could not read %q: %v", p, err), nil)
 	}
 	return string(key), nil
 }
 
-func (c *managedIdentityClient) createAzureArcAuthRequest(ctx context.Context, id ManagedIDKind, resources []string, key string) (*policy.Request, error) {
+func (c *managedIdentityClient) createAzureArcAuthRequest(ctx context.Context, resources []string, key string) (*policy.Request, error) {
 	request, err := azruntime.NewRequest(ctx, http.MethodGet, c.endpoint)
 	if err != nil {
 		return nil, err
@@ -461,21 +482,13 @@ func (c *managedIdentityClient) createAzureArcAuthRequest(ctx context.Context, i
 	request.Raw().Header.Set(headerMetadata, "true")
 	request.Raw().Header.Set("Authorization", fmt.Sprintf("Basic %s", key))
 	q := request.Raw().URL.Query()
-	q.Add("api-version", azureArcAPIVersion)
-	q.Add("resource", strings.Join(resources, " "))
-	if id != nil {
-		log.Write(EventAuthentication, "WARNING: Azure Arc doesn't support user-assigned managed identities")
-		if id.idKind() == miResourceID {
-			q.Add(miResID, id.String())
-		} else {
-			q.Add(qpClientID, id.String())
-		}
-	}
+	q.Set("api-version", azureArcAPIVersion)
+	q.Set("resource", strings.Join(resources, " "))
 	request.Raw().URL.RawQuery = q.Encode()
 	return request, nil
 }
 
-func (c *managedIdentityClient) createCloudShellAuthRequest(ctx context.Context, id ManagedIDKind, scopes []string) (*policy.Request, error) {
+func (c *managedIdentityClient) createCloudShellAuthRequest(ctx context.Context, scopes []string) (*policy.Request, error) {
 	request, err := azruntime.NewRequest(ctx, http.MethodPost, c.endpoint)
 	if err != nil {
 		return nil, err
@@ -488,14 +501,5 @@ func (c *managedIdentityClient) createCloudShellAuthRequest(ctx context.Context,
 	if err := request.SetBody(body, "application/x-www-form-urlencoded"); err != nil {
 		return nil, err
 	}
-	if id != nil {
-		log.Write(EventAuthentication, "WARNING: Cloud Shell doesn't support user-assigned managed identities")
-		q := request.Raw().URL.Query()
-		if id.idKind() == miResourceID {
-			q.Add(miResID, id.String())
-		} else {
-			q.Add(qpClientID, id.String())
-		}
-	}
 	return request, nil
 }
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_credential.go
index 13c043d8e..1d53579cf 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/managed_identity_credential.go
@@ -22,8 +22,9 @@ const credNameManagedIdentity = "ManagedIdentityCredential"
 type managedIdentityIDKind int
 
 const (
-	miClientID   managedIdentityIDKind = 0
-	miResourceID managedIdentityIDKind = 1
+	miClientID managedIdentityIDKind = iota
+	miObjectID
+	miResourceID
 )
 
 // ManagedIDKind identifies the ID of a managed identity as either a client or resource ID
@@ -32,7 +33,12 @@ type ManagedIDKind interface {
 	idKind() managedIdentityIDKind
 }
 
-// ClientID is the client ID of a user-assigned managed identity.
+// ClientID is the client ID of a user-assigned managed identity. [NewManagedIdentityCredential]
+// returns an error when a ClientID is specified on the following platforms:
+//
+//   - Azure Arc
+//   - Cloud Shell
+//   - Service Fabric
 type ClientID string
 
 func (ClientID) idKind() managedIdentityIDKind {
@@ -44,7 +50,31 @@ func (c ClientID) String() string {
 	return string(c)
 }
 
-// ResourceID is the resource ID of a user-assigned managed identity.
+// ObjectID is the object ID of a user-assigned managed identity. [NewManagedIdentityCredential]
+// returns an error when an ObjectID is specified on the following platforms:
+//
+//   - Azure Arc
+//   - Azure ML
+//   - Cloud Shell
+//   - Service Fabric
+type ObjectID string
+
+func (ObjectID) idKind() managedIdentityIDKind {
+	return miObjectID
+}
+
+// String returns the string value of the ID.
+func (o ObjectID) String() string {
+	return string(o)
+}
+
+// ResourceID is the resource ID of a user-assigned managed identity. [NewManagedIdentityCredential]
+// returns an error when a ResourceID is specified on the following platforms:
+//
+//   - Azure Arc
+//   - Azure ML
+//   - Cloud Shell
+//   - Service Fabric
 type ResourceID string
 
 func (ResourceID) idKind() managedIdentityIDKind {
@@ -60,9 +90,10 @@ func (r ResourceID) String() string {
 type ManagedIdentityCredentialOptions struct {
 	azcore.ClientOptions
 
-	// ID is the ID of a managed identity the credential should authenticate. Set this field to use a specific identity
-	// instead of the hosting environment's default. The value may be the identity's client ID or resource ID, but note that
-	// some platforms don't accept resource IDs.
+	// ID of a managed identity the credential should authenticate. Set this field to use a specific identity instead of
+	// the hosting environment's default. The value may be the identity's client, object, or resource ID.
+	// NewManagedIdentityCredential returns an error when the hosting environment doesn't support user-assigned managed
+	// identities, or the specified kind of ID.
 	ID ManagedIDKind
 
 	// dac indicates whether the credential is part of DefaultAzureCredential. When true, and the environment doesn't have
@@ -73,10 +104,11 @@ type ManagedIdentityCredentialOptions struct {
 	dac bool
 }
 
-// ManagedIdentityCredential authenticates an Azure managed identity in any hosting environment supporting managed identities.
+// ManagedIdentityCredential authenticates an [Azure managed identity] in any hosting environment supporting managed identities.
 // This credential authenticates a system-assigned identity by default. Use ManagedIdentityCredentialOptions.ID to specify a
-// user-assigned identity. See Microsoft Entra ID documentation for more information about managed identities:
-// https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview
+// user-assigned identity.
+//
+// [Azure managed identity]: https://learn.microsoft.com/entra/identity/managed-identities-azure-resources/overview
 type ManagedIdentityCredential struct {
 	client *confidentialClient
 	mic    *managedIdentityClient
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/public_client.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/public_client.go
index b3d22dbf3..73363e1c9 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/public_client.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/public_client.go
@@ -30,12 +30,12 @@ type publicClientOptions struct {
 	azcore.ClientOptions
 
 	AdditionallyAllowedTenants     []string
+	Cache                          Cache
 	DeviceCodePrompt               func(context.Context, DeviceCodeMessage) error
 	DisableAutomaticAuthentication bool
 	DisableInstanceDiscovery       bool
 	LoginHint, RedirectURL         string
-	Record                         authenticationRecord
-	TokenCachePersistenceOptions   *tokenCachePersistenceOptions
+	Record                         AuthenticationRecord
 	Username, Password             string
 }
 
@@ -48,7 +48,7 @@ type publicClient struct {
 	host                     string
 	name                     string
 	opts                     publicClientOptions
-	record                   authenticationRecord
+	record                   AuthenticationRecord
 	azClient                 *azcore.Client
 }
 
@@ -107,19 +107,19 @@ func newPublicClient(tenantID, clientID, name string, o publicClientOptions) (*p
 	}, nil
 }
 
-func (p *publicClient) Authenticate(ctx context.Context, tro *policy.TokenRequestOptions) (authenticationRecord, error) {
+func (p *publicClient) Authenticate(ctx context.Context, tro *policy.TokenRequestOptions) (AuthenticationRecord, error) {
 	if tro == nil {
 		tro = &policy.TokenRequestOptions{}
 	}
 	if len(tro.Scopes) == 0 {
 		if p.defaultScope == nil {
-			return authenticationRecord{}, errScopeRequired
+			return AuthenticationRecord{}, errScopeRequired
 		}
 		tro.Scopes = p.defaultScope
 	}
 	client, mu, err := p.client(*tro)
 	if err != nil {
-		return authenticationRecord{}, err
+		return AuthenticationRecord{}, err
 	}
 	mu.Lock()
 	defer mu.Unlock()
@@ -152,7 +152,7 @@ func (p *publicClient) GetToken(ctx context.Context, tro policy.TokenRequestOpti
 		return p.token(ar, err)
 	}
 	if p.opts.DisableAutomaticAuthentication {
-		return azcore.AccessToken{}, newauthenticationRequiredError(p.name, tro)
+		return azcore.AccessToken{}, newAuthenticationRequiredError(p.name, tro)
 	}
 	at, err := p.reqToken(ctx, client, tro)
 	if err == nil {
@@ -222,13 +222,13 @@ func (p *publicClient) client(tro policy.TokenRequestOptions) (msalPublicClient,
 }
 
 func (p *publicClient) newMSALClient(enableCAE bool) (msalPublicClient, error) {
-	cache, err := internal.NewCache(p.opts.TokenCachePersistenceOptions, enableCAE)
+	c, err := internal.ExportReplace(p.opts.Cache, enableCAE)
 	if err != nil {
 		return nil, err
 	}
 	o := []public.Option{
 		public.WithAuthority(runtime.JoinPaths(p.host, p.tenantID)),
-		public.WithCache(cache),
+		public.WithCache(c),
 		public.WithHTTPClient(p),
 	}
 	if enableCAE {
@@ -244,8 +244,7 @@ func (p *publicClient) token(ar public.AuthResult, err error) (azcore.AccessToke
 	if err == nil {
 		p.record, err = newAuthenticationRecord(ar)
 	} else {
-		res := getResponseFromError(err)
-		err = newAuthenticationFailedError(p.name, err.Error(), res, err)
+		err = newAuthenticationFailedErrorFromMSAL(p.name, err)
 	}
 	return azcore.AccessToken{Token: ar.AccessToken, ExpiresOn: ar.ExpiresOn.UTC()}, err
 }
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/username_password_credential.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/username_password_credential.go
index 294ed81e9..740abd470 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/username_password_credential.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/username_password_credential.go
@@ -25,18 +25,20 @@ type UsernamePasswordCredentialOptions struct {
 	// application is registered.
 	AdditionallyAllowedTenants []string
 
-	// authenticationRecord returned by a call to a credential's Authenticate method. Set this option
+	// AuthenticationRecord returned by a call to a credential's Authenticate method. Set this option
 	// to enable the credential to use data from a previous authentication.
-	authenticationRecord authenticationRecord
+	AuthenticationRecord AuthenticationRecord
+
+	// Cache is a persistent cache the credential will use to store the tokens it acquires, making
+	// them available to other processes and credential instances. The default, zero value means the
+	// credential will store tokens in memory and not share them with any other credential instance.
+	Cache Cache
 
 	// DisableInstanceDiscovery should be set true only by applications authenticating in disconnected clouds, or
 	// private clouds such as Azure Stack. It determines whether the credential requests Microsoft Entra instance metadata
 	// from https://login.microsoft.com before authenticating. Setting this to true will skip this request, making
 	// the application responsible for ensuring the configured authority is valid and trustworthy.
 	DisableInstanceDiscovery bool
-
-	// tokenCachePersistenceOptions enables persistent token caching when not nil.
-	tokenCachePersistenceOptions *tokenCachePersistenceOptions
 }
 
 // UsernamePasswordCredential authenticates a user with a password. Microsoft doesn't recommend this kind of authentication,
@@ -54,13 +56,13 @@ func NewUsernamePasswordCredential(tenantID string, clientID string, username st
 		options = &UsernamePasswordCredentialOptions{}
 	}
 	opts := publicClientOptions{
-		AdditionallyAllowedTenants:   options.AdditionallyAllowedTenants,
-		ClientOptions:                options.ClientOptions,
-		DisableInstanceDiscovery:     options.DisableInstanceDiscovery,
-		Password:                     password,
-		Record:                       options.authenticationRecord,
-		TokenCachePersistenceOptions: options.tokenCachePersistenceOptions,
-		Username:                     username,
+		AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
+		Cache:                      options.Cache,
+		ClientOptions:              options.ClientOptions,
+		DisableInstanceDiscovery:   options.DisableInstanceDiscovery,
+		Password:                   password,
+		Record:                     options.AuthenticationRecord,
+		Username:                   username,
 	}
 	c, err := newPublicClient(tenantID, clientID, credNameUserPassword, opts)
 	if err != nil {
@@ -70,7 +72,7 @@ func NewUsernamePasswordCredential(tenantID string, clientID string, username st
 }
 
 // Authenticate the user. Subsequent calls to GetToken will automatically use the returned AuthenticationRecord.
-func (c *UsernamePasswordCredential) authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (authenticationRecord, error) {
+func (c *UsernamePasswordCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (AuthenticationRecord, error) {
 	var err error
 	ctx, endSpan := runtime.StartSpan(ctx, credNameUserPassword+"."+traceOpAuthenticate, c.client.azClient.Tracer(), nil)
 	defer func() { endSpan(err) }()
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go
index 4305b5d3d..4fa22dcc1 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/version.go
@@ -14,5 +14,5 @@ const (
 	module = "github.com/Azure/azure-sdk-for-go/sdk/" + component
 
 	// Version is the semantic version (see http://semver.org) of this module.
-	version = "v1.7.0"
+	version = "v1.8.0"
 )
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/workload_identity.go b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/workload_identity.go
index 3e43e788e..6fecada2f 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/workload_identity.go
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/workload_identity.go
@@ -39,15 +39,24 @@ type WorkloadIdentityCredentialOptions struct {
 	// Add the wildcard value "*" to allow the credential to acquire tokens for any tenant in which the
 	// application is registered.
 	AdditionallyAllowedTenants []string
+
+	// Cache is a persistent cache the credential will use to store the tokens it acquires, making
+	// them available to other processes and credential instances. The default, zero value means the
+	// credential will store tokens in memory and not share them with any other credential instance.
+	Cache Cache
+
 	// ClientID of the service principal. Defaults to the value of the environment variable AZURE_CLIENT_ID.
 	ClientID string
+
 	// DisableInstanceDiscovery should be set true only by applications authenticating in disconnected clouds, or
 	// private clouds such as Azure Stack. It determines whether the credential requests Microsoft Entra instance metadata
 	// from https://login.microsoft.com before authenticating. Setting this to true will skip this request, making
 	// the application responsible for ensuring the configured authority is valid and trustworthy.
 	DisableInstanceDiscovery bool
+
 	// TenantID of the service principal. Defaults to the value of the environment variable AZURE_TENANT_ID.
 	TenantID string
+
 	// TokenFilePath is the path of a file containing a Kubernetes service account token. Defaults to the value of the
 	// environment variable AZURE_FEDERATED_TOKEN_FILE.
 	TokenFilePath string
@@ -81,6 +90,7 @@ func NewWorkloadIdentityCredential(options *WorkloadIdentityCredentialOptions) (
 	w := WorkloadIdentityCredential{file: file, mtx: &sync.RWMutex{}}
 	caco := ClientAssertionCredentialOptions{
 		AdditionallyAllowedTenants: options.AdditionallyAllowedTenants,
+		Cache:                      options.Cache,
 		ClientOptions:              options.ClientOptions,
 		DisableInstanceDiscovery:   options.DisableInstanceDiscovery,
 	}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 9d25727a0..447131057 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -61,7 +61,7 @@ github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime
 github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming
 github.com/Azure/azure-sdk-for-go/sdk/azcore/to
 github.com/Azure/azure-sdk-for-go/sdk/azcore/tracing
-# github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0
+# github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
 ## explicit; go 1.18
 github.com/Azure/azure-sdk-for-go/sdk/azidentity
 github.com/Azure/azure-sdk-for-go/sdk/azidentity/internal


Test patch:
diff --git a/pkg/provider/azure_loadbalancer_test.go b/pkg/provider/azure_loadbalancer_test.go
index 46dd26709..39e44c62a 100644
--- a/pkg/provider/azure_loadbalancer_test.go
+++ b/pkg/provider/azure_loadbalancer_test.go
@@ -1103,10 +1103,10 @@ func TestShouldReleaseExistingOwnedPublicIP(t *testing.T) {
 		desiredPipName        string
 		existingPip           network.PublicIPAddress
 		ipTagRequest          serviceIPTagRequest
-		tags                  map[string]*string
 		lbShouldExist         bool
 		lbIsInternal          bool
 		isUserAssignedPIP     bool
+		serviceReferences     []string
 		expectedShouldRelease bool
 	}{
 		{
@@ -1218,12 +1218,12 @@ func TestShouldReleaseExistingOwnedPublicIP(t *testing.T) {
 			expectedShouldRelease: true,
 		},
 		{
-			desc:           "should delete orphaned managed public IP",
-			existingPip:    existingPipWithTag,
-			lbShouldExist:  false,
-			lbIsInternal:   false,
-			desiredPipName: *existingPipWithTag.Name,
-			tags:           map[string]*string{consts.ServiceTagKey: pointer.String("")},
+			desc:              "should delete orphaned managed public IP",
+			existingPip:       existingPipWithTag,
+			lbShouldExist:     false,
+			lbIsInternal:      false,
+			desiredPipName:    *existingPipWithTag.Name,
+			serviceReferences: []string{},
 			ipTagRequest: serviceIPTagRequest{
 				IPTagsRequestedByAnnotation: true,
 				IPTags:                      existingPipWithTag.PublicIPAddressPropertiesFormat.IPTags,
@@ -1231,24 +1231,24 @@ func TestShouldReleaseExistingOwnedPublicIP(t *testing.T) {
 			expectedShouldRelease: true,
 		},
 		{
-			desc:           "should not delete managed public IP which has references",
-			existingPip:    existingPipWithTag,
-			lbShouldExist:  false,
-			lbIsInternal:   false,
-			desiredPipName: *existingPipWithTag.Name,
-			tags:           map[string]*string{consts.ServiceTagKey: pointer.String("svc1")},
+			desc:              "should not delete managed public IP which has references",
+			existingPip:       existingPipWithTag,
+			lbShouldExist:     false,
+			lbIsInternal:      false,
+			desiredPipName:    *existingPipWithTag.Name,
+			serviceReferences: []string{"svc1"},
 			ipTagRequest: serviceIPTagRequest{
 				IPTagsRequestedByAnnotation: true,
 				IPTags:                      existingPipWithTag.PublicIPAddressPropertiesFormat.IPTags,
 			},
 		},
 		{
-			desc:           "should not delete orphaned unmanaged public IP",
-			existingPip:    existingPipWithTag,
-			lbShouldExist:  false,
-			lbIsInternal:   false,
-			desiredPipName: *existingPipWithTag.Name,
-			tags:           map[string]*string{consts.ServiceTagKey: pointer.String("")},
+			desc:              "should not delete orphaned unmanaged public IP",
+			existingPip:       existingPipWithTag,
+			lbShouldExist:     false,
+			lbIsInternal:      false,
+			desiredPipName:    *existingPipWithTag.Name,
+			serviceReferences: []string{},
 			ipTagRequest: serviceIPTagRequest{
 				IPTagsRequestedByAnnotation: true,
 				IPTags:                      existingPipWithTag.PublicIPAddressPropertiesFormat.IPTags,
@@ -1259,11 +1259,8 @@ func TestShouldReleaseExistingOwnedPublicIP(t *testing.T) {
 
 	for _, c := range tests {
 		t.Run(c.desc, func(t *testing.T) {
-			if c.tags != nil {
-				c.existingPip.Tags = c.tags
-			}
 			existingPip := c.existingPip
-			actualShouldRelease := shouldReleaseExistingOwnedPublicIP(&existingPip, c.lbShouldExist, c.lbIsInternal, c.isUserAssignedPIP, c.desiredPipName, c.ipTagRequest)
+			actualShouldRelease := shouldReleaseExistingOwnedPublicIP(&existingPip, c.serviceReferences, c.lbShouldExist, c.lbIsInternal, c.isUserAssignedPIP, c.desiredPipName, c.ipTagRequest)
 			assert.Equal(t, c.expectedShouldRelease, actualShouldRelease)
 		})
 	}
@@ -4384,8 +4381,11 @@ func TestReconcilePublicIPsCommon(t *testing.T) {
 			},
 			existingPIPs: []network.PublicIPAddress{
 				{
-					Name: pointer.String("pip1"),
-					Tags: map[string]*string{consts.ServiceTagKey: pointer.String("default/test1")},
+					Name: ptr.To("pip1"),
+					Tags: map[string]*string{
+						consts.ServiceTagKey:       ptr.To("default/test1"),
+						consts.LegacyServiceTagKey: ptr.To("foo"), // It should be ignored when ServiceTagKey is present.
+					},
 					PublicIPAddressPropertiesFormat: &network.PublicIPAddressPropertiesFormat{
 						PublicIPAddressVersion: network.IPv4,
 						IPAddress:              pointer.String("1.2.3.4"),
@@ -5521,25 +5521,74 @@ func TestBindServicesToPIP(t *testing.T) {
 }
 
 func TestUnbindServiceFromPIP(t *testing.T) {
-	pips := []*network.PublicIPAddress{
-		{Tags: nil},
-		{Tags: map[string]*string{consts.ServiceTagKey: pointer.String("")}},
-		{Tags: map[string]*string{consts.ServiceTagKey: pointer.String("ns1/svc1")}},
-		{Tags: map[string]*string{consts.ServiceTagKey: pointer.String("ns1/svc1,ns2/svc2")}},
-	}
-	serviceName := "ns2/svc2"
-	service := getTestService(serviceName, v1.ProtocolTCP, nil, false, 80)
-	setServiceLoadBalancerIP(&service, "1.2.3.4")
-	expectedTags := []map[string]*string{
-		nil,
-		{consts.ServiceTagKey: pointer.String("")},
-		{consts.ServiceTagKey: pointer.String("ns1/svc1")},
-		{consts.ServiceTagKey: pointer.String("ns1/svc1")},
+	tests := []struct {
+		Name                      string
+		InputTags                 map[string]*string
+		InputIsUserAssigned       bool
+		ExpectedTags              map[string]*string
+		ExpectedServiceReferences []string
+		ExpectedErr               bool
+	}{
+		{
+			Name:        "Nil",
+			ExpectedErr: true,
+		},
+		{
+			Name:                "Empty tags",
+			InputTags:           map[string]*string{},
+			InputIsUserAssigned: true,
+			ExpectedTags:        map[string]*string{},
+		},
+		{
+			Name: "Single service",
+			InputTags: map[string]*string{
+				consts.ServiceTagKey: ptr.To("ns1/svc1"),
+			},
+			ExpectedTags: map[string]*string{
+				consts.ServiceTagKey: ptr.To("ns1/svc1"),
+			},
+			ExpectedServiceReferences: []string{"ns1/svc1"},
+		},
+		{
+			Name: "Multiple services #1",
+			InputTags: map[string]*string{
+				consts.ServiceTagKey: ptr.To("ns1/svc1,ns2/svc2"),
+			},
+			ExpectedTags: map[string]*string{
+				consts.ServiceTagKey: ptr.To("ns1/svc1"),
+			},
+			ExpectedServiceReferences: []string{"ns1/svc1"},
+		},
+		{
+			Name: "Multiple services #2",
+			InputTags: map[string]*string{
+				consts.ServiceTagKey: ptr.To("ns1/svc1,ns2/svc2,ns3/svc3"),
+			},
+			ExpectedTags: map[string]*string{
+				consts.ServiceTagKey: ptr.To("ns1/svc1,ns3/svc3"),
+			},
+			ExpectedServiceReferences: []string{"ns1/svc1", "ns3/svc3"},
+		},
 	}
 
-	for i, pip := range pips {
-		_ = unbindServiceFromPIP(pip, &service, serviceName, "", false)
-		assert.Equal(t, expectedTags[i], pip.Tags)
+	for _, tt := range tests {
+		t.Run(tt.Name, func(t *testing.T) {
+			svcName := "ns2/svc2"
+			svc := getTestService(svcName, v1.ProtocolTCP, nil, false, 80)
+			setServiceLoadBalancerIP(&svc, "1.2.3.4")
+
+			pip := &network.PublicIPAddress{
+				Tags: tt.InputTags,
+			}
+			serviceReferences, err := unbindServiceFromPIP(pip, svcName, tt.InputIsUserAssigned)
+			if tt.ExpectedErr {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+				assert.Equal(t, tt.ExpectedServiceReferences, serviceReferences)
+				assert.Equal(t, tt.ExpectedTags, pip.Tags)
+			}
+		})
 	}
 }
 
diff --git a/pkg/provider/azure_test.go b/pkg/provider/azure_test.go
index 921b04efe..bcfdcc155 100644
--- a/pkg/provider/azure_test.go
+++ b/pkg/provider/azure_test.go
@@ -63,23 +63,6 @@ import (
 
 const (
 	testClusterName = "testCluster"
-	testLBName      = "testCluster" // FIXME: there are lots of hard-coded lb named testCluster
-)
-
-var (
-	testIPs = []map[bool]string{
-		{false: "192.168.77.88", true: "fe::1"},
-		{false: "192.168.33.44", true: "fe::2"},
-		{false: "192.168.99.11", true: "fe::3"},
-		{false: "192.168.22.33", true: "fe::4"},
-	}
-
-	testRuleNames = []map[bool]string{
-		{false: "shared-TCP-80-Internet", true: "shared-TCP-80-Internet-IPv6"},
-		{false: "shared-TCP-4444-Internet", true: "shared-TCP-4444-Internet-IPv6"},
-		{false: "shared-TCP-8888-Internet", true: "shared-TCP-8888-Internet-IPv6"},
-		{false: "TCP-80-Internet", true: "TCP-80-Internet-IPv6"},
-	}
 )
 
 // Test flipServiceInternalAnnotation
@@ -2840,197 +2823,6 @@ func TestInitializeCloudFromConfig(t *testing.T) {
 	assert.Equal(t, az.Config.LoadBalancerBackendPoolConfigurationType, consts.LoadBalancerBackendPoolConfigurationTypeNodeIPConfiguration)
 }
 
-func TestFindSecurityRule(t *testing.T) {
-	srs := []network.SecurityRule{
-		{
-			Name: pointer.String(testRuleNames[3][false]),
-			SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-				Protocol:                   network.SecurityRuleProtocolTCP,
-				SourcePortRange:            pointer.String("*"),
-				SourceAddressPrefix:        pointer.String("Internet"),
-				DestinationPortRange:       pointer.String("80"),
-				DestinationAddressPrefix:   pointer.String(testIPs[0][false]),
-				DestinationAddressPrefixes: &([]string{}),
-				Access:                     network.SecurityRuleAccessAllow,
-				Direction:                  network.SecurityRuleDirectionInbound,
-			},
-		},
-		{
-			Name: pointer.String(testRuleNames[3][true]),
-			SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-				Protocol:                   network.SecurityRuleProtocolTCP,
-				SourcePortRange:            pointer.String("*"),
-				SourceAddressPrefix:        pointer.String("Internet"),
-				DestinationPortRange:       pointer.String("80"),
-				DestinationAddressPrefix:   pointer.String(testIPs[0][true]),
-				DestinationAddressPrefixes: &([]string{}),
-				Access:                     network.SecurityRuleAccessAllow,
-				Direction:                  network.SecurityRuleDirectionInbound,
-			},
-		},
-	}
-	testCases := []struct {
-		desc     string
-		testRule network.SecurityRule
-		expected bool
-	}{
-		{
-			desc:     "false should be returned for an empty rule",
-			testRule: network.SecurityRule{},
-			expected: false,
-		},
-		{
-			desc: "false should be returned when rule name doesn't match",
-			testRule: network.SecurityRule{
-				Name: pointer.String("not-the-right-name"),
-			},
-			expected: false,
-		},
-		{
-			desc: "false should be returned when protocol doesn't match",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol: network.SecurityRuleProtocolUDP,
-				},
-			},
-			expected: false,
-		},
-		{
-			desc: "false should be returned when SourcePortRange doesn't match",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol:        network.SecurityRuleProtocolUDP,
-					SourcePortRange: pointer.String("1.2.3.4/32"),
-				},
-			},
-			expected: false,
-		},
-		{
-			desc: "false should be returned when SourceAddressPrefix doesn't match",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol:            network.SecurityRuleProtocolUDP,
-					SourcePortRange:     pointer.String("*"),
-					SourceAddressPrefix: pointer.String("2.3.4.0/24"),
-				},
-			},
-			expected: false,
-		},
-		{
-			desc: "false should be returned when DestinationPortRange doesn't match",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol:             network.SecurityRuleProtocolUDP,
-					SourcePortRange:      pointer.String("*"),
-					SourceAddressPrefix:  pointer.String("Internet"),
-					DestinationPortRange: pointer.String("443"),
-				},
-			},
-			expected: false,
-		},
-		{
-			desc: "false should be returned when DestinationAddressPrefix doesn't match",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol:                 network.SecurityRuleProtocolUDP,
-					SourcePortRange:          pointer.String("*"),
-					SourceAddressPrefix:      pointer.String("Internet"),
-					DestinationPortRange:     pointer.String("80"),
-					DestinationAddressPrefix: pointer.String(testIPs[1][false]),
-				},
-			},
-			expected: false,
-		},
-		{
-			desc: "false should be returned when Access doesn't match",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol:                 network.SecurityRuleProtocolUDP,
-					SourcePortRange:          pointer.String("*"),
-					SourceAddressPrefix:      pointer.String("Internet"),
-					DestinationPortRange:     pointer.String("80"),
-					DestinationAddressPrefix: pointer.String(testIPs[0][false]),
-					Access:                   network.SecurityRuleAccessDeny,
-					// Direction:                network.SecurityRuleDirectionInbound,
-				},
-			},
-			expected: false,
-		},
-		{
-			desc: "false should be returned when Direction doesn't match",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol:                 network.SecurityRuleProtocolUDP,
-					SourcePortRange:          pointer.String("*"),
-					SourceAddressPrefix:      pointer.String("Internet"),
-					DestinationPortRange:     pointer.String("80"),
-					DestinationAddressPrefix: pointer.String(testIPs[0][false]),
-					Access:                   network.SecurityRuleAccessAllow,
-					Direction:                network.SecurityRuleDirectionOutbound,
-				},
-			},
-			expected: false,
-		},
-		{
-			desc: "true should be returned when everything matches but protocol is in different case",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol:                 network.SecurityRuleProtocol("TCP"),
-					SourcePortRange:          pointer.String("*"),
-					SourceAddressPrefix:      pointer.String("Internet"),
-					DestinationPortRange:     pointer.String("80"),
-					DestinationAddressPrefix: pointer.String(testIPs[0][false]),
-					Access:                   network.SecurityRuleAccessAllow,
-					Direction:                network.SecurityRuleDirectionInbound,
-				},
-			},
-			expected: true,
-		},
-		{
-			desc: "true should be returned when everything matches but DestinationAddressPrefixes is nil",
-			testRule: network.SecurityRule{
-				Name: pointer.String(testRuleNames[3][false]),
-				SecurityRulePropertiesFormat: &network.SecurityRulePropertiesFormat{
-					Protocol:                   network.SecurityRuleProtocolTCP,
-					SourcePortRange:            pointer.String("*"),
-					SourceAddressPrefix:        pointer.String("Internet"),
-					DestinationPortRange:       pointer.String("80"),
-					DestinationAddressPrefix:   pointer.String(testIPs[0][false]),
-					DestinationAddressPrefixes: nil,
-					Access:                     network.SecurityRuleAccessAllow,
-					Direction:                  network.SecurityRuleDirectionInbound,
-				},
-			},
-			expected: true,
-		},
-		{
-			desc:     "true should be returned when everything matches IPv4",
-			testRule: srs[0],
-			expected: true,
-		},
-		{
-			desc:     "true should be returned when everything matches IPv6",
-			testRule: srs[1],
-			expected: true,
-		},
-	}
-
-	for i := range testCases {
-		t.Run(testCases[i].desc, func(t *testing.T) {
-			found := findSecurityRule(srs, testCases[i].testRule)
-			assert.Equal(t, testCases[i].expected, found)
-		})
-	}
-}
-
 func TestSetLBDefaults(t *testing.T) {
 	ctrl := gomock.NewController(t)
 	defer ctrl.Finish()
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-post.ps1 b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-post.ps1
index a69bbce34..1a07fede6 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-post.ps1
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources-post.ps1
@@ -5,7 +5,19 @@
 
 param (
   [hashtable] $AdditionalParameters = @{},
-  [hashtable] $DeploymentOutputs
+  [hashtable] $DeploymentOutputs,
+
+  [Parameter(ParameterSetName = 'Provisioner', Mandatory = $true)]
+  [ValidateNotNullOrEmpty()]
+  [string] $TenantId,
+
+  [Parameter()]
+  [ValidatePattern('^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$')]
+  [string] $TestApplicationId,
+
+  # Captures any arguments from eng/New-TestResources.ps1 not declared here (no parameter errors).
+  [Parameter(ValueFromRemainingArguments = $true)]
+  $RemainingArguments
 )
 
 $ErrorActionPreference = 'Stop'
@@ -16,14 +28,14 @@ if ($CI) {
     Write-Host "Skipping post-provisioning script because resources weren't deployed"
     return
   }
-  az login --service-principal -u $DeploymentOutputs['AZIDENTITY_CLIENT_ID'] -p $DeploymentOutputs['AZIDENTITY_CLIENT_SECRET'] --tenant $DeploymentOutputs['AZIDENTITY_TENANT_ID']
+  az login --federated-token $env:OIDC_TOKEN --service-principal -t $TenantId -u $TestApplicationId
   az account set --subscription $DeploymentOutputs['AZIDENTITY_SUBSCRIPTION_ID']
 }
 
 Write-Host "Building container"
 $image = "$($DeploymentOutputs['AZIDENTITY_ACR_LOGIN_SERVER'])/azidentity-managed-id-test"
 Set-Content -Path "$PSScriptRoot/Dockerfile" -Value @"
-FROM mcr.microsoft.com/oss/go/microsoft/golang:latest as builder
+FROM mcr.microsoft.com/oss/go/microsoft/golang:latest AS builder
 ENV GOARCH=amd64 GOWORK=off
 COPY . /azidentity
 WORKDIR /azidentity/testdata/managed-id-test
@@ -53,9 +65,11 @@ az container create -g $rg -n $aciName --image $image `
   --role "Storage Blob Data Reader" `
   --scope $($DeploymentOutputs['AZIDENTITY_STORAGE_ID']) `
   -e AZIDENTITY_STORAGE_NAME=$($DeploymentOutputs['AZIDENTITY_STORAGE_NAME']) `
-     AZIDENTITY_STORAGE_NAME_USER_ASSIGNED=$($DeploymentOutputs['AZIDENTITY_STORAGE_NAME_USER_ASSIGNED']) `
-     AZIDENTITY_USER_ASSIGNED_IDENTITY=$($DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY']) `
-     FUNCTIONS_CUSTOMHANDLER_PORT=80
+  AZIDENTITY_STORAGE_NAME_USER_ASSIGNED=$($DeploymentOutputs['AZIDENTITY_STORAGE_NAME_USER_ASSIGNED']) `
+  AZIDENTITY_USER_ASSIGNED_IDENTITY=$($DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY']) `
+  AZIDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID=$($DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID']) `
+  AZIDENTITY_USER_ASSIGNED_IDENTITY_OBJECT_ID=$($DeploymentOutputs['AZIDENTITY_USER_ASSIGNED_IDENTITY_OBJECT_ID']) `
+  FUNCTIONS_CUSTOMHANDLER_PORT=80
 Write-Host "##vso[task.setvariable variable=AZIDENTITY_ACI_NAME;]$aciName"
 
 # Azure Functions deployment: copy the Windows binary from the Docker image, deploy it in a zip
diff --git a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep
index 2a2165293..135feb017 100644
--- a/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep
+++ b/vendor/github.com/Azure/azure-sdk-for-go/sdk/azidentity/test-resources.bicep
@@ -135,6 +135,14 @@ resource azfunc 'Microsoft.Web/sites@2021-03-01' = if (deployResources) {
           name: 'AZIDENTITY_USER_ASSIGNED_IDENTITY'
           value: deployResources ? usermgdid.id : null
         }
+        {
+          name: 'AZIDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID'
+          value: deployResources ? usermgdid.properties.clientId : null
+        }
+        {
+          name: 'AZIDENTITY_USER_ASSIGNED_IDENTITY_OBJECT_ID'
+          value: deployResources ? usermgdid.properties.principalId : null
+        }
         {
           name: 'AzureWebJobsStorage'
           value: 'DefaultEndpointsProtocol=https;AccountName=${deployResources ? sa.name : ''};EndpointSuffix=${deployResources ? environment().suffixes.storage : ''};AccountKey=${deployResources ? sa.listKeys().keys[0].value : ''}'
@@ -217,3 +225,4 @@ output AZIDENTITY_STORAGE_NAME_USER_ASSIGNED string = deployResources ? saUserAs
 output AZIDENTITY_USER_ASSIGNED_IDENTITY string = deployResources ? usermgdid.id : ''
 output AZIDENTITY_USER_ASSIGNED_IDENTITY_CLIENT_ID string = deployResources ? usermgdid.properties.clientId : ''
 output AZIDENTITY_USER_ASSIGNED_IDENTITY_NAME string = deployResources ? usermgdid.name : ''
+output AZIDENTITY_USER_ASSIGNED_IDENTITY_OBJECT_ID string = deployResources ? usermgdid.properties.principalId : ''