SSL Certificate Verification Failed In Curl And Python Requests: Diagnosing And Fixing CERTIFICATE_VERIFY_FAILED Errors
SSL Certificate Verification Failed: Quick Reference for curl and Python requests
SSL verification errors are one of those issues that bite you at the worst possible moment — usually in production, usually when you're on-call. Here's your no-nonsense reference for diagnosing and fixing CERTIFICATE_VERIFY_FAILED errors fast.
Quick Diagnosis Checklist
Before touching any code, run through this:
- Is the certificate expired?
- Is the hostname mismatched?
- Is the CA chain incomplete (missing intermediate certs)?
- Is the system CA bundle outdated?
- Are you behind a corporate proxy doing SSL inspection?
Diagnose with curl First
curl is your fastest diagnostic tool. Always start here.
# Basic check — verbose output shows the full handshake
curl -vvv https://your-endpoint.com
# Show certificate details without downloading content
curl -vvv --head https://your-endpoint.com 2>&1 | grep -A5 "Server certificate"
# Test with explicit CA bundle
curl --cacert /path/to/ca-bundle.crt https://your-endpoint.com
# Check what cert the server is actually presenting
openssl s_client -connect your-endpoint.com:443 -showcerts 2>/dev/null | openssl x509 -noout -text | grep -E "Subject:|Issuer:|Not After"
# Test a specific SNI (critical for multi-tenant endpoints)
openssl s_client -connect your-endpoint.com:443 -servername your-endpoint.com
Common Error Messages Decoded
| Error | Likely Cause |
|---|---|
CERTIFICATE_VERIFY_FAILED | CA not trusted or chain broken |
SSL: CERTIFICATE_VERIFY_FAILED | Python urllib/requests CA mismatch |
curl: (60) SSL certificate problem | Missing or untrusted CA |
certificate has expired | Obvious — cert rotation needed |
unable to get local issuer certificate | Missing intermediate certificate |
hostname mismatch | SAN/CN doesn't match requested host |
Python requests Fixes
The Right Way — Provide the CA Bundle
import requests
# Point to your CA bundle (preferred approach)
response = requests.get(
"https://your-endpoint.com",
verify="/path/to/ca-bundle.crt"
)
# For corporate/internal CAs — bundle them yourself
response = requests.get(
"https://internal-api.corp.com",
verify="/etc/ssl/certs/corporate-ca.pem"
)
Find Where Python Is Looking for CAs
import ssl
import certifi
# What CA bundle is Python currently using?
print(ssl.get_default_verify_paths())
# Where certifi stores its bundle
print(certifi.where())
# Check the actual SSL context
ctx = ssl.create_default_context()
print(ctx.get_ca_certs())
Fix for macOS (Python 3.6+)
macOS Python installations famously don't use the system keychain. Run this once:
# Usually found in your Python install directory
/Applications/Python\ 3.x/Install\ Certificates.command
# Or install certifi and point to it
pip install certifi
import ssl
import certifi
# Override the default SSL context
ssl_context = ssl.create_default_context(cafile=certifi.where())
Append a Custom CA to certifi's Bundle
import certifi
import shutil
import os
# One-time setup: append your corporate CA
custom_ca_path = "/tmp/combined-ca-bundle.pem"
shutil.copy(certifi.where(), custom_ca_path)
with open(custom_ca_path, "ab") as outfile:
with open("/path/to/corporate-ca.pem", "rb") as infile:
outfile.write(infile.read())
# Use the combined bundle
response = requests.get("https://internal-api.corp.com", verify=custom_ca_path)
Environment Variable Shortcuts
These work globally without code changes — useful for quick debugging:
# Point requests/urllib to a specific CA bundle
export REQUESTS_CA_BUNDLE=/path/to/ca-bundle.crt
export SSL_CERT_FILE=/path/to/ca-bundle.crt
# For curl
export CURL_CA_BUNDLE=/path/to/ca-bundle.crt
Corporate Proxy / SSL Inspection Fix
If you're behind a proxy doing SSL inspection (very common in enterprise environments), you need the proxy's CA cert in your trust store.
# Linux — add the corporate CA system-wide
sudo cp corporate-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates # Debian/Ubuntu
sudo update-ca-trust # RHEL/CentOS
# Verify it's in the system bundle now
grep "Corporate CA" /etc/ssl/certs/ca-certificates.crt
# Python — combine system CAs with proxy CA
import requests
session = requests.Session()
session.verify = "/etc/ssl/certs/ca-certificates.crt" # Updated system bundle
response = session.get("https://external-api.com")
Kubernetes-Specific: Mounting CA Certs into Pods
# Mount a corporate CA as a ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: corporate-ca
data:
ca.crt: |
-----BEGIN CERTIFICATE-----
<your-ca-cert-here>
-----END CERTIFICATE-----
---
# In your Pod spec
volumes:
- name: ca-bundle
configMap:
name: corporate-ca
containers:
- name: app
env:
- name: REQUESTS_CA_BUNDLE
value: /etc/ssl/custom/ca.crt
volumeMounts:
- name: ca-bundle
mountPath: /etc/ssl/custom
The Nuclear Option (Don't Do This in Production)
I'm including this only so you know what it looks like — and can recognize it in code reviews and reject it.
# DO NOT USE IN PRODUCTION
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
response = requests.get("https://your-endpoint.com", verify=False) # ❌ Never
# curl equivalent — also never in production
curl -k https://your-endpoint.com # ❌ -k/--insecure disables all verification
verify=False silences the error by removing all protection. You're not fixing the problem — you're just agreeing to be MITM'd quietly.
Quick Decision Tree
SSL error hit?
├── Run openssl s_client → cert expired? → Rotate the cert
├── Hostname mismatch? → Fix the SAN on the cert or use correct hostname
├── "unable to get local issuer" → Missing intermediate → get full chain from server owner
├── Corporate proxy? → Add proxy CA to system trust store
└── macOS Python? → Run Install Certificates.command or use certifi
Bottom line: Always fix the root cause. The correct CA bundle should be in your trust store, your containers should mount custom CAs via ConfigMaps, and verify=False should never survive a code review. Take the extra 10 minutes to do it right.
Was this article helpful?
Senior Kubernetes Architect
10+ years orchestrating containers in production. Battle-tested opinions on everything from pod scheduling to service mesh. I've seen clusters burn and helped rebuild them better.
Related Articles
AWS IAM Policy Conditions For Cross-Account Resource Access Without Over-Privileging
Cross-account resource access in AWS is like giving someone the keys to your house—you want them to get in, but only through the right door, at the right t...
Kubernetes Security Hardening for Production: The Complete Guide
Harden Kubernetes clusters for production with RBAC, network policies, pod security standards, secrets management, and admission controllers.
Security Headers & Configs: Cheat Sheet
Security headers and configuration reference — copy-paste snippets for Nginx, Kubernetes Ingress, Cloudflare, and Helmet.js.
Automated Dependency Vulnerability Scanning in CI: Stop Shipping Known CVEs
Add automated dependency vulnerability scanning to your CI pipeline using Trivy and Grype. Catch known CVEs before they hit production.
OPA Gatekeeper: Enforcing Kubernetes Admission Control Policies That Actually Stop Misconfigurations
Deploy OPA Gatekeeper to enforce Kubernetes admission policies — block privileged containers, enforce labels, and prevent misconfigurations.
Mozilla SOPS: Encrypted Secrets in Git for GitOps Workflows That Don't Leak
Use Mozilla SOPS to encrypt secrets in Git for secure GitOps workflows. Covers AGE, AWS KMS, and ArgoCD integration with real examples.
More in Security
View all →Container Image Scanning with Trivy: Complete Setup Guide
Set up Trivy for container image vulnerability scanning — from local development to CI/CD pipeline integration with actionable remediation.
Kubernetes RBAC: A Practical Guide to Least-Privilege Access Control
Implement least-privilege RBAC in Kubernetes to prevent lateral movement and privilege escalation — with real threat models and pipeline-ready examples.
HashiCorp Vault and Kubernetes: Secrets Management That Actually Works
Integrate HashiCorp Vault with Kubernetes to eliminate static secrets from your cluster — with working manifests, threat models, and pipeline automation.
Container Supply Chain Security With Sigstore and Cosign
Sign and verify your container images with Sigstore Cosign to prevent supply chain attacks — with keyless signing, SBOM attestation, and Kubernetes admission enforcement.