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: Acesso → Clone → Instalar (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:
- 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. - UCS de destino — o host air-gapped dentro do data center. Roda
airgap-deploy.shdepois 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: Reademnollagluiz/AI_forSE— exportado comoGH_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.shempurrar 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 complementaCLONE_FOR_INSTALL.md— Opção D (tarball) é o queairgap-stage.shusa internamente para o código-fontePRIVATE_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