Azure / azure-cosmos-db-emulator-docker

This repo serves as hub for managing issues, gathering feedback, and having discussions regarding the Cosmos DB Emulator Docker.
https://learn.microsoft.com/en-us/azure/cosmos-db/how-to-develop-emulator?tabs=docker-linux%2Ccsharp&pivots=api-nosql
MIT License
145 stars 43 forks source link

Unable to connect to cosmos db emulator when using linux containers with container network #76

Open ajaygoyal opened 8 months ago

ajaygoyal commented 8 months ago

I have a .net 6 app that needs to connect to cosmos db emulator.

I have below setup:

test-app: env_file:

Downloaded the cert on host using: curl -k https://host.docker.internal:8081/_explorer/emulator.pem > /c/certs/emulatorcert.crt

But application fails to connect to the cosmos with below error:

2023-10-22 20:06:51 ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. 2023-10-22 20:06:51 ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch

Disabling SSL is not something that we want to do.

kbegiedza commented 8 months ago

Did you install downloaded cert inside your test-app container?

abkolant-MSFT commented 8 months ago

Could you check the example YAML file and this folder in the .NET examples. This example shows how to use Cosmos DB Emulator with containers and networks. The example, also shows how to download and install certs into your test app, that connects to the Emulator.

JoeAmedeo commented 5 months ago

Is there a way to make this work without using HttpClientHandler.DangerousAcceptAnyServerCertificateValidator as a cert validation callback? I am trying to set up effectively the same application as the example, but with the Azure Cosmos DB Migration Tool where I can't make this configuration, and removing that from the example app causes the same RemoteCertificateNameMismatch error.

I am not super confident on my understanding of SSL certificates, but is it possible to use the /GenCert={host name for the service} arg to make this work? I have been following this example from another issue and tried overriding the ./startup.sh file to use said argument, but at that point the emulator will not start.

Davilink commented 4 months ago

This really seem like an oversight. I can't use cosmos emulator in devcontainer because of this simple issue... one thing could be to add the hostname as an alternate name in the certificate.

Davilink commented 4 months ago

I got it working without using the HttpClientHandler.DangerousAcceptAnyServerCertificateValidator.

I inspected the certificate and found out that it does contains alternate subject name, but there a twist, you have to declare a hostname for your service.

docker-compose.yml (good)

version: '3'
services:
  cosmos:
    image:  mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest
    hostname: cosmos # <-- required
    restart: unless-stopped
    ports:
      - 8081:8081
    networks:
      game:
        aliases:
          - "cosmos.domain" # <-- required

image

If you don't specifiy a hostname, docker will generate a random one example:

docker-compose.yml (bad)

version: '3'
services:
  cosmos:
    image:  mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest
    # hostname: cosmos
    restart: unless-stopped
    ports:
      - 8081:8081
    networks:
      game:
        aliases:
          - "cosmos.domain" # <-- required

image

Note: I tried using the cosmosdbemulatormtls.localhost but it doesn't work (problably because of the .localhost at the end).

The hostname doesn't have to be cosmos, i just choose that name, but if you change it don't forget to update the aliase use in the docker compose file.

docker-compose.yml (alternate config good)

version: '3'
services:
  cosmos:
    image:  mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest
    hostname: othername
    restart: unless-stopped
    ports:
      - 8081:8081
    networks:
      game:
        aliases:
          - "othername.domain"

Once the cosmos emulator container is started, it take a minute or so to be able to retrieve the certificate. I'm currently setting up a devcontainer using cosmos emulator and added this in my postCreateCommand.sh script:

#!/bin/bash
echo "Installing cosmos db emulator ssl certificate"

mkdir /usr/share/ca-certificates/cosmos

for i in {1..60};
do
  curl -fsk https://cosmos.domain:8081/_explorer/emulator.pem > /usr/share/ca-certificates/cosmos/emulator.crt
  if [ $? -eq 0 ];  then
    echo "Cosmos emulator ready"
    break
  else
    echo "Not ready yet..."
    sleep 10
  fi
done

chmod o+r /usr/share/ca-certificates/cosmos/emulator.crt
echo "cosmos/emulator.crt" >> /etc/ca-certificates.conf
update-ca-certificates

after this, you will need to use the cosmos.domain:8081 (update the port number if your setup use an another port)

appsetings.Development.json

{
  // ...
  "ConnectionStrings": {
    "CosmosConnection": "AccountEndpoint=https://cosmos.domain:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
  },
  // ...
}

The account key is the default one used by the cosmos emulator, so you can copy-paste the connection string for you use.

cdytoby commented 2 months ago

Additional information to the post above:

curl is default not installed. So for automation, you need to install curl.

This is the example snippet to the Dockerfile of the asp.net project

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
RUN apt-get update && apt-get install -y curl
EXPOSE 8080

Credit: https://stackoverflow.com/questions/73678713/how-to-install-curl-from-dockerfile

PS: after add this RUN line, you need to delete relevant containers and re-pull and build.

But..... I still get SSL error:

The SSL connection could not be established, see inner exception.

InnerException: The remote certificate is invalid according to the validation procedure: RemoteCertificateNameMismatch, RemoteCertificateChainErrors

hughesjs commented 1 month ago

I'm getting the same as @cdytoby... Any ideas beyond just disabling SSL validation for now?

hughesjs commented 3 weeks ago

Okay, so I worked out my problem.

The cosmos.domain listed as an alias above isn't just "any generic domain" it's literally ".domain".

Seems to me you can summarise that long post into:

This will then ensure that you can resolve the emulator with a hostname that is present in the certificate's alternate names

You can probably get all of this from the long answer above, but I missed it so figured I'd share what I learned a bit more concisely.

hughesjs commented 3 weeks ago

So following on from my last post, I can go one better.

I don't think you even need the alias, just set the hostname to cosmos.domain and refer to it through that everywhere else. I'd even recommend leaving out the container_name so you can't resolve it any other way unless you really like having nicely named containers.

  cosmos-db-emulator:
    image: mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:latest
    hostname: cosmos.domain # <--- This .domain is the only thing that matters really
    environment:
      AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE: true
      AZURE_COSMOS_EMULATOR_PARTITION_COUNT: 1
    networks:
      - internal