-
Notifications
You must be signed in to change notification settings - Fork 494
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to use V3 CosmosClient with Emulator while ignoring SSL errors? #1232
Comments
The emulator has documented steps on how to setup the certificate on linux and Mac environments. |
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. |
It was decided that importing the certificate somewhere is the safer option that brings the testing environment closer to actual production. It's very easy to let a client option to get passed up through production causing a big security issue. There is no easy way to detect it is the emulator and detecting if it is production has it's own security issues. |
@olivermue This is a similar scenario to when you run an HTTPS application in a local server with 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? |
Why not add an option to run the emulator with HTTP connection? 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. |
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. 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. |
@whung1 Are you working with the latest version of the Emulator? When we released this updated doc: https://docs.microsoft.com/en-us/azure/cosmos-db/local-emulator#running-on-mac-or-linux, I went through and tested this on Docker, WSL2, and on Mac, and in all cases, we were able to connect to the Emulator because we updated the cert that the Emulator produces to contain the required information OpenSSL was asking for. |
Sorry, I didn't mean to hijack this thread for my troubleshooting. Asking a user to connect to the emulator via ipconfig and then replacing environment values inside the container is not an ideal solution if I'm producing a remote development container that will work with the whole team, as ip can change per user and it's a manual step, and it's hard to grab the external ip of the host machine from the container during container's build in the Dockerfile. Unfortunately this might be the only solution left available. Using the latest version, I am still generating a RSA public key of 1024 bits, which I noted above, will cause openssl issues based on default configurations. I tried doing multiple clean installs from a previous version so not sure if that's a factor. It seems like the PR linked by @j82w will resolve this current issue we're on for bypassing SSL since we are able to provide the http client with a http client handler to ignore SSL via the injected http client factory. I'm not sure if my (host.docker.internal resolution) issue that I gave screenshots of above isn't exactly addressed since I'm not sure what is transforming host.docker.internal incorrectly to 127.0.0.1. I'm also not sure if my issue is worth the investment for the team with the timeline for the docker linux container. I can open a separate github issue on connecting via host.docker.internal if that's preferred, where it can be resolved either through changing the client or having the emulator containerized in linux. |
The issue with V3 SDK has Direct mode by default, which uses a different set of ports than Gateway mode, did you try using Gateway mode? In all honesty, I used docker and was able to connect to the Emulator running on the Windows instance after importing the certificate as explained in the guide on the linux docker instance. We did the same thing on a Mac, running the Emulator inside a Windows VM. The missing piece was the certificate was missing the Are you starting the Emulator with Network access enabled? ( What you need to make sure is that the machine with Windows and the Emulator, has the ports open correctly so an external process can connect to those ports, this is not particular to the Emulator, if I wanted an external instance to connect to a SQL Server running in a Windows machine, I would need to make sure that the ports are open and there is no Firewall blocking anything. |
Thanks for the help @ealsur I was able to get
Steps:
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. |
Another vote for an "insecure" dev mode. I have spent far too long trying to get this to work in docker across several languages. |
It sounds like I need to carefully analyze @whung1 's answer. Our dev scenario:
The SSL issue is stopping us because of localhost vs host.docker.internal in the SAN/CN/subject/whatever. |
@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 This is making me feel like I'm obviously missing something. EDIT: Forgot to mention that as soon as we try to call
which is before a new |
Some digging into this usecase got into #1548 |
@ealsur That is some VERY impressive quick turnaround. Before we implement this in our system (we're currently in a spike for learning how to use Cosmos), can you think of any other classes in the SDK where we may still need to do some tweaks to utilize the HttpClientFactory? I'm happy to run some preliminary tests to see if we can use this after this PR is accepted. |
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 |
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. |
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. |
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:
It manages:
But, in regards to this topic, it also:
So, I just added the necessary SSL certs from Cosmos DB to be a part of the "Initial Setup" steps described above. |
@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! :( |
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. |
Additional comment... Ideally, we'll be using EF Core Cosmos DB provider. However, in version 3.1, it doesn't support 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 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. |
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 |
3.12.0 is released with the necessary changes. Here are examples on how to configure it:
Or if you are using a NET Standard 2.1 project:
|
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 optionsnew 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
The text was updated successfully, but these errors were encountered: