raijin-server 0.2.8__tar.gz → 0.2.10__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {raijin_server-0.2.8/src/raijin_server.egg-info → raijin_server-0.2.10}/PKG-INFO +60 -4
  2. {raijin_server-0.2.8 → raijin_server-0.2.10}/README.md +59 -3
  3. {raijin_server-0.2.8 → raijin_server-0.2.10}/setup.cfg +1 -1
  4. raijin_server-0.2.10/src/raijin_server/__init__.py +5 -0
  5. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/cli.py +108 -3
  6. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/kubernetes.py +93 -0
  7. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/traefik.py +1 -2
  8. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/validators.py +23 -22
  9. {raijin_server-0.2.8 → raijin_server-0.2.10/src/raijin_server.egg-info}/PKG-INFO +60 -4
  10. raijin_server-0.2.8/src/raijin_server/__init__.py +0 -5
  11. {raijin_server-0.2.8 → raijin_server-0.2.10}/LICENSE +0 -0
  12. {raijin_server-0.2.8 → raijin_server-0.2.10}/pyproject.toml +0 -0
  13. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/config.py +0 -0
  14. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/healthchecks.py +0 -0
  15. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/__init__.py +0 -0
  16. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/apokolips_demo.py +0 -0
  17. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/bootstrap.py +0 -0
  18. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/calico.py +0 -0
  19. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/cert_manager.py +0 -0
  20. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/essentials.py +0 -0
  21. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/firewall.py +0 -0
  22. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/full_install.py +0 -0
  23. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/grafana.py +0 -0
  24. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/hardening.py +0 -0
  25. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/harness.py +0 -0
  26. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/istio.py +0 -0
  27. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/kafka.py +0 -0
  28. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/kong.py +0 -0
  29. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/loki.py +0 -0
  30. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/minio.py +0 -0
  31. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/network.py +0 -0
  32. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/observability_dashboards.py +0 -0
  33. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/observability_ingress.py +0 -0
  34. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/prometheus.py +0 -0
  35. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/sanitize.py +0 -0
  36. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/secrets.py +0 -0
  37. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/ssh_hardening.py +0 -0
  38. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/velero.py +0 -0
  39. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/modules/vpn.py +0 -0
  40. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/scripts/__init__.py +0 -0
  41. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/scripts/checklist.sh +0 -0
  42. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/scripts/install.sh +0 -0
  43. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/scripts/log_size_metric.sh +0 -0
  44. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/scripts/pre-deploy-check.sh +0 -0
  45. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server/utils.py +0 -0
  46. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server.egg-info/SOURCES.txt +0 -0
  47. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server.egg-info/dependency_links.txt +0 -0
  48. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server.egg-info/entry_points.txt +0 -0
  49. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server.egg-info/requires.txt +0 -0
  50. {raijin_server-0.2.8 → raijin_server-0.2.10}/src/raijin_server.egg-info/top_level.txt +0 -0
  51. {raijin_server-0.2.8 → raijin_server-0.2.10}/tests/test_full_install_sequence.py +0 -0
  52. {raijin_server-0.2.8 → raijin_server-0.2.10}/tests/test_registry.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: raijin-server
3
- Version: 0.2.8
3
+ Version: 0.2.10
4
4
  Summary: CLI para automacao de setup e hardening de servidores Ubuntu Server.
5
5
  Home-page: https://example.com/raijin-server
6
6
  Author: Equipe Raijin
@@ -44,6 +44,8 @@ CLI em Python (Typer) para automatizar setup e hardening de servidores Ubuntu Se
44
44
  - Arquitetura: [ARCHITECTURE.md](ARCHITECTURE.md)
45
45
  - Auditoria: [AUDIT.md](AUDIT.md)
46
46
  - Segurança: [SECURITY.md](SECURITY.md)
47
+ - Acesso SSH (Windows): [docs/SSH_WINDOWS.md](docs/SSH_WINDOWS.md)
48
+ - VPN para acesso remoto (WireGuard): [docs/VPN_REMOTE_ACCESS.md](docs/VPN_REMOTE_ACCESS.md)
47
49
 
48
50
  ## Destaques
49
51
 
@@ -60,6 +62,12 @@ CLI em Python (Typer) para automatizar setup e hardening de servidores Ubuntu Se
60
62
  - ✅ **Modo Dry-run**: Simula execução sem aplicar mudanças
61
63
 
62
64
  ## Requisitos
65
+ Ubuntu Server 20.04+ com Python 3 disponível. Se precisar instalar/atualizar no host alvo:
66
+
67
+ ```bash
68
+ sudo apt update
69
+ sudo apt install -y python3 python3-venv python3-pip
70
+ ```
63
71
 
64
72
  ## Instalação (sempre em venv midgard)
65
73
 
@@ -110,6 +118,10 @@ sudo -E ~/.venvs/midgard/bin/raijin-server validate
110
118
  sudo -E ~/.venvs/midgard/bin/raijin-server menu
111
119
  ```
112
120
 
121
+ ### Rollback de módulos
122
+ - No menu, após escolher o módulo, selecione `r` para rollback; se houver dependentes já executados, será pedido confirmacao para rollback em cascata dos dependentes antes.
123
+ - Linha de comando: `sudo -E ~/.venvs/midgard/bin/raijin-server rollback <modulo> --cascade/--no-cascade` (best-effort; alguns módulos podem exigir limpeza manual). Caso seja apenas para revisar o efeito, use `-n/--dry-run` no comando principal para não aplicar.
124
+
113
125
  ### Execução Direta de Módulos
114
126
  ```bash
115
127
  # Executar módulo específico
@@ -173,6 +185,9 @@ sudo -E ~/.venvs/midgard/bin/raijin-server debug journal --service containerd --
173
185
  - **[AUDIT.md](AUDIT.md)**: Relatório completo de auditoria e melhorias implementadas
174
186
  - **[ARCHITECTURE.md](ARCHITECTURE.md)**: Arquitetura técnica do ambiente
175
187
  - **[SECURITY.md](SECURITY.md)**: Políticas de segurança e reporte de vulnerabilidades
188
+ - **Publicação PyPI**: ver seção "Publicar no PyPI" abaixo
189
+ - **CNI automático**: Calico aplicado automaticamente no passo Kubernetes (override com `RAIJIN_CNI=none`)
190
+ - Para reaplicar CNI (forçar mesmo se já houver): `RAIJIN_FORCE_CNI=1`
176
191
 
177
192
  ## Fluxo de Execução Recomendado
178
193
 
@@ -329,6 +344,46 @@ bash "$SCRIPT_PATH"
329
344
 
330
345
  O helper garante o caminho absoluto correto independentemente de onde o pacote foi instalado.
331
346
 
347
+ ## Publicar no PyPI
348
+
349
+ Use o venv local do repositório (`.venv`) para garantir dependências corretas:
350
+
351
+ ```bash
352
+ cd /home/rafael/github/raijin-server
353
+ python3 -m venv .venv
354
+ source .venv/bin/activate
355
+ python -m pip install -U pip build twine
356
+ ```
357
+
358
+ Gerar artefatos limpos:
359
+
360
+ ```bash
361
+ rm -rf dist build
362
+ python -m build --sdist --wheel --outdir dist
363
+ ```
364
+
365
+ Publicar no PyPI (requere token):
366
+
367
+ ```bash
368
+ export TWINE_USERNAME="__token__"
369
+ export TWINE_PASSWORD="pypi-xxxxx" # token do PyPI
370
+ python -m twine upload dist/*
371
+ ```
372
+
373
+ Opcional: validar no TestPyPI antes de publicar (precisa token de TestPyPI):
374
+
375
+ ```bash
376
+ export TWINE_USERNAME="__token__"
377
+ export TWINE_PASSWORD="pypi-xxxxx" # token do TestPyPI
378
+ python -m twine upload --repository testpypi dist/*
379
+ ```
380
+
381
+ Depois de publicar, atualize/instale:
382
+
383
+ ```bash
384
+ pip install -U raijin-server
385
+ ```
386
+
332
387
  ## Teste de ingress (Apokolips)
333
388
 
334
389
  O módulo [src/raijin_server/modules/apokolips_demo.py](src/raijin_server/modules/apokolips_demo.py) cria um namespace dedicado, ConfigMap com HTML, Deployment NGINX, Service e Ingress Traefik com uma landing page "Apokolips" para validar o tráfego externo.
@@ -437,17 +492,18 @@ O Twine é a ferramenta oficial para enviar pacotes Python ao PyPI com upload se
437
492
  Passo a passo:
438
493
  ```bash
439
494
  # 1) Gere artefatos
440
- python -m build --sdist --wheel --outdir dist/
495
+ python3 -m pip install --user build
496
+ python3 -m build --sdist --wheel --outdir dist/
441
497
 
442
498
  # 2) Configure o token (crie em https://pypi.org/manage/account/token/)
443
499
  export TWINE_USERNAME=__token__
444
500
  export TWINE_PASSWORD="<seu-token>"
445
501
 
446
502
  # 3) Envie para o PyPI
447
- python -m twine upload dist/*
503
+ python3 -m twine upload dist/*
448
504
 
449
505
  # 4) Verifique instalação
450
- python -m pip install -U raijin-server
506
+ python3 -m pip install -U raijin-server
451
507
  raijin-server --version
452
508
  ```
453
509
 
@@ -11,6 +11,8 @@ CLI em Python (Typer) para automatizar setup e hardening de servidores Ubuntu Se
11
11
  - Arquitetura: [ARCHITECTURE.md](ARCHITECTURE.md)
12
12
  - Auditoria: [AUDIT.md](AUDIT.md)
13
13
  - Segurança: [SECURITY.md](SECURITY.md)
14
+ - Acesso SSH (Windows): [docs/SSH_WINDOWS.md](docs/SSH_WINDOWS.md)
15
+ - VPN para acesso remoto (WireGuard): [docs/VPN_REMOTE_ACCESS.md](docs/VPN_REMOTE_ACCESS.md)
14
16
 
15
17
  ## Destaques
16
18
 
@@ -27,6 +29,12 @@ CLI em Python (Typer) para automatizar setup e hardening de servidores Ubuntu Se
27
29
  - ✅ **Modo Dry-run**: Simula execução sem aplicar mudanças
28
30
 
29
31
  ## Requisitos
32
+ Ubuntu Server 20.04+ com Python 3 disponível. Se precisar instalar/atualizar no host alvo:
33
+
34
+ ```bash
35
+ sudo apt update
36
+ sudo apt install -y python3 python3-venv python3-pip
37
+ ```
30
38
 
31
39
  ## Instalação (sempre em venv midgard)
32
40
 
@@ -77,6 +85,10 @@ sudo -E ~/.venvs/midgard/bin/raijin-server validate
77
85
  sudo -E ~/.venvs/midgard/bin/raijin-server menu
78
86
  ```
79
87
 
88
+ ### Rollback de módulos
89
+ - No menu, após escolher o módulo, selecione `r` para rollback; se houver dependentes já executados, será pedido confirmacao para rollback em cascata dos dependentes antes.
90
+ - Linha de comando: `sudo -E ~/.venvs/midgard/bin/raijin-server rollback <modulo> --cascade/--no-cascade` (best-effort; alguns módulos podem exigir limpeza manual). Caso seja apenas para revisar o efeito, use `-n/--dry-run` no comando principal para não aplicar.
91
+
80
92
  ### Execução Direta de Módulos
81
93
  ```bash
82
94
  # Executar módulo específico
@@ -140,6 +152,9 @@ sudo -E ~/.venvs/midgard/bin/raijin-server debug journal --service containerd --
140
152
  - **[AUDIT.md](AUDIT.md)**: Relatório completo de auditoria e melhorias implementadas
141
153
  - **[ARCHITECTURE.md](ARCHITECTURE.md)**: Arquitetura técnica do ambiente
142
154
  - **[SECURITY.md](SECURITY.md)**: Políticas de segurança e reporte de vulnerabilidades
155
+ - **Publicação PyPI**: ver seção "Publicar no PyPI" abaixo
156
+ - **CNI automático**: Calico aplicado automaticamente no passo Kubernetes (override com `RAIJIN_CNI=none`)
157
+ - Para reaplicar CNI (forçar mesmo se já houver): `RAIJIN_FORCE_CNI=1`
143
158
 
144
159
  ## Fluxo de Execução Recomendado
145
160
 
@@ -296,6 +311,46 @@ bash "$SCRIPT_PATH"
296
311
 
297
312
  O helper garante o caminho absoluto correto independentemente de onde o pacote foi instalado.
298
313
 
314
+ ## Publicar no PyPI
315
+
316
+ Use o venv local do repositório (`.venv`) para garantir dependências corretas:
317
+
318
+ ```bash
319
+ cd /home/rafael/github/raijin-server
320
+ python3 -m venv .venv
321
+ source .venv/bin/activate
322
+ python -m pip install -U pip build twine
323
+ ```
324
+
325
+ Gerar artefatos limpos:
326
+
327
+ ```bash
328
+ rm -rf dist build
329
+ python -m build --sdist --wheel --outdir dist
330
+ ```
331
+
332
+ Publicar no PyPI (requere token):
333
+
334
+ ```bash
335
+ export TWINE_USERNAME="__token__"
336
+ export TWINE_PASSWORD="pypi-xxxxx" # token do PyPI
337
+ python -m twine upload dist/*
338
+ ```
339
+
340
+ Opcional: validar no TestPyPI antes de publicar (precisa token de TestPyPI):
341
+
342
+ ```bash
343
+ export TWINE_USERNAME="__token__"
344
+ export TWINE_PASSWORD="pypi-xxxxx" # token do TestPyPI
345
+ python -m twine upload --repository testpypi dist/*
346
+ ```
347
+
348
+ Depois de publicar, atualize/instale:
349
+
350
+ ```bash
351
+ pip install -U raijin-server
352
+ ```
353
+
299
354
  ## Teste de ingress (Apokolips)
300
355
 
301
356
  O módulo [src/raijin_server/modules/apokolips_demo.py](src/raijin_server/modules/apokolips_demo.py) cria um namespace dedicado, ConfigMap com HTML, Deployment NGINX, Service e Ingress Traefik com uma landing page "Apokolips" para validar o tráfego externo.
@@ -404,17 +459,18 @@ O Twine é a ferramenta oficial para enviar pacotes Python ao PyPI com upload se
404
459
  Passo a passo:
405
460
  ```bash
406
461
  # 1) Gere artefatos
407
- python -m build --sdist --wheel --outdir dist/
462
+ python3 -m pip install --user build
463
+ python3 -m build --sdist --wheel --outdir dist/
408
464
 
409
465
  # 2) Configure o token (crie em https://pypi.org/manage/account/token/)
410
466
  export TWINE_USERNAME=__token__
411
467
  export TWINE_PASSWORD="<seu-token>"
412
468
 
413
469
  # 3) Envie para o PyPI
414
- python -m twine upload dist/*
470
+ python3 -m twine upload dist/*
415
471
 
416
472
  # 4) Verifique instalação
417
- python -m pip install -U raijin-server
473
+ python3 -m pip install -U raijin-server
418
474
  raijin-server --version
419
475
  ```
420
476
 
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = raijin-server
3
- version = 0.2.8
3
+ version = 0.2.10
4
4
  description = CLI para automacao de setup e hardening de servidores Ubuntu Server.
5
5
  long_description = file: README.md
6
6
  long_description_content_type = text/markdown
@@ -0,0 +1,5 @@
1
+ """Pacote principal do CLI Raijin Server."""
2
+
3
+ __version__ = "0.2.10"
4
+
5
+ __all__ = ["__version__"]
@@ -45,7 +45,7 @@ from raijin_server.modules import (
45
45
  vpn,
46
46
  )
47
47
  from raijin_server.utils import ExecutionContext, logger, active_log_file, available_log_files, page_text, ensure_tool
48
- from raijin_server.validators import validate_system_requirements, check_module_dependencies
48
+ from raijin_server.validators import validate_system_requirements, check_module_dependencies, MODULE_DEPENDENCIES
49
49
  from raijin_server.healthchecks import run_health_check
50
50
  from raijin_server.config import ConfigManager
51
51
 
@@ -85,9 +85,9 @@ MODULES: Dict[str, Callable[[ExecutionContext], None]] = {
85
85
  "vpn": vpn.run,
86
86
  "kubernetes": kubernetes.run,
87
87
  "calico": calico.run,
88
+ "traefik": traefik.run, # mover antes do cert_manager para refletir dependencia
88
89
  "cert_manager": cert_manager.run,
89
90
  "istio": istio.run,
90
- "traefik": traefik.run,
91
91
  "kong": kong.run,
92
92
  "minio": minio.run,
93
93
  "prometheus": prometheus.run,
@@ -103,6 +103,11 @@ MODULES: Dict[str, Callable[[ExecutionContext], None]] = {
103
103
  "full_install": full_install.run,
104
104
  }
105
105
 
106
+ # Rollbacks sao opcionais; por padrao apenas removem marcador de conclusao e avisam
107
+ ROLLBACK_HANDLERS: Dict[str, Callable[[ExecutionContext], None]] = {
108
+ # Exemplos para futuras customizacoes: "traefik": traefik.rollback
109
+ }
110
+
106
111
  MODULE_DESCRIPTIONS: Dict[str, str] = {
107
112
  "sanitize": "Remove instalacoes antigas de Kubernetes e prepara ambiente",
108
113
  "bootstrap": "Instala ferramentas: helm, kubectl, istioctl, velero, containerd",
@@ -253,6 +258,79 @@ def _is_completed(name: str) -> bool:
253
258
  return _state_file(name).exists()
254
259
 
255
260
 
261
+ def _clear_completed(name: str) -> None:
262
+ try:
263
+ path = _state_file(name)
264
+ if path.exists():
265
+ path.unlink()
266
+ typer.secho(f"Estado removido: {name}", fg=typer.colors.YELLOW)
267
+ except Exception as exc:
268
+ console.print(f"[yellow]Nao foi possivel limpar estado de {name}: {exc}[/yellow]")
269
+
270
+
271
+ def _dependents_of(module: str) -> list[str]:
272
+ dependents = []
273
+ for mod, deps in MODULE_DEPENDENCIES.items():
274
+ if module in deps:
275
+ dependents.append(mod)
276
+ return dependents
277
+
278
+
279
+ def _default_rollback(exec_ctx: ExecutionContext, name: str) -> None:
280
+ """Rollback padrao: nao aplica alteracoes, apenas sinaliza ausencia de implementacao."""
281
+ if exec_ctx.dry_run:
282
+ typer.secho(f"[dry-run] Rollback para '{name}' nao automatizado (necessario reverter manualmente).", fg=typer.colors.YELLOW)
283
+ else:
284
+ typer.secho(
285
+ f"Rollback para '{name}' ainda nao foi automatizado. Reverta recursos manualmente e reexecute se necessario.",
286
+ fg=typer.colors.YELLOW,
287
+ )
288
+
289
+
290
+ def _get_rollback_handler(name: str) -> Callable[[ExecutionContext], None]:
291
+ return ROLLBACK_HANDLERS.get(name, lambda ctx: _default_rollback(ctx, name))
292
+
293
+
294
+ def _rollback_module(
295
+ ctx: typer.Context,
296
+ name: str,
297
+ *,
298
+ cascade_prompt: bool = True,
299
+ visited: set[str] | None = None,
300
+ ) -> None:
301
+ handler = _get_rollback_handler(name)
302
+ exec_ctx = ctx.obj or ExecutionContext()
303
+
304
+ visited = visited or set()
305
+ if name in visited:
306
+ return
307
+ visited.add(name)
308
+
309
+ dependents = _dependents_of(name)
310
+ completed_dependents = [dep for dep in dependents if _is_completed(dep)]
311
+
312
+ if completed_dependents and cascade_prompt:
313
+ typer.secho(
314
+ "Dependencias detectadas apos este modulo: " + ", ".join(completed_dependents),
315
+ fg=typer.colors.YELLOW,
316
+ )
317
+ typer.secho(
318
+ "Rollback em cascata vai tentar reverter esses modulos primeiro para evitar estado inconsistente.",
319
+ fg=typer.colors.YELLOW,
320
+ )
321
+ if not typer.confirm("Prosseguir com rollback em cascata?", default=False):
322
+ typer.secho("Rollback cancelado.", fg=typer.colors.RED)
323
+ return
324
+
325
+ for dep in completed_dependents:
326
+ _rollback_module(ctx, dep, cascade_prompt=False, visited=visited)
327
+
328
+ typer.secho(f"\n[ROLLBACK] {name}", fg=typer.colors.CYAN, bold=True)
329
+ handler(exec_ctx)
330
+ _clear_completed(name)
331
+ typer.secho(f"Rollback finalizado (best-effort) para {name}\n", fg=typer.colors.GREEN)
332
+
333
+
256
334
  def _render_menu(dry_run: bool) -> int:
257
335
  table = Table(
258
336
  title="Selecione um modulo para executar",
@@ -326,9 +404,21 @@ def interactive_menu(ctx: typer.Context) -> None:
326
404
  console.print("[red]Opcao invalida[/red]")
327
405
  continue
328
406
 
407
+ action = Prompt.ask(
408
+ "Acao (e=executar, r=rollback, c=cancelar)",
409
+ choices=["e", "r", "c"],
410
+ default="e",
411
+ )
412
+
329
413
  exec_ctx = ExecutionContext(dry_run=current_dry_run)
330
414
  ctx.obj = exec_ctx
331
- _run_module(ctx, name)
415
+
416
+ if action == "e":
417
+ _run_module(ctx, name)
418
+ elif action == "r":
419
+ _rollback_module(ctx, name)
420
+ else:
421
+ console.print("[yellow]Acao cancelada[/yellow]")
332
422
  # Loop continua e menu eh re-renderizado, refletindo status atualizado quando nao eh dry-run.
333
423
 
334
424
 
@@ -375,6 +465,21 @@ def menu(ctx: typer.Context) -> None:
375
465
  interactive_menu(ctx)
376
466
 
377
467
 
468
+ @app.command()
469
+ def rollback(
470
+ ctx: typer.Context,
471
+ module: str = typer.Argument(..., help="Modulo a reverter"),
472
+ cascade: bool = typer.Option(
473
+ True,
474
+ "--cascade/--no-cascade",
475
+ help="Quando habilitado, pergunta e aplica rollback em dependentes concluidos primeiro",
476
+ ),
477
+ ) -> None:
478
+ """Executa rollback best-effort de um modulo (com aviso sobre dependencias)."""
479
+
480
+ _rollback_module(ctx, module, cascade_prompt=cascade)
481
+
482
+
378
483
  @app.command()
379
484
  def hardening(ctx: typer.Context) -> None:
380
485
  _run_module(ctx, "hardening")
@@ -17,6 +17,12 @@ from raijin_server.utils import (
17
17
  )
18
18
 
19
19
 
20
+ CALICO_VERSION = "v3.28.0"
21
+ CALICO_URL = f"https://raw.githubusercontent.com/projectcalico/calico/{CALICO_VERSION}/manifests/calico.yaml"
22
+ DEFAULT_CNI = os.environ.get("RAIJIN_CNI", "calico").lower() # calico|none
23
+ FORCE_CNI = os.environ.get("RAIJIN_FORCE_CNI", "0") == "1"
24
+
25
+
20
26
  def _cleanup_old_repo(ctx: ExecutionContext) -> None:
21
27
  """Remove repo legado apt.kubernetes.io se existir para evitar erro 404."""
22
28
 
@@ -49,6 +55,69 @@ def _reset_cluster(ctx: ExecutionContext) -> None:
49
55
  typer.secho("✓ Limpeza concluida.", fg=typer.colors.GREEN)
50
56
 
51
57
 
58
+ def _cni_present(ctx: ExecutionContext) -> bool:
59
+ """Detecta se ja existe um CNI aplicado (qualquer DaemonSet tipico)."""
60
+
61
+ result = run_cmd(
62
+ [
63
+ "kubectl",
64
+ "get",
65
+ "daemonset",
66
+ "-n",
67
+ "kube-system",
68
+ "-o",
69
+ "jsonpath={.items[*].metadata.name}",
70
+ ],
71
+ ctx,
72
+ check=False,
73
+ )
74
+ if result.returncode != 0:
75
+ return False
76
+ names = (result.stdout or "").split()
77
+ for name in names:
78
+ if any(token in name for token in ("calico", "cilium", "flannel", "weave", "canal")):
79
+ return True
80
+ return False
81
+
82
+
83
+ def _apply_calico(pod_cidr: str, ctx: ExecutionContext) -> None:
84
+ """Aplica Calico com CIDR alinhado ao podSubnet informado."""
85
+
86
+ typer.echo(f"Aplicando Calico ({CALICO_VERSION}) com pod CIDR {pod_cidr}...")
87
+
88
+ if ctx.dry_run:
89
+ typer.echo("[dry-run] kubectl apply -f <calico.yaml>")
90
+ return
91
+
92
+ cmd = (
93
+ f"curl -fsSL --retry 3 --retry-delay 2 {CALICO_URL} "
94
+ f"| sed 's#192.168.0.0/16#{pod_cidr}#g' "
95
+ f"| kubectl apply -f -"
96
+ )
97
+ run_cmd(cmd, ctx, use_shell=True)
98
+
99
+ # Aguarda o daemonset subir para evitar Node NotReady por falta de CNI
100
+ run_cmd(
101
+ ["kubectl", "-n", "kube-system", "rollout", "status", "daemonset/calico-node", "--timeout", "300s"],
102
+ ctx,
103
+ check=False,
104
+ )
105
+ run_cmd(
106
+ [
107
+ "kubectl",
108
+ "-n",
109
+ "kube-system",
110
+ "rollout",
111
+ "status",
112
+ "deployment/calico-kube-controllers",
113
+ "--timeout",
114
+ "300s",
115
+ ],
116
+ ctx,
117
+ check=False,
118
+ )
119
+
120
+
52
121
  def run(ctx: ExecutionContext) -> None:
53
122
  require_root(ctx)
54
123
  typer.echo("Instalando e preparando Kubernetes (kubeadm/kubelet/kubectl)...")
@@ -238,3 +307,27 @@ cgroupDriver: systemd
238
307
 
239
308
  typer.echo("Comando de join para workers:")
240
309
  run_cmd(["kubeadm", "token", "create", "--print-join-command"], ctx, check=False)
310
+
311
+ # CNI padrao: Calico (pode ser desabilitado via RAIJIN_CNI=none)
312
+ cni_choice = DEFAULT_CNI
313
+ if cni_choice == "none":
314
+ typer.secho(
315
+ "CNI nao aplicado (RAIJIN_CNI=none). Node permanecera NotReady ate aplicar um CNI manual.",
316
+ fg=typer.colors.YELLOW,
317
+ )
318
+ else:
319
+ if _cni_present(ctx) and not FORCE_CNI:
320
+ typer.secho("CNI ja detectado em kube-system; pulando aplicacao automatica (defina RAIJIN_FORCE_CNI=1 para reaplicar).", fg=typer.colors.YELLOW)
321
+ else:
322
+ _apply_calico(pod_cidr, ctx)
323
+
324
+ # Pequeno health check basico para sinalizar ao usuario
325
+ typer.echo("Validando node apos CNI...")
326
+ run_cmd([
327
+ "kubectl",
328
+ "wait",
329
+ "--for=condition=Ready",
330
+ "nodes",
331
+ "--all",
332
+ "--timeout=180s",
333
+ ], ctx, check=False)
@@ -15,8 +15,7 @@ def run(ctx: ExecutionContext) -> None:
15
15
  values = [
16
16
  "ingressClass.enabled=true",
17
17
  "ingressClass.isDefaultClass=true",
18
- "ports.web.redirectTo=websecure=true",
19
- "ports.websecure.tls.enabled=true",
18
+ "ports.web.redirectTo=websecure", # valor esperado é o nome da porta de destino
20
19
  "service.type=LoadBalancer",
21
20
  f"certificatesResolvers.letsencrypt.acme.email={acme_email}",
22
21
  "certificatesResolvers.letsencrypt.acme.storage=/data/acme.json",
@@ -15,6 +15,27 @@ import typer
15
15
 
16
16
  from raijin_server.utils import ExecutionContext, logger
17
17
 
18
+ # Grafo de dependencias entre modulos (usado por validacoes e funcoes de rollback)
19
+ MODULE_DEPENDENCIES = {
20
+ "kubernetes": ["essentials", "network", "firewall"],
21
+ "calico": ["kubernetes"],
22
+ "cert_manager": ["kubernetes", "traefik"],
23
+ "istio": ["kubernetes", "calico"],
24
+ "traefik": ["kubernetes"],
25
+ "kong": ["kubernetes"],
26
+ "minio": ["kubernetes"],
27
+ "prometheus": ["kubernetes"],
28
+ "grafana": ["kubernetes", "prometheus"],
29
+ "loki": ["kubernetes"],
30
+ "secrets": ["kubernetes"],
31
+ "harness": ["kubernetes"],
32
+ "velero": ["kubernetes"],
33
+ "kafka": ["kubernetes"],
34
+ "observability_ingress": ["traefik", "prometheus", "grafana"],
35
+ "observability_dashboards": ["prometheus", "grafana"],
36
+ "apokolips_demo": ["kubernetes", "traefik"],
37
+ }
38
+
18
39
 
19
40
  class ValidationError(Exception):
20
41
  """Erro de validacao de pre-requisitos."""
@@ -215,30 +236,10 @@ def check_module_dependencies(module: str, ctx: ExecutionContext) -> bool:
215
236
  Returns:
216
237
  True se todas as dependencias foram satisfeitas
217
238
  """
218
- dependencies = {
219
- "kubernetes": ["essentials", "network", "firewall"],
220
- "calico": ["kubernetes"],
221
- "cert_manager": ["kubernetes", "traefik"],
222
- "istio": ["kubernetes", "calico"],
223
- "traefik": ["kubernetes"],
224
- "kong": ["kubernetes"],
225
- "minio": ["kubernetes"],
226
- "prometheus": ["kubernetes"],
227
- "grafana": ["kubernetes", "prometheus"],
228
- "loki": ["kubernetes"],
229
- "secrets": ["kubernetes"],
230
- "harness": ["kubernetes"],
231
- "velero": ["kubernetes"],
232
- "kafka": ["kubernetes"],
233
- "observability_ingress": ["traefik", "prometheus", "grafana"],
234
- "observability_dashboards": ["prometheus", "grafana"],
235
- "apokolips_demo": ["kubernetes", "traefik"],
236
- }
237
-
238
- if module not in dependencies:
239
+ if module not in MODULE_DEPENDENCIES:
239
240
  return True
240
241
 
241
- required = dependencies[module]
242
+ required = MODULE_DEPENDENCIES[module]
242
243
  missing = []
243
244
 
244
245
  # Verifica arquivos de estado
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: raijin-server
3
- Version: 0.2.8
3
+ Version: 0.2.10
4
4
  Summary: CLI para automacao de setup e hardening de servidores Ubuntu Server.
5
5
  Home-page: https://example.com/raijin-server
6
6
  Author: Equipe Raijin
@@ -44,6 +44,8 @@ CLI em Python (Typer) para automatizar setup e hardening de servidores Ubuntu Se
44
44
  - Arquitetura: [ARCHITECTURE.md](ARCHITECTURE.md)
45
45
  - Auditoria: [AUDIT.md](AUDIT.md)
46
46
  - Segurança: [SECURITY.md](SECURITY.md)
47
+ - Acesso SSH (Windows): [docs/SSH_WINDOWS.md](docs/SSH_WINDOWS.md)
48
+ - VPN para acesso remoto (WireGuard): [docs/VPN_REMOTE_ACCESS.md](docs/VPN_REMOTE_ACCESS.md)
47
49
 
48
50
  ## Destaques
49
51
 
@@ -60,6 +62,12 @@ CLI em Python (Typer) para automatizar setup e hardening de servidores Ubuntu Se
60
62
  - ✅ **Modo Dry-run**: Simula execução sem aplicar mudanças
61
63
 
62
64
  ## Requisitos
65
+ Ubuntu Server 20.04+ com Python 3 disponível. Se precisar instalar/atualizar no host alvo:
66
+
67
+ ```bash
68
+ sudo apt update
69
+ sudo apt install -y python3 python3-venv python3-pip
70
+ ```
63
71
 
64
72
  ## Instalação (sempre em venv midgard)
65
73
 
@@ -110,6 +118,10 @@ sudo -E ~/.venvs/midgard/bin/raijin-server validate
110
118
  sudo -E ~/.venvs/midgard/bin/raijin-server menu
111
119
  ```
112
120
 
121
+ ### Rollback de módulos
122
+ - No menu, após escolher o módulo, selecione `r` para rollback; se houver dependentes já executados, será pedido confirmacao para rollback em cascata dos dependentes antes.
123
+ - Linha de comando: `sudo -E ~/.venvs/midgard/bin/raijin-server rollback <modulo> --cascade/--no-cascade` (best-effort; alguns módulos podem exigir limpeza manual). Caso seja apenas para revisar o efeito, use `-n/--dry-run` no comando principal para não aplicar.
124
+
113
125
  ### Execução Direta de Módulos
114
126
  ```bash
115
127
  # Executar módulo específico
@@ -173,6 +185,9 @@ sudo -E ~/.venvs/midgard/bin/raijin-server debug journal --service containerd --
173
185
  - **[AUDIT.md](AUDIT.md)**: Relatório completo de auditoria e melhorias implementadas
174
186
  - **[ARCHITECTURE.md](ARCHITECTURE.md)**: Arquitetura técnica do ambiente
175
187
  - **[SECURITY.md](SECURITY.md)**: Políticas de segurança e reporte de vulnerabilidades
188
+ - **Publicação PyPI**: ver seção "Publicar no PyPI" abaixo
189
+ - **CNI automático**: Calico aplicado automaticamente no passo Kubernetes (override com `RAIJIN_CNI=none`)
190
+ - Para reaplicar CNI (forçar mesmo se já houver): `RAIJIN_FORCE_CNI=1`
176
191
 
177
192
  ## Fluxo de Execução Recomendado
178
193
 
@@ -329,6 +344,46 @@ bash "$SCRIPT_PATH"
329
344
 
330
345
  O helper garante o caminho absoluto correto independentemente de onde o pacote foi instalado.
331
346
 
347
+ ## Publicar no PyPI
348
+
349
+ Use o venv local do repositório (`.venv`) para garantir dependências corretas:
350
+
351
+ ```bash
352
+ cd /home/rafael/github/raijin-server
353
+ python3 -m venv .venv
354
+ source .venv/bin/activate
355
+ python -m pip install -U pip build twine
356
+ ```
357
+
358
+ Gerar artefatos limpos:
359
+
360
+ ```bash
361
+ rm -rf dist build
362
+ python -m build --sdist --wheel --outdir dist
363
+ ```
364
+
365
+ Publicar no PyPI (requere token):
366
+
367
+ ```bash
368
+ export TWINE_USERNAME="__token__"
369
+ export TWINE_PASSWORD="pypi-xxxxx" # token do PyPI
370
+ python -m twine upload dist/*
371
+ ```
372
+
373
+ Opcional: validar no TestPyPI antes de publicar (precisa token de TestPyPI):
374
+
375
+ ```bash
376
+ export TWINE_USERNAME="__token__"
377
+ export TWINE_PASSWORD="pypi-xxxxx" # token do TestPyPI
378
+ python -m twine upload --repository testpypi dist/*
379
+ ```
380
+
381
+ Depois de publicar, atualize/instale:
382
+
383
+ ```bash
384
+ pip install -U raijin-server
385
+ ```
386
+
332
387
  ## Teste de ingress (Apokolips)
333
388
 
334
389
  O módulo [src/raijin_server/modules/apokolips_demo.py](src/raijin_server/modules/apokolips_demo.py) cria um namespace dedicado, ConfigMap com HTML, Deployment NGINX, Service e Ingress Traefik com uma landing page "Apokolips" para validar o tráfego externo.
@@ -437,17 +492,18 @@ O Twine é a ferramenta oficial para enviar pacotes Python ao PyPI com upload se
437
492
  Passo a passo:
438
493
  ```bash
439
494
  # 1) Gere artefatos
440
- python -m build --sdist --wheel --outdir dist/
495
+ python3 -m pip install --user build
496
+ python3 -m build --sdist --wheel --outdir dist/
441
497
 
442
498
  # 2) Configure o token (crie em https://pypi.org/manage/account/token/)
443
499
  export TWINE_USERNAME=__token__
444
500
  export TWINE_PASSWORD="<seu-token>"
445
501
 
446
502
  # 3) Envie para o PyPI
447
- python -m twine upload dist/*
503
+ python3 -m twine upload dist/*
448
504
 
449
505
  # 4) Verifique instalação
450
- python -m pip install -U raijin-server
506
+ python3 -m pip install -U raijin-server
451
507
  raijin-server --version
452
508
  ```
453
509
 
@@ -1,5 +0,0 @@
1
- """Pacote principal do CLI Raijin Server."""
2
-
3
- __version__ = "0.2.7"
4
-
5
- __all__ = ["__version__"]
File without changes