The Error
You're pulling an image from a private registry, making an API call inside a pod, or configuring a webhook โ and you hit this:
x509: certificate signed by unknown authority
Sometimes it comes with more context:
Error response from daemon: Get "https://registry.internal/v2/": x509: certificate signed by unknown authority
Post "https://webhook.internal/validate": x509: certificate signed by unknown authority
The underlying problem is always the same: Go's TLS stack (Docker, kubectl, kubelet โ all written in Go) can't verify the certificate chain. The CA that signed the certificate simply isn't in the system trust store. That's it.
Diagnosis
Before touching any config, confirm what certificate the server is actually serving:
# Check what cert the server is serving
openssl s_client -connect registry.internal:443 -showcerts </dev/null 2>&1 | openssl x509 -noout -issuer -subject
# Or with curl to see the full chain
curl -v https://registry.internal/v2/ 2>&1 | grep -A5 "SSL connection"
See an issuer like CN=My Corp CA or CN=registry.internal? That's a private or self-signed cert. No public CA signed it, so you need to add that CA to the trust store yourself.
Fix 1: Add CA cert to the Docker daemon (private registry)
Pulling from an internal registry with a self-signed or private-CA cert? This fix handles it. Docker has its own per-registry certificate directory, separate from the system store.
# Create the directory for the registry
sudo mkdir -p /etc/docker/certs.d/registry.internal:5000
# Copy your CA cert (get it from your infra team or extract from the server)
sudo cp ca.crt /etc/docker/certs.d/registry.internal:5000/ca.crt
# Restart Docker
sudo systemctl restart docker
The directory name must match exactly: /etc/docker/certs.d/<host>:<port>/ca.crt. On port 443, you can drop the port entirely.
Verify the fix right away:
docker pull registry.internal:5000/myimage:latest
Fix 2: Add CA to the system trust store (Linux)
kubelet, kubectl plugins, custom operators โ any Go binary on the host reads the system trust store, not Docker's cert directory. That's where this fix applies.
# Ubuntu/Debian
sudo cp ca.crt /usr/local/share/ca-certificates/my-corp-ca.crt
sudo update-ca-certificates
# RHEL/CentOS/Fedora
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/my-corp-ca.crt
sudo update-ca-trust extract
# Verify it was added
certutil -L -d /etc/pki/nssdb | grep "My Corp" # RHEL
# or just test with curl
curl https://registry.internal/v2/
Fix 3: Kubernetes โ add CA to containerd (node-level)
Pods can't pull images, or kubelet is logging this error? The fix lives on each node, in containerd's config โ not in Kubernetes itself.
# On each node, edit containerd config
sudo mkdir -p /etc/containerd/certs.d/registry.internal:5000
cat <<EOF | sudo tee /etc/containerd/certs.d/registry.internal:5000/hosts.toml
[host."https://registry.internal:5000"]
ca = "/etc/ssl/certs/my-corp-ca.crt"
EOF
# Copy your CA cert
sudo cp ca.crt /etc/ssl/certs/my-corp-ca.crt
# Restart containerd
sudo systemctl restart containerd
On managed clusters (EKS, GKE, AKS), you can't SSH into nodes freely. Use a DaemonSet or wire the CA into the node pool's bootstrap script instead.
Fix 4: Kubernetes โ inject CA via ConfigMap into pods
The error happens inside a running pod โ your app is calling an internal HTTPS service and the Go HTTP client rejects the cert. Mount the CA as a volume and point Go to it via an environment variable.
apiVersion: v1
kind: ConfigMap
metadata:
name: corp-ca-bundle
data:
ca.crt: |
-----BEGIN CERTIFICATE-----
MIIBxTCCAW+gAwIBAgIJA...
-----END CERTIFICATE-----
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
volumes:
- name: ca-bundle
configMap:
name: corp-ca-bundle
containers:
- name: myapp
image: myapp:latest
volumeMounts:
- name: ca-bundle
mountPath: /etc/ssl/certs/corp-ca.crt
subPath: ca.crt
env:
- name: SSL_CERT_FILE
value: /etc/ssl/certs/corp-ca.crt
SSL_CERT_FILE is a Go-specific env var that overrides the default CA bundle path. Another approach: mount the cert into the default bundle directory and run update-ca-certificates in an init container before your app starts.
Fix 5: Kubernetes admission webhooks
Seeing this error in kube-apiserver logs when a webhook fires? The caBundle field in your MutatingWebhookConfiguration or ValidatingWebhookConfiguration is either wrong or missing entirely. The API server uses that bundle to verify the webhook server's certificate.
# Check what CA bundle the webhook is currently using
kubectl get mutatingwebhookconfiguration my-webhook -o jsonpath='{.webhooks[0].clientConfig.caBundle}' | base64 -d | openssl x509 -noout -text
# Patch in the correct CA
CA_BUNDLE=$(cat ca.crt | base64 -w0)
kubectl patch mutatingwebhookconfiguration my-webhook \
--type='json' \
-p="[{'op': 'replace', 'path': '/webhooks/0/clientConfig/caBundle', 'value': '${CA_BUNDLE}'}]"
Running cert-manager? Add the cert-manager.io/inject-ca-from annotation and it handles rotation automatically โ no manual patching needed.
Getting the CA certificate
No CA cert file on hand? Pull it straight from the server. The safest approach is saving the full chain and using that:
# Save the full chain and use it as the CA bundle
openssl s_client -connect registry.internal:443 -showcerts </dev/null 2>&1 \
| sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' > chain.crt
The chain extraction one-liner you'll find online (with nested openssl calls and awk offsets) is fragile and breaks on chains longer than two certs. Don't use it in scripts. Ask your infra team for the CA cert directly โ it's the right call.
Verification
# Docker registry
docker pull registry.internal:5000/myimage:latest
# curl with system trust store
curl https://registry.internal/v2/
# From inside a pod
kubectl run -it --rm debug --image=alpine --restart=Never -- wget -O- https://internal-service.default.svc/health
# Go binary respects SSL_CERT_FILE
SSL_CERT_FILE=/path/to/ca.crt your-go-binary
Quick reference
- Docker pull fails โ
/etc/docker/certs.d/<registry>/ca.crt - kubelet/containerd pull fails โ containerd
hosts.tomlon the node - App inside pod fails โ mount CA via ConfigMap +
SSL_CERT_FILE - Webhook validation fails โ fix
caBundlein webhook config - CLI tools fail โ add CA to system trust store +
update-ca-certificates

