azure-cosmos-dotnet-v3: How to use V3 CosmosClient with Emulator while ignoring SSL errors?

Describe the bug Impossible to connect CosmosClient to Emulator while trying to ignore SSL certificates.

I already searched this repo and the web to find some information about how to ignore the SSL error if we try to connect to the emulator. All I could find was some hints on how to solve these problems on V2 DocumentClient (like #42), but nothing for V3 CosmosClient.

I dig through the public interface of the class, their options, etc. and the only maybe promising I could find was the Collection<RequestHandler> CustomHandlers. So I wrote my own handler (see below), added it to the options new CosmosClient(EndPoint, Key, new CosmosClientOptions { CustomHandlers = { new IgnoringSSLErrorsRequestHandler() } }); and guess what, it won’t be called (so I also don’t know if the implementation is correct or does really work).

Expected behavior Some code example on how it is possible to instantiate an CosmosClient that will ignore SSL errors.

Actual behavior Nothing is available to work around this problem, except importing the certificate to the windows certificate store, but we need some solution in pure code.

Environment summary SDK Version: 3.6.0 OS Version: Windows

Additional context

internal class IgnoringSSLErrorsRequestHandler : RequestHandler
{
    private readonly HttpClient _httpClient;

    public IgnoringSSLErrorsRequestHandler()
    {
        var messageHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = (req, cert, chain, errors) => true };
        _httpClient = new HttpClient(messageHandler);
    }

    public override async Task<ResponseMessage> SendAsync(RequestMessage request, CancellationToken cancellationToken)
    {
        var httpRequest = new HttpRequestMessage
        {
            Method = request.Method,
            RequestUri = request.RequestUri,
        };

        foreach (var headerKey in request.Headers.AllKeys())
        {
            httpRequest.Headers.Add(headerKey, request.Headers[headerKey]);
        }

        foreach (var kvp in request.Properties)
        {
            httpRequest.Properties.Add(kvp);
        }

        var response = await _httpClient.SendAsync(httpRequest, cancellationToken);

        return new ResponseMessage(response.StatusCode, request)
        {
            Content = await response.Content.ReadAsStreamAsync()
        };
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 28 (9 by maintainers)

Most upvoted comments

When thinking about how to allow us to get past this SSL issue (without the huge ‘create a special cert for Docker, blah blah’)

I gave up trying to work around the ssl issue, and I am currently trying to get a custom cosmos docker image to work.

Honestly, this has been the biggest waste of dev time in my entire life. The MS Cosmos team should add a no SSL config option; just like the rest of the tools we use! You dont have to run mongo, mysql, etc etc locally with a cert… you can if you want to, but it isn’t mandatory. That’s the part that annoys me most; treating developers with kid gloves!

Another vote for an “insecure” dev mode. I have spent far too long trying to get this to work in docker across several languages.

I’d really like to NOT import a certificate somewhere. I’d like to use the emulator locally without validating the certificate in my test code. That should really be possible, especially for testing.

Why not add an option to run the emulator with HTTP connection? Similar to asp.net core where you have both HTTP and HTTPS. I wonder actually why HTTPS is used for the emulator. Someone was going to run the emulator on prod environment?

I might be wrong, but having HTTP option will solve all problems with accessing emulator from other machines or containers. And also this option will allow use exactly same code for dev and prod environments.

@olivermue This is a similar scenario to when you run an HTTPS application in a local server with a self-signed certificate. If you want to connect to that HTTPS application from other machine or instance, you need to trust that certificate by adding it to your list of trusted ones because it is a self-signed certificate.

The Emulator has its own certificate, that when you run locally in the same machine, it is automatically trusted because it is the same machine. This works out of the box.

If you want to access the Emulator from a different machine or environment (if you use Docker or a VM), you need to trust the certificate in order to establish an HTTPS connection, this is a basic HTTPS usage scenario for any secure application.

As @j82w said, adding programmatic ways to disable SSL only leads to production security issues when that code is accidentally pushed to production. The “hassle” of correctly trusting the certificate in a testing environment is rather better than the potential security breach of pushing code to production, don’t you think?

I totally agree with the developers above, just because it is the “Right Way” doesn’t mean that we should do “Rocket Science” to perform a simple stupid connection with the emulator that is ONLY NEEDED for dev mode. This is very frustrating and people that are working with Docker and CosmosDB cannot do simple development at the moment of writing this post.

Either write the correct docs pages on Microsoft website with a step-by-step guide or give a possibility to disable SSL when developing with docker.

BTW: I have also opened a ticket for this issue #1551

To echo @erjok sentiment, I think we (as MSFT) should give developers the benefit of the doubt of being smart enough to not disable SSL for production environment and provide a way to ignore SSL errors.

Currently I’m dealing with the issue of trying to get Remote Development containers work with Cosmos Db Emulator. This is because my MSFT team develops in Windows but wants to move towards containers.

We previously supported overriding the SSL in v2’s DocumentClient as seen in the documentation here.

However, using v2 does not work for me due to implementation of v2 not supporting host.docker.internal URIs as seen by the issue here, which is the only clean way to connect from my container to the host machine that hosts Cosmos Db Emulator because MSFT hasn’t been able to move the emulator into a linux container since June 2018 because of constant delays.

I also understand/appreciate intended sentiment on installing the local development certificate because we consider this the “right way”. However, even installing the cert locally as @j82w suggested does not work as .NET Core relies on OpenSSL and OpenSSL says the generated cert’s public key for CosmosDbEmulator (RSA 1024 bit), is too weak. I manually downgraded the openssl configuration, but alas, the alternative subject name obviously wouldn’t match, since I’ll never be trying to hit the host machine through localhost from my Linux container.

So just to trust the cert locally in my container, am I supposed to generate my own cert that’s valid for Cosmos Db Emulator with DNS of host.docker.internal, export the pfx on windows, convert the pfx to a crt on my linux container, trust the crt on my Linux container, downgrade openssl config SECLEVEL in my container on bootup, and then distribute that to the rest of my team because this is the “right way”? I did get the SSL somewhat working via the GenCert argument provided by Cosmos Db Emulator, but I’m dreading scripting the first half and getting the second half working with the mounted volume during Dockerfile.

I’m still having issues getting the actual client to work because of an “Endpoint not reachable. Refresh cache and retry” warning because the v3 client for some reason resolves https://host.docker.internal:8081 to https://127.0.0.1:8081/ which it can’t hit because obviously 127.0.0.1:8081 does not exist in the container. image image

I will probably give up this approach, and figure out a way to grab my host machine’s external ip from my container (which is such a niche need I have no idea where to start) as per this reply and abandon v3 cosmosclient for documentclient.

Meanwhile, I would prefer if there was an alternative solution that is a bit cleaner and developer friendly so I didn’t have to jump through so many hoops to get to this conclusion.

@DaleyKD

Sorry for not seeing your replies. I have the same dev scenario as you. I already unblocked my team on this and have it working for multiple members but am waiting for the cleaner solution still as well.

While the Cosmos team does the good work to circumvent SSL, my steps should unblock you. The point of the /GenCert flag is to generate the cert with host.docker.internal as part of the SAN. Then the Fail on ssl mismatch flag makes sure the emulator doesn’t generate a new one that doesnt have host.docker.internal as part of the cert SAN. I’m providing the exact scripts I use below.

I would recommend manually cleaning the certs if running through my steps above again as you might have some leftover certs generated from before, or running my new script below that does that for you. When you start the cosmos emulator via the command I supplied, you can click the browser and verify its using the cert you expect by hitting the lock button and checking the cert generated and is being used as expected image image

Here is my setup script that I use for my team to both install and output the cert in the current directory. NOTE: I now output directly in source directory instead of depending on mounted directory like I did before because the bash script will not be able to access the mounted directory during dockerfile build. This was not an issue with Visual Studio Code containers since they can run commands after the dockerfile is built, but is an issue for more vanilla docker setups that I needed to support. image

Stop-Process -Name "Microsoft.Azure.Cosmos.*"

# Cosmos DB Emulator Installation
$confirmation = Read-Host "Do you want to install Cosmos Database Emulator? (y/n)"
if ($confirmation -eq 'y') {
    Write-Host "Installing Azure Cosmos Db Emulator"
    $installer = "$PSScriptRoot/cosmosEmulatorInstaller.msi"
    curl https://aka.ms/cosmosdb-emulator -O $installer
    Start-Process -Wait -FilePath msiexec -ArgumentList /i, $installer
    Remove-Item $installer
}

# Custom Certificate Generation to work with host.docker.internal
$certFriendlyName="DocumentDbEmulatorCertificate"
$pfxPath=$PSScriptRoot + '\' + 'cosmosdbemulator.pfx'
# Remove any existing cosmos emulator certs, then generate a new one
if (Test-Path $pfxPath) {
    Write-Host "Removing existing PFX cert"
    Remove-Item -Path $pfxPath
}
Get-ChildItem -path Cert:\LocalMachine\My -Recurse | where {$_.FriendlyName -eq $certFriendlyName} | Remove-Item # Note that this doesn't remove in cert manager for some reason
$cosmosDb = Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath } | where {$_.DisplayName -eq 'Azure Cosmos DB Emulator'} | Select InstallLocation
cd $cosmosDb.InstallLocation
.\Microsoft.Azure.Cosmos.Emulator.exe /GenCert=host.docker.internal
# Start sleep to allow cert generation to propagate before continuing
Start-Sleep -s 5

# Export cert to script directory
$pfxPwd=ConvertTo-SecureString 'SecurePwdGoesHere' -asplaintext -force
Get-ChildItem -path Cert:\LocalMachine\My -Recurse | where {$_.FriendlyName -eq $certFriendlyName} | Export-PfxCertificate -Filepath $pfxPath -Password $pfxPwd

Then I slightly modified my bash script in the same folder to run as a step during the dockerfile

#!/bin/bash

# Save current working directory
PWD=`pwd`
pushd $PWD

# Find and move to the location of this script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR

if [ -n "$1" ]; then
    COSMOS_DB_EMULATOR_PFX=$1
else
    COSMOS_DB_EMULATOR_PFX="./cosmosdbemulator.pfx"
fi
COSMOS_DB_EMULATOR_PFX_PASSWORD="SecurePwdGoesHere"
CERT_TO_TRUST="cosmosdbemulator.crt"

# Generate .crt file if pfx exists
if [ -f "$COSMOS_DB_EMULATOR_PFX" ]; then
    openssl pkcs12 -in $COSMOS_DB_EMULATOR_PFX -clcerts -nokeys -out cosmosdbemulator.crt -passin pass:$COSMOS_DB_EMULATOR_PFX_PASSWORD;
fi

# Trust Cert (will end located in /etc/ssl/certs/ based on *.crt name as a *.pem, e.g. /etc/ssl/certs/cosmosdbemulator.pem for cosmosdbemulator.crt)
if [ -f "$CERT_TO_TRUST" ]; then
    cp $CERT_TO_TRUST /usr/local/share/ca-certificates/
    update-ca-certificates
    rm $CERT_TO_TRUST;
fi

# Restore working directory
popd

Then for Visual Studio Code containers simply add the bash script as part of the postCreateCommand in devcontainer.json. For vanilla dockerfiles add the script to run by copying and running it. Of course pay attention that the scripts folder is same level or below your Dockerfile context. For Visual Studio Code Remote Development Containers: image For Dockerfile:

WORKDIR /scripts
COPY /scripts/ .
RUN ./trust_cosmos_db_emulator_crt.sh

Then the run script is the same, but just a bit nicer to people that don’t want to install in default location for some reason and restarts process if it’s already running.

Stop-Process -Name "Microsoft.Azure.Cosmos.*"
$cosmosDb = Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath } | where {$_.DisplayName -eq 'Azure Cosmos DB Emulator'} | Select InstallLocation
& "$($cosmosDb.InstallLocation)\Microsoft.Azure.Cosmos.Emulator.exe" /FailOnSslCertificateNameMismatch /AllowNetworkAccess /Key=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==

Then overall steps are the same for the user. Run setup script the first time, then rebuild docker container calling the bash script that has the .pfx file, then make sure cosmos is running via the run script before the service starts up.

I hope that helps meanwhile.

I also have the same use case as @whung1 and there does exist disableSSLVerification key in other cosmos-db language SDKs. I was able to use the disableSSLVerification for python and it was neat and something which I was looking for C# as well. While searching , I got to know that similar thing exists in azure-cosmos-js as well. It’s way better to have a disableSSLVerification feature added to avoid the hassle of extra automation as suggested above and increase adoption. Do consider adding disableSSLVerification feature in your coming sprints, because clearly from the thread above, it’s not just folks at Microsoft ( @whung1 and me), but others too who are looking forward to it.

Thanks for the help @ealsur

I was able to get host.docker.internal working with /AllowNetworkAccess. This makes it so we don’t have to do ipconfig on host machine to manually replace any containerized env variable endpoints for development containers.

  • This does not work on the v2 client because v2 client is not able to resolve host.docker.internal (gives Name or Service not known) where as v3 does
  • Direct/Gateway mode both work on v3
  • I’m still unsure on why Gremlin endpoint with Cosmos Db Emulator did not need /AllowNetworkAccess to work with host.docker.internal based on my experience there before

Steps:

  1. Use .\Microsoft.Azure.Cosmos.Emulator.exe /GenCert=host.docker.internal to generate and install a cert that allows host.docker.internal to be trusted.
  2. Export the PFX to a directory that will be bind mounted in the container.
    • Example script that outputs to directory based on defaults of Dotnet Core’s default bootstrap container for Visual Studio Code’s Remote Development.
$pfxPath=$env:USERPROFILE + '\.aspnet\https\' + 'cosmosdbemulator.pfx'
$pfxPwd=ConvertTo-SecureString 'SecurePwdGoesHere' -asplaintext -force
Get-ChildItem -path Cert:\LocalMachine\My -Recurse | where {$_.FriendlyName -eq 'DocumentDbEmulatorCertificate'} | Export-PfxCertificate -Filepath $pfxPath -Password $pfxPwd
  1. Mount the directory in docker for the PFX export if not done already
  2. Follow the existing linux import certificate documentation steps.
    • This needs to be done every time after your container is built, since we cannot access the pfx in the mounted directory during the Dockerfile to run these scripts.
    • This is my example script that I am using postCreateCommand in Remote Development’s devcontainer.json. I do not know an alternative method to run scripts after the container is built with just docker. I’ll give my example script below.
#!/bin/bash

# Save current working directory
PWD=`pwd`
pushd $PWD

# Find and move to the location of this script
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd $DIR

COSMOS_DB_EMULATOR_PFX="/home/vscode/.aspnet/https/cosmosdbemulator.pfx" # Mounted pfx file
COSMOS_DB_EMULATOR_PFX_PASSWORD="SecurePwdGoesHere"
CERT_TO_TRUST="cosmosdbemulator.crt"

# Generate .crt file if pfx exists and .crt does not already exist
if [ -f "$COSMOS_DB_EMULATOR_PFX" ] && ! [ -f "$CERT_TO_TRUST" ]; then
    openssl pkcs12 -in $COSMOS_DB_EMULATOR_PFX -clcerts -nokeys -out cosmosdbemulator.crt -passin pass:$COSMOS_DB_EMULATOR_PFX_PASSWORD;
fi

# Trust Cert (will be located in /etc/ssl/certs/)
if [ -f "$CERT_TO_TRUST" ]; then
    cp $CERT_TO_TRUST /usr/local/share/ca-certificates/
    update-ca-certificates;
fi

# Restore working directory
popd
  1. Run the emulator on your host machine via .\Microsoft.Azure.Cosmos.Emulator.exe /FailOnSslCertificateNameMismatch /allownetworkaccess /Key=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==
  2. Connect using v3 CosmosClient with URI of https://host.docker.internal:8081

As you can see, installing the certificate is not trivial (steps 1-4, where step 4 is especially inconvenient). Thus hopefully as per this ticket, we can ignore SSL errors in the future and then steps 5-6 are trivial to get a nice development container working irregardless of where the emulator is hosted (on host machine, on another linux container within the same docker network).

Again, I think the PR #1441 linked by j82w worked on by ealsur might be able give this workaround by adding clienthandler to the httpclient from the httpfactory example.

@j82w - Man, that would BE AWESOME.

However, when I try to use the HttpClientFactory func in CosmosClientOptions, it appears to never hit the breakpoint of trying to get an HttpClient.

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpClient("cosmosHttpClient").ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
    {
        ClientCertificateOptions = ClientCertificateOption.Manual,
        ServerCertificateCustomValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) => true
    });

    services.AddSingleton(sp =>
    {
        var httpClientFactory = sp.GetService<IHttpClientFactory>();
        var cosmosClientOptions = new CosmosClientOptions()
        {
            HttpClientFactory = () => httpClientFactory.CreateClient("cosmosHttpClient"),
            ConnectionMode = ConnectionMode.Gateway
        };

        return new CosmosClient("https://host.docker.internal:8081", "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", cosmosClientOptions);
    });

    services.AddRazorPages();
}

Index.cshtml.cs

public class IndexModel : PageModel
{
    private readonly CosmosClient _cosmosClient;

    public IndexModel(CosmosClient cosmosClient)
    {
        _cosmosClient = cosmosClient;
    }

    public async Task OnGetAsync()
    {
        var database = await _cosmosClient.CreateDatabaseIfNotExistsAsync("MyDatabaseName");
    }
}

When we get to .CreateDatabaseIfNotExistsAsync, the breakpoint on HttpClientFactory is never hit, nor is the one in my HttpClientHandler for the SSL verification.

This is making me feel like I’m obviously missing something.

EDIT: Forgot to mention that as soon as we try to call .CreateDatabaseIfNotExistsAsync, we get the good ol’ AuthenticationException: The remote certificate is invalid according to the validation procedure. I see nothing in the callstack that refers to GatewayStoreModel, but I do see:

Microsoft.Azure.Cosmos.DocumentClient.InitializeGatewayConfigurationReaderAsync()
Microsoft.Azure.Cosmos.DocumentClient.GetInitializationTaskAsync(IStoreClientFactory storeClientFactory)
Microsoft.Azure.Cosmos.DocumentClient.EnsureValidClientAsync()

which is before a new GatewayStoreModel is instantiated. It’s like the DocumentClient doesn’t want to use the HttpClientFactory option.

It sounds like I need to carefully analyze @whung1 's answer.

Our dev scenario:

  • Windows 10 Host
  • Many microservices in docker Linux containers
  • Azure Cosmos DB Emulator in the Windows 10 Host
  • Microservice in Linux container needs to access the Cosmos DB Emulator via https://host.docker.internal:8081

The SSL issue is stopping us because of localhost vs host.docker.internal in the SAN/CN/subject/whatever.

Additional comment…

Ideally, we’ll be using EF Core Cosmos DB provider. However, in version 3.1, it doesn’t support IDictionary<string, object>, so I’ve got a strange hybrid where I use a DbContext, but then insert/update/select using the underlying CosmosClient.

When thinking about how to allow us to get past this SSL issue (without the huge ‘create a special cert for Docker, blah blah’), is it possible for you to coordinate with EF Core and find a way to allow us to bypass SSL issues using the DbContext ?

I’ve fought the emulator a LOT lately, and it’s greatly frustrated me, simply because of this local dev issue. We get it to work for a while, but then the emulator decides to regenerate the old style key.

Haha. I joined our current cloud product team in October with no knowledge of Docker, Cosmos, Azure, Azure Storage, etc. I cursed Docker for weeks until I wrote that .ps1. I think getting that .ps1 to do what I needed it to do took a full Planning Increment week and some of the next sprint. A big portion of that was learning NGINX and what it took to mirror our Azure Cloud setup.

Once I learned all of this, next thing I know, it’s not so bad. And that includes getting this SSL issue for Cosmos DB resolved. All the work (especially SSL certs) is done thru the .ps1 instead of in each docker image.

To be fair, we haven’t fully stood it up in local dev yet. We should be getting that working on Monday.

@DaleyKD thank you so much for your detailed response!

Getting cosmos up and running locally for development, and in CI for our functional testing, has been a real nightmare. This is something that should have taken hours, not days! 😦

How funny! I had started working on my .ps1 (I’ve got one we use to help manage our local docker images/container), and this is the function I wrote:

I’m guessing these scripts are run within the dockerfile as part of the build?

@joshystuart - For me, I use the .ps1 as part of the development cycle. It has assisted us with managing the docker-compose and Docker containers. It helps:

  • Starts up (or Starts up + Builds) one of 4 different sets of docker-compose
  • Shuts them down
  • Quick option to Prune
  • Quick option to inspect containers/images
  • Quick option to see logs or access bash/shell.

It manages:

  • Dependencies, such as NGINX, SQL, Azurite, Consul, etc.
  • The core set of microservices, including Identity Server and Ocelot gateways
  • The 4 different web sites we have

But, in regards to this topic, it also:

  • Downloads any prereq pieces of software, like Azure Cosmos DB and Open SSL
  • Modifies our hosts file to set some URLs, like “https://myapp.domain.local
  • Generates SSL scripts needed for NGINX and other containers to allow no SSL cert issues

So, I just added the necessary SSL certs from Cosmos DB to be a part of the “Initial Setup” steps described above.

How funny! I had started working on my .ps1 (I’ve got one we use to help manage our local docker images/container), and this is the function I wrote:

function InstallCosmosDbEmulator() {
	$r = Get-WmiObject Win32_Product | Where {$_.IdentifyingNumber -match '{DF0D8EAC-4939-400C-B122-4BC715BF2DB6}' }
	if ($r -eq $null) {
		Invoke-WebRequest 'https://aka.ms/cosmosdb-emulator' -OutFile 'cosmosdb-emulator.msi'
		.\cosmosdb-emulator.msi
	} else {
		Write-Host "Azure Cosmos DB Emulator is already installed." -ForegroundColor Green
	}

	$tmpPath = Join-Path -Path $PSScriptRoot -ChildPath "nginx/certs/DocumentDbEmulatorCertificate.crt"
	if (!(Test-Path $tmpPath)) {
		CosmosDbEmulatorCert
	}

	# Modify the .lnk file (ASSUMES ADMIN ACCESS)
	Push-Location -EA Stop "$env:AllUsersProfile\Microsoft\Windows\Start Menu\Programs\Azure Cosmos DB Emulator"

	$shell = New-Object -COM WScript.Shell
	$shortcut = $shell.CreateShortcut((Get-Location).Path + "\Azure Cosmos DB Emulator.lnk")
	$shortcut.Arguments = "/FailOnSslCertificateNameMismatch /AllowNetworkAccess /Key=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="
	$shortcut.Save()

	Pop-Location
}

function CosmosDbEmulatorCert() {
	$cosmosDb = Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath } | where {$_.DisplayName -eq 'Azure Cosmos DB Emulator'} | Select InstallLocation
	Push-Location -EA Stop $cosmosDb.InstallLocation

	# Proper shut down
	$x = Start-Process "Microsoft.Azure.Cosmos.Emulator.exe" -ArgumentList "/GetStatus" -PassThru
	if ($x.ExitCode -ne 2) {
		.\Microsoft.Azure.Cosmos.Emulator.exe /Shutdown
		$process = Get-Process "Microsoft.Azure.Cosmos.Emulator" -ErrorAction SilentlyContinue
		Wait-Process -InputObject $process
	}

	.\Microsoft.Azure.Cosmos.Emulator.exe /GenCert=host.docker.internal
	Start-Sleep -Seconds 5
	Pop-Location

	$tmpPath = Join-Path -Path $PSScriptRoot -ChildPath "nginx/certs"
	if (!(Test-Path $tmpPath)) {
		New-Item -ItemType Directory -Force -Path $tmpPath
	}

	# set certificate password here
	$pfxPassword = ConvertTo-SecureString -String "password" -Force -AsPlainText
	$pfxFilePath = "$($tmpPath)\DocumentDbEmulatorCertificate.pfx"
	$cerFilePath = "$($tmpPath)\DocumentDbEmulatorCertificate.crt"
	
	$cert = Get-ChildItem -Path cert:\LocalMachine\My -Recurse | where {$_.FriendlyName -eq 'DocumentDbEmulatorCertificate'}
	Export-PfxCertificate -Cert $cert -Filepath $pfxFilePath -Password $pfxPassword
	
	Push-Location -EA Stop "$env:ProgramFiles\OpenSSL\bin\"
	.\openssl pkcs12 -in $pfxFilePath -clcerts -nokeys -out $cerFilePath -passin pass:password
	Pop-Location
}

We already had OpenSSL installed for previous reasons.

Then, I was simply going to modify my docker-compose to mount the .crt.