[BUG] Handling all errors instead of just 403 in ManagedIdentitySource causes unexpected regression error #46709
Description
Library name and version
Azure.Identity 1.13.0
Describe the bug
When updating from 1.12.1 to 1.13.0 I get a regression error with AzureDefaultCredential usage (in a .NET app) inside Github Actions using Federated Credentials for a UAI to migrate my database.
I'm relying on the AzureCliCredentials inside my action, but the following change seems to stop the credential chain because the github action has a endpoint that responds with Bad Request: https://github.com/Azure/azure-sdk-for-net/pull/45236/files#diff-72571e3cca761ecd73c5855b39621f8883c8ee115319a0ecbb629deb5b8c0513L85
Expected behavior
DefaultAzureCredentials() is not able to get a managed identity and proceeds through the default chain to AzureCliCredential
With 1.12.1 I get:
Build started...
Build succeeded.
No migrations were applied. The database is already up to date.
Done.
Actual behavior
The IMDS endpoint responds with 400 Bad Request and stops the chain.
With 1.13.0 I get:
Build started...
Build succeeded.
Npgsql.NpgsqlException (0x80004005): An exception was thrown from the periodic password provider
---> Azure.Identity.AuthenticationFailedException: ManagedIdentityCredential authentication failed: [Managed Identity] Authentication unavailable. Either the requested identity has not been assigned to this resource, or other errors could be present. Ensure the identity is correctly assigned and check the inner exception for more details. For more information, visit https://aka.ms/msal-managed-identity.
Status: BadRequest
Content:
{"error":"invalid_request","error_description":"Identity not found"}
Headers:
Server: IMDS/150.870.65.1475
x-ms-request-id: a366dbbd-5d47-405d-b636-dc4d8bca40d5
Date: Fri, 18 Oct 2024 14:21:55 GMT
[Managed Identity] Error Code: invalid_request Error Description: Identity not found
See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot
---> MSAL.NetCore.4.65.0.0.MsalServiceException:
ErrorCode: managed_identity_request_failed
Microsoft.Identity.Client.MsalServiceException: [Managed Identity] Authentication unavailable. Either the requested identity has not been assigned to this resource, or other errors could be present. Ensure the identity is correctly assigned and check the inner exception for more details. For more information, visit https://aka.ms/msal-managed-identity.
Status: BadRequest
Content:
{"error":"invalid_request","error_description":"Identity not found"}
Headers:
Server: IMDS/150.870.65.1475
x-ms-request-id: a366dbbd-5d47-405d-b636-dc4d8bca40d5
Date: Fri, 18 Oct 2024 14:21:55 GMT
[Managed Identity] Error Code: invalid_request Error Description: Identity not found
at Microsoft.Identity.Client.ManagedIdentity.ImdsManagedIdentitySource.HandleResponseAsync(AcquireTokenForManagedIdentityParameters parameters, HttpResponse response, CancellationToken cancellationToken)
at Microsoft.Identity.Client.ManagedIdentity.AbstractManagedIdentity.AuthenticateAsync(AcquireTokenForManagedIdentityParameters parameters, CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.ManagedIdentityAuthRequest.SendTokenRequestForManagedIdentityAsync(ILoggerAdapter logger, CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.ManagedIdentityAuthRequest.GetAccessTokenAsync(CancellationToken cancellationToken, ILoggerAdapter logger)
at Microsoft.Identity.Client.Internal.Requests.ManagedIdentityAuthRequest.ExecuteAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.<>c__DisplayClass11_1.<<RunAsync>b__1>d.MoveNext()
--- End of stack trace from previous location ---
at Microsoft.Identity.Client.Utils.StopwatchService.MeasureCodeBlockAsync(Func`1 codeBlock)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.ApiConfig.Executors.ManagedIdentityExecutor.ExecuteAsync(AcquireTokenCommonParameters commonParameters, AcquireTokenForManagedIdentityParameters managedIdentityParameters, CancellationToken cancellationToken)
at Azure.Identity.MsalManagedIdentityClient.AcquireTokenForManagedIdentityAsyncCore(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.MsalManagedIdentityClient.AcquireTokenForManagedIdentityAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.ImdsManagedIdentityProbeSource.AuthenticateAsync(Boolean async, TokenRequestContext context, CancellationToken cancellationToken)
at Azure.Identity.ManagedIdentityClient.AuthenticateCoreAsync(Boolean async, TokenRequestContext context, CancellationToken cancellationToken)
at Azure.Identity.ManagedIdentityClient.AuthenticateAsync(Boolean async, TokenRequestContext context, CancellationToken cancellationToken)
at Azure.Identity.ManagedIdentityCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
StatusCode: 0
ResponseBody:
Headers:
--- End of inner exception stack trace ---
at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex, String additionalMessage, Boolean isCredentialUnavailable)
at Azure.Identity.ManagedIdentityCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.ManagedIdentityCredential.GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] sources, TokenRequestContext requestContext, Boolean async, CancellationToken cancellationToken)
at Azure.Identity.DefaultAzureCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex, String additionalMessage, Boolean isCredentialUnavailable)
at Azure.Identity.DefaultAzureCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.DefaultAzureCredential.GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
at Infrastructure.DatabaseContext.<>c__DisplayClass6_0.<<OnConfiguring>b__1>d.MoveNext() in /home/runner/work/someproject/api/src/Infrastructure/DatabaseContext.cs:line 34
--- End of stack trace from previous location ---
at Npgsql.NpgsqlDataSource.RefreshPassword()
at Npgsql.NpgsqlDataSource.RefreshPassword()
at Npgsql.NpgsqlDataSource.<GetPassword>g__GetInitialPeriodicPassword|83_0(Boolean async)
at Npgsql.NpgsqlConnection.CloneWith(String connectionString)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlRelationalConnection.CloneWith(String connectionString)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlDatabaseCreator.Exists(Boolean async, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlDatabaseCreator.Exists()
at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()
at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrations()
at Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Internal.NpgsqlMigrator.Migrate(String targetMigration)
at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
An exception was thrown from the periodic password provider
Error: Process completed with exit code 1.
Reproduction Steps
This is the code I use with Npsql inside my DbContext to get a token:
TokenCredential tokenCredential = string.IsNullOrEmpty(config.Value.UserAssignedManagedIdentityClientId)
? new DefaultAzureCredential()
: new ManagedIdentityCredential(config.Value.UserAssignedManagedIdentityClientId);
var accessToken = await tokenCredential.GetTokenAsync(
new TokenRequestContext(["https://ossrdbms-aad.database.windows.net/.default"]),
cancellationToken
);
return accessToken.Token;
The config value is set in my Container App, but in the github action it logs in with a seperate UAI (with Federated Credentials setup up) that can do migrations on the database:
- name: Azure login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
Environment
This is inside a Github Action:
deploy_api:
name: deploy-api
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
needs: build_and_test
env:
DATABASE_SERVER: xxxxxxxx
DATABASE_NAME: xxxxxxxx
DATABASE_USER_ID: xxxxxxxxxxx
steps:
- uses: actions/checkout@v4
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
global-json-file: ./api/global.json
- name: Azure login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Install EF tools
working-directory: api
run: dotnet tool install --global dotnet-ef
- name: Get access token and run database migrations
working-directory: api
env:
InfrastructureConfig__ConnectionString: Host=${{env.DATABASE_SERVER}};Database=${{env.DATABASE_NAME}};Username=${{env.DATABASE_USER_ID}};Ssl Mode=Require
run: |
echo "connectionString=$InfrastructureConfig__ConnectionString"
dotnet ef database update --project src/Infrastructure/ --startup-project src/Api
Metadata
Assignees
Labels
Type
Projects
Status
Done