QCecuring - Enterprise Security Solutions

Self-Signed Certificates

Mounith Reddy

Key Takeaways

  • Self-signed certificates provide encryption but no third-party identity verification
  • Legitimate uses: development, internal testing, air-gapped systems, and bootstrapping trust
  • In production, self-signed certs train users to ignore security warnings — creating MITM vulnerability
  • If the signing key is compromised, there's no revocation mechanism — you must manually remove trust everywhere

A self-signed certificate is a TLS certificate where the issuer and the subject are the same entity. Instead of being signed by a Certificate Authority, the certificate is signed by its own private key. This means it provides encryption (the TLS handshake still works), but no independent party has verified the identity of the server. Any machine can generate a self-signed certificate claiming to be any domain — there’s nothing stopping it.


Why it matters

  • No trust chain — browsers and clients have no way to verify the certificate is legitimate. It doesn’t chain to any root in their trust store, so they show a warning or reject the connection outright.
  • Encryption without authentication — the connection is encrypted, but you have no proof you’re talking to the right server. This is the exact condition a man-in-the-middle attack exploits.
  • No revocation — if the private key is compromised, there’s no CRL or OCSP responder to check. You must manually remove the certificate from every trust store that accepted it.
  • Development speed — for local development and testing, self-signed certs let you test HTTPS flows without waiting for CA issuance or configuring ACME.
  • Air-gapped systems — networks with no internet access can’t reach public CAs. Self-signed or private CA certs are the only option.

How it works

  1. Generate a private key — create an RSA (2048+ bit) or ECDSA (P-256) private key
  2. Create a CSR — define the subject (CN, SANs) in a certificate signing request
  3. Self-sign — instead of sending the CSR to a CA, sign it with the same private key
  4. Set validity — choose an expiration date (typically 365 days for dev, longer for internal systems)
  5. Deploy — install the certificate and key on the server
  6. Trust manually — add the certificate to the client’s trust store, or configure the client to skip verification (dangerous)

OpenSSL one-liner:

openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes \
  -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1"

In real systems

Local development — tools like mkcert generate self-signed certificates and automatically install the root into your OS/browser trust store. This gives you valid HTTPS locally without browser warnings:

mkcert localhost 127.0.0.1 ::1
# Creates localhost+2.pem and localhost+2-key.pem, trusted by your browser

Kubernetes internal communication — cert-manager can issue self-signed certificates for internal services that don’t need public trust. The selfSigned issuer type generates certs without any CA:

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}

However, most production K8s deployments use a private CA issuer instead — it provides the same internal-only trust but with a proper chain and revocation capability.

Docker and CI/CD — test environments often use self-signed certs to simulate HTTPS. The risk is when CI pipelines set NODE_TLS_REJECT_UNAUTHORIZED=0 or curl -k to bypass verification, and that configuration leaks into production code or deployment scripts.


Where it breaks

Self-signed certificate in production — a team deploys a self-signed cert on an internal API because “it’s not public-facing.” Other services connecting to it must either trust the cert explicitly or disable verification. Over time, new services are deployed without the trust configuration, connections fail with UNABLE_TO_VERIFY_LEAF_SIGNATURE, and someone adds rejectUnauthorized: false to the HTTP client as a “quick fix.” Now every connection from that service skips certificate validation entirely — for all destinations, not just the internal API.

Key compromise with no revocation path — the private key for a self-signed certificate used across 20 internal services is leaked. With a CA-signed certificate, you revoke it and the CA publishes the revocation. With self-signed, you must: generate a new certificate, deploy it to the server, and update the trust store on all 20 clients. There’s no broadcast mechanism. Until every client is updated, some are still trusting the compromised certificate.


Operational insight

The real danger of self-signed certificates isn’t technical — it’s behavioral. When users and developers routinely click through “Your connection is not private” warnings or add --insecure flags, they lose the ability to distinguish a legitimate warning from an actual attack. A self-signed cert on a staging environment trains the team to ignore the exact signal that would alert them to a man-in-the-middle on production. Use mkcert or a private CA for development so that warnings remain meaningful — when one appears, it actually means something is wrong.


Ready to Secure Your Enterprise?

Experience how our cryptographic solutions simplify, centralize, and automate identity management for your entire organization.

Stay ahead on cryptography & PKI

Get monthly insights on certificate management, post-quantum readiness, and enterprise security. No spam.

We respect your privacy. Unsubscribe anytime.