raijin-server 0.2.41__py3-none-any.whl → 0.3.1__py3-none-any.whl
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.
Potentially problematic release.
This version of raijin-server might be problematic. Click here for more details.
- raijin_server/__init__.py +1 -1
- raijin_server/cli.py +6 -0
- raijin_server/modules/__init__.py +3 -1
- raijin_server/modules/grafana.py +365 -16
- raijin_server/modules/internal_dns.py +446 -0
- raijin_server/modules/kong.py +8 -4
- raijin_server/modules/minio.py +15 -5
- raijin_server/modules/observability_ingress.py +29 -1
- raijin_server/modules/prometheus.py +266 -3
- raijin_server/modules/traefik.py +35 -1
- raijin_server/modules/vpn_client.py +526 -0
- raijin_server-0.3.1.dist-info/METADATA +362 -0
- {raijin_server-0.2.41.dist-info → raijin_server-0.3.1.dist-info}/RECORD +17 -15
- raijin_server-0.2.41.dist-info/METADATA +0 -564
- {raijin_server-0.2.41.dist-info → raijin_server-0.3.1.dist-info}/WHEEL +0 -0
- {raijin_server-0.2.41.dist-info → raijin_server-0.3.1.dist-info}/entry_points.txt +0 -0
- {raijin_server-0.2.41.dist-info → raijin_server-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {raijin_server-0.2.41.dist-info → raijin_server-0.3.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
"""Configuração de DNS interno para domínios privados (*.asgard.internal)."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import textwrap
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from raijin_server.utils import (
|
|
11
|
+
ExecutionContext,
|
|
12
|
+
kubectl_apply,
|
|
13
|
+
logger,
|
|
14
|
+
require_root,
|
|
15
|
+
run_cmd,
|
|
16
|
+
write_file,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
NAMESPACE = "kube-system"
|
|
20
|
+
MANIFEST_PATH = Path("/tmp/raijin-internal-dns.yaml")
|
|
21
|
+
INGRESS_MANIFEST_PATH = Path("/tmp/raijin-internal-ingress.yaml")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _get_node_ip(ctx: ExecutionContext) -> str:
|
|
25
|
+
"""Obtém o IP do nó do cluster."""
|
|
26
|
+
result = run_cmd(
|
|
27
|
+
[
|
|
28
|
+
"kubectl",
|
|
29
|
+
"get",
|
|
30
|
+
"nodes",
|
|
31
|
+
"-o",
|
|
32
|
+
"jsonpath={.items[0].status.addresses[?(@.type=='InternalIP')].address}",
|
|
33
|
+
],
|
|
34
|
+
ctx,
|
|
35
|
+
check=False,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
if result.returncode == 0 and result.stdout.strip():
|
|
39
|
+
return result.stdout.strip()
|
|
40
|
+
|
|
41
|
+
return "10.8.0.1" # Fallback para IP da VPN
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _get_current_corefile(ctx: ExecutionContext) -> str:
|
|
45
|
+
"""Obtém o Corefile atual do CoreDNS."""
|
|
46
|
+
result = run_cmd(
|
|
47
|
+
[
|
|
48
|
+
"kubectl", "get", "configmap", "coredns", "-n", NAMESPACE,
|
|
49
|
+
"-o", "jsonpath={.data.Corefile}",
|
|
50
|
+
],
|
|
51
|
+
ctx,
|
|
52
|
+
check=False,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
if result.returncode == 0:
|
|
56
|
+
return result.stdout.strip()
|
|
57
|
+
|
|
58
|
+
return ""
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _build_coredns_patch(domain: str, node_ip: str, current_corefile: str) -> str:
|
|
62
|
+
"""Cria patch para adicionar zona customizada ao Corefile existente."""
|
|
63
|
+
# Bloco de configuração para o domínio interno
|
|
64
|
+
internal_zone = f"""
|
|
65
|
+
{domain}:53 {{
|
|
66
|
+
errors
|
|
67
|
+
cache 30
|
|
68
|
+
hosts {{
|
|
69
|
+
{node_ip} grafana.{domain}
|
|
70
|
+
{node_ip} prometheus.{domain}
|
|
71
|
+
{node_ip} alertmanager.{domain}
|
|
72
|
+
{node_ip} loki.{domain}
|
|
73
|
+
{node_ip} minio.{domain}
|
|
74
|
+
{node_ip} traefik.{domain}
|
|
75
|
+
{node_ip} kong.{domain}
|
|
76
|
+
fallthrough
|
|
77
|
+
}}
|
|
78
|
+
}}
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
# Se já tem configuração para o domínio, não adiciona duplicado
|
|
82
|
+
if f"{domain}:53" in current_corefile:
|
|
83
|
+
return ""
|
|
84
|
+
|
|
85
|
+
# Adiciona a nova zona no início do Corefile
|
|
86
|
+
new_corefile = internal_zone + "\n" + current_corefile
|
|
87
|
+
|
|
88
|
+
return new_corefile
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _build_coredns_configmap(domain: str, node_ip: str, current_corefile: str) -> str:
|
|
92
|
+
"""Cria ConfigMap do CoreDNS atualizado com zona customizada."""
|
|
93
|
+
new_corefile = _build_coredns_patch(domain, node_ip, current_corefile)
|
|
94
|
+
|
|
95
|
+
if not new_corefile:
|
|
96
|
+
return ""
|
|
97
|
+
|
|
98
|
+
# Escapa caracteres especiais para JSON
|
|
99
|
+
escaped_corefile = new_corefile.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
|
|
100
|
+
|
|
101
|
+
return textwrap.dedent(
|
|
102
|
+
f"""
|
|
103
|
+
apiVersion: v1
|
|
104
|
+
kind: ConfigMap
|
|
105
|
+
metadata:
|
|
106
|
+
name: coredns
|
|
107
|
+
namespace: {NAMESPACE}
|
|
108
|
+
data:
|
|
109
|
+
Corefile: |
|
|
110
|
+
{textwrap.indent(new_corefile, ' ')}
|
|
111
|
+
"""
|
|
112
|
+
).strip()
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _build_internal_ingress(domain: str, services: list[dict]) -> str:
|
|
116
|
+
"""Cria Ingress interno para os serviços administrativos."""
|
|
117
|
+
ingress_rules = []
|
|
118
|
+
|
|
119
|
+
for svc in services:
|
|
120
|
+
name = svc["name"]
|
|
121
|
+
namespace = svc["namespace"]
|
|
122
|
+
port = svc["port"]
|
|
123
|
+
host = svc["host"]
|
|
124
|
+
|
|
125
|
+
ingress_rules.append(
|
|
126
|
+
textwrap.dedent(
|
|
127
|
+
f"""
|
|
128
|
+
---
|
|
129
|
+
apiVersion: networking.k8s.io/v1
|
|
130
|
+
kind: Ingress
|
|
131
|
+
metadata:
|
|
132
|
+
name: {name}-internal
|
|
133
|
+
namespace: {namespace}
|
|
134
|
+
annotations:
|
|
135
|
+
traefik.ingress.kubernetes.io/router.entrypoints: web
|
|
136
|
+
traefik.ingress.kubernetes.io/router.priority: "10"
|
|
137
|
+
spec:
|
|
138
|
+
ingressClassName: traefik
|
|
139
|
+
rules:
|
|
140
|
+
- host: {host}.{domain}
|
|
141
|
+
http:
|
|
142
|
+
paths:
|
|
143
|
+
- path: /
|
|
144
|
+
pathType: Prefix
|
|
145
|
+
backend:
|
|
146
|
+
service:
|
|
147
|
+
name: {name}
|
|
148
|
+
port:
|
|
149
|
+
number: {port}
|
|
150
|
+
"""
|
|
151
|
+
).strip()
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return "\n".join(ingress_rules)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _detect_services(ctx: ExecutionContext) -> list[dict]:
|
|
158
|
+
"""Detecta serviços instalados que podem ter Ingress interno."""
|
|
159
|
+
services = [
|
|
160
|
+
{
|
|
161
|
+
"name": "grafana",
|
|
162
|
+
"namespace": "observability",
|
|
163
|
+
"port": 80,
|
|
164
|
+
"host": "grafana",
|
|
165
|
+
"label": "Grafana"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"name": "kube-prometheus-stack-prometheus",
|
|
169
|
+
"namespace": "observability",
|
|
170
|
+
"port": 9090,
|
|
171
|
+
"host": "prometheus",
|
|
172
|
+
"label": "Prometheus"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"name": "kube-prometheus-stack-alertmanager",
|
|
176
|
+
"namespace": "observability",
|
|
177
|
+
"port": 9093,
|
|
178
|
+
"host": "alertmanager",
|
|
179
|
+
"label": "Alertmanager"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"name": "loki",
|
|
183
|
+
"namespace": "observability",
|
|
184
|
+
"port": 3100,
|
|
185
|
+
"host": "loki",
|
|
186
|
+
"label": "Loki"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"name": "minio-console",
|
|
190
|
+
"namespace": "minio",
|
|
191
|
+
"port": 9001,
|
|
192
|
+
"host": "minio",
|
|
193
|
+
"label": "MinIO Console"
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"name": "traefik",
|
|
197
|
+
"namespace": "traefik",
|
|
198
|
+
"port": 9000,
|
|
199
|
+
"host": "traefik",
|
|
200
|
+
"label": "Traefik Dashboard"
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"name": "kong-admin",
|
|
204
|
+
"namespace": "kong",
|
|
205
|
+
"port": 8001,
|
|
206
|
+
"host": "kong",
|
|
207
|
+
"label": "Kong Admin API"
|
|
208
|
+
},
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
available = []
|
|
212
|
+
for svc in services:
|
|
213
|
+
result = run_cmd(
|
|
214
|
+
["kubectl", "get", "svc", svc["name"], "-n", svc["namespace"]],
|
|
215
|
+
ctx,
|
|
216
|
+
check=False,
|
|
217
|
+
)
|
|
218
|
+
if result.returncode == 0:
|
|
219
|
+
available.append(svc)
|
|
220
|
+
|
|
221
|
+
return available
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def _update_vpn_dns(domain: str, node_ip: str, ctx: ExecutionContext) -> None:
|
|
225
|
+
"""Atualiza configuração do WireGuard para usar DNS interno."""
|
|
226
|
+
wg_conf = Path("/etc/wireguard/wg0.conf")
|
|
227
|
+
|
|
228
|
+
if not wg_conf.exists():
|
|
229
|
+
typer.secho(
|
|
230
|
+
"⚠ Arquivo /etc/wireguard/wg0.conf não encontrado.",
|
|
231
|
+
fg=typer.colors.YELLOW,
|
|
232
|
+
)
|
|
233
|
+
typer.echo("Configure a VPN primeiro com: sudo raijin vpn")
|
|
234
|
+
return
|
|
235
|
+
|
|
236
|
+
if ctx.dry_run:
|
|
237
|
+
typer.echo(f"[dry-run] Atualizaria DNS no WireGuard para {node_ip}")
|
|
238
|
+
return
|
|
239
|
+
|
|
240
|
+
content = wg_conf.read_text()
|
|
241
|
+
|
|
242
|
+
# Procura pela linha DNS na seção [Interface]
|
|
243
|
+
lines = content.split("\n")
|
|
244
|
+
updated = False
|
|
245
|
+
|
|
246
|
+
for i, line in enumerate(lines):
|
|
247
|
+
if line.strip().startswith("DNS ="):
|
|
248
|
+
# Atualiza para usar o DNS do cluster
|
|
249
|
+
lines[i] = f"DNS = {node_ip}"
|
|
250
|
+
updated = True
|
|
251
|
+
break
|
|
252
|
+
|
|
253
|
+
if updated:
|
|
254
|
+
wg_conf.write_text("\n".join(lines))
|
|
255
|
+
logger.info("DNS do WireGuard atualizado para %s", node_ip)
|
|
256
|
+
|
|
257
|
+
# Atualiza clientes existentes
|
|
258
|
+
clients_dir = Path("/etc/wireguard/clients")
|
|
259
|
+
if clients_dir.exists():
|
|
260
|
+
for client_conf in clients_dir.glob("*.conf"):
|
|
261
|
+
client_content = client_conf.read_text()
|
|
262
|
+
client_lines = client_content.split("\n")
|
|
263
|
+
|
|
264
|
+
for i, line in enumerate(client_lines):
|
|
265
|
+
if line.strip().startswith("DNS ="):
|
|
266
|
+
client_lines[i] = f"DNS = {node_ip}"
|
|
267
|
+
break
|
|
268
|
+
|
|
269
|
+
client_conf.write_text("\n".join(client_lines))
|
|
270
|
+
logger.info("DNS atualizado no cliente %s", client_conf.name)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
def run(ctx: ExecutionContext) -> None:
|
|
274
|
+
"""Configura DNS interno para domínios privados."""
|
|
275
|
+
require_root(ctx)
|
|
276
|
+
|
|
277
|
+
typer.secho("\n🌐 Configuração de DNS Interno", fg=typer.colors.CYAN, bold=True)
|
|
278
|
+
typer.echo("\nEsta ferramenta configura DNS interno para acessar serviços via")
|
|
279
|
+
typer.echo("domínios amigáveis como grafana.asgard.internal")
|
|
280
|
+
|
|
281
|
+
typer.secho("\n⚠ Importante:", fg=typer.colors.YELLOW, bold=True)
|
|
282
|
+
typer.echo("- Use extensões reservadas para redes privadas (.internal, .home.arpa)")
|
|
283
|
+
typer.echo("- Evite TLDs reais como .io, .com, .net, etc.")
|
|
284
|
+
typer.echo("- Recomendado: .internal (RFC 6762)")
|
|
285
|
+
|
|
286
|
+
domain = typer.prompt(
|
|
287
|
+
"\nDomínio base (sem o ponto inicial)",
|
|
288
|
+
default="asgard.internal",
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
if "." not in domain:
|
|
292
|
+
typer.secho("⚠ Use um domínio com extensão, ex: asgard.internal", fg=typer.colors.YELLOW)
|
|
293
|
+
if not typer.confirm("Continuar mesmo assim?", default=False):
|
|
294
|
+
raise typer.Exit(0)
|
|
295
|
+
|
|
296
|
+
# Valida extensões não recomendadas
|
|
297
|
+
if any(domain.endswith(ext) for ext in [".io", ".com", ".net", ".org", ".dev"]):
|
|
298
|
+
typer.secho(
|
|
299
|
+
f"⚠ Extensão '{domain.split('.')[-1]}' é um TLD real, não recomendado para uso interno!",
|
|
300
|
+
fg=typer.colors.RED,
|
|
301
|
+
bold=True,
|
|
302
|
+
)
|
|
303
|
+
typer.echo("Recomendação: use .internal, .local, ou .home.arpa")
|
|
304
|
+
if not typer.confirm("Continuar mesmo assim?", default=False):
|
|
305
|
+
raise typer.Exit(0)
|
|
306
|
+
|
|
307
|
+
node_ip = _get_node_ip(ctx)
|
|
308
|
+
typer.echo(f"\nIP do nó detectado: {node_ip}")
|
|
309
|
+
|
|
310
|
+
custom_ip = typer.prompt(
|
|
311
|
+
"IP para resolver os domínios (ENTER para usar o detectado)",
|
|
312
|
+
default=node_ip,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
if custom_ip != node_ip:
|
|
316
|
+
node_ip = custom_ip
|
|
317
|
+
|
|
318
|
+
# 1. Configura CoreDNS
|
|
319
|
+
typer.secho("\n1️⃣ Configurando CoreDNS...", fg=typer.colors.CYAN)
|
|
320
|
+
|
|
321
|
+
# Obtém Corefile atual
|
|
322
|
+
current_corefile = _get_current_corefile(ctx)
|
|
323
|
+
|
|
324
|
+
if not current_corefile:
|
|
325
|
+
typer.secho(
|
|
326
|
+
"⚠ Não foi possível obter o Corefile atual do CoreDNS.",
|
|
327
|
+
fg=typer.colors.YELLOW,
|
|
328
|
+
)
|
|
329
|
+
typer.echo("Verifique se o cluster está acessível.")
|
|
330
|
+
raise typer.Exit(1)
|
|
331
|
+
|
|
332
|
+
# Verifica se já está configurado
|
|
333
|
+
if f"{domain}:53" in current_corefile:
|
|
334
|
+
typer.secho(
|
|
335
|
+
f"✓ Domínio {domain} já está configurado no CoreDNS.",
|
|
336
|
+
fg=typer.colors.GREEN,
|
|
337
|
+
)
|
|
338
|
+
typer.echo("Pulando configuração do CoreDNS...")
|
|
339
|
+
else:
|
|
340
|
+
coredns_cm = _build_coredns_configmap(domain, node_ip, current_corefile)
|
|
341
|
+
|
|
342
|
+
if not coredns_cm:
|
|
343
|
+
typer.secho("⚠ Não foi possível gerar a configuração do CoreDNS.", fg=typer.colors.YELLOW)
|
|
344
|
+
raise typer.Exit(1)
|
|
345
|
+
|
|
346
|
+
# Mostra preview antes de aplicar
|
|
347
|
+
if not ctx.dry_run:
|
|
348
|
+
typer.secho("\n📄 Preview da nova configuração do CoreDNS:", fg=typer.colors.YELLOW)
|
|
349
|
+
typer.echo("─" * 60)
|
|
350
|
+
# Mostra apenas a zona adicionada (não o Corefile inteiro)
|
|
351
|
+
typer.echo(f"Nova zona para {domain}:")
|
|
352
|
+
typer.echo(f" - grafana.{domain} → {node_ip}")
|
|
353
|
+
typer.echo(f" - prometheus.{domain} → {node_ip}")
|
|
354
|
+
typer.echo(f" - alertmanager.{domain} → {node_ip}")
|
|
355
|
+
typer.echo(f" - loki.{domain} → {node_ip}")
|
|
356
|
+
typer.echo(f" - minio.{domain} → {node_ip}")
|
|
357
|
+
typer.echo(f" - traefik.{domain} → {node_ip}")
|
|
358
|
+
typer.echo(f" - kong.{domain} → {node_ip}")
|
|
359
|
+
typer.echo("─" * 60)
|
|
360
|
+
|
|
361
|
+
typer.secho("\nℹ️ Esta alteração:", fg=typer.colors.CYAN)
|
|
362
|
+
typer.echo(" ✓ Adiciona zona DNS para *." + domain)
|
|
363
|
+
typer.echo(" ✓ Mantém todas as configurações existentes do CoreDNS")
|
|
364
|
+
typer.echo(" ✓ Resolve domínios internos para " + node_ip)
|
|
365
|
+
|
|
366
|
+
if not typer.confirm("\nAplicar configuração do CoreDNS?", default=True):
|
|
367
|
+
typer.secho("⏭️ Pulando configuração do CoreDNS", fg=typer.colors.YELLOW)
|
|
368
|
+
raise typer.Exit(0)
|
|
369
|
+
|
|
370
|
+
write_file(MANIFEST_PATH, coredns_cm, ctx)
|
|
371
|
+
kubectl_apply(str(MANIFEST_PATH), ctx)
|
|
372
|
+
|
|
373
|
+
# Reinicia CoreDNS
|
|
374
|
+
typer.echo("Reiniciando CoreDNS...")
|
|
375
|
+
run_cmd(
|
|
376
|
+
["kubectl", "rollout", "restart", "deployment/coredns", "-n", NAMESPACE],
|
|
377
|
+
ctx,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
# 2. Detecta serviços disponíveis
|
|
381
|
+
typer.secho("\n2️⃣ Detectando serviços...", fg=typer.colors.CYAN)
|
|
382
|
+
services = _detect_services(ctx)
|
|
383
|
+
|
|
384
|
+
if not services:
|
|
385
|
+
typer.secho(
|
|
386
|
+
"⚠ Nenhum serviço administrativo encontrado.",
|
|
387
|
+
fg=typer.colors.YELLOW,
|
|
388
|
+
)
|
|
389
|
+
typer.echo("Instale Grafana, Prometheus, MinIO, etc. primeiro.")
|
|
390
|
+
else:
|
|
391
|
+
typer.echo(f"\nEncontrados {len(services)} serviços:")
|
|
392
|
+
for svc in services:
|
|
393
|
+
typer.echo(f" ✓ {svc['label']}: {svc['host']}.{domain}")
|
|
394
|
+
|
|
395
|
+
if typer.confirm("\nCriar Ingress interno para esses serviços?", default=True):
|
|
396
|
+
typer.secho("\n3️⃣ Criando Ingress interno...", fg=typer.colors.CYAN)
|
|
397
|
+
|
|
398
|
+
ingress_manifest = _build_internal_ingress(domain, services)
|
|
399
|
+
|
|
400
|
+
# Preview dos Ingress
|
|
401
|
+
if not ctx.dry_run:
|
|
402
|
+
typer.secho("\n📄 Preview dos Ingress (primeiros 30 linhas):", fg=typer.colors.YELLOW)
|
|
403
|
+
typer.echo("─" * 60)
|
|
404
|
+
lines = ingress_manifest.split("\n")
|
|
405
|
+
typer.echo("\n".join(lines[:30]))
|
|
406
|
+
if len(lines) > 30:
|
|
407
|
+
typer.echo(f"... ({len(lines) - 30} linhas restantes)")
|
|
408
|
+
typer.echo("─" * 60)
|
|
409
|
+
|
|
410
|
+
typer.secho("\nℹ️ Esses Ingress:", fg=typer.colors.CYAN)
|
|
411
|
+
typer.echo(" ✓ Têm sufixo '-internal' no nome")
|
|
412
|
+
typer.echo(" ✓ Não alteram Ingress existentes")
|
|
413
|
+
typer.echo(" ✓ Roteiam por hostname via Traefik")
|
|
414
|
+
|
|
415
|
+
if not typer.confirm("\nAplicar Ingress internos?", default=True):
|
|
416
|
+
typer.secho("⏭️ Pulando criação de Ingress", fg=typer.colors.YELLOW)
|
|
417
|
+
return
|
|
418
|
+
|
|
419
|
+
write_file(INGRESS_MANIFEST_PATH, ingress_manifest, ctx)
|
|
420
|
+
kubectl_apply(str(INGRESS_MANIFEST_PATH), ctx)
|
|
421
|
+
|
|
422
|
+
# 3. Atualiza VPN
|
|
423
|
+
if typer.confirm("\n4️⃣ Atualizar DNS do WireGuard?", default=True):
|
|
424
|
+
_update_vpn_dns(domain, node_ip, ctx)
|
|
425
|
+
|
|
426
|
+
typer.secho("\n⚠ Ação necessária:", fg=typer.colors.YELLOW, bold=True)
|
|
427
|
+
typer.echo("1. Reinicie o WireGuard no servidor:")
|
|
428
|
+
typer.echo(" sudo wg-quick down wg0 && sudo wg-quick up wg0")
|
|
429
|
+
typer.echo("\n2. Distribua novos arquivos .conf aos clientes:")
|
|
430
|
+
typer.echo(" sudo ls /etc/wireguard/clients/")
|
|
431
|
+
typer.echo("\n3. Clientes devem reconectar ao VPN para usar o novo DNS")
|
|
432
|
+
|
|
433
|
+
typer.secho("\n✓ DNS interno configurado com sucesso!", fg=typer.colors.GREEN, bold=True)
|
|
434
|
+
|
|
435
|
+
if services:
|
|
436
|
+
typer.secho("\n📋 Acesso aos serviços:", fg=typer.colors.CYAN, bold=True)
|
|
437
|
+
typer.echo("\nDepois de conectar à VPN, acesse:")
|
|
438
|
+
for svc in services:
|
|
439
|
+
typer.echo(f" • {svc['label']}: http://{svc['host']}.{domain}")
|
|
440
|
+
|
|
441
|
+
typer.secho("\n💡 Dica:", fg=typer.colors.CYAN)
|
|
442
|
+
typer.echo("Você não precisa mais de port-forward!")
|
|
443
|
+
typer.echo("Basta conectar à VPN e acessar diretamente os domínios.")
|
|
444
|
+
|
|
445
|
+
typer.secho("\n🔍 Testar resolução DNS:", fg=typer.colors.CYAN)
|
|
446
|
+
typer.echo(f"kubectl run -it --rm dns-test --image=busybox --restart=Never -- nslookup grafana.{domain}")
|
raijin_server/modules/kong.py
CHANGED
|
@@ -393,16 +393,20 @@ podAnnotations:
|
|
|
393
393
|
# Mostra informacoes uteis
|
|
394
394
|
typer.secho("\n✓ Kong Gateway instalado com sucesso.", fg=typer.colors.GREEN, bold=True)
|
|
395
395
|
|
|
396
|
-
typer.echo("\n📌 Acesso ao Kong Proxy:")
|
|
396
|
+
typer.echo("\n📌 Acesso ao Kong Proxy (APIs públicas):")
|
|
397
397
|
if service_type == "LoadBalancer":
|
|
398
398
|
typer.echo(" kubectl -n kong get svc kong-kong-proxy # Aguarde EXTERNAL-IP")
|
|
399
399
|
else:
|
|
400
400
|
typer.echo(" kubectl -n kong get svc kong-kong-proxy # Use NodePort")
|
|
401
401
|
|
|
402
402
|
if enable_admin:
|
|
403
|
-
typer.
|
|
404
|
-
typer.echo("
|
|
405
|
-
typer.echo("
|
|
403
|
+
typer.secho("\n🔒 Admin API - Acesso Seguro via VPN:", fg=typer.colors.CYAN, bold=True)
|
|
404
|
+
typer.echo("\n1. Configure VPN: sudo raijin vpn")
|
|
405
|
+
typer.echo("2. Conecte via WireGuard")
|
|
406
|
+
typer.echo("3. Port-forward:")
|
|
407
|
+
typer.echo(" kubectl -n kong port-forward svc/kong-kong-admin 8001:8001")
|
|
408
|
+
typer.echo("4. Teste:")
|
|
409
|
+
typer.echo(" curl http://localhost:8001/status")
|
|
406
410
|
|
|
407
411
|
if enable_metrics:
|
|
408
412
|
typer.echo("\n📌 Métricas Prometheus:")
|
raijin_server/modules/minio.py
CHANGED
|
@@ -243,6 +243,9 @@ def _set_default_storage_class(ctx: ExecutionContext, name: str) -> None:
|
|
|
243
243
|
|
|
244
244
|
def _ensure_storage_class(ctx: ExecutionContext) -> str:
|
|
245
245
|
"""Garante que existe uma StorageClass disponivel, instalando local-path se necessario."""
|
|
246
|
+
if ctx.dry_run:
|
|
247
|
+
return "local-path" # Retorna um valor dummy para dry-run
|
|
248
|
+
|
|
246
249
|
default_sc = _get_default_storage_class(ctx)
|
|
247
250
|
available = _list_storage_classes(ctx)
|
|
248
251
|
|
|
@@ -509,9 +512,16 @@ def run(ctx: ExecutionContext) -> None:
|
|
|
509
512
|
typer.echo("\nCredenciais:")
|
|
510
513
|
typer.echo(f" Root User: {root_user}")
|
|
511
514
|
typer.echo(f" Root Password: {root_password}")
|
|
512
|
-
|
|
513
|
-
typer.echo(" kubectl -n minio port-forward svc/minio 9000:9000")
|
|
515
|
+
|
|
514
516
|
if enable_console:
|
|
515
|
-
typer.
|
|
516
|
-
typer.echo("
|
|
517
|
-
typer.echo("
|
|
517
|
+
typer.secho("\n🔒 Acesso Seguro ao MinIO Console via VPN:", fg=typer.colors.CYAN, bold=True)
|
|
518
|
+
typer.echo("\n1. Configure VPN (se ainda não tiver):")
|
|
519
|
+
typer.echo(" sudo raijin vpn")
|
|
520
|
+
typer.echo("\n2. Conecte via WireGuard")
|
|
521
|
+
typer.echo("\n3. Faça port-forward:")
|
|
522
|
+
typer.echo(" kubectl -n minio port-forward svc/minio-console 9001:9001")
|
|
523
|
+
typer.echo("\n4. Acesse no navegador:")
|
|
524
|
+
typer.echo(" http://localhost:9001")
|
|
525
|
+
|
|
526
|
+
typer.echo("\nPara acessar a API S3 (port-forward):")
|
|
527
|
+
typer.echo(" kubectl -n minio port-forward svc/minio 9000:9000")
|
|
@@ -163,7 +163,35 @@ spec:
|
|
|
163
163
|
|
|
164
164
|
def run(ctx: ExecutionContext) -> None:
|
|
165
165
|
require_root(ctx)
|
|
166
|
-
|
|
166
|
+
|
|
167
|
+
typer.secho("⚠️ AVISO DE SEGURANÇA", fg=typer.colors.RED, bold=True)
|
|
168
|
+
typer.secho(
|
|
169
|
+
"\nExpor ferramentas de observabilidade publicamente é um RISCO DE SEGURANÇA significativo!",
|
|
170
|
+
fg=typer.colors.YELLOW,
|
|
171
|
+
)
|
|
172
|
+
typer.secho(
|
|
173
|
+
"Mesmo com TLS e BasicAuth, você estará expondo informações sensíveis do cluster.\n",
|
|
174
|
+
fg=typer.colors.YELLOW,
|
|
175
|
+
)
|
|
176
|
+
typer.secho("✅ RECOMENDAÇÃO FORTE:", fg=typer.colors.GREEN, bold=True)
|
|
177
|
+
typer.echo("1. Configure VPN: sudo raijin vpn")
|
|
178
|
+
typer.echo("2. Use port-forward via VPN para acesso seguro")
|
|
179
|
+
typer.echo("3. Mantenha os dashboards APENAS na rede interna\n")
|
|
180
|
+
|
|
181
|
+
proceed = typer.confirm(
|
|
182
|
+
"Você REALMENTE quer expor os dashboards publicamente?",
|
|
183
|
+
default=False
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
if not proceed:
|
|
187
|
+
typer.secho("\n✓ Boa decisão! Use VPN para acesso seguro.", fg=typer.colors.GREEN)
|
|
188
|
+
typer.echo("\nPara acessar via VPN + port-forward:")
|
|
189
|
+
typer.echo(" kubectl -n observability port-forward svc/grafana 3000:80")
|
|
190
|
+
typer.echo(" kubectl -n observability port-forward svc/kube-prometheus-stack-prometheus 9090:9090")
|
|
191
|
+
typer.echo(" kubectl -n observability port-forward svc/kube-prometheus-stack-alertmanager 9093:9093")
|
|
192
|
+
raise typer.Exit(0)
|
|
193
|
+
|
|
194
|
+
typer.echo("\nProvisionando ingress seguro para observabilidade...")
|
|
167
195
|
|
|
168
196
|
namespace = typer.prompt("Namespace dos componentes", default="observability")
|
|
169
197
|
ingress_class = typer.prompt("IngressClass dedicada", default="traefik")
|