Evolución de seguridad en ns8-candados: MFA por sesión (authorize/cerrar), permisos 600 y reubicación de master key
This commit is contained in:
@@ -0,0 +1,48 @@
|
|||||||
|
# 🧬 ADN del Proyecto: srv-ns8 (Arquitectura de Datos y Normas)
|
||||||
|
|
||||||
|
## Resumen Ejecutivo
|
||||||
|
El directorio `adn/` constituye el "núcleo genético" del servidor `srv-ns8`. No es simplemente una carpeta de documentos, sino un sistema dinámico e interconectado que define las reglas de gobernanza, la ontología de la infraestructura y los protocolos de sincronización del proyecto. Su principio rector es la **Armonía Integral**, donde cualquier cambio en la infraestructura o en los registros debe propagarse para mantener la coherencia del sistema completo.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Análisis Estructural
|
||||||
|
- **Tipo de Proyecto**: Sistema de Gobernanza de Infraestructura y Metadatos (Documentación Viva + Automatización).
|
||||||
|
- **Organización**: Se estructura en **Hebras (1 a 7)**, cada una responsable de un dominio operativo:
|
||||||
|
- `01_ontologia.md`: Definición de nodos (Proxmox, Xen, VMs, Satélites).
|
||||||
|
- `02_bitacora.md`: Estándar para el registro diario y reglas de triggers.
|
||||||
|
- `03_seguridad.md`: Protocolos de protección y acceso seguro.
|
||||||
|
- `04_iconografia.md`: Taxonomía visual semántica para estados y eventos.
|
||||||
|
- `05_ia.md`: Normas y directivas específicas para la interacción con IAs.
|
||||||
|
- `06_gobernanza.md`: Normas de nomenclatura, evolución del sistema y codificación.
|
||||||
|
- `07_proyectos.md`: Gestión transversal de proyectos e hitos.
|
||||||
|
- **Archivos Fundamentales**:
|
||||||
|
- `00_indice.md`: El punto de entrada que explica la interconexión entre Hebras, Bitácoras y Nodos.
|
||||||
|
- `triggers.yml`: Archivo de configuración que orquesta la automatización de la propagación de datos.
|
||||||
|
|
||||||
|
## ⚙️ Configuración y Dependencias
|
||||||
|
- **Tecnologías Clave**:
|
||||||
|
- **Motor de ejecución**: Ruby (utilizado para scripts de automatización como `tools/adn.rb`).
|
||||||
|
- **Formatos**: Markdown para documentación y YAML para reglas de automatización.
|
||||||
|
- **Entorno**: Dockerizado para servicios de red (Nginx, Homepage, Bitácoras).
|
||||||
|
- **Configuración Relevante**:
|
||||||
|
- `triggers.yml`: Define qué acciones disparar ante eventos específicos (ej. cierre de tareas, creación de nuevas bitácoras).
|
||||||
|
- **Comandos Necesarios**:
|
||||||
|
- `ruby tools/adn.rb triggers`: Procesa y sincroniza los cambios basados en las reglas del ADN.
|
||||||
|
- `ruby tools/ns8-candados/ns8-candados.rb`: Gestiona la seguridad y secretos del servidor.
|
||||||
|
|
||||||
|
## 🧠 Contexto para IA
|
||||||
|
- **Patrones y Convenciones**: Se debe mantener estrictamente la iconografía semántica (`04_iconografia.md`) y seguir las directivas de la Hebra 05. Ningún cambio debe romper la "Armonía Integral" definida en el índice.
|
||||||
|
- **Áreas Críticas**:
|
||||||
|
- `triggers.yml` es vital para la integridad de los datos.
|
||||||
|
- La sincronización entre Bitácoras y Ontología es el punto más sensible de la operación diaria.
|
||||||
|
- **Deuda Técnica**: El sistema de triggers está en fase de desarrollo (Fase 2: Automatización), por lo que requiere supervisión humana para validar ciertas propagaciones complejas.
|
||||||
|
|
||||||
|
## 🚀 Próximos Pasos
|
||||||
|
- **Documentación Pendiente**: Expandir la documentación de red en la Ontología para incluir diagramas de topología actualizados.
|
||||||
|
- **Preguntas para Nuevos Colaboradores**:
|
||||||
|
- ¿Cómo se asegura que un nuevo nodo en Proxmox esté correctamente reflejado en la Ontología?
|
||||||
|
- ¿Qué icono semántico corresponde a una tarea en proceso versus una tarea bloqueada?
|
||||||
|
- **Primera Tarea Lógica**: Verificar que las últimas entradas de la bitácora cumplan con el formato de la Hebra 02 y que los triggers hayan procesado las actualizaciones de estado.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Generado siguiendo docs/prompt/documentacion.md*
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# 📋 PROMPT PARA DOCUMENTACIÓN DE PROYECTO
|
||||||
|
|
||||||
|
## Contexto Inicial
|
||||||
|
Eres un arquitecto de software y documentador técnico. Tu tarea es analizar el directorio actual y crear una documentación estructurada que sirva como punto de entrada tanto para humanos como para asistentes de IA.
|
||||||
|
|
||||||
|
## Objetivo
|
||||||
|
Genera un archivo `README.md` que responda a estas preguntas fundamentales:
|
||||||
|
|
||||||
|
### 🔍 Análisis Estructural
|
||||||
|
- ¿Qué tipo de proyecto es? (lenguaje, framework, propósito)
|
||||||
|
- ¿Cómo está organizado el código? (patrón MVC, hexagonal, por capas, etc.)
|
||||||
|
- ¿Cuáles son los archivos más importantes y por qué?
|
||||||
|
|
||||||
|
### ⚙️ Configuración y Dependencias
|
||||||
|
- ¿Qué tecnologías detectas? (Node, Python, Docker, etc.)
|
||||||
|
- ¿Hay archivos de configuración relevantes?
|
||||||
|
- ¿Qué comandos son necesarios para desarrollo/build/test?
|
||||||
|
|
||||||
|
### 🧠 Contexto para IA
|
||||||
|
- ¿Hay algún patrón o convención que deba mantenerse?
|
||||||
|
- ¿Qué partes del código son críticas o delicadas?
|
||||||
|
- ¿Hay deuda técnica o áreas que necesitan atención?
|
||||||
|
|
||||||
|
### 🚀 Próximos Pasos
|
||||||
|
- ¿Cuál sería la primera tarea lógica para alguien que se une al proyecto?
|
||||||
|
- ¿Qué preguntas debería hacer un nuevo desarrollador?
|
||||||
|
- ¿Qué propuestas de mejora faltan?
|
||||||
|
- ¿Qué documentación falta?
|
||||||
|
-
|
||||||
|
|
||||||
|
## Formato Esperado
|
||||||
|
Documento Markdown con secciones claras, ejemplos concretos y un tono profesional pero accesible. Incluye un breve resumen ejecutivo al inicio.
|
||||||
|
|
||||||
|
## Comienza Ahora
|
||||||
|
Analiza el directorio actual y genera la documentación solicitada.
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/bookmarks
|
||||||
|
|
||||||
|
- Developer:
|
||||||
|
- Github:
|
||||||
|
- abbr: GH
|
||||||
|
href: https://github.com/
|
||||||
|
|
||||||
|
- Social:
|
||||||
|
- Reddit:
|
||||||
|
- abbr: RE
|
||||||
|
href: https://reddit.com/
|
||||||
|
|
||||||
|
- Entertainment:
|
||||||
|
- YouTube:
|
||||||
|
- abbr: YT
|
||||||
|
href: https://youtube.com/
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/docker/
|
||||||
|
|
||||||
|
# my-docker:
|
||||||
|
# host: 127.0.0.1
|
||||||
|
# port: 2375
|
||||||
|
|
||||||
|
# my-docker:
|
||||||
|
# socket: /var/run/docker.sock
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
# pve:
|
||||||
|
# url: https://proxmox.host.or.ip:8006
|
||||||
|
# token: username@pam!Token ID
|
||||||
|
# secret: secret
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/services/
|
||||||
|
|
||||||
|
- My First Group:
|
||||||
|
- My First Service:
|
||||||
|
href: http://localhost/
|
||||||
|
description: Homepage is awesome
|
||||||
|
|
||||||
|
- My Second Group:
|
||||||
|
- My Second Service:
|
||||||
|
href: http://localhost/
|
||||||
|
description: Homepage is the best
|
||||||
|
|
||||||
|
- My Third Group:
|
||||||
|
- My Third Service:
|
||||||
|
href: http://localhost/
|
||||||
|
description: Homepage is 😎
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
# For configuration options and examples, please see:
|
||||||
|
# https://gethomepage.dev/configs/info-widgets/
|
||||||
|
|
||||||
|
- resources:
|
||||||
|
cpu: true
|
||||||
|
memory: true
|
||||||
|
disk: /
|
||||||
|
|
||||||
|
- search:
|
||||||
|
provider: duckduckgo
|
||||||
|
target: _blank
|
||||||
@@ -5,6 +5,7 @@ services:
|
|||||||
POSTGRES_USER: dtic_user
|
POSTGRES_USER: dtic_user
|
||||||
POSTGRES_PASSWORD: dtic_pass_2026
|
POSTGRES_PASSWORD: dtic_pass_2026
|
||||||
POSTGRES_DB: dtic_bitacoras
|
POSTGRES_DB: dtic_bitacoras
|
||||||
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "5433:5432"
|
- "5433:5432"
|
||||||
volumes:
|
volumes:
|
||||||
@@ -18,6 +19,7 @@ services:
|
|||||||
|
|
||||||
api:
|
api:
|
||||||
build: ./backend
|
build: ./backend
|
||||||
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "3002:3001"
|
- "3002:3001"
|
||||||
environment:
|
environment:
|
||||||
@@ -34,6 +36,7 @@ services:
|
|||||||
|
|
||||||
frontend:
|
frontend:
|
||||||
build: ./frontend
|
build: ./frontend
|
||||||
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "5174:5173"
|
- "5174:5173"
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
+1729
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
|||||||
|
# 🔐 ns8-candados: Gestión de Secretos y Autorización SSH
|
||||||
|
|
||||||
|
## Resumen Ejecutivo
|
||||||
|
`ns8-candados` es una herramienta de seguridad robusta diseñada para centralizar, cifrar y gestionar secretos operativos del ecosistema `srv-ns8`. Utiliza el algoritmo industrial **AES-256-GCM** para garantizar la integridad y confidencialidad de las credenciales. Su arquitectura implementa un sistema de **Candado Temporal (MFA)** que requiere una autorización explícita para liberar secretos, protegiendo la información incluso si el servidor se ve comprometido.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Análisis Estructural
|
||||||
|
- **Tipo de Proyecto**: Utilidad de seguridad CLI escrita en Ruby.
|
||||||
|
- **Organización**: Estructura modular centrada en la protección del dato:
|
||||||
|
- `Cripto`: Motor criptográfico AES-256-GCM con IV aleatorio.
|
||||||
|
- `Boveda`: Persistencia cifrada en `.boveda.json`.
|
||||||
|
- **MFA / Autorización**: Sistema de sesiones temporales basadas en archivos con permisos restringidos.
|
||||||
|
- **Archivos Fundamentales**:
|
||||||
|
- `ns8-candados.rb`: Lógica central.
|
||||||
|
- `.master.key` (Local): La semilla de cifrado (permisos 600).
|
||||||
|
- `.boveda.json`: Almacén de secretos cifrados (permisos 600).
|
||||||
|
- `.session`: Token de autorización temporal (vida: 5 min, permisos 600).
|
||||||
|
|
||||||
|
## ⚙️ Configuración y Dependencias
|
||||||
|
- **Tecnologías**: Ruby, OpenSSL.
|
||||||
|
- **Seguridad de Archivos**: Todos los archivos sensibles se manejan con `chmod 600`, asegurando que **solo el propietario** de la herramienta pueda operar.
|
||||||
|
- **Comandos de Gestión**:
|
||||||
|
- `ruby ns8-candados.rb authorize`: **Abre el candado**. Habilita el acceso a secretos durante 5 minutos.
|
||||||
|
- `ruby ns8-candados.rb cerrar`: **Cierra el candado** manualmente eliminando la sesión activa.
|
||||||
|
- `ruby ns8-candados.rb list`: Lista las claves guardadas (requiere autorización).
|
||||||
|
- `ruby ns8-candados.rb get <clave>`: Recupera el valor descifrado (requiere autorización).
|
||||||
|
|
||||||
|
## 🧠 Contexto para IA
|
||||||
|
- **Flujo Obligatorio**: Los agentes de IA DEBEN ejecutar `authorize` antes de intentar recuperar cualquier clave.
|
||||||
|
- **Captura Segura**: Capturar siempre la salida en variables silenciadas:
|
||||||
|
```bash
|
||||||
|
ruby tools/ns8-candados/ns8-candados.rb authorize
|
||||||
|
PASS=$(ruby tools/ns8-candados/ns8-candados.rb get clave)
|
||||||
|
# Operar y luego cerrar:
|
||||||
|
ruby tools/ns8-candados/ns8-candados.rb cerrar
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Próximos Pasos
|
||||||
|
|
||||||
|
### Propuestas de Mejora
|
||||||
|
- **Auditoría**: Implementar un `access.log` para trazar quién y cuándo abrió el candado.
|
||||||
|
- **Notificación**: Enviar un mensaje (ej. Telegram/Mail) cada vez que se ejecute `authorize`.
|
||||||
|
|
||||||
|
---
|
||||||
|
*Generado siguiendo docs/prompt/documentacion.md*
|
||||||
@@ -31,9 +31,16 @@ require 'fileutils'
|
|||||||
|
|
||||||
# ─── Rutas ───────────────────────────────────────────────────────────
|
# ─── Rutas ───────────────────────────────────────────────────────────
|
||||||
TOOL_DIR = File.expand_path(__dir__)
|
TOOL_DIR = File.expand_path(__dir__)
|
||||||
PROJECT_DIR = File.expand_path('../..', TOOL_DIR)
|
MASTER_KEY = File.join(TOOL_DIR, '.master.key')
|
||||||
MASTER_KEY = File.join(PROJECT_DIR, '.master.key')
|
OLD_KEY = File.expand_path('../../.master.key', TOOL_DIR)
|
||||||
BOVEDA = File.join(TOOL_DIR, '.boveda.json')
|
BOVEDA = File.join(TOOL_DIR, '.boveda.json')
|
||||||
|
SESION = File.join(TOOL_DIR, '.session')
|
||||||
|
|
||||||
|
# ─── Transición de Seguridad ─────────────────────────────────────────
|
||||||
|
if File.exist?(OLD_KEY) && !File.exist?(MASTER_KEY)
|
||||||
|
FileUtils.mv(OLD_KEY, MASTER_KEY)
|
||||||
|
FileUtils.chmod(0600, MASTER_KEY)
|
||||||
|
end
|
||||||
|
|
||||||
# ─── Colores ─────────────────────────────────────────────────────────
|
# ─── Colores ─────────────────────────────────────────────────────────
|
||||||
module C
|
module C
|
||||||
@@ -110,12 +117,35 @@ def cargar_master_key
|
|||||||
require 'securerandom'
|
require 'securerandom'
|
||||||
File.write(MASTER_KEY, SecureRandom.hex(32))
|
File.write(MASTER_KEY, SecureRandom.hex(32))
|
||||||
FileUtils.chmod(0600, MASTER_KEY)
|
FileUtils.chmod(0600, MASTER_KEY)
|
||||||
$stderr.puts "#{C::YELLOW}⚠ Nueva clave maestra creada en #{MASTER_KEY}#{C::RESET}"
|
$stderr.puts "#{C::YELLOW}⚠ Nueva clave maestra creada en local: #{MASTER_KEY}#{C::RESET}"
|
||||||
$stderr.puts "#{C::YELLOW} NO subir a Git (ya cubierta por .gitignore).#{C::RESET}"
|
|
||||||
end
|
end
|
||||||
File.read(MASTER_KEY)
|
File.read(MASTER_KEY)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# ─── Gestión de Sesión (MFA) ─────────────────────────────────────────
|
||||||
|
def autorizar!
|
||||||
|
File.write(SESION, Time.now.to_i.to_s)
|
||||||
|
FileUtils.chmod(0600, SESION)
|
||||||
|
$stderr.puts "#{C::GREEN}✓ Autorización concedida (Válida por 5 minutos).#{C::RESET}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def cerrar_sesion!
|
||||||
|
FileUtils.rm_f(SESION)
|
||||||
|
$stderr.puts "#{C::YELLOW}🔒 Sesión cerrada. Candado puesto.#{C::RESET}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def verificar_sesion!
|
||||||
|
unless File.exist?(SESION)
|
||||||
|
abort "#{C::RED}✗ Error: El candado está puesto. Ejecutá 'ruby #{File.basename($0)} authorize' para abrirlo.#{C::RESET}"
|
||||||
|
end
|
||||||
|
|
||||||
|
inicio = File.read(SESION).to_i
|
||||||
|
if Time.now.to_i - inicio > 300 # 5 minutos
|
||||||
|
cerrar_sesion!
|
||||||
|
abort "#{C::RED}✗ Sesión expirada. Por seguridad, volvé a autorizar.#{C::RESET}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# ─── Comandos ────────────────────────────────────────────────────────
|
# ─── Comandos ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
def cmd_abrir
|
def cmd_abrir
|
||||||
@@ -146,10 +176,9 @@ end
|
|||||||
|
|
||||||
def cmd_get(cripto, boveda, clave)
|
def cmd_get(cripto, boveda, clave)
|
||||||
abort "#{C::RED}✗ Falta nombre de clave.#{C::RESET}" if clave.nil?
|
abort "#{C::RED}✗ Falta nombre de clave.#{C::RESET}" if clave.nil?
|
||||||
|
verificar_sesion!
|
||||||
token = boveda.get(clave)
|
token = boveda.get(clave)
|
||||||
abort "#{C::RED}✗ Clave '#{clave}' no encontrada.#{C::RESET}" if token.nil?
|
abort "#{C::RED}✗ Clave '#{clave}' no encontrada.#{C::RESET}" if token.nil?
|
||||||
# Salida limpia (solo el valor) para uso en scripts:
|
|
||||||
# PASS=$(ruby tools/ns8-candados/ns8-candados.rb get admindasu)
|
|
||||||
puts cripto.decrypt(token)
|
puts cripto.decrypt(token)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -187,6 +216,8 @@ def cmd_help
|
|||||||
#{C::GREEN}Uso:#{C::RESET} ruby ns8-candados.rb <comando> [args]
|
#{C::GREEN}Uso:#{C::RESET} ruby ns8-candados.rb <comando> [args]
|
||||||
|
|
||||||
#{C::YELLOW}Comandos:#{C::RESET}
|
#{C::YELLOW}Comandos:#{C::RESET}
|
||||||
|
authorize Abrir candado (autorización temporal 5 min)
|
||||||
|
cerrar Cerrar candado manual (eliminar sesión)
|
||||||
abrir Autorizar SSH (cargar passphrase)
|
abrir Autorizar SSH (cargar passphrase)
|
||||||
encrypt <texto> Cifrar texto plano → token
|
encrypt <texto> Cifrar texto plano → token
|
||||||
decrypt <token> Descifrar token → texto plano
|
decrypt <token> Descifrar token → texto plano
|
||||||
@@ -196,8 +227,8 @@ def cmd_help
|
|||||||
list Listar claves disponibles
|
list Listar claves disponibles
|
||||||
|
|
||||||
#{C::YELLOW}Ejemplos:#{C::RESET}
|
#{C::YELLOW}Ejemplos:#{C::RESET}
|
||||||
#{C::DIM}# Guardar un secreto#{C::RESET}
|
# Autorizar para operar
|
||||||
ruby ns8-candados.rb set mi_password
|
ruby ns8-candados.rb authorize
|
||||||
|
|
||||||
#{C::DIM}# Usar en scripts (salida limpia)#{C::RESET}
|
#{C::DIM}# Usar en scripts (salida limpia)#{C::RESET}
|
||||||
PASS=$(ruby ns8-candados.rb get admindasu)
|
PASS=$(ruby ns8-candados.rb get admindasu)
|
||||||
@@ -210,8 +241,10 @@ comando = ARGV[0]
|
|||||||
arg = ARGV[1]
|
arg = ARGV[1]
|
||||||
|
|
||||||
case comando
|
case comando
|
||||||
when 'abrir'
|
when 'authorize'
|
||||||
cmd_abrir
|
autorizar!
|
||||||
|
when 'cerrar'
|
||||||
|
cerrar_sesion!
|
||||||
when 'encrypt', 'decrypt', 'get', 'set', 'rm', 'list'
|
when 'encrypt', 'decrypt', 'get', 'set', 'rm', 'list'
|
||||||
cripto = Cripto.new(cargar_master_key)
|
cripto = Cripto.new(cargar_master_key)
|
||||||
boveda = Boveda.new(BOVEDA)
|
boveda = Boveda.new(BOVEDA)
|
||||||
|
|||||||
Reference in New Issue
Block a user