adllm Insights logo adllm Insights logo

Troubleshooting `SSLError: CERTIFICATE_VERIFY_FAILED` in Python `requests` with custom enterprise root CAs

Published on by The adllm Team. Last modified: . Tags: python ssl certificate-verification enterprise-ca requests-library

Introduction

Encountering SSLError: CERTIFICATE_VERIFY_FAILED in Python’s requests library is a common hurdle for developers working in enterprise environments. This error indicates that the server’s certificate cannot be verified against the client’s trusted root certificates. This article addresses how to resolve this issue when dealing with custom enterprise root Certificate Authorities (CAs), ensuring secure communication without bypassing SSL verification.

Understanding the Problem

When Python applications using the requests library attempt to connect to servers with certificates signed by custom enterprise root CAs, an SSLError: CERTIFICATE_VERIFY_FAILED can occur. This happens because these CAs are not recognized by default by the system or the library.

Why This Error Occurs

  • SSL/TLS Handshake: During the SSL/TLS handshake, the server presents a certificate chain. The client must verify this chain against its trusted root CAs.
  • Custom Root CAs: In many enterprises, internal services use certificates signed by custom root CAs, not included in the default trusted set.

Best Practices for Resolving the Error

To resolve this error, you should configure the requests library to trust custom root CAs.

Adding Custom Root CAs

You can add custom root CAs by specifying a path to a file containing these certificates using the verify parameter in requests. This approach ensures that your application only trusts specified certificates.

1
2
3
4
5
6
7
import requests

# Path to custom CA bundle
ca_bundle_path = '/path/to/custom/ca-bundle.crt'

# Example of using the verify parameter
response = requests.get('https://internal.api.example.com', verify=ca_bundle_path)

Using Environment Variables

Another approach is to set the REQUESTS_CA_BUNDLE environment variable to point to the custom CA certificate file.

1
export REQUESTS_CA_BUNDLE=/path/to/custom/ca-bundle.crt

Using Session Objects for Efficiency

For applications making multiple requests, use requests.Session() to reuse connections and efficiently apply the same CA configuration across requests.

1
2
3
session = requests.Session()
session.verify = ca_bundle_path
response = session.get('https://internal.api.example.com')

Diagnostic and Debugging Techniques

Verbose Logging

Enable logging in requests to gain insights into the SSL handshake process.

1
2
3
4
import logging

logging.basicConfig(level=logging.DEBUG)
logging.getLogger("urllib3").setLevel(logging.DEBUG)

Using OpenSSL for Manual Verification

Use OpenSSL to manually verify the certificate chain, ensuring that the CA bundle is correct.

1
openssl s_client -connect internal.api.example.com:443 -CAfile /path/to/custom/ca-bundle.crt

Analyzing Traffic with Wireshark

Wireshark can be used to capture and analyze SSL/TLS handshakes to identify where the verification process fails.

Common Challenges and Anti-Patterns

Disabling SSL Verification

A common but insecure approach is setting verify=False in requests. This disables SSL verification entirely, exposing your application to potential man-in-the-middle attacks.

Misconfigured CA Bundle

Ensure the path to the CA bundle is correct and the file is properly formatted. Misconfigurations can lead to persistent verification failures.

Incomplete Certificate Chains

Ensure that the certificate chain is complete. Even with the correct root CA, incomplete chains can cause verification failures.

Certificate Transparency

The adoption of certificate transparency logs is increasing, impacting how enterprises handle custom CAs.

Automated Certificate Management

Solutions like Let’s Encrypt and ACME protocols are influencing enterprise SSL strategies, potentially reducing reliance on custom CAs.

Conclusion

Resolving SSLError: CERTIFICATE_VERIFY_FAILED in Python’s requests library requires configuring the library to trust custom enterprise root CAs. By following best practices such as using the verify parameter or environment variables, and avoiding insecure anti-patterns, developers can ensure secure communication in enterprise environments. Future trends in automated certificate management may further simplify this process.

For further reading, consult the Python requests documentation, OpenSSL documentation, and Wireshark documentation.