On June 3, 2025, Google made the GoogleContainerTools/kaniko repository read-only. No more commits, no more pull requests, no more releases from the team that built it — the tool that made "build a container image inside a Kubernetes pod, without a Docker daemon and without root" a solved problem for half the industry's CI pipelines just stopped moving. If your git-push PaaS builds tenant images inside unprivileged Kubernetes pods, and a nontrivial share of those builds fall back to a Dockerfile instead of Cloud Native Buildpacks' auto-detection, kaniko is very likely the tool doing that work today. This is what actually changes if you move it to Buildah.
Archived Doesn't Mean Gone, But It Does Mean Frozen
Within a day of Google's announcement, Chainguard forked the project — chainguard-forks/kaniko shipped its first release inside a week, staffed in part by Priya Wadhwa and Dan Lorenc, two of kaniko's original creators, now both at Chainguard. That's a faster, more credible continuity story than most archived CNCF-adjacent tools get. But read the fork's own scope carefully: it exists to patch CVEs and merge minor bug fixes on a best-effort basis. No new features are planned. It's life support, not a roadmap — and life support is exactly the wrong foundation for a component sitting in the critical path of every tenant's git push.
Buildah, by contrast, is still moving. Version 1.44.0 shipped May 27, 2026, out of the same containers/ GitHub organization that maintains Podman and Skopeo — a Red Hat-backed, daemonless, OCI-native toolchain with an actual release cadence, not a maintenance-only holding pattern. That's the real asymmetry driving 2026's builder comparisons: it isn't "which tool is better," it's "one of these two projects can still absorb a feature request or a new Kubernetes security default, and one of them structurally can't."
Two Build Paths, Not One — and Only One of Them Touches This Choice
Before touching any YAML, it's worth being precise about where a builder like kaniko or Buildah actually sits in a buildpacks-based platform, because the naive framing — "swap kaniko for Buildah everywhere" — describes a system most Cloud Native Buildpacks (CNB) platforms don't actually run.
A CNB build has two distinct paths:
- The buildpacks-native path. When a repo matches a buildpack's detection (a
package.json, aGemfile, ago.mod), the CNB lifecycle's ownexporterphase constructs and pushes the final OCI image directly, using its own Go image libraries. No kaniko, no Buildah, no Dockerfile involved at all. This is the majority path for a git-push PaaS defaulting new repos to buildpacks. - The Dockerfile-fallback path. For the repos that don't fit buildpack auto-detection — an unusual build step, a multi-service Dockerfile, a tenant who just wrote one — the platform needs its own general-purpose Dockerfile builder running inside an unprivileged Kubernetes pod. This is where kaniko or Buildah actually gets invoked.
Kaniko-to-Buildah migration is a path-2 problem. It changes nothing about how the majority of buildpack-detected builds run. What it changes is the pod spec, caching model, and registry auth for the fallback path every buildpacks platform still needs, because "recommend buildpacks, require a Dockerfile" is a worse default than "recommend buildpacks, fall back to a Dockerfile automatically."
The Pod Spec Diff
Kaniko's whole design pitch was avoiding privileged operations by snapshotting the filesystem directly rather than mounting an overlay filesystem — it needs no /dev/fuse, no elevated storage-driver capabilities, just a plain unprivileged container. Buildah's rootless mode gets there differently, and the pod spec has to reflect it.
A kaniko build pod is close to the Kubernetes default: run as a non-root UID, mount a registry-credentials secret, point --dockerfile and --destination at the build context and target tag, done. A Buildah build pod needs three additions that a naive lift-and-shift will miss:
securityContext:
runAsUser: 1000
runAsGroup: 1000
capabilities:
add: ["SETUID", "SETGID"]
env:
- name: BUILDAH_ISOLATION
value: "chroot"
- name: STORAGE_DRIVER
value: "overlay"SETUID/SETGID let Buildah's rootless user-namespace remapping work without a full privileged container. BUILDAH_ISOLATION=chroot picks the isolation mode that doesn't require the CAP_SYS_ADMIN a plain container sandbox won't grant. The storage driver is the part worth getting right the first time: on a kernel 5.13+ node — which any reasonably current Cluster API-managed fleet is running — native rootless overlay works out of the box with no /dev/fuse device needed at all. fuse-overlayfs is now a fallback for older kernels, not the default recommendation it was a couple of years ago, and vfs is the last-resort option that works everywhere but is meaningfully slower on anything but a trivial image. Get the storage driver wrong and Buildah still builds — it just silently falls back to the slow path, and the first symptom is a support ticket about "builds got slower," not an error.
The Caching Model Is a Genuine Architecture Decision, Not a Flag Swap
This is the part of the migration a pod-spec diff won't warn you about. Kaniko's --cache=true --cache-repo pushes and pulls layer cache through the same container registry the final image lands in — which means the cache is stateless from the pod's point of view. Every build pod is disposable; the registry is the only thing that needs to persist. That property is a near-perfect match for the ephemeral, horizontally-scaled build-pod model a Cluster API-managed fleet already runs.
Buildah's cache is local: faster to read and write than a network round-trip to a registry, but it lives on the pod's own storage, which means it dies with the pod unless something makes it not. Move to Buildah without changing anything else and you haven't broken builds — you've silently turned every build cold, because the next build pod the scheduler places has none of the previous pod's cache. The fix is a real infrastructure addition, not a config flag: either a PersistentVolumeClaim mounted at Buildah's storage path and reused across build pods for the same tenant (works, but reintroduces state into a fleet that was deliberately stateless), or a shared cache volume keyed by base image and dependency lockfile hash that multiple build pods can attach to concurrently. Either way, budget this as its own line item in the migration, not a footnote — it's the difference between Buildah matching kaniko's incremental-rebuild speed and regressing every tenant's build time the week you ship the switch.
Registry Push Auth: Different Mechanism, Same Shape
The good news is that registry authentication maps over cleanly, even though the exact convention differs. Kaniko reads Docker's standard config.json credential format, typically mounted into the pod at /kaniko/.docker/config.json from a Kubernetes secret, and understands the usual cloud credential helpers (ECR, GCR, GAR) natively in its executor binary. Buildah, via the same containers/image library that backs Podman and Skopeo, reads an equivalent auth file — pointed at via the REGISTRY_AUTH_FILE environment variable or a --authfile flag on buildah push — and supports the same docker-credential-* helper binaries for cloud registries.
| Kaniko | Buildah | |
|---|---|---|
| Auth file format | Docker config.json | containers-auth.json (same JSON shape) |
| How it's supplied | Mounted secret at /kaniko/.docker/config.json | Mounted secret + REGISTRY_AUTH_FILE env var |
| Cloud credential helpers | Built into the executor | Standard docker-credential-* binaries on $PATH |
Practically: the same Kubernetes secret object that already holds registry push credentials for kaniko can be reused for Buildah with a different mount path and one environment variable — this is the one piece of the migration that's close to a mechanical swap.
The Catch You Can't Migrate Away From
Here's the part most Buildah-vs-Kaniko comparisons skip, and it's the reason "get off kaniko" isn't a fully achievable goal for a buildpacks platform even after this migration ships. The CNB lifecycle itself — the same binary that runs the buildpacks-native detect/build/export phases described above — uses kaniko as an internal Go library dependency to implement its extend phase: applying build.Dockerfile/run.Dockerfile output from image extensions onto the builder or run base image. This isn't a platform-level choice a git-push PaaS makes; it's baked into the lifecycle you run regardless of which builder handles your own Dockerfile fallback path.
The CNB maintainers know this is a problem. Spec issue #414, "Decouple extend phase from kaniko," states it plainly: kaniko "has fallen into unmaintained status, making it impractical and undesirable to rely on this dependency," and proposes letting platforms "bring their own extender" instead of the lifecycle hard-depending on kaniko's code. As of this writing that decoupling hasn't shipped as a stable, generally available option — which means a platform using CNB image extensions at all is still running kaniko-derived code inside its build pipeline, just one layer further down and entirely out of its own control to swap. You can migrate the Dockerfile-fallback path you operate directly. You can't currently migrate the part of the buildpacks lifecycle you don't operate at all.
For a platform that doesn't use image extensions, this is moot — the extend phase never runs. For one that does, it's worth stating precisely in any internal migration writeup: "we removed our direct kaniko dependency" and "we removed kaniko from our pipeline" are not the same claim, and conflating them is the kind of thing that surfaces awkwardly in a security review six months later.
What This Actually Buys a Cluster API-Managed Fleet
None of this changes what tenants see. A git push still produces a running HTTPS service either way — that's the entire point of keeping the builder an implementation detail rather than something a tenant configures. What it changes is whether the fallback path a platform's own Dockerfile builds run through is still receiving security patches from an actively maintained upstream five years from now, or quietly depending on a fork whose maintainers have explicitly scoped their own commitment to "CVEs and minor bug fixes, best effort." For infrastructure sitting in the build path of every tenant that doesn't fit buildpack auto-detection, that's not a marginal distinction — it's the whole reason to make the move before the fork's best-effort maintenance becomes the thing you're depending on during an incident.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, built on Cluster API and Cloud Native Buildpacks by default. Star the repo on GitHub or deploy your first app today.
Sources
- State of Kaniko: Unmaintained? — GoogleContainerTools/kaniko Issue #3348
- Fork Yeah: We're Bringing Kaniko Back — Chainguard
- chainguard-forks/kaniko — GitHub
- Decouple extend phase from kaniko — buildpacks/spec Issue #414
- Extend — Cloud Native Buildpacks docs
- What is an image extension? — Cloud Native Buildpacks docs
- Rootless container builds on Kubernetes — Kubernetes @ CERN
- Kaniko vs. Buildah: Rootless, Daemonless Container Builds in Kubernetes — ayedo
- Buildah Release Announcements — buildah.io
All figures and dates above are drawn directly from the linked sources.



