There’s a class of infrastructure problem that most developers never encounter: deploying software to networks that have no internet access. Air-gapped networks—completely isolated from the public internet—are the norm in classified government environments, critical infrastructure, and highly regulated industries. If you’ve ever tried to run helm install in one of these environments, you know the unique joy of watching everything fail because nothing can reach the internet.
Zarf solves this problem. It’s a tool built specifically to package, transport, and deploy Kubernetes applications in disconnected environments. And it’s genuinely good.
What Zarf Actually Does
Zarf bundles everything required to deploy a Kubernetes application—container images, Helm charts, manifests, init scripts, and even a local container registry and package manager—into a single compressed archive. You build this bundle in a connected environment, transfer it to your air-gapped network (physically, on a USB drive or a secure transfer mechanism), and deploy it there.
The bundle is self-contained. No external network calls. No pulling images from Docker Hub. No downloading Helm charts. Everything is already in the package.
The Zarf Package
A Zarf package is defined by a zarf.yaml file:
kind: ZarfPackageConfig
metadata:
name: my-application
description: "My application for air-gapped deployment"
version: 1.0.0
components:
- name: my-app
required: true
charts:
- name: my-app
url: https://my-helm-repo.example.com
version: 2.1.0
namespace: my-app
valuesFiles:
- values.yaml
images:
- myregistry.example.com/my-app:2.1.0
- myregistry.example.com/sidecar:1.0.0
repos:
- https://github.com/my-org/my-config.git
When you run zarf package create, Zarf:
- Downloads the Helm chart
- Pulls all referenced container images
- Clones specified repositories
- Packages everything into a compressed
.zstarchive with an OCI-compatible structure
The result is a single file you can move however you move files to your air-gapped network.
Deploying in the Air Gap
On the receiving end:
# Transfer my-application-1.0.0-amd64.tar.zst to the air-gapped network
# Then:
zarf package deploy my-application-1.0.0-amd64.tar.zst
Zarf handles everything:
- Pushing images to the local Zarf-managed registry
- Installing the Helm chart with updated image references pointing to the local registry
- Applying manifests
- Running any init scripts
Zarf Init Package
One of Zarf’s best features is the “init” package. Before you can deploy anything, you need a Kubernetes cluster with a container registry. Zarf ships an init package that bootstraps:
- A local container registry (a Harbor or Crane registry)
- A Git server (Gitea) for air-gapped GitOps
- An optional K3s cluster if you don’t have Kubernetes yet
# Get the init package (downloaded in connected environment)
zarf tools download-init
# Deploy it in the air gap
zarf init
After zarf init, you have a functioning Kubernetes cluster with a local registry and Git server. Then you deploy your application packages on top.
GitOps in an Air Gap
Combining Zarf with Flux creates a powerful air-gapped GitOps workflow:
- In the connected environment: build a Zarf package containing your Flux configuration and all required Helm charts/images
- Transfer the package to the air gap
- Deploy with Zarf, which pushes images to the local registry and charts to the local Gitea instance
- Flux (running in the cluster) reconciles from the local Gitea server
The result: full GitOps capability in an environment with no external connectivity. Changes to your configuration in the local Gitea trigger Flux reconciliation, just like a cloud GitOps workflow but entirely self-contained.
# Flux HelmRepository pointing to local Zarf-managed Gitea
apiVersion: source.toolkit.fluxcd.io/v1
kind: HelmRepository
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1h
url: http://zarf-gitea-http.zarf.svc.cluster.local:3000/zarf-git-user/mirror__my-helm-repo
Image Reference Rewriting
One of Zarf’s clever features is automatic image reference rewriting. Your Helm charts reference images from docker.io/library/nginx:1.25. In the air-gapped cluster, that image lives in your local registry at 127.0.0.1:5000/library/nginx:1.25. Zarf automatically rewrites all image references in your Helm charts during deployment—you don’t have to maintain separate air-gapped versions of your charts.
This is huge. It means you can use upstream, unmodified Helm charts in air-gapped environments without maintaining forks.
Compliance and Security
For DoD and government environments, Zarf’s supply chain security features matter:
- Package signing: Zarf packages can be signed with cosign. Before deploying, verify the signature to ensure the package hasn’t been tampered with during transit.
- SBOM generation: Zarf automatically generates Software Bill of Materials (SBOM) for all images in a package, documenting every component.
- Checksums: Every file in a Zarf package is checksummed and verified on deployment.
# Sign a package
zarf package create --signing-key my-key.key
# Verify before deploying
zarf package deploy --key my-key.pub my-application-1.0.0-amd64.tar.zst
The Namespace Bypass
If you’re running Zarf alongside other tooling that intercepts namespace operations (like certain admission controllers), you can configure namespaces to bypass Zarf’s management. This matters in heterogeneous environments where Zarf coexists with other platform tooling.
When Not to Use Zarf
Zarf is purpose-built for air-gapped and disconnected environments. If you have reliable internet access, it adds complexity without proportional benefit. For connected Kubernetes clusters, stick with Flux/Argo CD and pull images from public registries directly.
But for the scenarios where it’s relevant—classified networks, ships, submarines, remote facilities, nuclear plants, financial systems with extreme network segmentation—Zarf is the best tool that exists. There was nothing like it before, and it’s filled a genuine void.
Getting Started
# Install Zarf
brew install defenseunicorns/tap/zarf # Mac
# or download from https://github.com/defenseunicorns/zarf/releases
# Create your first package
mkdir my-zarf-package && cd my-zarf-package
# Create zarf.yaml
zarf package create .
# Deploy in connected environment first to validate
zarf package deploy my-package.tar.zst
The Defense Unicorns team (who built Zarf) has excellent documentation and the tool is actively maintained. If you’re dealing with air-gapped deployments and aren’t using Zarf, you’re working harder than you need to.