πŸ“šBook Signing at KubeCon EU 2026Meet us at Booking.com HQ (Mon 18:30-21:00) & vCluster booth #521 (Tue 24 Mar, 12:30-1:30pm) β€” free book giveaway!RSVP Booking.com Event
Security advanced ⏱ 15 minutes K8s 1.28+

Kubernetes Certificate Signing Requests

Use the Kubernetes CSR API to issue, approve, and manage TLS certificates. Automate certificate workflows for services, users, and kubelet rotation.

By Luca Berton β€’ β€’ πŸ“– 5 min read

πŸ’‘ Quick Answer: The CSR API lets you request certificates signed by the cluster CA. Create a CSR resource, approve it (manually or via controller), then retrieve the signed certificate from .status.certificate.

The Problem

Internal services need TLS certificates signed by a trusted CA. Options:

  • Self-signed certs (no trust chain)
  • External CA (complex, slow)
  • cert-manager (requires installation)

The CSR API provides a built-in certificate workflow using the cluster CA β€” no external tools needed for internal mTLS.

The Solution

Generate Key and CSR

# Generate private key
openssl genrsa -out app.key 2048

# Create CSR (specify the service DNS names)
openssl req -new -key app.key -subj "/CN=web-api.production.svc" \
  -addext "subjectAltName=DNS:web-api.production.svc,DNS:web-api.production.svc.cluster.local" \
  -out app.csr

# Base64 encode the CSR
CSR_BASE64=$(cat app.csr | base64 | tr -d '\n')

Submit CSR to Kubernetes

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: web-api-tls
spec:
  request: ${CSR_BASE64}
  signerName: kubernetes.io/kubelet-serving
  usages:
    - digital signature
    - key encipherment
    - server auth
  expirationSeconds: 31536000  # 1 year

Approve and Retrieve

# List pending CSRs
kubectl get csr

# Approve the CSR
kubectl certificate approve web-api-tls

# Retrieve the signed certificate
kubectl get csr web-api-tls -o jsonpath='{.status.certificate}' | base64 -d > app.crt

# Create a TLS secret
kubectl create secret tls web-api-tls \
  --cert=app.crt \
  --key=app.key \
  -n production

Auto-Approval with RBAC

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: csr-approver
rules:
  - apiGroups: ["certificates.k8s.io"]
    resources: ["certificatesigningrequests/approval"]
    verbs: ["update"]
  - apiGroups: ["certificates.k8s.io"]
    resources: ["signers"]
    resourceNames: ["kubernetes.io/kubelet-serving"]
    verbs: ["approve"]

User Certificate (kubectl access)

# Generate user key and CSR
openssl genrsa -out developer.key 2048
openssl req -new -key developer.key -subj "/CN=developer/O=dev-team" -out developer.csr
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: developer-access
spec:
  request: <base64-encoded-csr>
  signerName: kubernetes.io/kube-apiserver-client
  usages:
    - client auth
  expirationSeconds: 86400  # 24 hours
sequenceDiagram
    participant U as User/Service
    participant API as API Server
    participant A as Approver
    participant CA as Cluster CA
    
    U->>API: Create CSR resource
    API-->>A: New CSR pending
    A->>API: Approve CSR
    API->>CA: Sign with cluster CA
    CA-->>API: Signed certificate
    U->>API: Get CSR .status.certificate
    API-->>U: Signed cert (PEM)

Common Issues

CSR stuck in Pending No approver is configured for the signer. Approve manually:

kubectl certificate approve <csr-name>

Certificate not trusted by other pods The cluster CA certificate must be in the trust store. Mount it from:

kubectl get cm kube-root-ca.crt -n <namespace>

Wrong signerName

  • kubernetes.io/kube-apiserver-client β€” client certs (user auth)
  • kubernetes.io/kubelet-serving β€” kubelet serving certs
  • kubernetes.io/legacy-unknown β€” custom use (not auto-approved)

CSR denied/expired CSRs have a TTL. Recreate if expired:

kubectl delete csr web-api-tls
# Resubmit

Best Practices

  • Use cert-manager for automated certificate lifecycle (renewal, revocation)
  • Use CSR API for one-off internal certificates or bootstrapping
  • Set short expirationSeconds for user certificates (24-72 hours)
  • Automate approval only for well-scoped signerNames with RBAC
  • Store private keys in Kubernetes Secrets (or external vault)
  • Use kubernetes.io/kubelet-serving signer for service TLS
  • Rotate certificates before expiry (80% of lifetime)

Key Takeaways

  • CSR API provides built-in certificate signing without external tools
  • Three built-in signers: kube-apiserver-client, kubelet-serving, legacy-unknown
  • CSRs require approval (manual or controller-based)
  • Signed certificate available in .status.certificate (base64-encoded PEM)
  • expirationSeconds controls certificate lifetime
  • For production workloads, prefer cert-manager over raw CSR API
#certificates #csr #tls #pki
Luca Berton
Written by Luca Berton

Principal Solutions Architect specializing in Kubernetes, AI/GPU infrastructure, and cloud-native platforms. Author of Kubernetes Recipes and creator of CopyPasteLearn courses.

Kubernetes Recipes book cover

Want More Kubernetes Recipes?

This recipe is from Kubernetes Recipes, our 750-page practical guide with hundreds of production-ready patterns.

Luca Berton Ansible Pilot Ansible by Example Open Empower K8s Recipes Terraform Pilot CopyPasteLearn ProteinLens