TT Lab
Get started
Learn Learning paths Courses

Air-Gapped Mirrors and a Private CA

Fetching side, using side, and three shapes of a mirror

Continue in TT Lab

In one line

Air-gapped infrastructure work always splits across two computers. The download side, which can reach the internet, collects what is needed at exact versions and attaches a list and signatures. The consuming side, which has no internet, stands that up as an internal mirror and makes every tool trust that mirror and the internal certificate. Every module in this course repeats this frame once per ecosystem.

Why this was needed

On an air-gapped server, pip install, npm ci, mvn package, go build, docker pull, and dnf install all fail in the same way: they cannot reach the outside repositories. Yet the fix differs from tool to tool. Python reads a PEP 503 index, npm uses the registry API, Maven depends on the directory layout of a repository, Go uses the module proxy protocol, containers use the OCI distribution specification, and dnf reads repodata. Memorizing each ecosystem separately never ends, but the frame is one: what to fetch from where, what to bundle it into, how to point at it, and what to make trusted.

How it works

The download side and the consuming side. The download side must fetch according to the conditions of the target server (operating system, Python, JDK, CPU). A file fetched on a laptop for the laptop will be wrong on the server. The consuming side verifies the media, stands up the mirror, and makes the tools look at the mirror with a single line of configuration. Between the two there is nothing but bundles of files, hash lists, and signatures. In a network-separated environment, a data transfer procedure (approved media or a transfer system, and import review) sits in between, and that round trip usually takes a day. That is why the skill of building a bundle that is complete in one pass is the real air-gapped skill.

Three shapes of mirror.

프록시 캐시   위(인터넷 저장소)를 당겨 남긴다. 연결된 동안 채우고, 끊으면 채운 것만 내준다
             verdaccio 의 uplink, Nexus 의 proxy 저장소, 레지스트리의 pull-through cache
원본 저장소   우리가 올린 것만 있다. 반입물을 올려 두거나 사내 산출물을 둔다
             Nexus 의 hosted 저장소, 파일을 늘어놓은 정적 웹 서버
스냅숏 동기화 특정 시점의 저장소를 통째로 복제한다. 목록이 아니라 "그날의 전체" 를 들고 들어간다
             배포판 저장소 복제, skopeo sync 같은 이미지 동기화

The Nexus documentation divides repositories into proxy, which caches a remote, hosted, which is the source itself, and group, which bundles several behind one address. Whatever equipment you meet in the field, it is a combination of these three. However, Nexus 3 officially requires 8GB of host memory and a default heap of 2703MB, so it does not fit in this course's lab Pod (2Gi). The labs therefore use lightweight tools with the same principle (http.server, verdaccio, a static file server, a distribution registry), and the reading maps them to the Nexus menus.

Two layers of trust. Once you stand up a mirror, you must make two things trusted. First, is this server really that mirror? This is the TLS certificate, that is, putting the private CA into each tool's trust store. Second, is this file really the original file? This is hashes and signatures. pip's hash-checking mode, the integrity field of the npm lock file, go.sum, Maven's .sha1, rpm's GPG signature, and the image digest are all this second layer. Trusting one layer does not mean you may switch off the other.

Names and time are infrastructure too. An internal mirror must be called by a name (for example pypi.airgap.internal) so that it matches the certificate's SAN and so that the configuration does not change when the server changes. There must be an internal DNS that resolves that name. And because TLS compares the certificate's validity period with the current time, a server with the wrong clock rejects a perfectly good certificate as "not yet valid" or "expired". An air-gapped network that cannot reach internet time servers needs an internal time server.

What it looks like in the field

Most air-gapped import accidents are one of three things: dependencies are missing and the trip has to be made again, the conditions of the download side and the consuming side differ so nothing fits, or the mirror is up but one tool does not trust the certificate and someone switches verification off. The first two are prevented by fetching "what the tool resolved, under the target's conditions", and the last is prevented by knowing each tool's trust store in a table. The labs in this course are designed so that you experience each of these three once per ecosystem. The lab Pod is by nature a room that cannot reach the outside (DNS only), which fits the air-gapped side exactly; only the labs that need the download side open the internet, and the air-gapped side is always checked by the grader with the outside blocked.

What you will do in the next module

You start with pip. On the download side, you fetch dependencies as wheels and pin them by hash, then on the consuming side you stand up a PEP 503 index and point to it with pip.conf. After that come npm, Go, the private CA, Maven, the RHEL family, the container registry, and the internal DNS and time server in turn, and in the last module you go through the whole import procedure from request to signature verification in one pass.

Reference documents: Nexus Repository Types · Nexus Formats · Nexus System Requirements · RFC 9525