dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.64k stars 3.15k forks source link

Can't connect with Managed Identity and Cosmos provider #34317

Closed ciacco85 closed 2 weeks ago

ciacco85 commented 1 month ago

Ask a question

I've followed these docs Authenticate .NET apps to Azure services during local development using developer accounts Use system-assigned managed identities to access Azure Cosmos DB data Inspected #26573, #26491 and #26491

Steps done

1 - Added the Cosmos DB Built-in Data Contributor to my identity for local debuging and to Azure resource with the following PS script

New-AzCosmosDBSqlRoleAssignment -AccountName $accountName -ResourceGroupName $resourceGroupName -RoleDefinitionId $BuiltInDataContributor Scope "/" -PrincipalId $principalId

2 - Execute my example Console APP using the following DI registration

services.AddDbContext<EFSNoSqlDbContext>(options => options.UseCosmos(
    cosmosConfigs.AccountEndpoint, new DefaultAzureCredential(), cosmosConfigs.DatabaseName));

3 - Execute a simple query command

var query = _dbContext.EventStore
    .AsNoTracking()
    .Take(10)
    .ToListAsync(cancellationToken);

Stack trace

An exception occurred while iterating over the results of a query for context type 'EFS.DAL.NoSql.EFSNoSqlDbContext'.
Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: Unauthorized (401); Substatus: 0; ActivityId: ee0795c7-14d9-45cf-9848-6700481762f3; Reason: (The input authorization token can't serve the request. The wrong key is being used or the expected payload is not built as per the protocol. For more info: https://aka.ms/cosmosdb-tsg-unauthorized. Server used the following payload to sign: 'get

tue, 30 jul 2024 11:08:29 gmt

'
ActivityId: ee0795c7-14d9-45cf-9848-6700481762f3, Microsoft.Azure.Documents.Common/2.14.0, Windows/10.0.22635 cosmos-netstandard-sdk/3.31.4);
   at Microsoft.Azure.Cosmos.GatewayStoreClient.ParseResponseAsync(HttpResponseMessage responseMessage, JsonSerializerSettings serializerSettings, DocumentServiceRequest request)
   at Microsoft.Azure.Cosmos.GatewayAccountReader.GetDatabaseAccountAsync(Uri serviceEndpoint)
   at Microsoft.Azure.Cosmos.Routing.GlobalEndpointManager.GetAccountPropertiesHelper.GetAndUpdateAccountPropertiesAsync(Uri endpoint)
   at Microsoft.Azure.Cosmos.Routing.GlobalEndpointManager.GetAccountPropertiesHelper.GetAccountPropertiesAsync()
   at Microsoft.Azure.Cosmos.GatewayAccountReader.InitializeReaderAsync()
   at Microsoft.Azure.Cosmos.CosmosAccountServiceConfiguration.InitializeAsync()
   at Microsoft.Azure.Cosmos.DocumentClient.InitializeGatewayConfigurationReaderAsync()
   at Microsoft.Azure.Cosmos.DocumentClient.GetInitializationTaskAsync(IStoreClientFactory storeClientFactory)
   at Microsoft.Azure.Documents.BackoffRetryUtility`1.ExecuteRetryAsync[TParam,TPolicy](Func`1 callbackMethod, Func`3 callbackMethodWithParam, Func`2 callbackMethodWithPolicy, TParam param, IRetryPolicy retryPolicy, IRetryPolicy`1 retryPolicyWithArg, Func`1 inBackoffAlternateCallbackMethod, Func`2 inBackoffAlternateCallbackMethodWithPolicy, TimeSpan minBackoffForInBackoffCallback, CancellationToken cancellationToken, Action`1 preRetryCallback)
   at Microsoft.Azure.Documents.ShouldRetryResult.ThrowIfDoneTrying(ExceptionDispatchInfo capturedException)
   at Microsoft.Azure.Documents.BackoffRetryUtility`1.ExecuteRetryAsync[TParam,TPolicy](Func`1 callbackMethod, Func`3 callbackMethodWithParam, Func`2 callbackMethodWithPolicy, TParam param, IRetryPolicy retryPolicy, IRetryPolicy`1 retryPolicyWithArg, Func`1 inBackoffAlternateCallbackMethod, Func`2 inBackoffAlternateCallbackMethodWithPolicy, TimeSpan minBackoffForInBackoffCallback, CancellationToken cancellationToken, Action`1 preRetryCallback)
   at Microsoft.Azure.Cosmos.AsyncCacheNonBlocking`2.GetAsync(TKey key, Func`2 singleValueInitFunc, Func`2 forceRefresh)
   at Microsoft.Azure.Cosmos.AsyncCacheNonBlocking`2.GetAsync(TKey key, Func`2 singleValueInitFunc, Func`2 forceRefresh)
   at Microsoft.Azure.Cosmos.DocumentClient.EnsureValidClientAsync(ITrace trace)
--- Cosmos Diagnostics ---{"Summary":{},"name":"FeedIterator Read Next Async","start datetime":"2024-07-30T11:08:29.789Z","duration in milliseconds":234.3518,"data":{"Client Configuration":{"Client Created Time Utc":"2024-07-30T11:08:29.7238599Z","MachineId":"hashedMachineName:b7d2d35f-c728-f6e0-6615-8e4b8bec5f80","NumberOfClientsCreated":1,"NumberOfActiveClients":1,"ConnectionMode":"Direct","User Agent":"cosmos-netstandard-sdk/3.35.4|1|X64|Microsoft Windows 10.0.22635|.NET 8.0.7|N| Microsoft.EntityFrameworkCore.Cosmos/8.0.7","ConnectionConfig":{"gw":"(cps:50, urto:6, p:False, httpf: False)","rntbd":"(cto: 5, icto: -1, mrpc: 30, mcpe: 65535, erd: True, pr: ReuseUnicastPort)","other":"(ed:False, be:False)"},"ConsistencyConfig":"(consistency: NotSet, prgns:[], apprgn: )","ProcessorCount":16},"Query Correlated ActivityId":"7474bc4e-9d41-40a7-b63f-251c14389788"},"children":[{"name":"Create Query Pipeline","duration in milliseconds":218.0909,"children":[{"name":"Get Container Properties","duration in milliseconds":215.5449,"children":[{"name":"Get Collection Cache","duration in milliseconds":214.6914,"children":[{"name":"Waiting for Initialization of client to complete","duration in milliseconds":213.8505}]}]}]}]}

Version

EF Core version: 8.0.7 Database provider: CosmosDB Target framework: .NET 8.0) Operating system:

AndriySvyryd commented 1 month ago

Are you able to query using the Cosmos SDK directly?

Not related, but you should move out the credential instance when configuring the context:

var credential = new DefaultAzureCredential();
services.AddDbContext<EFSNoSqlDbContext>(options => options.UseCosmos(
    cosmosConfigs.AccountEndpoint, credential, cosmosConfigs.DatabaseName));
ciacco85 commented 2 weeks ago

Honestly I have never used the Cosmos SDK directly, however with your suggestion the issue has not been solved. Any other idea? @AndriySvyryd

AndriySvyryd commented 2 weeks ago

Honestly I have never used the Cosmos SDK directly, however with your suggestion the issue has not been solved.

What was the result of using it directly? Did it work?

ciacco85 commented 2 weeks ago

@AndriySvyryd In the services registration pipeline of our startup

services.AddNosqlDbContexts(configuration, cosmosConfigSection)
    .Configure<CosmosConfigs>(configuration.GetSection(cosmosConfigSection))
    .RegisterNosqlRepository()
    .EnsureMigrationOfNoSqlContext<EFSNoSqlDbContext>();

we essentially register DB context, register repositories and ensure the creation of the DB

 var sp = services.BuildServiceProvider();
 using (var context = sp.GetService<T>())
 {
     if (forceDelete)
         context.Database.EnsureDeleted();
     context.Database.EnsureCreated();
 }

The problem was that the built-in role Cosmos DB Built-in Data Contributor cannot perform this operation, but exception was hidden during startup operation (my bad) and not logged inside Log Stream nor Application Insight

AndriySvyryd commented 2 weeks ago

The problem was that the built-in role Cosmos DB Built-in Data Contributor cannot perform this operation, but exception was hidden during startup operation (my bad) and not logged inside Log Stream nor Application Insight

Right. Also, Cosmos SDK (used by EF) can't perform configuration operations using RBAC, you'd have to perform them using the ARM SDK or via portal.