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: Acceso → Clone → Instalar (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:
- 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. - UCS de destino — el host air-gapped dentro del data center. Ejecuta
airgap-deploy.shdespué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: Readennollagluiz/AI_forSE— exportado comoGH_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.shempuje 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 complementaCLONE_FOR_INSTALL.md— la Opción D (tarball) es lo queairgap-stage.shusa internamente para el código fuentePRIVATE_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