Safeguard
Security Guides•

How should you configure TLS and certificates in Kestrel?

Leave Kestrel SslProtocols at None so the OS picks the protocol, supply a real certificate in production, and keep PFX passwords out of appsettings.

Safeguard Security Team
4 min read

In Kestrel, leave SslProtocols at its default of None, which lets the operating system choose the protocol, and provide an explicit certificate in production because the development certificate is not installed outside development. Do not store certificate passwords in plain text in appsettings.json. Use a secret source and a managed store.

What the Kestrel documentation says

On protocols: "The default value, SslProtocols.None, causes Kestrel to use the operating system defaults to choose the best protocol. Unless you have a specific reason to select a protocol, use the default." You can set protocols in configuration, for example Tls12 and Tls13, or in code through ConfigureHttpsDefaults.

On certificates: the development certificate is used only locally. "In production, a TLS certificate must be explicitly configured. At a minimum, a default certificate must be provided." If an HTTPS endpoint has no certificate and no default is available, the server throws an exception and fails to start, which is the safe outcome.

On client certificates: the default ClientCertificateMode is NoCertificate, meaning Kestrel does not request or require one. Mutual TLS needs you to set it deliberately.

Why not hard code protocol versions

Microsoft's TLS guidance for .NET Framework makes the same argument that applies generally. If an app explicitly sets a protocol, it opts out of the OS defaults, and an explicit lower version prevents a TLS 1.3 connection. Letting the OS choose means the app picks up newer protocols later and the OS can block protocols found to be insecure. That guidance also warns against SslProtocols.Default, which forces older protocols. It is a .NET Framework page, so treat it as supporting reasoning, and use the Kestrel page for Kestrel settings.

If a policy requires a floor, for example no TLS 1.2 on an internal mesh, setting an explicit list is a legitimate choice. Document it so future upgrades revisit it. See also TLS 1.3 versus 1.2 and what to disable.

Certificate sources

Kestrel can load certificates from configuration or code:

SourceSettings
PFX filePath and Password
PEM filesPath, KeyPath and Password
Certificate storeSubject and Store, with optional Location and AllowInvalid, which defaults to false

The docs warn against plain text passwords and show a placeholder, recommending user secrets for development and Azure Key Vault for production. Keep AllowInvalid false so a bad certificate does not slip in.

{
  "Kestrel": {
    "Certificates": {
      "Default": {
        "Path": "/etc/certs/site.pem",
        "KeyPath": "/etc/certs/site.key"
      }
    }
  }
}

PEM with an unencrypted key file avoids a password in configuration, but then the key file permissions are the control. Restrict it to the service account and mount it read only. Rotation also matters. Certificate lifetimes keep shrinking, so plan for renewal without a manual step.

Steps

  1. Do not set SslProtocols unless a policy needs it. If it does, list the allowed versions and record why.
  2. Provide a default certificate in production configuration.
  3. Keep passwords and private keys out of source control and plain configuration.
  4. Restrict file permissions on key files.
  5. Set ClientCertificateMode only where mutual TLS is intended.
  6. Test the endpoint with a TLS scanner and a client that offers only old protocols.

Try it yourself

Click through it at your own pace, or open it full screen. See how a scan looks at a live endpoint from outside.

Quick check

Does Kestrel use the development certificate in production?

No. The docs say the development certificate is not installed in non development environments, and a certificate must be configured explicitly.

Should I turn on client certificates everywhere?

Only for endpoints that should use mutual TLS. The default is not to request one.

Safeguard dependency scanning and SBOM generation cover the NuGet packages in your ASP.NET Core service, and the free scan is at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.