Skip to content

Certificate chain not trusted on Windows due to missing root CA (self-signed) in trust store #255

@danielscholl

Description

@danielscholl

Summary

The solution is configured with Cert-Manager to issue a wildcard certificate using a self-singed root CA (root-ca). The certificate and root CA are installed in the Kubernetes cluster and the certificate is then served by Istio ingress. While connections from macOS can be made (with some caveats), Windows clients are unable to verify the certificate chain and receive an "unable to verify the first certificate" or "unable to get local issuer certificate" error.

Steps to Reproduce

  1. Deploy Cert-Manager with a selfsigned-cluster-issuer and create a root CA certificate (root-ca-secret).
  2. Create a ClusterIssuer (root-ca-cluster-issuer) that references the root CA.
  3. Issue a wildcard certificate (e.g., *.osdu-developer.com) using that root-ca-cluster-issuer.
  4. Configure the Istio Gateway to serve tls.crt and tls.key from the resulting secret.
  5. Attempt to access the HTTPS endpoint from Windows (using curl, openssl s_client, or a browser).

Observed Behavior

  • Windows clients fail to validate the certificate chain and display a trust error.
  • OpenSSL on Windows reports:
    verify error:num=20:unable to get local issuer certificate
    verify error:num=21:unable to verify the first certificate
    
  • macOS also shows an untrusted certificate when using openssl s_client directly, but may allow a connection if the user manually bypasses browser warnings or if the root CA has already been added to the macOS Keychain.

Expected Behavior

  • The wildcard certificate should be trusted automatically by any Windows or macOS client that is properly configured to trust the root CA.
  • Ideally, we want an easy process to install the root CA. If this must be externally accessible to the public, the certificate should be signed by a publicly trusted CA (e.g., Let’s Encrypt, DigiCert, etc.).

Suggested Resolution

Use a Publicly Trusted CA

If we want external clients to trust the certificate without manual steps, switch to a public CA like Let’s Encrypt. This removes the requirement for manual root installation.

(Alternative) Ensure Full Chain is Provided

If there were an intermediate certificate between the leaf and the root, it must be included in the tls.crt (the “full chain”). In this case, because we have a single-tier (root → leaf), only two certs exist. Typically, the server only serves the leaf certificate. The root CA must be in the client’s trust store.

Install the Self-Signed Root CA in Windows/macOS Trust Stores

Since this is a private, self-signed CA, each client needs the root-ca installed in their local OS trust store.

For Windows:

  1. Export the root-ca.crt from the Kubernetes secret.
  2. Double-click → “Install Certificate” → place it in “Trusted Root Certification Authorities.”

For macOS:

  1. Open Keychain Access, import the root-ca.crt, and select “Always Trust.”

Requested Action

  1. Use Let’s Encrypt or Another Public CA: If external accessibility is needed, integrate Let’s Encrypt or another well-known CA to provide a valid trusted chain.
  2. (Optional) Add Documentation/Automation: Update our deployment scripts or documentation to clarify that Windows clients require the self-signed root CA in their trust store if we continue using a private CA.

Additional Context

Versions:

  • Istio IngressGateway
  • Cert-Manager: 1.13.x
  • OpenSSL tested on Windows (3.4.1) and macOS (3.4.0) both indicating a trust/chain issue.

Logs:

verify error:num=20:unable to get local issuer certificate
verify error:num=21:unable to verify the first certificate

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions