Add Root CA(s) to a host's Trust Store

The certificate file must be:

RHEL/Fedora : /etc/pki/ca-trust/source/anchors/

# Install the package
dnf install -y p11-kit-trust ca-certificates
# Create the source dir
mkdir -p /etc/pki/ca-trust/source/anchors/
# Copy the CA cert(s) to the source dir
cp -p lime-dc1-ca.crt /etc/pki/ca-trust/source/anchors/
# Add : Process source CAs by creating symlinks and hash (c_rehash)
update-ca-trust extract
# Verify
openssl x509 -subject -issuer -noout -in /etc/pki/tls/certs/ca-bundle.crt
# Validate
curl -sSIX GET https://dc1.lime.lan/

Debian/Ubuntu : /usr/local/share/ca-certificates/

# Install the package
apt-get install -y ca-certificates
# Copy the CA cert(s) to the source dir
cp -p lime-dc1-ca.crt /usr/local/share/ca-certificates/
# Add : Process source CAs by creating symlinks and hash (c_rehash)
update-ca-certificates
# Verify
openssl x509 -subject -issuer -noout -in /etc/ssl/certs/ca-bundle.crt
# Validate
curl -sSIX GET https://dc1.lime.lan/

Symlink Creation (c_rehash):

The c_rehash command is run on the /etc/ssl/certs/ directory. Every .crt and .pem file in the directory is processed. A hash of the certificate's subject name is created and used to map the symlink to the source certificate; f10e7a5c.0 -> lime-dc1-ca.crt

SSL_CERT_FILE

Setting SSL_CERT_FILE to point to a single file containing all your private CA certificates in PEM format is a common and often successful strategy, but it is not a universal solution. Its success depends entirely on whether the client library you are using respects that specific environment variable and how it implements trust.

Here’s a detailed breakdown:

How SSL_CERT_FILE Works (The Theory)

The SSL_CERT_FILE environment variable is a convention used primarily by OpenSSL and software that directly uses the OpenSSL library (like many compiled programs, curl built with OpenSSL, Python's requests library when linked against OpenSSL, etc.).

So, for any tool that uses OpenSSL and respects this variable, your unprocessed ca-bundle.crt file would be sufficient.

The Reality: A Fragmented Landscape of HTTP Clients

Not all HTTP clients or programming languages use OpenSSL or respect this variable. Here’s a categorization:

Category 1: Likely to Work (Uses OpenSSL & respects SSL_CERT_FILE)

Category 2: Will NOT Work (Ignores SSL_CERT_FILE)

Category 3: Has Its Own Mechanism

The Critical "Hashed Symlink" Requirement for SSL_CERT_DIR

You might see advice to use SSL_CERT_DIR instead. This is even more strict. SSL_CERT_DIR must point to a directory (e.g., /etc/ssl/certs) that contains the hashed symlinks (f10e7a5c.0 -> some-cert.pem). A directory containing just the raw .pem files without the symlinks will not work for OpenSSL unless the application specifically calls SSL_CTX_load_verify_locations on the file directly.

Best Practice and Recommendation

1. For Application-Specific Control (Recommended): Use the environment variable specific to your runtime if it exists. This is the most reliable method. * Node.js: NODE_EXTRA_CA_CERTS * Python Requests: REQUESTS_CA_BUNDLE * General OpenSSL: SSL_CERT_FILE * curl/wget: CURL_CA_BUNDLE (though they also respect SSL_CERT_FILE)

2. For System-Wide Control (For Containers/Images): The most robust and portable solution is still to build the certificates into the system trust store using update-ca-certificates (Debian) or update-ca-trust (RHEL). This ensures that every tool on the system (that respects the OS defaults) will work without any special environment variables.

3. For your specific question: If you control the environment and know for a fact that every HTTP client you need to support is in Category 1 (e.g., a container running a Python app using requests and some curl commands), then setting SSL_CERT_FILE to your unprocessed ca-bundle.crt is a perfectly valid and simple solution.

However, if there's any chance a Java app, Node.js app, or web browser might be involved, it will not be sufficient. You must employ additional strategies for those specific runtimes.


TLS v. Other : ca-bundle.crt v ca-bundle.trust.crt

When an application requests the CA certificate bundle, the correct file to provide depends on:

  1. The application’s TLS library (OpenSSL, GnuTLS, NSS, etc.)
  2. Whether it expects trust flags (i.e., "trusted for server auth")
  3. The expected format (PEM, DER, trust-annotated PEM)

Let’s break it down.


🔍 When to Provide Which CA Bundle

Use Case / Application Provide This CA Bundle Why?
OpenSSL, curl, wget, git, dnf/yum /etc/ssl/certs/ca-bundle.crt
(on RHEL: symlink to /etc/pki/tls/certs/ca-bundle.crt)
OpenSSL expects plain PEM format
GnuTLS (used by GNOME apps, wget on Fedora), glib-networking /etc/pki/tls/certs/ca-bundle.trust.crt GnuTLS requires trust bits, supported in *.trust.crt
Firefox, NSS-based apps Internal NSS DB or /etc/pki/nssdb Uses its own cert store; must be updated via certutil
Python requests (via certifi) Use certifi.where() or override via REQUESTS_CA_BUNDLE Python uses its own vendored CA list unless overridden
Java (JVM) $JAVA_HOME/lib/security/cacerts (Java Keystore) Expects JKS or PKCS#12, not PEM — needs conversion
Go binaries (static) Uses system default (if dynamically linked) or may bundle its own Built-in Go TLS honors /etc/ssl/certs on Linux unless overridden

🧭 General Recommendation for Linux Systems


🔧 Custom Environment Variable Overrides (for applications)

If an app doesn’t pick up the right bundle:

export SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt

Or in systemd units:

[Service]
Environment="SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt"

🛠️ Summary Table

Bundle Path Format Suitable For
/etc/ssl/certs/ca-bundle.crt PEM Most CLI tools (OpenSSL, curl, etc)
/etc/pki/tls/certs/ca-bundle.trust.crt PEM w/ trust GnuTLS, glib-networking
/etc/pki/nssdb/, Firefox profile DBs NSS DB Firefox, Thunderbird, some security tools
Java keystore (cacerts) JKS Java applications

✅ TL;DR

Most applications expect /etc/ssl/certs/ca-bundle.crt — the plain PEM file — unless you're using GnuTLS-based tools, NSS (like Firefox), or Java, which have different requirements.


Yes — most container images do include at least one CA bundle, especially if the image is based on a full Linux distribution (e.g., RHEL UBI, Alpine, Debian, etc.). Here's how and why:


Why CA Bundles Are Included in Container Images

Most containers need CA bundles for TLS certificate validation, including:

If the CA bundle is missing:


📦 Typical CA Bundle Locations in Container Images

Base Image Trust File Package Providing It
RHEL / UBI /etc/pki/tls/certs/ca-bundle.crt ca-certificates
Debian/Ubuntu /etc/ssl/certs/ca-certificates.crt ca-certificates
Alpine /etc/ssl/certs/ca-certificates.crt ca-certificates (musl/OpenSSL-based)

🔹 These are symlinks or files pointing to trusted root bundles maintained by each distro's update mechanism.


🧼 Are They Always Included?

Not always:


🧰 In Custom or Air-Gapped Containers

You may:


✅ TL;DR

Yes, container images typically include CA bundles, especially standard ones like ca-bundle.crt or ca-certificates.crt, so that tools and applications can validate HTTPS/TLS connections.

Minimal images might omit them for size, but in practice, most working containers need them — and you'll have to add them explicitly in custom or stripped-down images.

You're absolutely right — RHEL (and many other Linux systems) maintain two primary CA bundle files, and their differing sizes and contents serve distinct purposes.

Here’s what they are and why both exist:


📁 The Two Bundles in RHEL

1. /etc/ssl/certs/ca-bundle.crt

(Approx. 270–300 KB)


2. /etc/pki/tls/certs/ca-bundle.trust.crt

(Approx. 500–600 KB)


🧠 Why Two Bundles?

Feature ca-bundle.crt ca-bundle.trust.crt
Format PEM PEM + trust flags (OpenSSL + p11-kit)
Consumers OpenSSL, curl, git, etc. GnuTLS, GNOME apps, systemd, Firefox*
Trust metadata ❌ No ✅ Yes
Size Smaller (~300 KB) Larger (~600 KB)

🔄 How They’re Maintained

Both are regenerated via:

update-ca-trust extract

...which reads from:


🧩 In Air-Gapped or Hardened Systems

You can:


✅ TL;DR

RHEL provides two CA bundles:

You need both to ensure compatibility across all system libraries and tools.