Search code examples
c#azureazure-cosmosdb

Cosmos db emulator - SSL connection could not be established


I'm running cosmos db emulator as a docker container for testing purposes. Unfortunately I'm having problems connecting to it. When executing, the following code

public async Task<IEnumerable<Item>> GetItemsAsync(int offset = 0, CancellationToken cancellationToken = default)
{
    var query = dbContext.Items
        .OrderBy(x => x.LastReadAt)
        .ThenByDescending(x => x.CreatedAt)
        .Skip(offset)
        .Take(10)
        .ToFeedIterator();

    var feedResponse = await query.ReadNextAsync(); // this is where the error occurs

    var result = feedResponse.ToList();

    return result.AsEnumerable();
}

this exception is being thrown

---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
[2024-01-21T18:28:23.229Z]  ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
[2024-01-21T18:28:23.230Z]    at System.Net.Security.SslStream.CompleteHandshake(SslAuthenticationOptions sslAuthenticationOptions)

The dbContext is just a class exposing IQueryable of Item

internal class MyDbContext(CosmosClient cosmosClient)
{
    private readonly Container items = cosmosClient.GetContainer("testdb", "items");

    public IQueryable<Item> Items => items.GetItemLinqQueryable<Item>();
}

and is registered like this

services.AddSingleton(serviceProvider =>
{
    var options = serviceProvider.GetRequiredService<IOptions<PersistenceOptions>>();

    return new CosmosClient(options.Value.ConnectionString);
});

After adding the certificate to Trusted Root Certification Authorities on Windows following the documentation (https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-develop-emulator?tabs=docker-linux%2Ccsharp&pivots=api-nosql#export-the-emulators-tlsssl-certificate), I found out that instead of exception being thrown, right now the code just hangs on var feedResponse = await query.ReadNextAsync(); and nothing happens afterwards. I don't know how can I check what is the problem and why I'm not being able to fetch the data.

The same thing happens if I'm trying to bypass SSL certificate validation registering the cosmos client as follows (I took the workaround from https://github.com/Azure/azure-cosmos-dotnet-v3/issues/1232#issuecomment-670673733)

services.AddSingleton(serviceProvider =>
{
    var options = serviceProvider.GetRequiredService<IOptions<PersistenceOptions>>();

    return new CosmosClient(options.Value.ConnectionString, new CosmosClientOptions
    {
        HttpClientFactory = () =>
        {
            HttpMessageHandler httpMessageHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (req, cert, chain, errors) => true
            };

            return new HttpClient(httpMessageHandler);
        },
        ConnectionMode = ConnectionMode.Gateway
    }
});

Everything works fine when I connect to real cosmos db instance on Azure. I'm wondering if anyone has the similar experience with cosmos db emulator. Are there some constraints I should be aware of? Is this a common problem?

UPDATE

The code that hangs on ReadNextAsync at some point will finally throw an exception

---> Microsoft.Azure.Cosmos.CosmosException : Response status code does not indicate success: ServiceUnavailable (503); Substatus: 20003; ActivityId: 00000000-0000-0000-0000-000000000000; Reason: (GatewayStoreClient Request Timeout. Start Time UTC:21/01/2024 20:33:50; Total Duration:45892.3326 Ms; Request Timeout 20000 Ms; Http Client Timeout:65000 Ms; Activity id: 00000000-0000-0000-0000-000000000000;);
[2024-01-21T20:34:36.408Z]  ---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.
[2024-01-21T20:34:36.408Z]  ---> System.Threading.Tasks.TaskCanceledException: The operation was canceled.
[2024-01-21T20:34:36.408Z]  ---> System.IO.IOException: Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
[2024-01-21T20:34:36.409Z]  ---> System.Net.Sockets.SocketException (995): The I/O operation has been aborted because of either a thread exit or an application request.

Solution

  • I've managed to solve this problem by changing LimitToEndpoint = true in CosmosClientOptions.

    The final configuration look as follows:

    return new CosmosClient(options.Value.ConnectionString, new CosmosClientOptions
    {
        HttpClientFactory = () =>
        {
            HttpMessageHandler httpMessageHandler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = (req, cert, chain, errors) => true
            };
    
            return new HttpClient(httpMessageHandler);
        },
        ConnectionMode = ConnectionMode.Gateway,
        LimitToEndpoint = true
    }
    

    This github issue helped me solving this problem https://github.com/Azure/azure-cosmos-db-emulator-docker/issues/63#issuecomment-1519107107