Foundations: what 'disconnected' really means and the four supply chains
What changes when you take the public internet off the install path. The four supply chains a disconnected cluster has to solve, the threat model that drives them, and the evidence trail you'll learn to produce.
Before you write your first imageset-config.yaml, it helps to be clear about what disconnected install actually changes and what it doesn’t. The cluster’s behaviour at runtime is mostly the same. The thing that changes is what the cluster is allowed to need from outside. This module sets the framing.
What “disconnected” means in practice
A disconnected OpenShift cluster is one where the cluster nodes have no route to the public internet at install time or runtime. That’s a stronger claim than it sounds:
| Common interpretation | Whether it counts as disconnected |
|---|---|
| ”We have a proxy to the internet” | No. Proxied still means the cluster eventually talks to quay.io. |
| ”Outbound is allowed from the bastion only” | Depends. If the cluster pulls through that bastion, no. If you mirror once on the bastion and the cluster never pulls externally, yes. |
| ”The cluster has an outbound allowlist” | No. Allowlisting *.redhat.com is still connected install. |
| ”The cluster is on an air-gapped fabric” | Yes. |
| ”The cluster is on a private VRF with no NAT” | Yes. |
| ”Workloads cannot reach the internet, but the cluster can” | No. The cluster’s posture is what defines disconnected. |
The acid test: set a default deny egress firewall on the cluster’s machine network. If the cluster installs and runs healthy through 30 days of operator upgrades, you’re disconnected.
Why the public internet drops off the install path
Three reasons cover most engagements:
- Regulatory — BFSI, healthcare, defence, telecom, OT/ICS. PCI-DSS, HIPAA, NIS2, IEC 62443, FedRAMP-Moderate all have controls that disfavour or forbid cluster-side outbound from production workload subnets.
- Operational — air-gapped sites with intermittent, expensive, or untrusted uplinks. Submarines, ships, ports, mines, oil platforms, plant floors, edge stores in countries with adversarial CDN posture.
- Defensive — supply-chain-attack containment. If a malicious operator bundle hits
registry.redhat.iofor a few hours, a connected cluster pulling on schedule may import it; a disconnected cluster only imports what an operator put into the ImageSet and approved into the mirror.
For most teams it’s a mix — regulation requires the disconnected posture, defence-in-depth is the bonus, and the operational complexity is what you trade against the bonus.
The four supply chains
The single most important framing in this track is that disconnected install isn’t one supply chain to solve. It’s four, each with its own source, transport, custody, and verification.
| # | Supply chain | What it contains | Tool | Lands in |
|---|---|---|---|---|
| 1 | Release payload | The OpenShift release image, every ClusterOperator image, RHCOS, openshift-install itself. | oc mirror --v2 | Mirror registry (Quay) |
| 2 | Operator catalog | Red Hat operator-index + certified-operator-index, the bundles those indexes reference, every related operand image. | oc mirror --v2 | Mirror registry (Quay) |
| 3 | Additional images | UBI base images, in-house “golden” images, CI/CD utility images, helper images. | skopeo copy or oc mirror’s additional-images block | Mirror registry (Quay) |
| 4 | Install-time inputs | The merged pull-secret, SSH key, CA trust bundle, custom CA certs, network plan. | Vault + a render host | Rendered install-config.yaml on the render host |
A team that maps each line to “this script runs on this host, the output lands in this place, this artefact proves it” can install a disconnected cluster. A team that thinks “disconnected means mirror the registry” will get to bootstrap-complete and then watch openshift-marketplace fill with ImagePullBackOff catalog pods.
The supporting service stack
The four supply chains depend on a small set of supporting services. The Day-0 question of any disconnected install is do all of these exist and respond healthy?
| Role | Why it exists | What the lab uses |
|---|---|---|
| Private DNS | Cluster API VIPs, ingress VIPs, master/worker hostnames must resolve in-network. The public internet is not consulted. | PowerDNS authoritative + recursor, on gf-ocp-pdns-01. |
| Edge ingress + TLS | Wildcard cert termination for VM-hosted tools; routes between VMs. | HAProxy on gf-ocp-haproxy-01. |
| Object storage | Blob backend for the registry, backup target for the registry, observability/log storage later. | MinIO. |
| Source control | The GitOps repo. The ImageSet config under version control. Operator-bumps as MRs. | GitLab CE on gf-ocp-gitlab-01. |
| Secret custody | Pull-secret, robot tokens, kubeconfigs, backup passphrases. Anything that’s not in Git. | Vault three-node Raft on gf-ocp-vault-r1-0[123]. |
| CMDB / IPAM | Authoritative IP/MAC/hostname assignment to prevent install-config collisions. | NetBox on gf-ocp-netbox-01. |
| Mirror registry | The blob server every cluster image pull eventually hits. | Quay standalone on gf-ocp-quay-01. |
| Mirror runner | The host that runs oc mirror --v2 with internet access — the only path internet content takes in. | The hypervisor itself (dl385-2) or a dedicated VM. |
| Render / operator host | Holds the merged pull-secret, runs openshift-install, produces the agent ISO. | gf-ocp-bootstrap-01 (a small Ubuntu VM). |
The track’s Module 02 walks through each of these in the order you’d stand them up. The order matters: object storage before registry, DNS before TLS, source control before GitOps, secret custody before anything that has a secret.
The threat model that drives the design
If you skim the lab manifests, three patterns will keep showing up. They all come from the same threat model:
- The cluster cannot pull from a host you didn’t intend it to. That’s why IDMS/ITMS rewrite every upstream registry reference to the mirror at the node level. That’s why default
OperatorHubsources are disabled. That’s why built-in OLM v1ClusterCatalogobjects are set toavailabilityMode: Unavailable. The cluster cannot pull fromregistry.redhat.ioeven if a workload manifest says it should. - A compromised mirror can poison the cluster. That’s why the install path verifies release signatures via signature ConfigMaps. That’s why operator catalogs ship as digest-pinned indexes. That’s why
Subscriptions carrystartingCSV— to prevent a re-mirror from silently advancing the cluster onto a digest nobody reviewed. - A compromised operator workstation can poison the mirror. That’s why pull-secrets live in Vault, never on disk where shell history can leak them. That’s why backup passphrases live in Vault. That’s why
oc mirrorruns from a dedicated host, not the operator’s daily laptop. That’s why the GitOps repo, not a console UI, is the change interface.
The disconnected posture isn’t paranoia — it’s an attempt to make the supply chain inspectable. Every artefact that lands in the cluster has a paper trail back to a reviewed change in Git.
The evidence trail
A useful litmus test for a disconnected install: pick any image running on the cluster — say, cluster-version-operator — and trace it back through six artefacts:
- The running pod’s
spec.containers[].image— a digest pin onquay.v7.comptech-lab.com/openshift-release/openshift/release-images@sha256:.... - The IDMS that rewrote it from
quay.io/openshift-release-dev/ocp-release@sha256:...to the mirror path. - The
oc-mirrormapping.txtentry from the most recent mirror pass. - The
imageset-config.yamlin Git that asked for that release. - The merge request that bumped the ImageSet to its current commit, with the reviewer’s name.
- The
oc adm release infodigest match against the upstream release.
A team that can produce that chain for any image has a healthy disconnected install. A team that can’t is one re-mirror away from a surprise. Module 10 (Day-2 mirror ops) builds the tooling that makes this chain inspectable in seconds.
What changes vs a connected install
| Stage | Connected | Disconnected |
|---|---|---|
| Get installer | curl mirror.openshift.com/.../openshift-install-linux.tar.gz | Same, once, on the mirror runner. The cluster never reaches it. |
| Pull secret | Red Hat customer pull-secret only | Merged pull-secret: customer + mirror-registry credential |
install-config.yaml | No imageDigestSources | imageDigestSources rewrites every release path |
agent-config.yaml (or platform baremetal:) | Optional cosmetics | Per-interface IP + DNS + IPv6 stance; the cluster gets no DHCP |
| Bootstrap | Online assisted-service or installer-provisioned | Agent-based; ISO contains the embedded payload reference |
| Day-1 baseline | Default OperatorHub works | IDMS/ITMS, signature ConfigMaps, CatalogSources, OperatorHub disable |
| Operator install | Sub picks latest from OperatorHub | Sub picks startingCSV from your mirrored CatalogSource |
| Operator upgrade | Auto on channel | Auto on channel within mirrored versions only; you control what’s mirrored |
| Pull secret rotation | Update one Secret | Update Vault, re-render merged pull-secret on render host, push as Secret/pull-secret in openshift-config |
| Image registry | Default operator-managed | Often Removed on management clusters; tenants use the mirror |
The cluster runs the same. The supply chain that feeds it is rebuilt from scratch with you as the responsible party.
The mental model
Carry these three sentences through the rest of the track:
- Disconnected install isn’t an install option, it’s an operating model. The install is two days. The model is forever.
- The mirror is the contract, the ImageSet is the spec, GitOps is the witness. Every image the cluster runs must be in the mirror; the mirror must reflect the ImageSet; the ImageSet must be in Git.
- Disconnected fails closed. A mistake produces
ImagePullBackOff, which is loud. A connected install fails open — you only notice the surprise on the day a new digest lands you didn’t ask for.
Exercise
Pick a connected OpenShift cluster you have access to (a dev cluster, CodeReady Containers, anything). Run:
oc get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
| head -1 \
| xargs -I{} oc debug node/{} -- chroot /host cat /etc/containers/registries.conf.d/*.conf 2>/dev/null
What you see is the file IDMS/ITMS rewrites on a disconnected cluster — empty or default on a connected one, fully populated on a disconnected one. By Module 06 you’ll know exactly what to expect there, and you’ll be the person writing the IDMS that produces it.
What’s next
Module 02 — Supporting services walks through DNS, MinIO, GitLab, Vault, HAProxy, and NetBox — the stack a disconnected cluster leans on, in the order you stand it up.