Python can't verify the server's chain: missing intermediate on the server, outdated certifi bundle, or a corporate proxy re-signing traffic. Fix the trust source, don't disable verification.
Python (unlike browsers) doesn't fetch missing intermediates. If the server sends only the leaf, verification can never complete. openssl s_client -showcerts confirms in one command.
requests uses certifi; system Python uses the OS store. Old Docker images / slim bases ship stale bundles. pip install --upgrade certifi, or update-ca-certificates.
The proxy re-signs everything with an internal CA. Without that CA in the bundle, every HTTPS call fails — the corporate-network tell.
openssl s_client -connect host:443 -servername host -showcerts </dev/null 2>/dev/null | grep -c 'BEGIN CERT'
pip install --upgrade certifi ; python -c "import certifi; print(certifi.where())"
# Debian: cp corp.pem /usr/local/share/ca-certificates/corp.crt && update-ca-certificates ; macOS python: run Install Certificates.command; or REQUESTS_CA_BUNDLE=/path/to/bundle
# requests.get(url, verify='/path/to/ca-bundle.pem') # still validates, just against your chosen bundle
verify=False in code is how outages become breaches: it disables validation everywhere that line runs. Use verify=<ca-bundle> instead. Docker: build with the CA install step, or mount /etc/ssl/certs — slim images are the usual offenders in CI.
They read different trust stores (OS bundle vs certifi) and Python won't AIA-fetch missing intermediates. Align the bundle (upgrade certifi / install the private CA) and both behave identically.
Install the CA in the image: COPY corp.pem /usr/local/share/ca-certificates/ && RUN update-ca-certificates — or pip install --upgrade certifi if it's just staleness. Never bake verify=False into app code.
Our most-documented failures, packaged as ready-to-ship starter kits: Docker, Kubernetes, and Terraform.
Browse the template store →One-time. Yours to modify. Instant download from the NinjaOps template store.