Skip to content

Instalação air-gapped — TLSStress.Art

Leia no seu idioma: English · Português · Español

Status do escopo (pós-congelamento de escopo 2026-05-10) — Ver ARCHITECTURE.md para os 37 MÓDULOs canônicos + 7 Test Kinds + arquitetura de safety DOM/CPOS/PIE-PA. ADRs 0014, 0019-0025 cobrem adições pós-Freeze.

Sequência de onboarding: AcessoCloneInstalar (caminho air-gap)você está aqui · alternativa padrão: Runbook First Install · setup do mantenedor: Private Repo Setup> Público-alvo: Operadores instalando o TLSStress.Art em um data center onde o host UCS não tem acesso à internet — típico de ambientes regulados / classificados / OOB.

O problema

A instalação padrão assume que o UCS consegue alcançar: - GitHub (para clonar o código-fonte) - Docker Hub / GHCR / Quay (para baixar imagens de container) - Mirrors apt do Ubuntu (para instalar dependências do host) - get.helm.sh, k3s.io (para baixar o Kubernetes)

Em um ambiente totalmente air-gapped, nada disso funciona. O operador precisa trazer tudo via sneakernet.

A solução — pré-staging em uma máquina conectada

Você usará duas máquinas:

  1. Máquina de staging — seu laptop (ou qualquer host) com acesso completo à internet. Roda airgap-stage.sh. Produz um único tarball de ~5–10 GB.
  2. UCS de destino — o host air-gapped dentro do data center. Roda airgap-deploy.sh depois que o bundle for transportado para dentro (drive USB, transferência 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       │
└──────────────────┘                └──────────────────────┘

Pré-requisitos

Na máquina de staging

  • bash 4+, curl, jq, sha256sum, tar
  • Docker (ou Podman com wrapper docker-cli) — usado para puxar/salvar imagens de container
  • Helm 3.x — para download do chart do cert-manager
  • Um fine-grained PAT do GitHub com Contents: Read em nollagluiz/AI_forSE — exportado como GH_TOKEN
  • ~15 GB de espaço livre em disco (working set + tarball final)
  • ~30 minutos de tempo de download dependente de banda

No UCS air-gapped

  • Ubuntu 22.04+ Server, instalação limpa
  • acesso root ou sudo
  • 32 GB de RAM, 16 vCPU, 200 GB de disco (igual à instalação padrão)
  • Porta USB ou outro meio de transporte para o bundle

Hardware no data center (sem mudança em relação ao runbook padrão)

  • Cisco Nexus 9000 com rede de gerência
  • NGFW DUT (Cisco FTD/ASA/Firepower, Palo Alto, Fortinet, etc.)
  • Trunks de VLAN, IPs e o cert da CA do NGFW em formato PEM, conforme exigidos

Passo 1 — Montar o bundle no seu 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

O que acontece — o script (nesta ordem): 1. Baixa o binário do K3s + imagens airgap (v1.30.5+k3s1 por padrão) 2. Puxa 9 imagens de container do TLSStress.Art (agent, dashboard, webserver, …) do GHCR 3. Puxa 15 imagens de terceiros (Postgres, Prometheus, Grafana, Loki, etc.) 4. Baixa o Helm chart do cert-manager + 3 imagens do cert-manager 5. Baixa o manifest do Multus CNI + imagem 6. Faz staging de 11 pacotes apt .deb (iproute2, nftables, NFS, SNMP, etc.) usando um container Ubuntu 22.04 one-shot 7. Baixa o tarball do código-fonte na tag de versão solicitada 8. Gera um manifest SHA-256 de cada arquivo e sela tudo em um único .tar.gz

Saída final: - <output> — o bundle (tipicamente 5–10 GB) - <output>.sha256 — arquivo sidecar com o SHA-256 do bundle (para verificação de integridade depois)

Passo 2 — Transportar o bundle (o que sua política permitir)

Drive USB, SSD externo criptografado, estação de transferência segura — o que a política do seu data center permitir. Prefira drives USB que tenham sido apagados + dedicados a este propósito para evitar contaminação cruzada.

Se a política do seu data center exige integridade de duas pessoas para mídia atravessando o air gap: peça a um segundo engenheiro para calcular sha256sum tlsstress-airgap-v3.6.0.tar.gz no laptop de staging e no UCS após a cópia. Os dois números precisam coincidir.

Passo 3 — Implantar no UCS (~15 min)

Quando o bundle estiver no UCS (tipicamente /media/usb/... ou /tmp/):

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

O que acontece — o script (nesta ordem): 1. Verifica o SHA-256 do bundle contra o sidecar .sha256 2. Extrai para /opt/tlsstress-airgap/ 3. Verifica o manifest interno contra os arquivos extraídos 4. Configura um repositório apt local em /var/local/tlsstress-apt/ a partir dos arquivos .deb 5. Instala dependências do host (iproute2, nftables, cliente NFS, SNMP, etc.) a partir do repo local 6. Instala o K3s offline usando o binário em staging + imagens airgap 7. Pré-carrega TODAS as imagens de container no containerd embutido do K3s (nenhum pull acontecerá depois) 8. Aplica o manifest do Multus CNI 9. Instala o cert-manager a partir do Helm chart em staging 10. Extrai o tarball do código-fonte para /home/<user>/tlsstress/AI_forSE/

Após a conclusão, você está no mesmo estado do passo 1.3 do RUNBOOK_FIRST_INSTALL.md. Continue com:

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)

Nenhum image pull será tentado — toda imagem já está no containerd, com a mesma tag que os manifests do K8s esperam.

O que o bundle contém (para auditoria + compliance)

O manifest SHA-256 do bundle (manifest/sha256sum.txt dentro do tarball) lista cada arquivo. Após a extração, verifique com:

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

Um sucesso significa que cada arquivo no bundle corresponde ao que a máquina de staging calculou. Esta é sua cadeia de custódia forense para a instalação.

O arquivo manifest/MANIFEST.txt dentro do bundle registra: - Tag de versão instalada - Versões de K3s, cert-manager, Multus - Total de arquivos + tamanho - Timestamp de geração + hostname - Termos de licença (PolyForm Noncommercial 1.0.0 + Appendix A)

Operação air-gapped após a instalação

Uma vez instalado, o próprio test bed roda sem internet — ele é totalmente autocontido: - Personas servem tráfego para si mesmas (sem DNS externo, sem CDN externa) - Prometheus faz scrape apenas de targets locais - Grafana renderiza apenas dados locais - O License Acceptance Modal do Dashboard não busca nenhum asset externo

O que você NÃO tem em modo air-gap: - ❌ git pull para upgrades — produza um novo bundle na máquina de staging para cada upgrade de versão - ❌ Alertas de segurança Dependabot ao vivo — aplique via snapshots de apt-mirror periodicamente - ❌ DNS externo para cloned personas — Cloned Personas precisam que seus domínios-alvo sejam resolvidos internamente; configure overrides de CoreDNS ou aceite "best-effort" domain replay - ❌ Sincronização NTP (frequentemente) — se o data center proíbe NTP público, aponte K3s + o host para o servidor NTP interno do laboratório

Upgrades para uma nova versão

Re-execute o mesmo fluxo:

# 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

O script de deploy é intencionalmente idempotente — rodar duas vezes é seguro.

Troubleshooting

Falhas de stage (no seu laptop)

Sintoma Causa Correção
docker pull falha com 401 Não logado no GHCR echo $GH_TOKEN \| docker login ghcr.io -u <user> --password-stdin
Pull do Helm chart falha Versão antiga do Helm Atualize para Helm 3.13+: brew install helm ou equivalente da sua distro
Tarball de código-fonte 404 PAT sem Contents:Read em AI_forSE Regere fine-grained PAT com o escopo correto
apt-get download retorna 0 pacotes Rodando em macOS sem proxy docker run ubuntu:22.04 Re-execute dentro de um container Linux conforme instruído pelo script
Disco cheio Bundle ~10 GB + cache de layers do Docker Limpe com docker system prune -a entre execuções

Falhas de deploy (no UCS)

Sintoma Causa Correção
sha256sum -c falha Bundle corrompido no transporte Re-transporte da máquina de staging; verifique SHA dos dois lados
K3s não inicia Caminho das imagens airgap errado / mismatch de versão Verifique se /var/lib/rancher/k3s/agent/images/ existe + k3s --version confere
containerd image import falha Mismatch de formato do tarball de imagem Re-stage com a mesma versão de Docker do host de deploy
Pods presos em ImagePullBackOff Tag de imagem no manifest do K8s não bate com o que está carregado Edite a tag do manifest OU re-stage com a mesma tag
DaemonSet do Multus preso em Pending Taints de nó da inicialização do K3s kubectl taint nodes --all node.kubernetes.io/not-ready-
Timeouts no webhook do cert-manager Resolução DNS dentro do cluster DNS do cluster estabiliza após 60 s; tente novamente; se persistir, verifique logs do coredns

Quando você não pode usar este método

Alguns cenários exigem uma abordagem diferente:

  • Operador proibido de conectar laptop à internet — bundles pré-staged precisam ser produzidos por um engenheiro separado em outra instalação e enviados em mídia física. Mesmos scripts; pessoa diferente os executa.
  • Site não permite drives USB — substitua pelo mecanismo de transferência aprovado pelo site (Cross-Domain Solution, fita por courier, …). O bundle é só um .tar.gz; o transporte é agnóstico.
  • Ambiente totalmente classificado sem acesso ao GitHub também no lado de staging — você precisa de uma entrega pontual de alguém com acesso ao GitHub. Bundles pré-staged podem ser re-empacotados e assinados por uma cadeia de custódios autorizados.
  • Múltiplos sites air-gapped precisando de instalações simultâneas — produza um bundle, envie cópias; ou monte um registry de imagens local dentro do air-gap e faça airgap-deploy.sh empurrar para ele em vez de para o containerd diretamente (o script não faz isso hoje; melhoria futura).

Relacionados

  • RUNBOOK_FIRST_INSTALL.md — o fluxo de primeira instalação em host conectado que este complementa
  • CLONE_FOR_INSTALL.md — Opção D (tarball) é o que airgap-stage.sh usa internamente para o código-fonte
  • PRIVATE_REPO_SETUP.md — por que o código-fonte vem de um repo privado (PAT necessário para staging)
  • USAGE_POLICY.md — restrições de licença se aplicam igualmente em instalações air-gapped