“unable to get local issuer certificate” means the TLS verifier can’t build a valid trust chain from the server’s cert → a trusted root. In plain English: the server didn’t send the right intermediate(s), or it’s using a CA your client doesn’t trust (e.g., a private CA or a Cloudflare Origin Certificate seen directly).
Here’s how to fix it fast in a Cloudflare → F5 → Kong → Upstream stack.
1) Identify which hop is failing
Run these from your laptop (replace host):unable to get local issuer certificate
# Client → Cloudflare (public hostname)
openssl s_client -showcerts -servername api.example.com -connect api.example.com:443 </dev/null | sed -n '1,/-END CERTIFICATE-/p'
# Client → F5 (bypass Cloudflare: hit the VIP IP)
openssl s_client -showcerts -connect <F5_PUBLIC_IP>:443 </dev/null
# Direct to Kong node (if it terminates TLS)
openssl s_client -showcerts -connect <KONG_NODE_IP>:8443 </dev/null
# From inside Kong to the upstream (what Kong sees)
docker exec -it kong sh -lc 'apk add --no-cache openssl >/dev/null 2>&1 || true; \
openssl s_client -showcerts -servername <UPSTREAM_HOST> -connect <UPSTREAM_HOST>:443 </dev/null'
Look at:
- The presented chain (server cert + intermediates)
Verify return code: (should be 0 (ok))
2) Common root causes & specific fixes
A) Missing intermediate on your origin (F5/Kong/upstream)
Symptom: OpenSSL shows only the server cert, or depth=0 ok then fails at depth=1 with this error.
Fix:
- F5: import the intermediate CA that issued your server cert and set it as the Chain in the Client SSL Profile bound to your VIP (Certificate + Key + Chain). Ensure the chain is complete (server → intermediate(s) → root).
- Kong terminating TLS (TLS Ingress on 8443): configure
cert + key using the full chain bundle (server + intermediates). Most proxies require fullchain.pem (not just cert.pem).
- Upstream service: install a proper cert and serve the intermediates.
B) You used a Cloudflare Origin Certificate and connected directly to F5
Cloudflare Origin Certs are only trusted by Cloudflare, not by browsers/curl.
Symptom: Works when proxied through Cloudflare (orange cloud), fails when you hit the F5 IP directly.
Fix options:
- Keep traffic proxied through Cloudflare (don’t bypass); or
- Install a publicly trusted cert on F5 (e.g., Let’s Encrypt) for direct access.
C) Kong → Upstream uses an internal/private CA
Symptom: Client to Kong is fine; Kong logs show upstream TLS verify errors, or your route returns 500/502.
Fix (Kong Admin API):
- Upload your internal CA:
curl -s -X POST :8001/ca_certificates -F cert=@corp-root-or-intermediate.pem
# -> returns {"id":"<CA_ID>", ...}
- Attach it to the Service and enforce verification:
curl -s -X PATCH :8001/services/<service_id> \
-d tls_verify=true \
-d tls_verify_depth=2 \
-d ca_certificates[]='<CA_ID>'
(Temporary only: you can set tls_verify=false to prove that CA trust is the issue—then turn it back on with the proper CA.)
D) Wrong SNI / Hostname mismatch
If the cert is for api.example.com but the TLS handshake SNI is different, validation fails.
- Ensure F5 sends correct SNI when it re-encrypts to Kong/upstream.
- In Kong Service for HTTPS upstreams, set
sni=<upstream-cert-hostname>.
E) Old client trust store / corporate MITM
- Older clients may lack newer roots (update trust store).
- If a corporate proxy is intercepting TLS, clients need that proxy’s root in their trust store.
3) Quick “good config” checklist per hop
Cloudflare → F5
- SSL mode: Full (strict).
- (Optional) Authenticated Origin Pull: F5 must trust CF Origin Pull CA and require client cert.
- F5 presents a cert chain your clients would trust when you test direct (unless you never hit it directly).
F5 → Kong
- If re-encrypting: Server SSL profile with proper SNI to Kong (if Kong expects it). Otherwise send HTTP on a private VLAN to keep it simple.
- Preserve headers (
X-Forwarded-Proto, X-Forwarded-For).
Kong → Upstream
- For HTTPS upstreams:
protocol=https, port=443, sni=<host>, tls_verify=true
- Attach internal CA certificate if upstream uses a private CA (see step 2C).
4) Don’t “fix” by disabling verification (except to isolate)
curl -k, Node’s NODE_TLS_REJECT_UNAUTHORIZED=0, Java -Dcom.sun.net.ssl.checkRevocation=false—use only for a one-off test. The real fix is serving the right chain or installing the proper CA.
5) One-command validator you can paste in tickets
openssl s_client -connect api.example.com:443 -servername api.example.com -verify_return_error </dev/null
You’ll get a clear reason (missing issuer / self-signed / hostname mismatch).
If you tell me which endpoint shows the error (Cloudflare URL, direct F5 VIP, Kong 8443, or Kong→Upstream) and paste the first ~40 lines of the openssl s_client output, I’ll point to the exact certificate/chain file you need to fix.