Load the HTTPS certificate while validating settings instead of at Kestrel bind time - #5891
Open
ramonsmits wants to merge 1 commit into
Open
ramonsmits wants to merge 1 commit into
ramonsmits wants to merge 1 commit into
Conversation
…strel bind time AddServiceControlHttps loaded the certificate inside the ConfigureHttpsDefaults callback, which Kestrel invokes when binding endpoints. An unusable certificate therefore failed only after RavenDB, the transport and every hosted service had started and had to be torn down again. ValidateCertificateConfiguration now loads the certificate too, and the failure names the file, its size and last-modified time, and whether a password was configured, but never the password itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
warwickschroeder
approved these changes
Sep 15, 2026
| // configuration error, and binding happens only after every hosted service has started. | ||
| try | ||
| { | ||
| Certificate = string.IsNullOrEmpty(CertificatePassword) |
Contributor
There was a problem hiding this comment.
Another scenario to consider is that the certificate file has no private key. This currently wont throw but just not allow any conections. Could we also check for !Certificate.HasPrivateKey and throw if false?
| var message = $"The HTTPS certificate could not be loaded, so this instance cannot start. " + | ||
| $"Https.CertificatePath: '{CertificatePath}' ({file.Length} bytes, last modified {file.LastWriteTimeUtc:u}). " + | ||
| $"Https.CertificatePassword configured: {!string.IsNullOrEmpty(CertificatePassword)}. " + | ||
| $"{ex.GetType().Name}: {ex.Message} " + |
Contributor
There was a problem hiding this comment.
Would this hide the actual issue? Should we use ex.GetBaseException()?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Is your improvement related to a problem? Please describe.
AddServiceControlHttpsloads the certificate inside theConfigureHttpsDefaultscallback, which Kestrel invokes when binding endpoints — the last step of startup. An unusable certificate therefore fails only after RavenDB, the transport and every hosted service have started and have to be torn down again. The reported error is .NET's own text, which names neither the file nor the setting that supplies the password.Describe the suggested solution
ValidateCertificateConfiguration()already runs before the host is built and already checks the path. It now loads the certificate as well, andAddServiceControlHttpsuses the loaded instance. Failures name the file, its size and last-modified time, and whether a password was configured — never the password itself, since .NET collapses several unrelated causes into "the password may be incorrect".Describe alternatives you've considered
Improving only the message and leaving the load where it is: keeps the discarded startup work and the ungraceful teardown that follows a failed
Host.StartAsync.Additional context
The test fixture used an empty
Path.GetTempFileName()as a stand-in certificate, which only worked because nothing opened it; it now generates real self-signed PFX files. Two tests added.