CLO-190: persist: refresh Azure workload identity tokens from rotated file - #38178
Open
jubrad wants to merge 3 commits into
Open
Conversation
The azure_identity default credential chain resolves AKS workload identity via a WorkloadIdentityCredential that reads AZURE_FEDERATED_TOKEN_FILE once at construction and holds the contents for the life of the process. Kubernetes rotates that projected token, so once the last cached AAD access token expired, every refresh presented a stale client assertion and failed, permanently locking long-running processes out of persist blob storage. Add a RefreshingWorkloadIdentityCredential that re-reads the projected token file on every AAD access token refresh and caches the resulting access token until near expiry, mirroring azure_identity's token cache semantics. Use it when the workload identity environment variables are present, falling back to the default credential chain (whose remaining credential types, e.g. IMDS managed identity, refresh correctly) otherwise. The SAS-token-in-URL path is unchanged. Fixes CLO-190. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A token provided directly via the AZURE_FEDERATED_TOKEN env var is static, so there is nothing to re-read on refresh. azure_identity's credential chain prefers it over AZURE_FEDERATED_TOKEN_FILE, so preserve that precedence when both are set. Part of CLO-190. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Part of CLO-190. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes CLO-190.
Seems to work on an Azure env I spun up.
Motivation
A customer environment on AKS lost persist auth into Azure Blob Storage after running for a while. Root cause:
azure_identity0.21's default credential chain resolves AKS workload identity viaWorkloadIdentityCredential, which reads the projected service account token fromAZURE_FEDERATED_TOKEN_FILEonce at construction and holds the contents for the life of the process. Kubernetes rotates that projected token, so once the last cached AAD access token expired, every refresh presented a stale client assertion to AAD and failed, permanently locking long-running processes out of persist blob storage.Changes
RefreshingWorkloadIdentityCredentialinsrc/persist/src/azure.rsthat re-reads the projected token file on every AAD access token refresh and exchanges it via the publicazure_identity::federated_credentials_flow::perform. Resulting access tokens are cached per scope until near expiry, mirroringazure_identity's internal token cache semantics (including its 20s expiry buffer), with refresh under a write lock to avoid stampeding AAD.AzureBlobConfig::newwhenAZURE_TENANT_ID,AZURE_CLIENT_ID, andAZURE_FEDERATED_TOKEN_FILEare all present (andAZURE_FEDERATED_TOKENis not, that static-token path keeps its upstream precedence). Otherwise fall back tocreate_default_credential(), whose remaining credential types (e.g. IMDS managed identity) refresh correctly.clear_cache, without contacting AAD (the exchange is injected).Out of scope
Migrating off the archived unofficial
azure_storage/azure_identity0.21 crates to the official Azure SDK for Rust is the long-term fix for this class of issue, but is a much larger change and not needed to resolve this incident class.Tips for reviewer
Compare with the vendored
azure_identity0.21 sources:WorkloadIdentityCredential::createreads the token file once (token_credentials/workload_identity_credentials.rs), and it enters the default chain viaEnvironmentCredential(token_credentials/environment_credentials.rs).Checklist
$T ⇔ Proto$Tmapping (possibly in a backwards-incompatible way), then it is tagged with aT-protolabel.🤖 Generated with Claude Code