Kuadrant / Kuadrant/architecture
Migrate all Kuadrant component images to Red Hat Hardened Images
- Dominant language
- No language data
- Stars
- 3
- Forks
- 16
- Avg merge
- 7d 11h
- Merged PRs (30d)
- 2
Description
## Motivation
Kuadrant's container images currently use **three different base image strategies** across seven components: Google distroless, UBI 9, and UBI 10. This fragmentation creates an inconsistent security and support posture.
Red Hat has released **[Red Hat Hardened Images](https://www.redhat.com/en/products/hardened-images)** (formerly Project Hummingbird) — a GA, free-of-charge catalog of minimal distroless container images that are:
- **Supported under the standard OpenShift SLA** for RHEL/OpenShift subscribers
- **Freely redistributable** (like UBI)
- **Built via Red Hat's SLSA Level 3 pipeline** with verifiable supply chain
- **Significantly smaller than UBI** (comparable to Google distroless)
- **Available with FIPS-validated crypto variants** (Go)
Migrating all components to Red Hat Hardened Images unifies the image strategy, optimizes image sizes, and provides Red Hat support coverage — without sacrificing the minimal footprint that distroless offers.
## Current State
| Component | Builder Image | Runtime Image |
|---|---|---|
| Kuadrant Operator | `golang:1.26` | `gcr.io/distroless/static:nonroot` |
| DNS Operator | `mirror.gcr.io/library/golang:1.26` | `gcr.io/distroless/static:nonroot` |
| Limitador Operator | `mirror.gcr.io/library/golang:1.26` | `gcr.io/distroless/static:nonroot` |
| Authorino Operator | `registry.access.redhat.com/ubi10/go-toolset:1.26` | `registry.access.redhat.com/ubi9-minimal:latest` |
| Authorino | `registry.access.redhat.com/ubi10/go-toolset:1.26` | `registry.access.redhat.com/ubi9-minimal:latest` |
| Limitador | `mirror.gcr.io/library/rust:1.88` | `registry.access.redhat.com/ubi10/ubi-minimal:10.1` |
| Wasm Shim | `mirror.gcr.io/library/alpine:3.23` + manual rustup | `scratch` (OCI artifact) |
## Target State
| Component | Builder Image | Runtime Image |
|---|---|---|
| Kuadrant Operator | `registry.access.redhat.com/hi/go:1.26` | `registry.access.redhat.com/hi/static:latest` |
| DNS Operator | `registry.access.redhat.com/hi/go:1.26` | `registry.access.redhat.com/hi/static:latest` |
| Limitador Operator | `registry.access.redhat.com/hi/go:1.26` | `registry.access.redhat.com/hi/static:latest` |
| Authorino Operator | `registry.access.redhat.com/hi/go:1.26` | `registry.access.redhat.com/hi/static:latest` |
| Authorino | `registry.access.redhat.com/hi/go:1.26` | `registry.access.redhat.com/hi/static:latest` |
| Limitador | `registry.access.redhat.com/hi/rust:latest` | `registry.access.redhat.com/hi/core-runtime:latest` |
| Wasm Shim | `registry.access.redhat.com/hi/rust:latest` | `scratch` (unchanged — OCI artifact) |
### Why These Targets
- **`hi/static`** — For all Go operators (built with `CGO_ENABLED=0`). Contains only CA certs, tzdata, and a nonroot user (UID 65532). No glibc, no shell. Drop-in replacement for `gcr.io/distroless/static:nonroot`.
- **`hi/core-runtime`** — For Limitador (Rust binary dynamically linked to glibc). Includes minimal glibc runtime (~13 MB). Replaces UBI 10 minimal (~100+ MB).
- **`hi/go`** — Replaces all Go builder images with a unified Red Hat-provided Go build environment.
- **`hi/rust`** — Replaces Rust builder images. Available versions: 1.94, 1.97.
- **`scratch`** — Wasm Shim stays on `scratch` since it's a pure OCI artifact.
## Migration Groups
### Group 1: Go Operators — Distroless-to-Distroless (Low complexity)
Near drop-in replacement. Both `distroless/static:nonroot` and `hi/static` share the same design.
**Changes per repo:**
1. Update builder `FROM` line to `registry.access.redhat.com/hi/go:1.26`
2. Update runtime `FROM` line to `registry.access.redhat.com/hi/static:latest`
3. Verify `USER` directive compatibility (both use UID 65532 / `nonroot`)
4. Update Dockerfile comments
**Components:**
- [ ] `kuadrant/kuadrant-operator`
- [ ] `kuadrant/dns-operator`
- [ ] `kuadrant/limitador-operator`
### Group 2: Go Operators — UBI-to-Distroless (Medium complexity)
Requires removing package installation, user creation, and permission setup that the hardened image handles natively.
**Changes per repo:**
1. Update builder `FROM` to `registry.access.redhat.com/hi/go:1.26`
2. Update runtime `FROM` to `registry.access.redhat.com/hi/static:latest`
3. Remove `microdnf install` of `shadow-utils`
4. Remove `useradd` command (built-in `nonroot` user at UID 65532)
5. Remove `chown`/`chmod` permission setup
6. Update `USER` directive to `nonroot` (65532)
7. Simplify to flat binary layout (e.g., `/manager` or `/authorino` at root)
**Components:**
- [ ] `kuadrant/authorino-operator`
- [ ] `kuadrant/authorino`
### Group 3: Rust Binary — UBI-to-Distroless (Medium-High complexity)
Rust version bump (1.88 → 1.94+), dynamic linking dependency verification, and three Dockerfiles to update (amd64, aarch64, s390x).
**Changes:**
1. Update builder `FROM` lines across all three Dockerfiles to `registry.access.redhat.com/hi/rust:latest`
2. Update runtime `FROM` lines to `registry.access.redhat.com/hi/core-runtime:latest`
3. Remove `microdnf install` of `libgcc libstdc++ shadow-utils`
4. Remove `useradd`, `chown`/`chmod` commands
5. Update `USER` directive to `nonroot` (65532)
6. Verify build dependencies (`protobuf-compiler`, `clang`) availability in `hi/rust`
7. Verify `core-runtime` provides needed shared libraries (`libgcc`, `libstdc++`)
8. Test all three architectures
**Key risk:** Cross-compilation Dockerfiles install toolchains via `apt`. If `hi/rust` has no package manager, may need to keep non-HI builder for cross-compile Dockerfiles while still migrating the runtime stage to `hi/core-runtime`.
**Components:**
- [ ] `kuadrant/limitador`
### Group 4: Wasm Shim — Builder Only (Low priority, can be deferred)
Only the builder changes; runtime (`scratch`) is already optimal.
**Changes:**
1. Runtime: **No change** — stays `FROM scratch`
2. Builder: Replace Alpine + manual rustup with `registry.access.redhat.com/hi/rust:latest` + `rustup target add wasm32-wasip1`
3. Verify `protoc` and build tool availability
**Components:**
- [ ] `kuadrant/wasm-shim`
## Suggested Execution Order
1. **Group 1** (Kuadrant Operator, DNS Operator, Limitador Operator) — lowest risk, builds confidence
2. **Group 2** (Authorino Operator, Authorino) — moderate changes, well-understood Go patterns
3. **Group 3** (Limitador) — highest complexity, benefits from lessons learned
4. **Group 4** (Wasm Shim) — deferred / best-effort
## OpenShift Compatibility
All target images are OpenShift-ready without special configuration:
- **UID handling:** `hi/static` and `hi/core-runtime` default to UID 65532 (`nonroot`). On OpenShift with `restricted-v2` SCC, the platform assigns a random UID — containers still work because these binaries don't depend on `/etc/passwd` lookups.
- **GID 0:** OpenShift adds the container process to GID 0. Since the binaries are read-only executables at fixed paths, no writable paths need GID 0 permissions.
- **Bare Kubernetes:** Same images work unchanged.
## Risks and Considerations
1. **Rust version bump for Limitador:** HI Rust is at 1.94/1.97 vs current 1.88. Run full test suite.
2. **Cross-compilation for Limitador:** `Dockerfile.aarch64` and `Dockerfile.s390x` install cross-compile toolchains via `apt`. HI Rust has no `apt`. May need hybrid approach (non-HI builder + HI runtime).
3. **HI image tagging:** `hi/static` currently only offers `:latest`. Consider pinning by digest (`@sha256:...`) for reproducible builds.
4. **HI is not UBI:** Built from upstream sources, not RHEL packages. Cannot be mixed with RHEL RPMs. Fine for upstream builds.
5. **Build dependencies:** Limitador needs `protobuf-compiler` and `clang` at build time. Verify availability in `hi/rust` or its `-builder` variant.
## Acceptance Criteria
- [ ] All runtime images use `hi/static` or `hi/core-runtime`
- [ ] All Go builder images use `hi/go`
- [ ] Rust builder images use `hi/rust` where feasible
- [ ] All components pass existing CI (unit + integration tests)
- [ ] Images build and run successfully on both plain Kubernetes and OpenShift
- [ ] Image sizes are equal to or smaller than current images
## References
- [Red Hat Hardened Images Product Page](https://www.redhat.com/en/products/hardened-images)
- [Exploring distroless containers with Project Hummingbird](https://developers.redhat.com/articles/2026/04/28/exploring-distroless-containers-project-hummingbird)
- [Red Hat Hardened Images Documentation](https://docs.redhat.com/en/documentation/red_hat_hardened_images/1-latest/html/build_and_deploy_secure_minimal_containers_with_red_hat_hardened_images/introduction-to-red-hat-hardened-images)
- [RHEL Container Compatibility Matrix](https://access.redhat.com/support/policy/rhel-container-compatibility)
- [Red Hat UBI vs. Red Hat Hardened Images: How to choose](https://developers.redhat.com/articles/2026/06/29/red-hat-ubi-vs-red-hat-hardened-images-how-to-choose)
Contributor guide
Research direction
Begin with the Group 1 repositories—kuadrant-operator, dns-operator, and limitador-operator—and inspect their Dockerfiles and existing CI. Then review the Authorino and Limitador Dockerfiles, including Dockerfile.aarch64 and Dockerfile.s390x, for package, user, and cross-compilation dependencies. Done means the target images build successfully, existing unit and integration tests pass, and all components meet the stated Kubernetes and OpenShift acceptance criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, go, kubernetes, rust
- Domain
- build-system, devops, infrastructure
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 35/100