kubernetes/security kubernetes/networking

01 - Cryptography and PKI Foundations
02 - Kubernetes PKI Architecture
Generate Certificates Manually | Kubernetes

Core Idea

A complete OpenSSL worked example for cluster TLS by hand: build a workspace, a root CA, then the admin client and kube-apiserver server certificates, and inspect the result.

  • Steps: secure workspace, root CA, admin client certificate, kube-apiserver server certificate.
  • Verification and inspection: certificate metadata, expiration dates, and the certificate chain.
  • Prerequisites and external resources frame when you would do this manually at all.

This document provides a complete, worked example of how to manually generate TLS certificates for a Kubernetes cluster using OpenSSL.

We will generate:

  1. A Root Certificate Authority (CA)
  2. An Admin client certificate (with RBAC mapping)
  3. A Kube-APIServer server certificate (with Subject Alternative Names)

Prerequisites

Ensure OpenSSL is installed on your local host:

openssl version

Step-by-Step Worked Example

Step 1: Create a Secure Workspace

First, create a clean directory to store your keys and restrict permissions. Private keys must not be readable by unauthorized local users.

mkdir -p /tmp/k8s-pki-lab && cd /tmp/k8s-pki-lab
chmod 700 /tmp/k8s-pki-lab

Step 2: Generate the Root CA

The CA certificate (ca.crt) signs all other certificates in the cluster. It requires a private key (ca.key).

  1. Generate the private key:
    openssl genrsa -out ca.key 2048
  2. Generate the Certificate Signing Request (CSR):
    openssl req -new -key ca.key -subj "/CN=KUBERNETES-CA" -out ca.csr
  3. Self-sign the certificate:
    openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt -days 3650

Output Files: ca.key (keep highly secure) and ca.crt (distribute to all nodes).

How It Works - Let’s Encrypt
CSR RFC

Step 3: Generate the Admin Client Certificate

We want to generate a client certificate that maps to the administrative group system:masters in Kubernetes.

  1. Generate the user’s private key:
    openssl genrsa -out admin.key 2048
  2. Generate the CSR:
    Notice the inclusion of O=system:masters in the Subject. This will bind the user to the administrator group.
    openssl req -new -key admin.key -subj "/CN=kube-admin/O=system:masters" -out admin.csr
  3. Sign the certificate using the Root CA:
    openssl x509 -req -in admin.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out admin.crt -days 365

Step 4: Generate the Kube-APIServer Server Certificate

The API server is accessed via different hostnames and IP addresses (e.g., node IP, service IP, cluster local DNS). These MUST be declared in the Subject Alternative Name (SAN) extensions, otherwise clients will reject the TLS connection with “Hostname mismatch”.

  1. Create an OpenSSL Config File (openssl.cnf):
    Create a config file declaring the extensions and alt names:

    [ req ]
    distinguished_name = req_distinguished_name
    req_extensions     = v3_req
    prompt             = no
     
    [ req_distinguished_name ]
    CN = kube-apiserver
     
    [ v3_req ]
    basicConstraints = CA:FALSE
    keyUsage         = nonRepudiation, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth
    subjectAltName   = @alt_names
     
    [ alt_names ]
    # DNS Names
    DNS.1 = kubernetes
    DNS.2 = kubernetes.default
    DNS.3 = kubernetes.default.svc
    DNS.4 = kubernetes.default.svc.cluster.local
    DNS.5 = api.k8s.local
    # IP Addresses
    IP.1  = 10.96.0.1      # Kubernetes Internal Service Cluster IP (typically the first IP in service range)
    IP.2  = 192.168.1.100  # Master Node Internal IP Address
    IP.3  = 127.0.0.1      # Local Loopback
  2. Generate the API Server Private Key:

    openssl genrsa -out apiserver.key 2048
  3. Generate the CSR using the Config File:

    openssl req -new -key apiserver.key -config openssl.cnf -out apiserver.csr
  4. Sign the API Server Certificate using the Root CA and Extensions:

    openssl x509 -req -in apiserver.csr \
      -CA ca.crt -CAkey ca.key -CAcreateserial \
      -extfile openssl.cnf -extensions v3_req \
      -out apiserver.crt -days 365

Step 5: Verification & Inspection

A. How to Inspect Certificate Metadata

To verify that the Common Name, Issuer, and SANs are correct, decode the certificate:

openssl x509 -in apiserver.crt -text -noout

Expected Output Excerpts:

  • Issuer: CN=KUBERNETES-CA
  • Subject: CN=kube-apiserver
  • X509v3 Subject Alternative Name:
    DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:api.k8s.local, IP Address:10.96.0.1, IP Address:192.168.1.100, IP Address:127.0.0.1

B. Verify the Expiration Dates

To view just the certificate start and end dates:

openssl x509 -in admin.crt -noout -dates

Output:

notBefore=Jun 20 07:00:00 2026 GMT
notAfter=Jun 20 07:00:00 2027 GMT

C. Verify the Certificate Chain

To check if the generated client/server certificate was indeed signed by the Root CA:

openssl verify -CAfile ca.crt apiserver.crt

Expected Output:

apiserver.crt: OK

If you get OK, your certificate chain is correct and client components trusting ca.crt will successfully establish connections with the API server.

External Resources & Notes