This is the multi-page printable view of this section. Click here to print.
Using a Project Hummingbird container image
- 1: Using a Project Hummingbird container image
- 2: Custom CA Certificates (OpenSSL)
- 3: Custom CA Certificates (Java)
- 4: Custom CA Certificates (Python)
1 - Using a Project Hummingbird container image
Project Hummingbird builds a collection of minimal, hardened, and secure container images with a significantly reduced attack surface. This strong focus on security combined with a highly automated update workflow aims to minimize CVE counts, targeting near-zero vulnerabilities. All images support amd64 and arm64 architectures.
Quick Start
All images are available from the Red Hat Hardened Images registry and work directly with Podman, Docker, or Kubernetes:
# Run a command directly with the curl image
podman run registry.access.redhat.com/hi/curl:latest -v https://example.com
# Start a PostgreSQL database
podman run -e POSTGRES_PASSWORD=mysecret -p 5432:5432 registry.access.redhat.com/hi/postgresql:latest
Example container build using the Hummingbird Python image:
FROM registry.access.redhat.com/hi/python:latest
COPY myapp.py /app/
WORKDIR /app
CMD ["python3", "myapp.py"]
Documentation for each image is available on the Red Hat Hardened Images Catalog.
Contents
- Available Images
- Hardened for Security
- Distroless Containers
- Understanding Image Variants
- Image Verification
- Vulnerability Scanning
- Sharing Host Data
- Custom CA Certificates
- Compatibility
- Reproducible Builds
- Content-Based Layers
- Source Containers
- Roadmap
- Relationship to Fedora
- Contributing
Available Images
Available images span language runtimes, databases, web servers, CLI tools, and base runtime images.
Browse the complete catalog at the Red Hat Hardened Images Catalog.
Hardened for Security
Hummingbird applies several measures to harden container images:
- Minimal Software Footprint: Images include only essential packages required for the workload, significantly reducing the attack surface and CVE count.
- Rapid Update Deployment: Package updates ship as quickly as possible, ensuring fixes are consumed early.
- Non-Root User Default: Containers default to a non-root user (UID 65532) where technically possible, reducing privileges within the container.
- Hermetic Build Environment: All containers are built in a hermetic environment without network access, preventing unintended package drift and maintaining full control over software versions.
- Distroless Security: Shipping only what is strictly necessary for the workload reduces the attack surface and makes certain types of attacks impossible.
- FIPS-Validated Cryptography: FIPS variants provide NIST-validated cryptographic modules for compliance-sensitive workloads.
Distroless Containers
Hummingbird builds distroless containers — images that do not ship with a package manager and most do not even provide a shell.
The distroless design makes the bundled application the container’s entrypoint, offering a streamlined experience. For example, with the curl image, arguments can be passed directly: podman run registry.access.redhat.com/hi/curl:latest -v https://www.redhat.com/en.
Purpose-built containers reduce the burden on users. Instead of building custom container images and managing their vulnerabilities, a Hummingbird image with the needed application avoids CVE management overhead entirely.
Understanding Image Variants
Hummingbird provides different variants to support various use cases while maintaining security by default.
Default Variant (:latest)
- Distroless: no package manager, no shell
- Minimal attack surface
- Recommended for production
- Example:
registry.access.redhat.com/hi/python:latest
Builder Variant (:latest-builder)
- Includes
dnfpackage manager andbash - For installing additional dependencies
- Intended for multi-stage builds and development
- Example:
registry.access.redhat.com/hi/python:latest-builder
Some images provide additional variants such as PHP’s FPM variant.
FIPS Variants (:latest-fips, :latest-fips-builder)
FIPS variants ship FIPS 140-3 validated cryptographic modules for workloads that require certified cryptography. Validation applies only when running on RHEL systems installed in FIPS mode.
Two cryptographic stacks are available depending on the image:
| Stack | Images | FIPS packages |
|---|---|---|
| OpenSSL | Go, Nginx, Node.js, Python, Ruby, curl | openssl-config-fips, crypto-policies-config-fips |
| NSS | OpenJDK | nss-softokn-fips, nss-softokn-freebl-fips |
FIPS is available in both distroless (:latest-fips) and builder (:latest-fips-builder) variants. FIPS variants are available for the Hummingbird distro only (not Rawhide). For implementation details, see the FIPS Variant Guide.
Support Levels
Images are published under two support levels:
- Red Hat supported — the majority of images. Built, tested, and maintained by the Hummingbird team with full CI/CD coverage, security updates, and vulnerability tracking. Available at
registry.access.redhat.com/hi/with official Red Hat signing keys — this is the recommended registry for all users. - Community — images where the upstream project does not follow standard open-source release practices (e.g., MinIO) or where the image is experimental (e.g., bootc-os). Built and tested in the same infrastructure but without the same support commitments. Community also serves as a staging ground for images being evaluated for promotion to Red Hat supported status. Published to
quay.io/hummingbird-community/.
Registry Organizations
| Registry | Description |
|---|---|
registry.access.redhat.com/hi/ |
Red Hat Hardened Container Images (recommended) |
quay.io/hummingbird/ |
Mirror of Red Hat supported images without official signing |
quay.io/hummingbird-community/ |
Community-supported images (e.g., MinIO, bootc-os) |
quay.io/hummingbird-rawhide/ |
Upstream Fedora Rawhide packages directly |
quay.io/hummingbird-ci/ |
Build infrastructure images |
Tool images used by pipelines (e.g., quay.io/hummingbird-ci/gitlab-ci) are published from
the tools repository.
Tagging Strategy
Images follow a version-based tagging scheme:
:latest— most recent version (may change):<version>— specific version (e.g.,:3.11,:16):<version>-builder— builder variant of a specific version:<version>-fips— FIPS variant of a specific version:<version>-fips-builder— FIPS builder variant of a specific version
Use versioned tags in production for reproducible builds. The :latest tag is convenient for development but may introduce unexpected changes.
For best practices on tag selection and digest pinning, see How to name, version, and reference container images.
Multi-version images:
For languages with multiple supported version families (Python, Node.js, .NET, etc.), separate images exist for each major version:
registry.access.redhat.com/hi/python:latest— latest Python (currently 3.14)registry.access.redhat.com/hi/python:3.11— Python 3.11.x (stays on 3.11)registry.access.redhat.com/hi/python:3.13— Python 3.13.x (stays on 3.13)
Version constraints prevent these images from accidentally upgrading to incompatible versions. See version constraints for details.
Multi-Stage Build Pattern
The recommended pattern for compiled languages:
# Build stage: use builder variant to install dependencies and compile
FROM registry.access.redhat.com/hi/go:latest-builder AS builder
RUN dnf install -y <build dependencies>
COPY . /src
WORKDIR /src
RUN go build -o /app .
# Runtime stage: use minimal base image for the compiled binary
FROM registry.access.redhat.com/hi/core-runtime:latest
COPY --from=builder /app /app
ENTRYPOINT ["/app"]
This approach provides build-time flexibility while maintaining a minimal production image.
Image Verification
Hummingbird images are signed and can be verified using cosign:
cosign verify \
--key "https://security.access.redhat.com/data/63405576.txt" \
--insecure-ignore-tlog \
registry.access.redhat.com/hi/<image>:<tag>
Vulnerability Scanning
Use Syft and Grype to locally inspect and scan images. For details on how production SBOMs are generated, see Software Bill of Materials.
To scan an image for vulnerabilities:
grype registry.access.redhat.com/hi/<image>:<tag>
For current vulnerability information across all variants and versions, see the Red Hat Hardened Images Catalog.
Sharing Host Data
By default, containers do not have access to host filesystem content. Volume mounts must be added explicitly:
podman run -v /path/on/host:/path/in/container registry.access.redhat.com/hi/curl:latest ...
SELinux Relabeling
On systems with SELinux enabled (such as Fedora and RHEL), mounted volumes must be relabeled to allow container access. Use the :z or :Z option:
podman run -v /path/on/host:/path/in/container:z registry.access.redhat.com/hi/curl:latest ...
The :z option relabels content to be accessible by any container sharing the mount. The :Z option relabels content to be uniquely accessible to one container.
File Permissions
Most Hummingbird images default to a non-root user. When mounting host directories that the container needs to write to, either make the directory world-writable (within a private directory):
mkdir -m 700 /path/on/host
mkdir -m 777 /path/on/host/mnt
podman run -v /path/on/host/mnt:/path/in/container:z ...
Or run as the root user (recommended only with rootless Podman, where the root user in the container maps to the calling user on the host):
podman run --user root -v /path/on/host:/path/in/container:z ...
For read-only access, no permission changes are needed as long as files are world-readable.
Custom CA Certificates
Hummingbird images can be configured to trust custom Certificate Authority (CA) certificates for TLS connections. The approach depends on the image’s TLS stack.
OpenSSL-Based Images (curl, Nginx, Python, etc.)
Mount a CA bundle to replace or extend the system trust store:
podman run --rm \
-v /path/to/ca.crt:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro,Z \
registry.access.redhat.com/hi/curl:latest https://internal-server/
For details on building derived images with merged trust stores, see the Custom CA (OpenSSL) guide.
Java-Based Images (OpenJDK, Tomcat)
Java uses its own PKCS12 truststore format. A custom truststore can be created using keytool and mounted at runtime:
podman run --rm \
-v /path/to/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro,Z \
registry.access.redhat.com/hi/openjdk:latest java -jar app.jar
For step-by-step truststore creation, see the Custom CA (Java) guide.
Compatibility
Hummingbird images are designed for compatibility with popular images from Docker Hub, Red Hat UBI, and other registries, enabling straightforward migration of existing workloads.
Key difference: Hummingbird images default to a non-root user (UID 65532) where technically possible, while most traditional images run as root. This may require adjusting file permissions on mounted volumes:
# Ensure correct ownership for mounted data
chown -R 65532:65532 /path/to/data
For detailed comparisons (environment variables, ports, sizes, default users), see the compatibility report, also available in machine-readable form.
Reproducible Builds
Reproducible builds ensure that the same inputs and build environment always produce bit-for-bit identical output. This allows independent verification that a published image corresponds to its claimed source materials, making it straightforward to detect if malware was injected during the build process.
Hummingbird images are fully reproducible. Given the signed SLSA provenance attestation that accompanies each image, anyone can rebuild the image from its inputs (this git repo and the RPMs it describes) to verify it matches the published version exactly.
For further background, see Reproducible builds: Project Hummingbird.
Verifying Reproducibility
The cosign and podman tools are required. First, download and verify the SLSA provenance attestation using cosign (see Image Verification for key details):
IMAGE=registry.access.redhat.com/hi/curl:latest
cosign verify-attestation --key "https://gitlab.com/redhat/hummingbird/containers/-/raw/main/ci/key.pub?ref_type=heads" --insecure-ignore-tlog \
--type slsaprovenance $IMAGE > attestation.json
Then, feed the attestation into the rebuild tool (capture the image ID for comparison):
iid=$(podman run -i --rm --privileged -v /mnt \
quay.io/hummingbird-ci/hummingbird-builder rebuild < attestation.json)
The --privileged flag is required because the build process uses nested containerization. However, this command is expected to be run rootless. A rootless container cannot gain more privileges than the calling user.
To verify reproducibility, pull the published image and compare image IDs:
iid2=$(podman pull $IMAGE)
[ $iid = $iid2 ] && echo "Identical"
The containers-storage image ID (a hash over the manifest and uncompressed content) is used here, not the repo digest (a hash over compressed content). Comparing uncompressed content avoids depending on the exact compression algorithm or registry format.
To keep the rebuilt image for further inspection, use the DUMP_OCIARCHIVE environment variable:
podman run -i --rm --privileged -e DUMP_OCIARCHIVE=1 -v /mnt \
quay.io/hummingbird-ci/hummingbird-builder rebuild < attestation.json | podman load
Content-Based Layers
Most container images have layers that mirror the Containerfile structure: each RUN or COPY instruction creates a layer. A single package update can invalidate a layer much larger than the package itself, requiring clients to re-pull content that has not changed.
Hummingbird images use chunkah to split images into content-based layers. Instead of layers reflecting the build process, files are grouped by the packages they belong to. This benefits both the network level (only new layers need downloading) and the storage level (common layers are stored once on disk).
Inspect which packages live in which layers using podman history (or docker history):
podman pull registry.access.redhat.com/hi/jq
podman history registry.access.redhat.com/hi/jq
Source Containers
The source code for all Hummingbird containers is available as source containers. A source container includes RPM and non-RPM content shipped in an image, pushed alongside each available tag with the -source suffix.
Inspect source container contents with skopeo:
IMAGE=registry.access.redhat.com/hi/curl:8.19.0-source
cd $(mktemp -d)
mkdir source
skopeo copy --override-os=linux docker://$IMAGE dir:source
cd source
mv version manifest.json ..
for f in $(ls); do tar xvf $f; done
Roadmap
- Image catalog expansion: The catalog of available images will continue to expand significantly.
- Image size optimization: Container-specific package configurations and dependency management to further reduce image sizes.
- Enhanced CVE and SBOM tooling: Improved vulnerability metadata and scanning integration, including methods like cargo-auditable for Rust supply chain transparency.
- Bootable containers: Expanding support for image-based OS deployments and updates.
Relationship to Fedora
Hummingbird builds and maintains its own RPM packages independently. Spec files are derived from Fedora but built in Hummingbird’s own infrastructure, allowing project-specific modifications and optimizations. Key differences from Fedora:
- Use of monorepos — one monorepo for packages and one for containers, simplifying management and automation.
- Heavy reliance on CI/CD — dependency management, testing, and releasing are automated.
- Secure supply chain requirements — container images and packages are built using Konflux, providing SLSA level 3 compliance.
- Greater emphasis on upstream tracking — software closely tracks upstream projects’ lifecycles, including parallel stable versions where offered.
There is a natural affinity between the two projects, and opportunities exist to contribute work from Hummingbird back into Fedora.
Contributing
Interested in contributing? The following resources cover the development workflow:
- Quickstart Guide — building and testing images locally, project structure, CI/CD pipeline
- Adding Images — step-by-step guide for new images and versioned variants
- FIPS Variant Guide — adding FIPS-validated cryptography to an image
- Testing Images — running tests locally and understanding automatic infrastructure retries
- Development Workflow — local setup and workflow
License
This project is licensed under the MIT License - see the LICENSE.txt file for details.
2 - Custom CA Certificates (OpenSSL)
Overview
You can configure OpenSSL-based container images (curl, nginx, etc.) to trust custom Certificate Authority (CA) certificates for TLS connections.
There are two approaches for custom CAs depending on your needs:
- Custom bundle file - Replace system CAs entirely with your own bundle
- Derived image - Build a new image with merged trust store
Approach 1: Custom Bundle File
Use this when you want to trust only your custom CAs and block all default CAs. This is a common case with OpenShift’s custom PKI bundle.
Mount your CA bundle to /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:
Custom bundle with Podman
podman run --rm \
-v /path/to/ca.crt:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro,Z \
quay.io/hummingbird/curl https://your-server/
Custom bundle with Kubernetes
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-ca-bundle
data:
tls-ca-bundle.pem: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
... more certificates if needed ...
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: quay.io/hummingbird/curl
volumeMounts:
- name: custom-ca
mountPath: /etc/pki/ca-trust/extracted/pem
readOnly: true
volumes:
- name: custom-ca
configMap:
name: custom-ca-bundle
Custom bundle on OpenShift with CA injection
On OpenShift, the cluster admin may have already added your organization’s CA certificates to the cluster-wide trust store. You can use OpenShift’s automatic CA injection feature to make these certificates available to your pods.
Create a ConfigMap with the config.openshift.io/inject-trusted-cabundle=true label. OpenShift will automatically populate it with the cluster CA bundle as a key named ca-bundle.crt:
# OpenShift will inject a "ca-bundle.crt" into this automatically
apiVersion: v1
kind: ConfigMap
metadata:
name: trusted-ca
labels:
config.openshift.io/inject-trusted-cabundle: "true"
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
image: quay.io/hummingbird/curl
volumeMounts:
- name: trusted-ca
mountPath: /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
subPath: ca-bundle.crt
readOnly: true
volumes:
- name: trusted-ca
configMap:
name: trusted-ca
The key detail is using subPath: ca-bundle.crt to mount OpenShift’s injected file to the correct location (tls-ca-bundle.pem) that OpenSSL expects.
See the Configuring a custom PKI OpenShift documentation for details on cluster-wide CA configuration.
Approach 2: Derived Image
Use this approach when you need to trust both your custom CA and the image’s builtin default CAs. This creates a new image with a merged trust store with the trust anchor command.
Create a multi-stage Containerfile with your ca.crt in the build context. This example derives from the curl image:
FROM quay.io/hummingbird/curl:latest-builder AS builder
USER root
COPY ca.crt /tmp/
RUN trust anchor /tmp/ca.crt
FROM quay.io/hummingbird/curl:latest
COPY --from=builder /etc/pki /etc/pki
Build and use your custom image:
podman build -t my-curl-with-ca .
podman run --rm my-curl-with-ca https://your-server/
3 - Custom CA Certificates (Java)
Overview
You can configure Java-based container images (openjdk, etc.) to trust custom Certificate Authority (CA) certificates for TLS connections. Java uses its own truststore format (PKCS12) rather than PEM files.
Java keystores require a password for integrity checking. The system truststore uses the standard password changeit, which is a well-known default used for tamper detection rather than confidentiality.
Volume Mount Approach
Create a custom truststore using the keytool command. You can either trust only your specific CAs (for internal-only applications) or merge with the default public CAs (typical for applications connecting to both internal and external services).
CERTDIR=$(mktemp -d) # or use a persistent directory for repeated runs
chmod 777 "$CERTDIR" # to work with non-privileged containers
# OPTIONAL: Copy the default Java truststore to merge with public CAs
# Skip this step to trust ONLY your custom CAs
podman run --rm -v "${CERTDIR}:/work:Z" \
quay.io/hummingbird/openjdk:latest \
cp /etc/pki/ca-trust/extracted/java/cacerts /work/cacerts
# Import your custom CA
podman run --rm -v "${CERTDIR}:/work:Z" \
quay.io/hummingbird/openjdk:latest \
keytool -import -noprompt -trustcacerts -alias my-custom-ca \
-file /work/my-ca.crt \
-keystore /work/cacerts \
-storepass changeit -storetype PKCS12 \
-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE
The -storetype PKCS12 and -J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE flags
are required for compatibility with FIPS images. The system truststore is PKCS12 format
with unencrypted certificate entries (generated by p11-kit). Without these flags,
keytool defaults to PBE-encrypted certificate bags that the FIPS security provider
cannot decrypt.
Podman Example
Mount the custom truststore to the system location:
podman run --rm \
-v "${CERTDIR}/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro,Z" \
quay.io/hummingbird/openjdk:latest \
java -jar myapp.jar
Kubernetes Example
In Kubernetes, use an init container to create the truststore, then share it via an emptyDir volume:
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-ca
data:
ca.crt: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
---
apiVersion: v1
kind: Pod
spec:
initContainers:
- name: prepare-truststore
image: quay.io/hummingbird/openjdk:latest
command: ["sh", "-c"]
args:
- |
# OPTIONAL: Copy the default truststore to merge with public CAs
# Skip this line to trust ONLY your custom CAs
cp /etc/pki/ca-trust/extracted/java/cacerts /truststore/cacerts
chmod 666 /truststore/cacerts
keytool -import -noprompt -trustcacerts -alias custom-ca \
-file /ca/ca.crt -keystore /truststore/cacerts \
-storepass changeit -storetype PKCS12 \
-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE
volumeMounts:
- name: custom-ca
mountPath: /ca
- name: truststore
mountPath: /truststore
containers:
- name: app
image: quay.io/hummingbird/openjdk:latest
volumeMounts:
- name: truststore
mountPath: /etc/pki/ca-trust/extracted/java
readOnly: true
volumes:
- name: custom-ca
configMap:
name: custom-ca
- name: truststore
emptyDir: {}
For the trust-only-specific-CAs approach, omit the cp command and create the keystore directly with keytool -import.
Derived Image Approach
Use this approach when it’s more practical to bake the certificates into the image instead of generating the truststore on each container startup. This creates a new image with a merged trust store with the trust anchor command.
Create a multi-stage Containerfile with your ca.crt in the build context. This example derives from the openjdk image:
FROM quay.io/hummingbird/openjdk:latest-builder AS builder
USER root
COPY ca.crt /tmp/
RUN trust anchor /tmp/ca.crt
FROM quay.io/hummingbird/openjdk:latest
COPY --from=builder /etc/pki /etc/pki
Build and use your custom image:
podman build -t my-openjdk-with-ca .
podman run --rm my-openjdk-with-ca java -jar myapp.jar
4 - Custom CA Certificates (Python)
Overview
You can configure Python container images to trust custom Certificate Authority (CA) certificates for TLS connections. Python libraries have different trust store behaviors compared to other OpenSSL-based images:
- urllib (built-in) reads CAs from both of these locations:
/etc/pki/tls/cert.pem- the main CA bundle file/etc/pki/tls/certs/- directory with hashed certificate symlinks
- requests (third-party) ignores
/etc/pkientirely and requires theREQUESTS_CA_BUNDLEenvironment variable to use system CAs
Note: The requests library is not included in the standard Python image. To use it, you need to build a derived image:
FROM quay.io/hummingbird/python:latest
RUN ["pip3", "install", "requests"]
podman build -t localhost/my-python-with-requests .
There are two approaches for custom CAs depending on your needs:
- Custom bundle file - Replace system CAs entirely with your own bundle
- Add custom CAs - Merge your custom CAs with the system defaults
Approach 1: Custom Bundle File
Use this when you want to trust only your custom CAs and block all default CAs. This is a common case with OpenShift’s custom PKI bundle.
Mount your CA bundle to /etc/pki/tls/cert.pem, set $REQUESTS_CA_BUNDLE to that, and block the hashed directory with an empty directory:
Custom bundle with Podman
podman run --rm \
-v /path/to/ca.crt:/etc/pki/tls/cert.pem:ro,Z \
--tmpfs /etc/pki/tls/certs:notmpcopyup \
-e REQUESTS_CA_BUNDLE=/etc/pki/tls/cert.pem \
localhost/my-python-with-requests python3 -c "
import urllib.request
print(urllib.request.urlopen('https://your-server/').status)
import requests
print(requests.get('https://your-server/').status_code)
"
Note: Podman requires the :notmpcopyup option as mounting tmpfs behaves like an overlay. Docker’s tmpfs creates an empty directory by default, and does not know that option, so drop that option with Docker.
Custom bundle with Kubernetes
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-ca-bundle
data:
cert.pem: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
... more certificates if needed ...
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
# Use quay.io/hummingbird/python for urllib only
# Use your derived image with requests installed for both libraries
image: registry.example.com/my-python-with-requests:latest
env:
- name: REQUESTS_CA_BUNDLE
value: /etc/pki/tls/cert.pem
volumeMounts:
- name: custom-ca
mountPath: /etc/pki/tls/cert.pem
subPath: cert.pem
readOnly: true
- name: empty-certs
mountPath: /etc/pki/tls/certs
readOnly: true
volumes:
- name: custom-ca
configMap:
name: custom-ca-bundle
- name: empty-certs
emptyDir: {}
Custom bundle on OpenShift with CA injection
On OpenShift, the cluster admin may have already added your organization’s CA certificates to the cluster-wide trust store. You can use OpenShift’s automatic CA injection feature to make these certificates available to your pods.
Create a ConfigMap with the config.openshift.io/inject-trusted-cabundle=true label. OpenShift will automatically populate it with the cluster CA bundle as a key named ca-bundle.crt:
# OpenShift will inject a "ca-bundle.crt" into this automatically
apiVersion: v1
kind: ConfigMap
metadata:
name: trusted-ca
labels:
config.openshift.io/inject-trusted-cabundle: "true"
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
# Use quay.io/hummingbird/python for urllib only
# Use your derived image with requests installed for both libraries
image: registry.example.com/my-python-with-requests:latest
env:
- name: REQUESTS_CA_BUNDLE
value: /etc/pki/tls/cert.pem
volumeMounts:
- name: trusted-ca
mountPath: /etc/pki/tls/cert.pem
subPath: ca-bundle.crt
readOnly: true
- name: empty-certs
mountPath: /etc/pki/tls/certs
readOnly: true
volumes:
- name: trusted-ca
configMap:
name: trusted-ca
- name: empty-certs
emptyDir: {}
The key detail is using subPath: ca-bundle.crt to mount OpenShift’s injected file to the correct location (/etc/pki/tls/cert.pem) that Python expects.
See the Configuring a custom PKI OpenShift documentation for details on cluster-wide CA configuration.
Approach 2: Add Custom CAs
Use this when you want to merge your custom CAs with the system defaults.
Mount your CA certificate as an individual file in /etc/pki/tls/certs/ with a properly hashed filename. The filename must be the output of openssl x509 -noout -subject_hash -in ca.crt followed by .0.
Also set $REQUESTS_CA_BUNDLE to that directory:
Custom CA file with Podman
# Generate the hashed filename
CA_HASH=$(openssl x509 -noout -subject_hash -in ca.crt)
echo "Hashed filename: ${CA_HASH}.0"
# Mount the CA certificate as an individual file in the certs directory
podman run --rm \
-v ./ca.crt:/etc/pki/tls/certs/${CA_HASH}.0:ro,Z \
-e REQUESTS_CA_BUNDLE=/etc/pki/tls/certs/ \
localhost/my-python-with-requests python3 -c "
import urllib.request
print(urllib.request.urlopen('https://your-server/').status)
print(urllib.request.urlopen('https://google.com/').status) # Default CAs still work
import requests
print(requests.get('https://your-server/').status_code)
print(requests.get('https://google.com/').status_code) # Default CAs still work
"
Custom CA file with Kubernetes
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-ca
data:
ca.crt: |
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
---
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
# Use quay.io/hummingbird/python for urllib only
# Use your derived image with requests installed for both libraries
image: registry.example.com/my-python-with-requests:latest
env:
- name: REQUESTS_CA_BUNDLE
value: /etc/pki/tls/certs/
volumeMounts:
- name: custom-ca
# REQUIRED: replace example hash with: `openssl x509 -noout -subject_hash -in ca.crt` and append .0
mountPath: /etc/pki/tls/certs/12abc456.0
subPath: ca.crt
readOnly: true
volumes:
- name: custom-ca
configMap:
name: custom-ca