kURL: a kubeadm installer that also handles the airgapped part
Production-grade, airgapped Kubernetes installer combining upstream k8s with overlays and popular components
At a glance
- What is it?
- A Replicated maintained installer that wraps kubeadm with pre and post tasks, ships a signed SBOM with every release, and pairs open source add-ons such as Rook, Contour and Velero with a Go CLI and a web UI.
- Who is it for?
- Adopt kURL if you are standing up Kubernetes in an environment with no internet access, or if you want the surrounding tasks around kubeadm init scripted and repeatable rather than hand-run. Do not adopt it if your target is a managed cluster or if you want the full control that comes from assembling kubeadm and CNI yourself, since kURL expresses its opinionated bundle.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The gap kURL fills is everything around kubeadm init
The description of the problem in the project notes is precise, and it is not that kubeadm is hard.
kURL relies on kubeadm to bring up the Kubernetes control plane. But there are a variety of tasks a system administrator must perform both before and after running kubeadm init in order to have a production-ready Kubernetes cluster. The examples given are installing Docker, configuring Pod networking and installing kubeadm itself. The purpose of the installer is to automate those tasks so that any user can deploy a Kubernetes cluster with a single script.
That framing explains the design better than the marketing phrase would. This is not a replacement for kubeadm; it is the layer that makes kubeadm usable repeatedly, which is what you need when you are provisioning more than one cluster or when you need to repeat the same install in a disaster recovery drill.
The airgap angle is the reason it exists at all rather than being a convenience feature. The repository topics name airgapped, bash, kubeadm, kubernetes-installer, ceph, contour and rook, so the add-on set is the storage and networking stack you would otherwise have to mirror and install by hand. An airgapped install needs every artefact pre-staged, and that is exactly the problem a scripted installer with a fixed bundle solves.
The project is Apache-2.0 licensed with the LICENSE file at the repository root, and the homepage is kurl.sh with documentation at kurl.sh/docs/.
A Go CLI, a web UI and a JavaScript watch layer
The repository is not a shell script collection, whatever the primary language field says. It is a Go codebase with a supporting web application.
The go.mod declares the module as github.com/replicatedhq/kurl on Go 1.27.2, and the dependency list is substantial and tells you what the tool actually does. Kubernetes client libraries at v0.37.1 across api, apimachinery, cli-runtime, client-go and code-generator, plus controller-runtime. Then `github.com/replicatedhq/kurlkinds` for the schema of the installer configuration, `github.com/replicatedhq/troubleshoot` for diagnostics, `github.com/replicatedhq/plumber/v2` for piping data between processes, and `github.com/replicatedhq/pvmigrate` for version migration of the config format.
The add-on dependencies are the interesting part, because they are the components the installer will deploy into your cluster: `github.com/rook/rook` at v1.21.0 for the storage operator, `github.com/longhorn/longhorn-manager` at v1.13.0 for the Longhorn storage system, `github.com/vmware-tanzu/velero` at v1.18.4 for backup and restore, and `github.com/minio/minio-go` for the MinIO client.
The web side is a separate package.json, private, with the `main` pointing at `bin/watchrsync.js` and three runtime dependencies: the AWS SDK S3 client, chokidar for file watching, and semver. That watcher is what lets a bundle definition be edited and the install reflect it without a manual reload.
The CLI itself uses cobra and viper, so it is a conventional Go command line application with a configuration file rather than a script with flags.
Signed SBOMs ship with every release, and you can check them
The SBOM section is the part of the project notes that reflects where supply chain expectations have landed.
Signed SBOMs for the Go and JavaScript dependencies are combined into a tar file and included with each release. There are three artefacts: kurl-sbom.tgz, which contains the SBOMs for the Go and JavaScript dependencies, kurl-sbom.tgz.sig, the digital signature for that tar file, and key.pub, the public key from the key pair used to sign it.
Verification uses cosign, and the documented command is short:
$ cosign verify-blob --key key.pub --signature kurl-sbom.tgz.sig kurl-sbom.tgz
Verified OKFor an installer that runs with root on a machine and is often pointed at an airgapped network, being able to verify the provenance of the build inputs offline is a real property, not a formality. The `.grype.yaml` file at the repository root suggests the SBOM is also used for vulnerability scanning in CI.
The release process is similarly explicit. Releases are created by a GitHub Workflow when a tag is pushed, and the tag format is `vYYYY.MM.DD-#`. The recent tags follow it exactly: v2026.10.18-1, v2026.10.13-0 and v2026.10.07-0.
For a maintainer, tagging from HEAD is a make target:
make tag-and-releaseand to tag a specific commit you pass the commit id:
make COMMIT_ID=<GITHUB_SHA> tag-and-releaseThe target enforces a clean git tree and a tag against the main branch, and the project notes document the escape hatch, calling the underlying script directly with `--no-main --outdated` when you need to override that.
Add-ons are open source but not all permissive
kURL offers several optional add-ons for cluster creation, and the README is unusually clear that the licensing situation is not uniform.
The add-ons are described as open source technology add-ons distributed under various open source licenses, which is the honest position but leaves the reader to check each one.
Two are called out. MinIO is available as an add-on for object storage, and its use is governed by the GNU AGPLv3 license. Prometheus via the Prometheus Operator is available for metrics and monitoring, and it includes Grafana, whose use is currently governed by the GNU AGPL v3 license.
The AGPL point deserves attention rather than a footnote. The core project is Apache-2.0, which is permissive with attribution. An AGPL component inside the cluster you build is a different matter, and the copyleft reach of AGPL extends to network use, so a SaaS built on top of that component has obligations the core project does not impose.
The list of add-ons in the repository topics also includes Ceph, Contour and Rook, and the topics name airgapped and kubernetes-cluster alongside them, which is the combination an airgapped production install needs: a storage operator, an ingress controller and a container image mirror.
Support for a question about using the tool goes to a Replicated community forum and a #kurl channel in Kubernetes Slack, and contributors are asked to comment on an existing issue or file a new one before starting work.
The repository layout shows the bundle model
The top level of the repository is where the design becomes visible.
There is an `addons/` directory, which holds the optional components, and a `bundles/` directory, which is where the install definitions live. A bundle is the thing that says which Kubernetes version, which add-ons and which configuration you want, and it is what you mirror into an airgapped network and what the installer consumes.
Then there are the parts of a normal Go repository: `cmd/` for command entry points, `pkg/` for library packages, `kurl_util/` for the utility library, and `packages/` alongside it. `bin/` holds scripts including the release script, `scripts/` and `hack/` hold more scripts, and `tools/` holds tooling.
The supporting directories tell you about the testing story. There is a `testgrid/` directory, which is the configuration for running tests across a grid of operating systems and versions, and `os-matrix.yaml` at the root defines that matrix. Because this tool installs Kubernetes across many Linux distributions and versions, its own test matrix has to be as broad as the one it ships.
There is also `design/` and `proposals/`, which is where design documents live, `ARCHITECTURE.md` at the root, `docs/` for documentation, and `web/` for the web UI. `CODEOWNERS` assigns reviewers per area.
The build system is a Makefile with a `##@` category convention that produces grouped help output, and it handles the macOS case explicitly, switching the in-place sed flag to a backup variant and skipping the dynamic library check when the host is Darwin.
Where kURL is the wrong choice
Three cases are worth naming.
The first is managed Kubernetes. If you are running GKE, EKS or AKS, none of this applies, because there is no kubeadm for you to install and no bundle to mirror.
The second is when you want full control of the install. kURL is opinionated by design: it ships a bundle of add-ons that it knows work together, and it pins versions of things like Rook, Longhorn, Velero and the Kubernetes libraries. That opinionation is what makes the airgapped case tractable, since you are getting a tested combination rather than assembling one. But it also means you are accepting a bundle rather than choosing every component and version yourself, and the `packages/` directory and the add-on mechanism are where you would extend it.
The third is the operational surface. The Go binary, the web UI, the watcher script and the add-on set together are a fair amount of machinery to own. For a single developer cluster that you rebuild by hand every few months, running kubeadm directly with a CNI you already know is less work.
The alternative to name is running kubeadm yourself with a separate tool for each of the tasks kURL bundles: a container runtime installer, a CNI manifest, an image mirroring tool such as a registry mirror or a pull-through cache, and a storage operator. The difference in approach is that kURL encodes a known-good combination and the mirror step, while manual setup lets you choose each piece but makes you responsible for every version and every offline artefact. For an airgapped install where you have to produce a mirror of tarballs and container images anyway, the scripted path is usually faster, which is the case kURL is built for.
Editorial conclusion
Adopt kURL if you are standing up Kubernetes in an environment with no internet access, or if you want the surrounding tasks around kubeadm init scripted and repeatable rather than hand-run. Do not adopt it if your target is a managed cluster or if you want the full control that comes from assembling kubeadm and CNI yourself, since kURL expresses its opinionated bundle. Verify first which add-ons you need and their licences, since some such as MinIO and Grafana are AGPL, and check that the version of kURL you pin matches the Kubernetes version your images are mirrored for.
Frequently asked questions
What is kURL and what problem does it solve?
It is a Kubernetes installer for airgapped and online clusters that relies on kubeadm for the control plane but automates the tasks a system administrator has to do before and after kubeadm init, such as installing Docker, configuring Pod networking and installing kubeadm, so a cluster can be deployed with a single script.
What is a kURL bundle?
A bundle is the install definition that says which Kubernetes version, which add-ons and which configuration to use, and it is what you mirror into an airgapped network. The repository has a bundles/ directory for them and an addons/ directory for the optional components such as Rook, Longhorn, Contour, Velero and MinIO.
How do I verify a kURL release?
Every release includes kurl-sbom.tgz with the SBOMs for the Go and JavaScript dependencies, kurl-sbom.tgz.sig as its signature, and key.pub as the public key. You check them with cosign verify-blob --key key.pub --signature kurl-sbom.tgz.sig kurl-sbom.tgz.
Are all kURL add-ons under the same licence?
No. The core project is Apache-2.0, but the add-ons are distributed under various open source licences. MinIO is governed by GNU AGPLv3, and Grafana, which comes with the Prometheus Operator add-on, is currently governed by GNU AGPL v3.
How are kURL releases tagged?
Releases are created by a GitHub Workflow when a tag is pushed, following the format vYYYY.MM.DD-#. A maintainer runs make tag-and-release from HEAD, or make COMMIT_ID=<GITHUB_SHA> tag-and-release for a specific commit, with the target enforcing a clean git tree and a tag against the main branch.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/replicatedhq-kurl)Was this useful?