Skip to content

Instalación air-gapped — TLSStress.Art

Lee en tu idioma: English · Português · Español

Estado del alcance (post-congelación de alcance 2026-05-10) — Ver ARCHITECTURE.md para los 37 MÓDULOs canónicos + 7 Test Kinds + arquitectura de safety DOM/CPOS/PIE-PA. ADRs 0014, 0019-0025 cubren adiciones post-Freeze.

Secuencia de onboarding: AccesoCloneInstalar (camino air-gap)estás aquí · alternativa estándar: Runbook First Install · setup del mantenedor: Private Repo Setup> Audiencia: Operadores que instalan TLSStress.Art en un data center donde el host UCS no tiene acceso a internet — típico de entornos regulados / clasificados / OOB.

El problema

La instalación estándar asume que el UCS puede alcanzar: - GitHub (para clonar el código fuente) - Docker Hub / GHCR / Quay (para descargar imágenes de contenedor) - Mirrors apt de Ubuntu (para instalar dependencias del host) - get.helm.sh, k3s.io (para descargar Kubernetes)

En un entorno totalmente air-gapped, nada de esto funciona. El operador debe traerlo todo por sneakernet.

La solución — pre-staging en una máquina conectada

Usarás dos máquinas:

  1. Máquina de staging — tu laptop (o cualquier host) con acceso completo a internet. Ejecuta airgap-stage.sh. Produce un único tarball de ~5–10 GB.
  2. UCS de destino — el host air-gapped dentro del data center. Ejecuta airgap-deploy.sh después de que el bundle se transporte adentro (unidad USB, transferencia segura, etc.).
┌──────────────────┐                ┌──────────────────────┐
│  Staging machine │                │  Air-gapped UCS      │
│  (your laptop)   │                │  (data center)       │
│                  │                │                      │
│  ./airgap-stage  │  ┌──USB──┐    │  ./airgap-deploy     │
│  →  bundle.tar.gz├─→│ 16 GB ├───→│  ←  bundle.tar.gz    │
│                  │  └───────┘    │                      │
│  full internet   │                │  zero internet       │
└──────────────────┘                └──────────────────────┘

Prerrequisitos

En la máquina de staging

  • bash 4+, curl, jq, sha256sum, tar
  • Docker (o Podman con wrapper docker-cli) — usado para hacer pull/save de imágenes de contenedor
  • Helm 3.x — para descargar el chart de cert-manager
  • Un fine-grained PAT de GitHub con Contents: Read en nollagluiz/AI_forSE — exportado como GH_TOKEN
  • ~15 GB de espacio libre en disco (working set + tarball final)
  • ~30 minutos de tiempo de descarga dependiente del ancho de banda

En el UCS air-gapped

  • Ubuntu 22.04+ Server, instalación limpia
  • acceso root o sudo
  • 32 GB de RAM, 16 vCPU, 200 GB de disco (igual que la instalación estándar)
  • Puerto USB u otro medio de transporte para el bundle

Hardware en el data center (sin cambios respecto al runbook estándar)

  • Cisco Nexus 9000 con red de gestión
  • NGFW DUT (Cisco FTD/ASA/Firepower, Palo Alto, Fortinet, etc.)
  • Trunks de VLAN, IPs y el cert de la CA del NGFW en formato PEM, según se requieran

Paso 1 — Armar el bundle en tu laptop (~30 min)

# On your connected machine:
git clone https://github.com/nollagluiz/AI_forSE.git
cd AI_forSE
export GH_TOKEN="<your-fine-grained-PAT>"

./scripts/airgap-stage.sh \
  --version v3.6.0 \
  --output /media/usb/tlsstress-airgap-v3.6.0.tar.gz

Qué ocurre — el script (en este orden): 1. Descarga el binario de K3s + imágenes airgap (v1.30.5+k3s1 por defecto) 2. Hace pull de 9 imágenes de contenedor de TLSStress.Art (agent, dashboard, webserver, …) desde GHCR 3. Hace pull de 15 imágenes de terceros (Postgres, Prometheus, Grafana, Loki, etc.) 4. Descarga el Helm chart de cert-manager + 3 imágenes de cert-manager 5. Descarga el manifest de Multus CNI + imagen 6. Hace staging de 11 paquetes apt .deb (iproute2, nftables, NFS, SNMP, etc.) usando un contenedor Ubuntu 22.04 one-shot 7. Descarga el tarball del código fuente en la tag de versión solicitada 8. Genera un manifest SHA-256 de cada archivo y sella todo en un único .tar.gz

Salida final: - <output> — el bundle (típicamente 5–10 GB) - <output>.sha256 — archivo sidecar con el SHA-256 del bundle (para verificación de integridad después)

Paso 2 — Transportar el bundle (lo que tu política permita)

Unidad USB, SSD externo cifrado, estación de transferencia segura — lo que la política de tu data center permita. Prefiere unidades USB que hayan sido borradas + dedicadas a este propósito para evitar contaminación cruzada.

Si la política de tu data center exige integridad de dos personas para medios que cruzan el air gap: pídele a un segundo ingeniero que calcule sha256sum tlsstress-airgap-v3.6.0.tar.gz en el laptop de staging y en el UCS después de la copia. Ambos números deben coincidir.

Paso 3 — Desplegar en el UCS (~15 min)

Una vez que el bundle esté en el UCS (típicamente /media/usb/... o /tmp/):

sudo bash /tmp/scripts/airgap-deploy.sh \
  --bundle /tmp/tlsstress-airgap-v3.6.0.tar.gz

Qué ocurre — el script (en este orden): 1. Verifica el SHA-256 del bundle contra el sidecar .sha256 2. Extrae a /opt/tlsstress-airgap/ 3. Verifica el manifest interno contra los archivos extraídos 4. Configura un repositorio apt local en /var/local/tlsstress-apt/ a partir de los archivos .deb 5. Instala dependencias del host (iproute2, nftables, cliente NFS, SNMP, etc.) desde el repo local 6. Instala K3s offline usando el binario en staging + imágenes airgap 7. Pre-carga TODAS las imágenes de contenedor en el containerd embebido de K3s (no se hará ningún pull después) 8. Aplica el manifest de Multus CNI 9. Instala cert-manager desde el Helm chart en staging 10. Extrae el tarball del código fuente a /home/<user>/tlsstress/AI_forSE/

Tras la finalización, estás en el mismo estado que el paso 1.3 de RUNBOOK_FIRST_INSTALL.md. Continúa con:

cd ~/tlsstress
kubectl apply -f k8s/
kubectl apply -k platform/
kubectl apply -k personas/
# then proceed to step 2 of the standard runbook (DUT connection)

No se intentará ningún image pull — cada imagen ya está en containerd, etiquetada con el mismo nombre que esperan los manifests de K8s.

Qué contiene el bundle (para auditoría + compliance)

El manifest SHA-256 del bundle (manifest/sha256sum.txt dentro del tarball) lista cada archivo. Tras la extracción, verifica con:

cd /opt/tlsstress-airgap
sha256sum -c manifest/sha256sum.txt

Un éxito significa que cada archivo en el bundle coincide con lo que la máquina de staging calculó. Esta es tu cadena de custodia forense para la instalación.

El archivo manifest/MANIFEST.txt dentro del bundle registra: - Tag de versión instalada - Versiones de K3s, cert-manager, Multus - Total de archivos + tamaño - Timestamp de generación + hostname - Términos de licencia (PolyForm Noncommercial 1.0.0 + Appendix A)

Operación air-gapped tras la instalación

Una vez instalado, el propio test bed funciona sin internet — es totalmente autocontenido: - Las personas sirven tráfico para sí mismas (sin DNS externo, sin CDN externa) - Prometheus hace scrape solo de targets locales - Grafana renderiza solo datos locales - El License Acceptance Modal del Dashboard no obtiene ningún asset externo

Lo que NO tienes en modo air-gap: - ❌ git pull para upgrades — produce un nuevo bundle en la máquina de staging para cada upgrade de versión - ❌ Alertas de seguridad Dependabot en vivo — aplica vía snapshots de apt-mirror periódicamente - ❌ DNS externo para cloned personas — Cloned Personas necesitan que sus dominios objetivo se resuelvan internamente; configura overrides de CoreDNS o acepta "best-effort" domain replay - ❌ Sincronización NTP (frecuentemente) — si el data center prohíbe NTP público, apunta K3s + el host al servidor NTP interno del laboratorio

Upgrades a una nueva versión

Re-ejecuta el mismo flujo:

# On the staging laptop:
./scripts/airgap-stage.sh --version v3.7.0 --output /media/usb/tlsstress-airgap-v3.7.0.tar.gz

# On the UCS:
sudo bash scripts/airgap-deploy.sh --bundle /media/usb/tlsstress-airgap-v3.7.0.tar.gz
# the script is idempotent — pre-loaded images for v3.7.0 are added alongside v3.6.0
# After the script finishes, edit your manifests / kustomize overlays to point at the new tag

El script de deploy es intencionalmente idempotente — ejecutarlo dos veces es seguro.

Troubleshooting

Fallos de stage (en tu laptop)

Síntoma Causa Solución
docker pull falla con 401 No logueado en GHCR echo $GH_TOKEN \| docker login ghcr.io -u <user> --password-stdin
Pull del Helm chart falla Versión antigua de Helm Actualiza a Helm 3.13+: brew install helm o equivalente de tu distro
Tarball de código fuente 404 PAT sin Contents:Read en AI_forSE Regenera fine-grained PAT con el scope correcto
apt-get download retorna 0 paquetes Ejecutándose en macOS sin proxy docker run ubuntu:22.04 Re-ejecuta dentro de un contenedor Linux según instruye el script
Disco lleno Bundle ~10 GB + cache de layers de Docker Limpia con docker system prune -a entre ejecuciones

Fallos de deploy (en el UCS)

Síntoma Causa Solución
sha256sum -c falla Bundle corrupto en el transporte Re-transporta desde la máquina de staging; verifica SHA en ambos lados
K3s no arranca Ruta de imágenes airgap incorrecta / mismatch de versión Verifica que /var/lib/rancher/k3s/agent/images/ existe + k3s --version coincide
containerd image import falla Mismatch de formato del tarball de imagen Re-stage con la misma versión de Docker que el host de deploy
Pods atascados en ImagePullBackOff Tag de imagen en el manifest de K8s no coincide con lo cargado Edita la tag del manifest O re-stage con la misma tag
DaemonSet de Multus atascado en Pending Taints de nodo de la inicialización de K3s kubectl taint nodes --all node.kubernetes.io/not-ready-
Timeouts en el webhook de cert-manager Resolución DNS dentro del cluster DNS del cluster se estabiliza tras 60 s; reintenta; si persiste, revisa los logs de coredns

Cuándo no puedes usar este método

Algunos escenarios necesitan un enfoque distinto:

  • Operador con prohibición de conectar el laptop a internet — los bundles pre-staged deben ser producidos por un ingeniero distinto en otra instalación y enviados en medios físicos. Mismos scripts; otra persona los ejecuta.
  • Sitio que no permite unidades USB — sustituye por el mecanismo de transferencia aprobado del sitio (Cross-Domain Solution, cinta por courier, …). El bundle es solo un .tar.gz; el transporte es agnóstico.
  • Entorno totalmente clasificado sin acceso a GitHub tampoco del lado de staging — necesitas una entrega puntual de alguien con acceso a GitHub. Los bundles pre-staged pueden ser re-empaquetados y firmados por una cadena de custodios autorizados.
  • Múltiples sitios air-gapped que necesitan instalaciones simultáneas — produce un bundle, envía copias; o monta un registry de imágenes local dentro del air-gap y haz que airgap-deploy.sh empuje a él en lugar de a containerd directamente (el script no hace esto hoy; mejora futura).

Relacionados

  • RUNBOOK_FIRST_INSTALL.md — el flujo de primera instalación en host conectado que este complementa
  • CLONE_FOR_INSTALL.md — la Opción D (tarball) es lo que airgap-stage.sh usa internamente para el código fuente
  • PRIVATE_REPO_SETUP.md — por qué el código fuente viene de un repo privado (PAT requerido para staging)
  • USAGE_POLICY.md — las restricciones de licencia aplican igualmente en instalaciones air-gapped