[{"content":"Introducción OpenCode es un agente de codificación con IA de código abierto, nativo de terminal, construido en Go. A diferencia de IDEs en la nube como Cursor o Claude Code, es completamente agnóstico respecto al proveedor: traes tus propias claves API, ejecutas modelos localmente, o te suscribes a planes gestionados, y OpenCode se encarga de la orquestación. Con soporte para más de 75 proveedores de LLM, integración nativa con LSP, extensibilidad MCP, y un ecosistema de plugins en crecimiento, se ha convertido en un referente para la codificación agentic.\nEsta guía está estructurada para llevarte desde la instalación hasta flujos de trabajo de producción. Comenzamos con conceptos centrales — agentes, subagentes, LSP y MCP — luego introducimos Desarrollo Guiado por Subagentes (SDD), la metodología que une orquestación, planificación y ejecución en un flujo coherente. Desde allí, mapeamos SDD a dominios del mundo real: desarrollo full-stack, operaciones de sysadmin e infraestructura DevOps, basándonos en casos de uso documentados por desarrolladores en el campo.\n¿Qué es OpenCode? OpenCode es un agente de codificación con IA de código abierto (licencia MIT) diseñado para ejecutarse en tu terminal, escritorio o IDE. Trata a los agentes como un sistema de runtime, no como prompts sueltos. Los agentes se definen en código o se cargan desde Markdown, se fusionan en un registro compartido, y se ejecutan a través de un pipeline unificado de prompt, permisos y sesión.\nCaracterísticas Clave Agnóstico respecto al proveedor: Claude, OpenAI, Google Gemini, Groq, Fireworks, Together AI, OpenRouter, Azure, AWS Bedrock, y modelos locales vía Ollama. Interfaz de terminal nativa: Construido con Bubble Tea (Go) para una experiencia TUI fluida. Soporte multi-sesión: Ejecuta múltiples agentes en paralelo, cada uno con su propio contexto. Integración LSP: Carga automáticamente servidores del Language Server Protocol para inteligencia de código. Soporte MCP: Extiende capacidades a través del Model Context Protocol. Sistema de plugins: Plugins de TypeScript/JavaScript con más de 25 hooks de ciclo de vida. Arquitectura cliente/servidor: Ejecuta el servidor sin cabeza y conecta desde múltiples clientes. Privacidad primero: No almacena tu código ni datos de contexto. Instalación 1 2 3 4 5 6 7 8 # Via install script curl -fsSL https://opencode.ai/install | bash # Via npm npm install -g opencode-ai # Start OpenCode opencode En el primer lanzamiento, OpenCode detecta tu estructura de proyecto, inicializa un directorio .opencode/ y te pide configurar un proveedor de modelos.\nOpenCode Go: Acceso a Modelos de Bajo Costo OpenCode Go es una suscripción de bajo costo ($5 el primer mes, luego $10/mes) que proporciona acceso confiable a modelos de codificación de código abierto seleccionados. Está diseñado para desarrolladores que quieren límites generosos y acceso global estable sin gestionar múltiples claves API.\nLo que Obtienes Precio: $5 primer mes, luego $10/mes. Cancela en cualquier momento. Modelos incluidos: GLM-5.1, GLM-5, Kimi K2.5, Kimi K2.6, MiMo-V2-Pro, MiMo-V2-Omni, MiMo-V2.5-Pro, MiMo-V2.5, Qwen3.5 Plus, Qwen3.6 Plus, MiniMax M2.5, MiniMax M2.7, DeepSeek V4 Pro, DeepSeek V4 Flash. Hosting: EE.UU., UE y Singapur para acceso global estable. Privacidad: Política de cero retención; los proveedores no usan tus datos para entrenamiento de modelos. Límites de Uso Los límites se definen en valor en dólares en lugar de recuentos de solicitudes fijos:\nVentana Límite Por 5 horas $12 Por semana $30 Por mes $60 Los modelos más baratos rinden más. DeepSeek V4 Flash permite ~31,650 solicitudes por 5 horas, mientras que GLM-5.1 permite ~880.\nConfiguración Suscríbete en opencode.ai/go. Copia tu clave API. En el TUI, ejecuta /connect, selecciona OpenCode Go y pega tu clave. Ejecuta /models para ver los modelos disponibles. Los IDs de modelo usan el formato opencode-go/\u0026lt;model-id\u0026gt;, por ejemplo:\n1 2 3 { \u0026#34;model\u0026#34;: \u0026#34;opencode-go/kimi-k2.6\u0026#34; } Conceptos Fundamentales Antes de sumergirte en los flujos de trabajo, es esencial entender los bloques de construcción de OpenCode: agentes, subagentes, LSP, MCP, y el sistema de reglas del proyecto.\nAgentes y Subagentes OpenCode tiene dos tipos de agentes:\nAgentes primarios: Los asistentes principales con los que interactúas directamente. Cycle through them with the Tab key. Los agentes primarios integrados incluyen Build (herramientas completas) y Plan (solo lectura, no puede modificar archivos). Subagentes: Asistentes especializados que los agentes primarios invocan para tareas específicas. También puedes invocarlos manualmente con @mención. Subagentes integrados:\nSubagente Rol Herramientas General Investigación y ejecución multi-paso Acceso completo excepto todo Explore Exploración rápida del código base en solo lectura Solo lectura y búsqueda Cuando un agente delega trabajo, no simplemente añade un prompt. Crea una sesión hija con contexto fresco, pasa una instrucción limitada, y recibe un resultado estructurado. Esto hace que la delegación sea basada en sesiones, reanudable e inspeccionable.\nLSP (Language Server Protocol) La integración LSP le da a OpenCode una inteligencia de código profunda. La IA puede ver información de tipos, firmas de funciones, rutas de importación y diagnósticos — no solo texto sin formato.\nOperaciones soportadas: goToDefinition, findReferences, hover, documentSymbol, workspaceSymbol, goToImplementation, prepareCallHierarchy, incomingCalls, outgoingCalls.\nLa herramienta lsp está disponible cuando se establece OPENCODE_EXPERIMENTAL_LSP_TOOL=true. OpenCode incluye servidores LSP pre-configurados para más de 30 idiomas.\nMCP (Model Context Protocol) Los servidores MCP extienden OpenCode con herramientas y servicios externos. Las herramientas integradas similares a MCP incluyen:\nwebsearch: Realiza búsquedas web vía Exa AI (no se requiere clave API con el proveedor OpenCode). webfetch: Obtiene y lee URLs específicas. lsp: Interactúa con Language Servers configurados. Los servidores MCP personalizados se configuran en opencode.json:\n1 2 3 4 5 6 7 8 9 10 { \u0026#34;mcpServers\u0026#34;: { \u0026#34;github\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;stdio\u0026#34;, \u0026#34;command\u0026#34;: \u0026#34;npx\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;-y\u0026#34;, \u0026#34;@modelcontextprotocol/server-github\u0026#34;], \u0026#34;env\u0026#34;: [\u0026#34;GITHUB_PERSONAL_ACCESS_TOKEN=ghp_...\u0026#34;] } } } Sé selectivo: los servidores MCP añaden definiciones de herramientas a tu ventana de contexto. El MCP de GitHub solo puede consumir tokens significativos.\nAGENTS.md y Reglas del Proyecto Ejecuta /init para generar un archivo AGENTS.md en la raíz de tu proyecto. Este archivo enseña a OpenCode sobre la estructura de tu proyecto, convenciones y patrones de codificación. Es similar a las reglas de Cursor y mejora la calidad del código generado.\nEjemplo de un monorepo de TypeScript en producción:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # Project: Payment Processing API This is a TypeScript monorepo using Bun workspaces. ## Structure - `packages/core/` - Shared business logic - `packages/api/` - Express API handlers - `packages/workers/` - Background job processors ## Conventions - Use Zod for all input validation - All database queries go through the repository pattern - Prefer composition over inheritance - Test files live next to source files (*.test.ts) ## Commands - `bun test` - Run all tests - `bun run lint` - Run ESLint and Prettier - `bun run build` - TypeScript compilation Permisos OpenCode filtra herramientas antes de que el modelo las vea, luego verifica permisos nuevamente en tiempo de ejecución. Esto hace que la orquestación esté limitada por políticas, no por confianza.\n1 2 3 4 5 6 7 { \u0026#34;permission\u0026#34;: { \u0026#34;bash\u0026#34;: \u0026#34;ask\u0026#34;, \u0026#34;edit\u0026#34;: \u0026#34;ask\u0026#34;, \u0026#34;write\u0026#34;: \u0026#34;allow\u0026#34; } } Valores: allow, deny, ask. Para producción o entornos sensibles, establece bash y edit en ask.\nOrquestación de Agentes con oh-my-opencode-slim oh-my-opencode-slim es un plugin de orquestación de agentes para OpenCode. En lugar de forzar a un solo modelo a manejar cada tarea, enruta trabajos a subagentes especializados, equilibrando calidad, velocidad y costo.\nEl Panteón Agente Rol Modelo Predeterminado Orchestrator Maestro delegador y coordinador estratégico openai/gpt-5.4 Explorer Búsqueda rápida en el código y coincidencia de patrones openai/gpt-5.4-mini Librarian Documentación externa e investigación de bibliotecas openai/gpt-5.4-mini Oracle Asesor técnico estratégico, revisor de código, simplificador openai/gpt-5.4 Designer Especialista en UI/UX para pulido visual openai/gpt-5.4-mini Fixer Especialista de implementación rápida para tareas delimitadas openai/gpt-5.4-mini Observer Análisis visual de solo lectura (imágenes, PDFs, diagramas) Deshabilitado por defecto Instalación 1 bunx oh-my-opencode-slim@latest install El instalador genera una configuración predeterminada de OpenAI. Edita ~/.config/opencode/oh-my-opencode-slim.json para usar Kimi, GitHub Copilot u otros proveedores. La configuración soporta JSONC e incluye un esquema JSON oficial para autocompletado.\nCaracterísticas Clave Council: Ejecuta múltiples modelos en paralelo y sintetiza una sola respuesta con @council. Multiplexer Integration: Observa a los agentes trabajar en vivo en paneles de Tmux o Zellij. Session Management: Reutiliza sesiones recientes de agentes hijos con alias cortos. Auto-continue: Reanuda automáticamente sesiones del orquestador con enfriamientos y verificaciones de seguridad. Preset Switching: Cambia presets de modelo de agente en tiempo de ejecución con /preset. Cartography Skill: Genera codemaps jerárquicos para entender bases de código grandes más rápido. Interview: Convierte ideas aproximada en especificaciones estructuradas en markdown vía un flujo de Q\u0026amp;A basado en navegador. Desarrollo Guiado por Subagentes (SDD) Desarrollo Guiado por Subagentes es la metodología que hace práctica la orquestación de agentes. No es una sola herramienta sino un patrón de flujo de trabajo: descompón el trabajo en tareas independientes, despacha un subagente fresco para cada tarea, y aplica revisión antes de completar. SDD previene la contaminación del contexto, controla costos y mantiene calidad.\nHay dos interpretaciones complementarias de SDD en el ecosistema de OpenCode:\nSpec-Driven Development: Requisitos → Diseño → Tareas → Implementación. Las especificaciones son andamiaje temporal; el código es la fuente de verdad. Elimina especificaciones después de la implementación. Subagent-Driven Development: Cada tarea independiente obtiene un subagente fresco con contexto aislado, seguido de revisión automática de dos etapas. En la práctica, estos se fusionan: escribes una especificación, la descompones en tareas, y despachas subagentes para cada tarea con puertas de revisión.\nCuándo Usar SDD Usa SDD cuando:\nTienes un plan de implementación detallado. Las tareas son mayormente independientes con dependencias débiles. Quieres completar todas las tareas en una sesión sin cambiar de contexto. Las puertas de calidad (cumplimiento de especificación + revisión de código) son innegociables. Evita SDD para cambios pequeños de un solo archivo donde la sobrecarga del despacho de subagentes excede el beneficio. En esos casos, usa un agente Build único directamente.\nEl Flujo de Trabajo SDD Fase 1: Exploración y Escritura de Especificaciones El agente Orchestrator o Planner analiza la solicitud y crea una especificación.\n1 2 3 4 5 # Initialize SDD scaffolding (if using sdd-flow or Agent Teams Lite) /sdd-init # Or manually: switch to Plan mode and ask for a spec \u0026#34;Plan a user authentication system with JWT tokens, refresh token rotation, and role-based access control. Write the spec to specs/auth.md\u0026#34; Fase 2: Descomposición de Tareas Divide la especificación en tareas independientes. Cada tarea debe tener un alcance único y delimitado.\nTareas de ejemplo para un sistema de auth:\nImplementar utilidades de generación y validación de tokens JWT. Crear endpoints de login y refresh. Agregar middleware para control de acceso basado en roles. Escribir pruebas unitarias para las utilidades de tokens. Fase 3: Despacho de Subagentes Para cada tarea, el Orchestrator genera un subagente fresco vía la herramienta Task. Cada subagente comienza con cero contexto de tareas previas, previniendo contaminación. El Orchestrator inyecta solo la sección de especificación relevante y los estándares del proyecto.\n1 Orchestrator → Task(subagent=\u0026#34;sdd-apply\u0026#34;, prompt=\u0026#34;Implement task 1: JWT utilities. Read specs/auth.md section 3.1. Follow TDD. Run tests before returning.\u0026#34;) Fase 4: Revisión de Dos Etapas Después de que un subagente completa su tarea, SDD aplica dos etapas de revisión antes de marcar la tarea como completa:\nRevisión de Cumplimiento de Especificación: Un subagente revisor verifica si la implementación coincide exactamente con la especificación. ¿Implementó lo que se pidió? ¿Las interfaces son correctas? Revisión de Calidad de Código: Un segundo revisor verifica seguridad, rendimiento, mantenibilidad y cobertura de pruebas. Si cualquiera de las revisiones falla, la tarea se devuelve al subagente implementador con retroalimentación. Esto crea puntos de control automáticos.\nFase 5: Integración y Validación Una vez que todas las tareas pasan revisión, el Orchestrator integra el trabajo, ejecuta el conjunto completo de pruebas y valida el comportamiento de extremo a extremo.\nHerramientas y Plugins de SDD Varios proyectos de la comunidad implementan flujos de trabajo SDD para OpenCode:\ncc-sdd (Spec-Driven Development) cc-sdd trae Spec-Driven Development estructurado a OpenCode con comandos de barra:\n1 npx cc-sdd@latest --opencode-skills Los comandos incluyen:\n/kiro-spec-init: Iniciar una nueva especificación de feature. /kiro-spec-requirements: Escribir requisitos. /kiro-spec-design: Crear diseño de arquitectura. /kiro-spec-tasks: Generar lista de tareas. /kiro-impl: Implementación autónoma con subagentes por tarea, TDD y revisión independiente. Cada tarea obtiene un implementador fresco corriendo TDD (RED → GREEN), un revisor independiente, y un paso de auto-depuración si se bloquea.\nsdd-flow sdd-flow es un plugin que incrusta SDD directamente en tu repositorio:\n1 2 3 4 5 6 7 8 9 # One-time bootstrap /sdd-init # Switch to the \u0026#34;Spec Driven\u0026#34; planning agent # Describe your feature in natural language # Approve each phase before it advances # Execute the plan /implement Los activos son locales del repositorio: .opencode/skills/, .specify/, specs/ y AGENTS.md. Esto significa que el flujo de trabajo viaja con el código, no solo con la configuración local del desarrollador.\nAgent Teams Lite (Gentleman Programming) Agent Teams Lite proporciona un orquestador SDD completo con 10 sub-agentes especializados y comandos de barra:\nComando Propósito /sdd-init Inicializar contexto SDD /sdd-explore Investigar una idea /sdd-new Iniciar un nuevo cambio /sdd-apply Implementar tareas /sdd-verify Validar implementación /sdd-archive Archivar cambio completado El sistema usa un registro de habilidades: .atl/skill-registry.md captura las convenciones del proyecto, y el orquestador inyecta reglas compactas en cada prompt de subagente como ## Project Standards (auto-resolved).\nSDD Profiles OpenCode SDD Profiles te permiten crear configuraciones de modelo nombradas y cambiar entre ellas con Tab dentro de OpenCode. Cada perfil genera su propio orquestador más 10 sub-agentes en opencode.json:\n1 2 3 gentle-ai sync \\ --profile cheap:anthropic/claude-haiku-3.5-20241022 \\ --profile-phase cheap:sdd-apply:anthropic/claude-sonnet-4-20250514 Esto crea un perfil \u0026ldquo;cheap\u0026rdquo; donde todo corre en Haiku excepto sdd-apply, que usa Sonnet. Presiona Tab para alternar entre sdd-orchestrator, sdd-orchestrator-cheap y sdd-orchestrator-premium.\nDelegación de Subagente a Subagente OpenCode PR #7756 introdujo la delegación de subagente a subagente con task_budget configurable y límites de profundidad para prevenir bucles infinitos. Por defecto, solo los agentes primarios pueden asignar tareas a subagentes. Para habilitar la delegación de subagentes, establece un presupuesto:\n1 2 3 4 5 6 7 8 9 10 11 12 { \u0026#34;agent\u0026#34;: { \u0026#34;sdd-apply\u0026#34;: { \u0026#34;task_budget\u0026#34;: 3, \u0026#34;permission\u0026#34;: { \u0026#34;task\u0026#34;: { \u0026#34;sdd-debug\u0026#34;: \u0026#34;allow\u0026#34; } } } } } Esto permite que un subagente implementador genere un subagente depurador hasta 3 veces si se queda atascado.\nConfiguración de Modelos y Presets Configuración de Alto Rendimiento 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 { \u0026#34;$schema\u0026#34;: \u0026#34;https://opencode.ai/config.json\u0026#34;, \u0026#34;agents\u0026#34;: { \u0026#34;coder\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;anthropic/claude-sonnet-4-5-20250929\u0026#34;, \u0026#34;maxTokens\u0026#34;: 8000, \u0026#34;reasoningEffort\u0026#34;: \u0026#34;medium\u0026#34; }, \u0026#34;task\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;openai/gpt-4.1-mini\u0026#34;, \u0026#34;maxTokens\u0026#34;: 5000 }, \u0026#34;title\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;openai/gpt-4.1-mini\u0026#34; } } } Configuración de Presupuesto (~$30/mes) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { \u0026#34;agents\u0026#34;: { \u0026#34;coder\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;opencode-go/kimi-k2.6\u0026#34;, \u0026#34;maxTokens\u0026#34;: 8000 }, \u0026#34;task\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;opencode-go/deepseek-v4-flash\u0026#34;, \u0026#34;maxTokens\u0026#34;: 5000 }, \u0026#34;title\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;copilot/gpt-4o-mini\u0026#34; } } } Configuración Gratuita 1 2 3 4 5 6 7 8 9 10 11 { \u0026#34;provider\u0026#34;: { \u0026#34;ollama\u0026#34;: { \u0026#34;api_url\u0026#34;: \u0026#34;http://localhost:11434/v1\u0026#34; } }, \u0026#34;model\u0026#34;: { \u0026#34;default\u0026#34;: \u0026#34;opencode/minimax-m2.5-free\u0026#34;, \u0026#34;fast\u0026#34;: \u0026#34;ollama/qwen3.6-35b-a3b\u0026#34; } } Configuración Enfocada en DevOps 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 { \u0026#34;$schema\u0026#34;: \u0026#34;https://opencode.ai/config.json\u0026#34;, \u0026#34;model\u0026#34;: \u0026#34;opencode-go/qwen3.6-plus\u0026#34;, \u0026#34;permission\u0026#34;: { \u0026#34;bash\u0026#34;: \u0026#34;ask\u0026#34;, \u0026#34;edit\u0026#34;: \u0026#34;ask\u0026#34;, \u0026#34;write\u0026#34;: \u0026#34;allow\u0026#34; }, \u0026#34;agents\u0026#34;: { \u0026#34;devops-engineer\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;opencode-go/glm-5\u0026#34;, \u0026#34;maxTokens\u0026#34;: 8000, \u0026#34;instructions\u0026#34;: \u0026#34;You are a DevOps specialist. Confirm before applying Kubernetes manifests. Prefer idempotent patterns.\u0026#34; } }, \u0026#34;lsp\u0026#34;: { \u0026#34;yaml\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;yaml-language-server\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;--stdio\u0026#34;] }, \u0026#34;terraform\u0026#34;: { \u0026#34;command\u0026#34;: \u0026#34;terraform-ls\u0026#34;, \u0026#34;args\u0026#34;: [\u0026#34;serve\u0026#34;] } } } Variantes y Perfiles de Modelos Muchos modelos soportan variantes de razonamiento. Usa variant_cycle para alternar entre low, medium, high y xhigh.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 { \u0026#34;provider\u0026#34;: { \u0026#34;anthropic\u0026#34;: { \u0026#34;models\u0026#34;: { \u0026#34;claude-sonnet-4-5-20250929\u0026#34;: { \u0026#34;options\u0026#34;: { \u0026#34;thinking\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;enabled\u0026#34;, \u0026#34;budgetTokens\u0026#34;: 16000 } } } } } } } Los fallbacks multi-proveedor previenen fallos de sesión:\n1 2 3 4 5 6 7 8 { \u0026#34;agents\u0026#34;: { \u0026#34;coder\u0026#34;: { \u0026#34;model\u0026#34;: \u0026#34;opencode-go/kimi-k2.6\u0026#34;, \u0026#34;fallback_models\u0026#34;: [\u0026#34;opencode-go/glm-5\u0026#34;, \u0026#34;anthropic/claude-sonnet-4-5\u0026#34;] } } } Aplicaciones Específicas por Dominio Las siguientes secciones mapean la metodología SDD a casos de uso del mundo real documentados por desarrolladores, sysadmins e ingenieros DevOps.\nDesarrollo Full-Stack Aplicación Greenfield con SDD En un tutorial basado en proyectos de ZBuild, un desarrollador construyó un gestor de marcadores full-stack en ~30 minutos usando OpenCode. El stack incluía Express.js/TypeScript, SQLite con FTS5, y un frontend vanilla.\nMapeado a fases SDD:\nSpec: El modo Plan delineó el modelo de datos, rutas de API y esquema de base de datos. La especificación se guardó en .opencode/plans/bookmark-manager.md. Tasks: Descompuesto en andamiaje, modelo de datos, endpoints de API, búsqueda, etiquetas, frontend y pruebas. Dispatch: El modo Build implementó cada tarea secuencialmente, con el agente ejecutando curl para verificar el comportamiento de la API después de cada endpoint. Review: El agente ejecutó el conjunto de pruebas y corrigió fallos antes de proceder. Este ciclo Plan/Build previene que la IA tome grandes decisiones estructurales a ciegas.\nRefactorización Multi-Agente con Orquestación Un ingeniero de Vercel documentó usar OpenCode con Vercel AI Gateway para migrar un módulo de autenticación de auth basada en sesiones a tokens JWT usando la palabra clave ulw (ultrawork).\nEl flujo de trabajo estilo SDD:\nOrchestrator (Claude Opus 4.6) recibió la solicitud. Generó dos subagentes en segundo plano en paralelo: Explore (GPT-5 Mini): Mapeó 12 archivos en el flujo de auth. Librarian (Claude Sonnet 4.6): Encontró el patrón JWT recomendado del framework. Después de recibir los hallazgos, el Orchestrator delegó subtareas: Lógica criptográfica → trabajador GPT-5.4. Actualizaciones de middleware → trabajador Claude Haiku 4.5. Agent-browser verificó el flujo de login en un navegador real. Resultado: ~70% de reducción de costos comparado con un solo modelo grande, sin cambio manual de modelos.\nRevisión de Código Multi-Lente como Verificación SDD JP Caparas construyó un sistema de revisión multi-agente que refleja el patrón de revisión de dos etapas de SDD. Un agente revisor líder analiza el diff, luego genera revisores especialistas en paralelo:\nreview-frontend: archivos .tsx, .jsx, .vue, .css, .scss. review-backend: .py, .go, .ts en api/ o services/. review-devops: Dockerfile, *.yaml, *.tf, .github/workflows/*. El agente líder sintetiza hallazgos en un reporte unificado: LGTM, NEEDS CHANGES o DISCUSS. Esta es la etapa de verificación de SDD aplicada a código existente en lugar de nueva implementación.\nE2B Sandbox para Equipos Un usuario de Reddit documentó ejecutar OpenCode dentro de E2B cloud sandboxes para usuarios no técnicos. El flujo de trabajo usa:\nUn AGENTS.md personalizado con reglas de persona y guardas anti-alucinación. Un sistema de tres archivos de contexto: PROJECT.md (spec), MEMORY.md (build notes), y un log de conversación slim. Verificación automatizada después de cada build (verificaciones de esquema, validación de cableado de API). Auto-commit cada 5 minutos. Esto muestra principios SDD aplicados en un entorno gestionado: spec primero, ejecución segundo, verificación siempre.\nSysAdmin y Operaciones Gestión Remota de Servidores en Lenguaje Natural El blog argv.cloud introdujo \u0026ldquo;Agentic Sysadmin\u0026rdquo; usando OpenCode con una herramienta personalizada remote.ts que ejecuta comandos sobre SSH.\nConfiguración:\n.ssh/config estándar con alias de host. Herramienta personalizada que envuelve execa para ejecutar ssh -o BatchMode=yes \u0026lt;host\u0026gt; \u0026lt;command\u0026gt;. Sudo opcional vía variable de entorno OC_SSH inyectada en stdin (la LLM nunca ve la contraseña). Mapeo SDD:\nSpec: \u0026ldquo;Audit test-server with Lynis and generate a Markdown summary.\u0026rdquo; Task: Ejecutar Lynis silenciosamente, luego leer el reporte. Dispatch: El agente ejecuta el comando remotamente y obtiene el reporte. Review: El agente sintetiza la salida cruda en Markdown estructurado localmente. Prompts de ejemplo:\n1 2 opencode ask \u0026#34;Update system packages on server-33 and check for leftover services\u0026#34; opencode ask \u0026#34;Create a crontab on big-pc that runs Lynis weekly and saves the report to /var/log/lynis-weekly.log\u0026#34; No hay YAML, ni playbook de Ansible, ni manifest de Puppet. La LLM razona sobre el estado actual y genera comandos apropiados sobre la marcha.\nDocumentación y Migración de Servidores Pedro Serey mapeó un servidor \u0026ldquo;caja negra\u0026rdquo; en documentación estructurada usando el agente Explore. Comandos de descubrimiento (lsblk, ip, systemctl list-units) fueron sintetizados en:\nstorage.md: Unidades, puntos de montaje, sistemas de archivos. services/README.md: Contenedores, archivos Docker Compose, variables de entorno. network.md: Interfaces, reglas de enrutamiento, reglas de firewall. Después del mapeo, la documentación sirvió como la spec para un plan de migración de Proxmox. El agente generó una rutina de respaldo disciplinada con dumps de base de datos apropiados, previniendo corrupción de datos.\nLección crítica: Después de que el agente preparó commits de git no intencionales durante la migración, el autor cambió a un flujo de trabajo human-in-the-loop: el agente Plan propone comandos, el humano ejecuta en tmux, la salida se pega de vuelta. Esto es el modo Plan usado como puerta de spec/revisión SDD antes de la ejecución.\nGeneración de Comandos Shell con IA El plugin zsh-ask-opencode integra OpenCode en ZSH. Presiona Ctrl+O para transformar lenguaje natural en comandos shell optimizados:\n1 2 3 4 5 $ list all files modified in the last 24 hours # ^O generates: find . -mtime -1 -type f $ compress all jpg files in this directory to 50% size # ^O generates: convert *.jpg -quality 50% compressed.jpg El plugin clasifica tres opciones por velocidad, seguridad y confiabilidad. Revisas antes de ejecutar — una puerta de revisión manual para tareas de una línea.\nGestión Interactiva de PTY El plugin opencode-pty le da a OpenCode control sobre pseudo-terminales. A diferencia de la herramienta síncrona bash, pty_spawn permite:\nProcesos en segundo plano (ej., tail -f /var/log/syslog). Entrada interactiva (Ctrl+C, teclas de flecha). Capturas de terminal sin ruido ANSI. Esperar hasta que el contenido de la pantalla coincida con una regex. Esto es esencial para tareas de sysadmin que involucran procesos de larga duración, como monitorear despliegues o navegar por instaladores interactivos.\nDevOps e Infraestructura Generación de Infraestructura como Código ComputingForGeeks documentó usar OpenCode para flujos de trabajo DevOps. El agente sobresale generando boilerplate:\nTerraform: Variables, outputs, andamiaje de recursos. Ansible: Playbooks con conciencia de SELinux y handlers. Kubernetes: Manifiestos de Deployment, Service, Ingress, HPA. Prompt de ejemplo:\n1 opencode run \u0026#34;Create Kubernetes manifests for a Python Flask app: a Deployment with 3 replicas, resource limits, health checks, and a non-root security context. Add a ClusterIP Service and an Ingress with TLS.\u0026#34; Evaluación honesta: Los agentes de IA consistentemente fallan en el versionado de proveedores y dependencias de estado complejas. Trata la infraestructura generada por IA como un pull request de un ingeniero junior: siempre ejecuta terraform plan y prueba en staging.\nMapeo SDD para IaC:\nSpec: \u0026ldquo;We need a three-tier AWS architecture with VPC, private subnets, RDS, and an EKS cluster.\u0026rdquo; Tasks: Módulo VPC, módulo subnets, módulo RDS, módulo EKS, outputs. Dispatch: Cada módulo obtiene un subagente. El LSP de Terraform valida la sintaxis. Review: terraform plan es la verificación de cumplimiento de spec. Un segundo revisor busca anti-patterns de seguridad (grupos de seguridad abiertos, secretos hardcodeados). Creación de Pipeline CI/CD Multi-Agente Usando el modo ultrawork:\n1 opencode run \u0026#34;@ultrawork Set up a complete CI/CD pipeline with GitHub Actions that builds a Docker image, pushes to ECR, runs Trivy security scan, deploys to EKS staging with Helm, runs integration tests, and promotes to production on approval.\u0026#34; El agente planner asegura cohesión:\n.github/workflows/deploy.yml referencia archivos de valores Helm exactos. La etiqueta de imagen Docker se propaga a través de cada paso. scripts/integration-test.sh golpea la URL de staging correcta. Esto es SDD a escala: una spec se convierte en docenas de archivos coordinados, con el planner actuando como el Orchestrator asegurando consistencia entre archivos.\nAgentes DevOps Específicos de Proyecto El repositorio jon23d/opencode-configs demuestra una jerarquía de agentes madura:\ndockerfile-best-practices/SKILL.md deployment-planning/SKILL.md kubernetes-manifests/SKILL.md El pipeline modela un ciclo de vida completo de entrega de software:\n1 2 3 4 5 6 7 8 9 10 User request → build (clarify) → architect (plan) → build (review plan) → backend/frontend engineers (implement) → code-reviewer → security-reviewer → observability-reviewer → qa (E2E + OpenAPI) → devops-engineer (infra change) → developer-advocate (docs, docker-compose) → build (report) Esto es SDD con subagentes especializados para cada etapa de revisión.\nAgentes Nativos de Kubernetes con KubeOpenCode KubeOpenCode ejecuta agentes OpenCode como Kubernetes CRDs:\n1 2 3 4 5 6 7 8 9 10 11 12 apiVersion: kubeopencode.io/v1alpha1 kind: Agent metadata: name: dev-agent spec: profile: \u0026#34;Interactive development agent\u0026#34; workspaceDir: /workspace persistence: sessions: size: \u0026#34;2Gi\u0026#34; standby: idleTimeout: \u0026#34;30m\u0026#34; Adjunta desde tu terminal:\n1 kubeoc agent attach default -n kubeopencode-system Esto es ideal para pipelines CI/CD y agentes compartidos en equipo. Usa un patrón de dos contenedores: un init container copia el binario de OpenCode, y el worker container ejecuta tareas.\nDocker y Ejecutores de Modelos Locales Proyectos de la comunidad proporcionan configuraciones Docker listas para usar:\nnimbleflux/opencode-docker: Imagen Docker, Compose y Helm chart. utek/opencode-docker: Entorno ligero con Node.js, Python, Git y GitHub CLI. Docker Model Runner: Conecta OpenCode a modelos servidos localmente. Seguridad, Protección y Mejores Prácticas Los Permisos Predeterminados Son Permisivos Por defecto, OpenCode habilita la mayoría de las herramientas sin aprobación. Un PSA de Reddit destacó que el agente puede generar un script de Python e inmediatamente ejecutarlo. Bloquea esto:\n1 2 3 4 5 6 7 { \u0026#34;permission\u0026#34;: { \u0026#34;bash\u0026#34;: \u0026#34;ask\u0026#34;, \u0026#34;edit\u0026#34;: \u0026#34;ask\u0026#34;, \u0026#34;write\u0026#34;: \u0026#34;ask\u0026#34; } } Usa el Modo Plan para Auditorías Para sysadmins y SREs, el modo Plan es esencial para auditar scripts e infraestructura como código sin ejecutar nada accidentalmente.\nHuman-in-the-Loop para Producción Incluso con buenas intenciones, un agente con acceso SSH puede preparar cambios no intencionales. El flujo de trabajo recomendado:\nEl agente propone el comando en modo Plan. El humano revisa y ejecuta manualmente (ej., en un panel de tmux). El humano pega la salida de vuelta al agente. Sandboxing Contenedores/VMs: Ejecuta OpenCode dentro de Docker o una VM. Sandboxing a nivel de SO: nono usa Landlock (Linux) y Seatbelt (macOS) para acceso deny-by-default. 1 nono run --allow ./my_project_dir -- opencode Gestión de Ventana de Contexto Desarrolladores han reportado que la compactación de contexto puede ocurrir múltiples veces durante tareas grandes. Mitigaciones:\nHabilita autoCompact: true. Usa la habilidad Cartography para generar codemaps. Divide tareas grandes en sesiones más pequeñas y delimitadas. En SDD, subagentes frescos por tarea naturalmente limitan la expansión del contexto. Configuración Avanzada Agentes Personalizados Crea agentes específicos de proyecto añadiendo archivos markdown a .opencode/agents/:\n1 2 3 4 5 6 7 8 9 --- description: \u0026#34;Reviews code for best practices and potential issues\u0026#34; mode: subagent model: anthropic/claude-sonnet-4-20250514 permission: edit: deny --- You are a code reviewer. Focus on security, performance, and maintainability. Do not make changes; only provide feedback. Rutas de Contexto Incluye archivos de contexto adicionales:\n1 2 3 4 5 6 7 { \u0026#34;contextPaths\u0026#34;: [ \u0026#34;.github/copilot-instructions.md\u0026#34;, \u0026#34;.cursorrules\u0026#34;, \u0026#34;opencode.md\u0026#34; ] } Auto-Compact 1 2 3 { \u0026#34;autoCompact\u0026#34;: true } Gestión de Sesiones Usa multi-sesión para trabajar en múltiples features en paralelo. Usa /undo y /redo para revertir cambios. Comparte enlaces de sesión con compañeros de equipo. Conclusión OpenCode representa un nuevo paradigma en desarrollo asistido por IA: código abierto, agnóstico respecto al proveedor, e integrado profundamente en las herramientas que los desarrolladores ya usan. Pero la herramienta por sí sola no es suficiente. Desarrollo Guiado por Subagentes proporciona la metodología que hace la orquestación de agentes coherente, segura y escalable.\nEl flujo de trabajo SDD — explorar, spec, descomponer, despachar, revisar, integrar — mapea naturalmente a desarrollo full-stack, operaciones de sysadmin e infraestructura DevOps. Practicantes del mundo real han demostrado que este patrón escala desde un gestor de marcadores de 30 minutos hasta pipelines CI/CD multi-agente, desde gestión de servidores en lenguaje natural hasta plataformas de agentes nativos de Kubernetes.\nPuntos clave:\nComienza con una spec. Usa el modo Plan, AGENTS.md y la habilidad Cartography para construir contexto antes de escribir código. Descompón en tareas independientes. Cada tarea obtiene un subagente fresco con contexto aislado. Aplica revisión de dos etapas. Cumplimiento de spec primero, calidad de código segundo. Ninguna tarea pasa sin ambas. Configura permisos cuidadosamente. Establece bash y edit en ask en producción. Usa sandboxes. Aprovecha agentes especializados. Deja que el Orchestrator enrute el trabajo; no fuerces a un modelo a hacer todo. Usa OpenCode Go para acceso confiable y de bajo costo a modelos de código abierto seleccionados. Mantén a un humano en el loop para operaciones de producción, especialmente cuando el agente tiene acceso a shell o SSH. ¡Feliz codificación agentic!\nReferencias OpenCode Official Site OpenCode Documentation OpenCode Go OpenCode GitHub Repository OpenCode Agents Documentation OpenCode Rules Documentation oh-my-opencode-slim GitHub Oh My OpenCode (Original Plugin) cc-sdd: Spec-Driven Development sdd-flow: Spec-Driven Development for OpenCode Agent Teams Lite Gentleman AI: SDD Profiles Subagent-Driven Development Tutorial Agentic Coding: Spec-Driven Development DEV Community: Agent Orchestration in OpenCode Vercel KB: OpenCode with AI Gateway ZBuild: Full-Stack Bookmark Manager Tutorial JP Caparas: Multi-Agent Code Review Graphwiz: Vibe Coding with OpenCode AI for You: OpenCode Practical Examples argv.cloud: Agentic Sysadmin Pedro Serey: Using OpenCode as a SysAdmin zsh-ask-opencode GitHub opencode-pty GitHub ComputingForGeeks: AI Agents for DevOps jon23d/opencode-configs GitHub KubeOpenCode Docker Docs: OpenCode with Docker Model Runner Sidekick Agent Hub (VS Code Extension) Reddit: E2B Cloud Sandboxes Reddit: Context Window Management Reddit: Security and Permissions ","date":"2026-05-02T10:00:00+01:00","permalink":"/p/opencode-orquestaci%C3%B3n-de-agentes-y-desarrollo-guiado-por-subagentes-una-gu%C3%ADa-completa/","title":"OpenCode, Orquestación de Agentes y Desarrollo Guiado por Subagentes: Una Guía Completa"},{"content":"Dónde estamos En los dos primeros posts de la serie montamos OPNsense desde cero y lo llevamos hasta una configuración que ya no es trivial. Conviene hacer un repaso rápido antes de seguir.\nCapa Qué se configuró Post Hardware Mini PC con Intel N100/N200, NICs Intel i226-V Primero Conectividad PPPoE en WAN, bridge en LAN, interfaz wireless Primero Detección Suricata IDS/IPS con rulesets ET Open, Abuse.ch, Feodo Primero Inteligencia compartida CrowdSec con bouncer de firewall y colecciones comunitarias Primero VPN WireGuard con peers configurados Primero Reglas de firewall Reglas básicas para LAN, WireGuard y WAN Primero Offloading Checksum, TSO, tunning de buffers TCP Primero Usuarios Admin dedicado con OTP, root restringido, WebUI protegida Primero Backups Cifrados con AES-256-CBC, automáticos, almacenamiento externo Segundo DPI Zenarmor con políticas por interfaz y categoría Segundo Segmentación 5 VLANs (Main, Guests, IoT, Servers, Management) con reglas inter-VLAN Segundo SSH Solo claves ed25519, puerto no estándar, acceso restringido por IP Segundo DNS Unbound con DNS over TLS hacia Quad9 y Cloudflare Segundo Logging Syslog remoto con TCP/TLS hacia Grafana+Loki o ELK Segundo Es una configuración sólida. Pero hasta ahora todo se ha hecho a mano, desde la interfaz web, sin un proceso formal de revisión ni una forma de reproducir la configuración si algo se rompe más allá del backup XML. Este post cubre lo que falta: prácticas avanzadas, automatización, un marco de auditoría serio y una comparativa con las alternativas para tomar decisiones informadas.\nRevisión de la postura de seguridad Defensa en profundidad: lo que tenemos Si miramos lo configurado como capas de defensa, la arquitectura tiene cierta profundidad:\nCapa de defensa Componente OPNsense Estado actual Perímetro Reglas WAN deny-all + WireGuard entrante Funcional Detección de intrusiones Suricata IPS con ET Open y Abuse.ch Funcional, tuning por defecto Análisis de logs CrowdSec con bouncer + inteligencia comunitaria Funcional Inspección de aplicaciones Zenarmor DPI con políticas por VLAN Funcional Segmentación 5 VLANs con reglas inter-VLAN deny-all por defecto Funcional Control de acceso Admin dedicado, OTP, SSH con claves ed25519 Funcional Cifrado DNS Unbound con DoT hacia Quad9/Cloudflare Funcional Backups Cifrados, automáticos, almacenamiento externo Funcional Cinco capas de detección y prevención, segmentación real y control de acceso razonable. Para un homelab o una oficina pequeña es más de lo que tiene la mayoría. Pero hay huecos.\nHuecos que quedan Siendo honesto, hay varias cosas que no se han tocado y que importan:\nNo hay filtrado por geolocalización. Todo el planeta puede intentar conectar a los puertos expuestos en WAN. La mayoría de ataques automatizados vienen de rangos de IP con los que no se tiene ninguna relación legítima. No hay reverse proxy. Si se exponen servicios auto-alojados (Nextcloud, Jellyfin), van directamente por NAT sin TLS terminado ni protección a nivel de aplicación. Suricata está con la configuración por defecto. Las reglas se activan, pero no se han ajustado los parámetros de rendimiento ni se han eliminado categorías irrelevantes. Todo se ha configurado a mano. Si mañana hay que reconstruir OPNsense desde cero, el backup XML es la única opción. No hay playbooks, no hay control de versiones de la configuración, no hay forma de revisar qué cambió y cuándo sin abrir el historial de la interfaz web. No hay cadencia formal de auditoría. En el segundo post se mencionó una rutina semanal/mensual/trimestral, pero sin un marco de referencia detrás es fácil que se quede en buenas intenciones. No hay feeds de amenazas automatizados más allá de las actualizaciones de reglas de Suricata. Las listas de bloqueo por IP no se actualizan solas. Los siguientes apartados cubren estos huecos.\nPrácticas avanzadas Bloqueo por GeoIP con MaxMind La idea es simple: si no hay razón legítima para que una conexión venga de ciertos países, bloquear esos rangos de IP reduce el ruido. No es una medida de seguridad real, porque cualquier atacante con una VPN la esquiva, pero sí elimina una cantidad significativa de escaneos automatizados y ataques de fuerza bruta.\nOPNsense usa las bases de datos GeoLite2 de MaxMind, que son gratuitas pero requieren una cuenta.\nRegistrar una cuenta gratuita en MaxMind y generar una license key. En Firewall \u0026gt; Aliases \u0026gt; GeoIP settings, introducir la license key. Crear un alias de tipo GeoIP en Firewall \u0026gt; Aliases: Nombre: GeoIP_Block Tipo: GeoIP Contenido: seleccionar los países a bloquear. En Firewall \u0026gt; Rules \u0026gt; WAN, añadir una regla al principio: Acción: Block Origen: GeoIP_Block Destino: * Descripción: Bloqueo geográfico Una advertencia: mantener esta lista actualizada. MaxMind actualiza las bases de datos semanalmente. Configurar la actualización automática en los ajustes de GeoIP para que no se queden obsoletas.\nTuning avanzado de Suricata OPNsense 26.1 incluye Suricata 8, que mejora el rendimiento multi-hilo y añade soporte para nuevos protocolos. Pero la configuración por defecto es conservadora. Si el hardware tiene margen, ajustar estos parámetros marca diferencia.\nEn Services \u0026gt; Intrusion Detection \u0026gt; Administration, la sección avanzada permite configurar parámetros que no están en la interfaz estándar. Los más relevantes:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # /usr/local/opnsense/service/conf/actions.d/conf.d/ # Ajustar según la RAM disponible (estos valores son para 8 GB) # Memoria máxima para seguimiento de flujos flow: memcap: 256mb hash-size: 65536 # Memoria máxima para reconstrucción de streams TCP stream: memcap: 512mb reassembly.memcap: 256mb # Tamaño del ring buffer para af-packet af-packet: - interface: igb0 ring-size: 30000 cluster-type: cluster_flow Además del tuning de memoria, revisar las categorías de reglas activas. Si no hay servidores SCADA, bases de datos expuestas ni servicios SMTP en la red, desactivar esas categorías. Cada regla activa consume CPU en cada paquete inspeccionado.\nPara identificar las reglas que más ruido generan, analizar el log EVE JSON:\n1 2 3 4 # Top 10 alertas por SID en las últimas 24 horas cat /var/log/suricata/eve.json | \\ jq -r \u0026#39;select(.event_type==\u0026#34;alert\u0026#34;) | .alert.signature_id\u0026#39; | \\ sort | uniq -c | sort -rn | head -10 Si una regla genera cientos de alertas diarias sin que ninguna sea un verdadero positivo, desactivarla o ajustar su umbral.\nReverse proxy con HAProxy y ACME Si se exponen servicios auto-alojados a internet, hacerlo directamente con port forwarding es funcional pero inseguro. Un reverse proxy permite terminar TLS con certificados válidos, aplicar rate limiting y tener un punto centralizado de control.\nInstalar los plugins os-haproxy y os-acme-client desde System \u0026gt; Firmware \u0026gt; Plugins.\nCertificados con Let\u0026rsquo;s Encrypt (ACME):\nEn Services \u0026gt; ACME Client \u0026gt; Accounts, crear una cuenta ACME. En Services \u0026gt; ACME Client \u0026gt; Challenge Types, configurar un desafío DNS-01. Es preferible al HTTP-01 porque no requiere abrir el puerto 80 y soporta wildcards. En Services \u0026gt; ACME Client \u0026gt; Certificates, crear los certificados para cada servicio. Configuración de HAProxy:\nEn Services \u0026gt; HAProxy \u0026gt; Real Servers, crear un backend por cada servicio interno (Nextcloud en 192.168.40.10:443, Jellyfin en 192.168.40.11:8096, etc.). En Services \u0026gt; HAProxy \u0026gt; Rules \u0026amp; Checks \u0026gt; Conditions, crear condiciones basadas en el SNI o el hostname. En Services \u0026gt; HAProxy \u0026gt; Virtual Services \u0026gt; Public Services, crear un frontend que escuche en el puerto 443, vincule los certificados ACME y enrute a los backends según las condiciones. Activar HSTS en las cabeceras HTTP para forzar HTTPS. Configurar rate limiting por IP para mitigar ataques de fuerza bruta contra formularios de login. Feeds de amenazas y alias programados Las listas de bloqueo por IP pierden valor si no se actualizan. OPNsense permite crear alias de tipo URL Table que se descargan automáticamente.\nEn Firewall \u0026gt; Aliases, crear alias con estas fuentes:\nAlias URL Frecuencia Descripción Spamhaus_DROP https://www.spamhaus.org/drop/drop.txt Diaria Rangos secuestrados o usados para spam Spamhaus_EDROP https://www.spamhaus.org/drop/edrop.txt Diaria Extensión de DROP Abusech_Feodo https://feodotracker.abuse.ch/downloads/ipblocklist.txt Cada 6h IPs de botnets bancarias Abusech_SSLBL https://sslbl.abuse.ch/blacklist/sslipblacklist.txt Cada 6h IPs con certificados maliciosos Aplicar estos alias como origen en reglas de bloqueo en WAN. Los alias de tipo URL Table se actualizan automáticamente según la frecuencia configurada.\nSnapshots ZFS para rollback Si durante la instalación se eligió ZFS como sistema de ficheros (en lugar de UFS), se puede usar una de sus mejores características: snapshots instantáneos con rollback.\nAntes de cualquier cambio importante (actualización de firmware, cambio de reglas masivo, instalación de plugins), crear un snapshot:\n1 2 3 4 5 6 7 8 # Crear un snapshot antes de actualizar zfs snapshot zroot/ROOT/default@pre-update-$(date +%Y%m%d) # Listar snapshots existentes zfs list -t snapshot # Si algo sale mal, rollback al snapshot anterior zfs rollback zroot/ROOT/default@pre-update-20260413 Esto devuelve el sistema de ficheros completo al estado del snapshot en segundos. Es un seguro contra actualizaciones fallidas que complementa los backups de configuración XML. El snapshot recupera todo el sistema; el backup XML solo recupera la configuración.\nInfrastructure as Code para OPNsense Hacer todo desde la interfaz web funciona, pero tiene problemas conocidos: no hay historial de cambios legible, no se puede revisar qué se modificó antes de aplicarlo, y reconstruir la configuración requiere seguir una guía paso a paso o restaurar un backup opaco.\nLa API REST de OPNsense OPNsense expone una API REST bastante completa. La documentación está en /api/ y cubre la mayoría de funcionalidades de la interfaz web: aliases, reglas de firewall, configuración de interfaces, IDS, CrowdSec, Unbound, HAProxy y más.\nPara usar la API, crear un par de clave/secreto en System \u0026gt; Access \u0026gt; Users, seleccionar el usuario administrador y generar una API key. OPNsense genera un archivo con la key y el secret.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # Consultar los alias de firewall curl -k -u \u0026#34;API_KEY:API_SECRET\u0026#34; \\ https://192.168.1.1/api/firewall/alias/searchItem # Crear un nuevo alias curl -k -u \u0026#34;API_KEY:API_SECRET\u0026#34; \\ -X POST \\ -H \u0026#34;Content-Type: application/json\u0026#34; \\ -d \u0026#39;{\u0026#34;alias\u0026#34;:{\u0026#34;name\u0026#34;:\u0026#34;test_alias\u0026#34;,\u0026#34;type\u0026#34;:\u0026#34;host\u0026#34;,\u0026#34;content\u0026#34;:\u0026#34;10.0.0.1\u0026#34;}}\u0026#39; \\ https://192.168.1.1/api/firewall/alias/addItem # Aplicar cambios pendientes en el firewall curl -k -u \u0026#34;API_KEY:API_SECRET\u0026#34; \\ -X POST \\ https://192.168.1.1/api/firewall/alias/reconfigure La API no cubre el 100% de la interfaz web. Algunas funciones de plugins (como partes de Zenarmor) no están expuestas. Pero para la gestión del firewall, aliases, reglas, interfaces y la mayoría de servicios core es suficiente.\nAnsible: ansibleguy/collection_opnsense La colección ansibleguy.opnsense es la opción más madura para gestionar OPNsense como código en 2026. Envuelve la API REST en módulos Ansible idempotentes.\n1 2 # Instalar la colección ansible-galaxy collection install ansibleguy.opnsense Un ejemplo de playbook que gestiona aliases y reglas de firewall:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 --- - name: Configurar firewall OPNsense hosts: opnsense connection: httpapi vars: ansible_httpapi_port: 443 ansible_httpapi_use_ssl: true ansible_httpapi_validate_certs: false tasks: - name: Crear alias RFC1918 ansibleguy.opnsense.alias: name: RFC1918 type: network content: - \u0026#34;10.0.0.0/8\u0026#34; - \u0026#34;172.16.0.0/12\u0026#34; - \u0026#34;192.168.0.0/16\u0026#34; description: \u0026#34;Redes privadas RFC1918\u0026#34; - name: Crear alias de administración ansibleguy.opnsense.alias: name: Admin_IPs type: host content: - \u0026#34;192.168.50.10\u0026#34; - \u0026#34;192.168.50.11\u0026#34; description: \u0026#34;IPs de administración\u0026#34; - name: Bloquear IoT hacia redes internas ansibleguy.opnsense.rule: interface: \u0026#34;opt3\u0026#34; # VLAN 30 IoT action: block source_net: \u0026#34;IoT net\u0026#34; destination_net: \u0026#34;RFC1918\u0026#34; description: \u0026#34;IoT sin acceso a redes internas\u0026#34; Ansible soporta modo check (--check) para ver qué cambiaría sin aplicar nada. Esto es especialmente útil para revisar cambios de firewall antes de ejecutarlos, algo que la interfaz web no permite.\nLa limitación principal es que no todos los módulos de OPNsense están cubiertos por la colección. Servicios como Zenarmor, CrowdSec o configuraciones avanzadas de Suricata pueden requerir llamadas directas a la API con el módulo uri de Ansible.\nControl de versiones del config.xml El enfoque más directo para tener la configuración bajo control de versiones: exportar el config.xml, cifrarlo y guardarlo en un repositorio Git privado. Es lo que ya se hace con los backups del segundo post, pero integrado en un flujo de trabajo Git.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #!/bin/bash # export_config.sh - Ejecutar desde cron o manualmente antes de cambios BACKUP_DIR=\u0026#34;/root/config-backups\u0026#34; REPO_DIR=\u0026#34;/root/opnsense-config\u0026#34; DATE=$(date +%Y%m%d_%H%M) # Exportar configuración actual cp /conf/config.xml \u0026#34;${BACKUP_DIR}/config_${DATE}.xml\u0026#34; # Cifrar con age (más simple que OpenSSL para este uso) age -r age1publickey... \\ -o \u0026#34;${REPO_DIR}/config_${DATE}.xml.age\u0026#34; \\ \u0026#34;${BACKUP_DIR}/config_${DATE}.xml\u0026#34; # Limpiar archivo sin cifrar rm \u0026#34;${BACKUP_DIR}/config_${DATE}.xml\u0026#34; # Commit al repositorio cd \u0026#34;${REPO_DIR}\u0026#34; git add . git commit -m \u0026#34;config: backup ${DATE}\u0026#34; git push origin main Con esto se tiene un historial de cambios en la configuración con timestamps y la posibilidad de hacer git diff entre versiones cifradas (o descifrar dos versiones y compararlas con diff). No es tan limpio como el modelo de VyOS donde la configuración es texto plano, pero funciona.\nPipeline CI/CD para validación Llevar la automatización un paso más allá: validar los cambios de configuración antes de aplicarlos. Un pipeline ligero en GitLab CI o GitHub Actions que:\nDescifre el config.xml en un entorno efímero. Valide la estructura XML con xmllint. Compruebe anti-patrones con reglas personalizadas (reglas con source=any destination=any action=pass, usuarios sin OTP, servicios innecesarios habilitados). Ejecute el playbook de Ansible en modo check contra un entorno de staging (si existe) o simplemente valide la sintaxis. Esto no reemplaza las pruebas manuales, pero detecta errores evidentes antes de que lleguen a producción.\nEn términos de madurez de IaC, OPNsense está en un punto intermedio:\nAspecto OPNsense VyOS OpenWrt API REST Completa Completa Limitada (ubus/JSON-RPC) Terraform Sin provider maduro Provider oficial (Foltik/vyos) Sin provider Ansible ansibleguy.opnsense vyos.vyos (oficial) Community roles Formato de config XML (config.xml) Texto plano CLI UCI (texto plano) Workflow Git Export manual o scripted Nativo (text config) Export manual VyOS gana en IaC por diseño: su configuración es texto plano desde el primer día, con commits atómicos y rollback nativo. OPNsense compensa con una API REST sólida y la colección de Ansible, pero requiere más esfuerzo para llegar al mismo nivel de automatización.\nMarco de auditoría: ISO 27001 y ENS Por qué importa aunque sea un homelab Es tentador pensar que un marco de auditoría formal es solo para empresas. Pero la realidad es más pragmática: un marco de auditoría es una checklist que personas con más experiencia que tú ya validaron. Seguirlo evita el problema de \u0026ldquo;se me olvidó revisar X\u0026rdquo; que aparece cuando la rutina de seguridad depende solo de la memoria.\nHay una razón adicional si estás en España: el Esquema Nacional de Seguridad (ENS, Real Decreto 311/2022) es obligatorio para el sector público y sus proveedores tecnológicos1. Esto incluye cada vez más a freelancers y pequeñas empresas que prestan servicios a administraciones públicas. Tener la infraestructura alineada con el ENS, aunque sea a nivel básico, no es solo buena práctica, es un requisito potencial.\nControles relevantes de ISO 27001:2022 ISO 27001:2022 organiza los controles de seguridad en el Anexo A2. Los que aplican directamente a lo configurado en esta serie:\nControl Descripción Implementación en OPNsense A.8.20 Seguridad de redes Firewall WAN deny-all, IPS, CrowdSec, GeoIP A.8.22 Segregación de redes 5 VLANs con reglas inter-VLAN restrictivas A.8.23 Filtrado web Zenarmor DPI con políticas por categoría A.8.15 Logging Syslog remoto con TLS, EVE JSON de Suricata A.8.16 Actividades de monitorización Alertas Suricata, dashboards CrowdSec, Zenarmor A.8.17 Sincronización de relojes NTP configurado en System \u0026gt; General (imprescindible para correlación de logs) A.5.15 Control de acceso Política least-privilege, admin dedicado A.5.17 Información de autenticación Contraseñas 16+ caracteres, OTP habilitado A.5.18 Derechos de acceso Revisión periódica de usuarios y permisos A.8.2 Acceso privilegiado Root restringido, admin separado, SSH solo con claves La norma no prescribe frecuencias exactas de revisión, pero los auditores esperan: revisión de reglas de firewall al menos trimestral, revisión de accesos privilegiados trimestral, y monitorización de logs continua con revisión manual semanal.\nMedidas del ENS aplicables El ENS (RD 311/2022) clasifica los sistemas en tres niveles: básico, medio y alto. Las medidas relevantes para un firewall:\nMedida ENS Descripción Nivel mínimo Implementación mp.com.1 Perímetro seguro Medio Firewall WAN, GeoIP, deny-all por defecto mp.com.2 Protección de confidencialidad Medio WireGuard VPN, DoT para DNS mp.com.4 Segregación de redes Medio VLANs con reglas inter-VLAN op.exp.2 Configuración de seguridad Básico Hardening SSH, servicios deshabilitados op.exp.8 Registro de actividad Básico Syslog remoto (retención 2 años para medio/alto) op.acc.1 Identificación Básico Usuarios únicos, sin cuentas compartidas op.acc.5 Mecanismo de autenticación Básico Contraseñas fuertes; OTP para medio/alto op.acc.7 Acceso remoto Básico WireGuard VPN obligatorio para administración remota op.mon.1 Detección de intrusiones Medio Suricata IPS + CrowdSec Las guías CCN-STIC del Centro Criptológico Nacional proporcionan instrucciones detalladas de implementación. En particular, la CCN-STIC-811 para interconexión y la CCN-STIC-408 para seguridad perimetral son las más relevantes para este contexto3.\nUn detalle importante del ENS: la retención de logs para nivel medio y alto es de dos años mínimo. Si el syslog remoto no tiene capacidad para eso, hay que planificarlo. Con Loki y compresión, los logs de firewall de un homelab no ocupan mucho, pero hay que tenerlo en cuenta desde el diseño.\nCalendario de auditoría Combinando las recomendaciones de ISO 27001 y ENS con lo que es realista para un entorno pequeño:\nFrecuencia Tarea Tipo Diaria Revisión automatizada de alertas IDS/IPS y decisiones CrowdSec Automática Semanal Revisión manual de logs: eventos bloqueados, intentos de login fallidos, tráfico anómalo Manual Mensual Revisión de reglas de firewall y actualización de alias. Verificar que los feeds de amenazas se actualizan Manual Trimestral Revisión completa de reglas: identificar reglas sin hits, reglas demasiado permisivas, reglas temporales olvidadas Manual Trimestral Revisión de accesos: usuarios activos, permisos, claves SSH vigentes, tokens API Manual Semestral Test de exposición básico: nmap desde fuera de la red contra la IP pública Manual Anual Revisión completa de la postura de seguridad. Comparar con el estado del año anterior Manual Para la revisión diaria automatizada, un script básico que se ejecuta con cron:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #!/bin/bash # /root/scripts/daily_audit.sh # Ejecutar con: crontab -e -\u0026gt; 0 7 * * * /root/scripts/daily_audit.sh LOG=\u0026#34;/var/log/daily_audit_$(date +%Y%m%d).log\u0026#34; echo \u0026#34;=== Auditoría diaria $(date) ===\u0026#34; \u0026gt; \u0026#34;$LOG\u0026#34; # Alertas críticas de Suricata en las últimas 24h echo -e \u0026#34;\\n--- Alertas Suricata (severity 1) ---\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; cat /var/log/suricata/eve.json | \\ jq -r \u0026#39;select(.event_type==\u0026#34;alert\u0026#34; and .alert.severity==1) | \u0026#34;\\(.timestamp) \\(.alert.signature) src=\\(.src_ip) dst=\\(.dest_ip)\u0026#34;\u0026#39; | \\ tail -50 \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; # Decisiones activas de CrowdSec echo -e \u0026#34;\\n--- CrowdSec decisiones activas ---\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; cscli decisions list -o raw 2\u0026gt;/dev/null | wc -l \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; # Antigüedad del último backup echo -e \u0026#34;\\n--- Último backup ---\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; LAST_BACKUP=$(ls -t /conf/backup/*.xml 2\u0026gt;/dev/null | head -1) if [ -n \u0026#34;$LAST_BACKUP\u0026#34; ]; then stat -f \u0026#34;%Sm\u0026#34; \u0026#34;$LAST_BACKUP\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; else echo \u0026#34;No se encontraron backups\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; fi # Estado del sistema echo -e \u0026#34;\\n--- Recursos del sistema ---\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; echo \u0026#34;CPU: $(sysctl -n dev.cpu.0.temperature 2\u0026gt;/dev/null || echo \u0026#39;N/A\u0026#39;)\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; echo \u0026#34;RAM: $(sysctl -n vm.stats.vm.v_free_count)\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; echo \u0026#34;States: $(pfctl -si 2\u0026gt;/dev/null | grep \u0026#39;current entries\u0026#39;)\u0026#34; \u0026gt;\u0026gt; \u0026#34;$LOG\u0026#34; # Enviar por email o copiar a syslog logger -t daily_audit \u0026#34;Auditoría completada. Ver $LOG\u0026#34; Este script no pretende ser un SIEM. Es una primera línea de revisión automática que señala si hay algo que requiere atención. Para un análisis serio de logs, la combinación de Grafana + Loki o un Wazuh dedicado es lo adecuado.\nOPNsense frente a las alternativas Antes de seguir invirtiendo tiempo en OPNsense, vale la pena comparar con las otras opciones serias de firewall/router open source. No para migrar ahora, sino para saber qué hay fuera y tomar decisiones informadas si las necesidades cambian.\nVyOS VyOS es un sistema operativo de red basado en Debian con un modelo de configuración CLI inspirado en JunOS. No tiene interfaz web.\nLo que hace mejor que OPNsense:\nConfiguración como texto plano. La config de VyOS es un archivo de texto legible, con commits atómicos y rollback nativo. Es el sueño del IaC: git diff funciona directamente sobre la configuración. Provider de Terraform oficial (Foltik/vyos). Infraestructura de red declarativa real. Routing avanzado. BGP, OSPF, IS-IS a escala. Soporta tablas de routing con más de un millón de prefijos BGP. Rendimiento. El dataplane VPP permite throughput de 10 Gbps+ con hardware adecuado. Cloud-native. Despliegue directo en AWS, Azure y GCP con soporte oficial. Lo que hace peor:\nSin GUI. Todo es CLI o API. La curva de aprendizaje es pronunciada si no vienes de networking empresarial. Seguridad integrada limitada. No hay equivalente a Suricata con GUI, no hay DPI tipo Zenarmor, no hay CrowdSec integrado. Se puede instalar Suricata manualmente, pero sin la integración que ofrece OPNsense. LTS de pago. Desde 2024, las imágenes LTS estables requieren suscripción. Las rolling son gratuitas pero sin garantía de estabilidad. OpenWrt OpenWrt es un sistema operativo para routers basado en Linux. Su fuerte es el soporte de hardware embebido.\nLo que hace mejor que OPNsense:\nSoporte de hardware masivo. Funciona en más de 500 modelos de routers comerciales, además de x86. WiFi nativo. Gestiona directamente las interfaces wireless, con soporte excelente de drivers y configuración avanzada de APs. Ligero. Puede funcionar con 128 MB de RAM y 16 MB de flash en hardware embebido. Ecosistema de paquetes. Más de 27.000 paquetes disponibles. Lo que hace peor:\nSeguridad básica. Firewall nftables sin IDS/IPS integrado. Los paquetes de Suricata y Snort son comunitarios, mal mantenidos y con problemas de rendimiento en hardware limitado. Sin DPI. No hay equivalente a Zenarmor. IaC limitado. UCI es scriptable pero no hay provider de Terraform ni API REST madura. Actualizaciones complicadas. En x86, actualizar OpenWrt implica reinstalar y restaurar configuración. OPNsense actualiza con un clic. Cuándo elegir cada uno Criterio OPNsense VyOS OpenWrt Seguridad integrada Excelente (Suricata, CrowdSec, Zenarmor) Básica Mínima IaC y automatización Buena (API + Ansible) Excelente (Terraform + text config) Limitada (UCI) Rendimiento 10G+ Moderado Excelente (VPP) No aplica Curva de aprendizaje Moderada (GUI) Pronunciada (CLI) Moderada Coste Gratuito LTS de pago, rolling gratuito Gratuito Caso de uso ideal Firewall/UTM perimetral Router enterprise o cloud edge AP WiFi, gateway ligero Para un homelab o una oficina pequeña donde la seguridad es la prioridad, OPNsense sigue siendo la mejor opción. La combinación de Suricata, CrowdSec y Zenarmor con una interfaz web usable no tiene equivalente en las alternativas.\nVyOS tiene sentido si el entorno crece hacia routing complejo (múltiples uplinks con BGP, SD-WAN) o si la infraestructura se gestiona exclusivamente con Terraform.\nOpenWrt tiene sentido como complemento: un AP WiFi corriendo OpenWrt detrás de un OPNsense es una combinación sólida. Pero como firewall perimetral para seguridad, se queda corto.\nConclusiones y próximos pasos En tres posts hemos pasado de un mini PC sin sistema operativo a una red segmentada con cinco VLANs, tres capas de detección (Suricata, CrowdSec, Zenarmor), VPN con WireGuard, DNS cifrado, backups automáticos, automatización con Ansible y un marco de auditoría basado en estándares reales.\nNo es perfecto. El IaC de OPNsense no llega al nivel de VyOS. Zenarmor tiene un modelo de licencias que limita las funciones avanzadas en la versión gratuita. Y mantener una rutina de auditoría requiere disciplina que es fácil dejar de lado cuando todo parece funcionar bien.\nPero es una base sólida sobre la que seguir construyendo. Hay temas que deliberadamente se han dejado fuera de esta serie porque merecen profundidad propia:\nIntegración con Wazuh como SIEM: correlación de eventos de Suricata, CrowdSec y los logs del sistema en un solo lugar, con alertas y dashboards centralizados. Es el paso natural para quien quiera monitorización de seguridad real. Multi-WAN y failover: configurar dos conexiones a internet con balanceo de carga y failover automático. Relevante cuando la disponibilidad importa. HAProxy avanzado: mutual TLS (mTLS) con certificados de cliente, autenticación por certificado para servicios internos, OAuth2 como capa de autenticación frente a aplicaciones auto-alojadas. Monitorización de red con NetFlow/Insight: análisis detallado del tráfico por protocolo, host y puerto para detectar anomalías que los IDS no capturan. Automatización completa con Terraform: si OPNsense llega a tener un provider de Terraform maduro (o si se migra parcialmente a VyOS para el routing), la gestión declarativa de toda la red. Si hay interés, un cuarto post puede cubrir la integración con Wazuh y la monitorización avanzada. Es donde el salto de \u0026ldquo;homelab seguro\u0026rdquo; a \u0026ldquo;infraestructura con visibilidad real\u0026rdquo; se hace más evidente.\nReal Decreto 311/2022, de 3 de mayo, por el que se regula el Esquema Nacional de Seguridad. BOE-A-2022-7191.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nISO/IEC 27001:2022 — Information security, cybersecurity and privacy protection — Information security management systems — Requirements.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nLas guías CCN-STIC del Centro Criptológico Nacional proporcionan instrucciones detalladas para la implementación del ENS. En particular, la CCN-STIC-811 cubre la interconexión de sistemas y la CCN-STIC-408 la seguridad perimetral.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2026-04-11T00:00:00Z","permalink":"/p/opnsense-auditor%C3%ADa-automatizaci%C3%B3n-y-pr%C3%A1cticas-avanzadas/","title":"OPNsense: auditoría, automatización y prácticas avanzadas"},{"content":"Backups cifrados nativos Perder la configuración de OPNsense después de horas de ajustes es el tipo de desastre que solo pasa una vez. Después de esa vez, se configuran los backups automáticos.\nOPNsense tiene un sistema de backup nativo que exporta toda la configuración en un archivo XML. Desde la versión 24.1, estos backups se pueden cifrar directamente desde la interfaz web.\nConfiguración de backups cifrados En System \u0026gt; Configuration \u0026gt; Backups:\nIr a la sección Google Drive / Nextcloud si se quiere backup remoto, o quedarse con el backup local. Marcar la casilla Encrypt backup e introducir una contraseña de cifrado. Esta contraseña es independiente de las credenciales del sistema. Guardarla en un gestor de contraseñas, porque sin ella el backup es irrecuperable. En la sección de backup automático (Scheduled), configurar la frecuencia. Un backup diario es razonable para la mayoría de entornos. Backup manual desde la interfaz En System \u0026gt; Configuration \u0026gt; Backups, el botón Download configuration genera un XML con toda la configuración actual. Si se marcó la opción de cifrado, el archivo descargado estará cifrado con AES-256-CBC.\nBackup desde la consola Para automatizar backups desde la línea de comandos:\n1 2 3 4 5 6 7 8 9 10 # Exportar la configuración cp /conf/config.xml /root/backup_$(date +%Y%m%d).xml # Cifrar con OpenSSL openssl enc -aes-256-cbc -salt -pbkdf2 \\ -in /root/backup_$(date +%Y%m%d).xml \\ -out /root/backup_$(date +%Y%m%d).xml.enc # Eliminar el archivo sin cifrar rm /root/backup_$(date +%Y%m%d).xml Es recomendable copiar los backups cifrados a un almacenamiento externo: un NAS, un bucket S3, o incluso un repositorio Git privado (el XML cifrado es pequeño, unos pocos cientos de KB).\nRestauración Para restaurar, ir a System \u0026gt; Configuration \u0026gt; Backups, subir el archivo y, si está cifrado, introducir la contraseña. OPNsense aplica la configuración y reinicia los servicios afectados.\nAsignación de IPs estáticas Hay dispositivos que necesitan tener siempre la misma IP: servidores, NAS, impresoras, cámaras de vigilancia. Se puede hacer de dos formas: configurando la IP fija en el propio dispositivo o, lo que es más limpio, asignando reservas DHCP en OPNsense.\nReservas DHCP (la forma recomendada) En Services \u0026gt; DHCPv4 \u0026gt; [interfaz]:\nIr a la sección DHCP Static Mappings. Añadir una nueva entrada con: MAC Address: la dirección MAC del dispositivo. IP Address: la IP que se quiere asignar siempre. Hostname: un nombre descriptivo. La ventaja de hacerlo así es que la gestión queda centralizada en OPNsense. Si cambias de router mañana, los dispositivos no necesitan reconfigurarse.\nConvención de rangos Una convención que funciona bien para organizar la red:\nRango Uso .1 Gateway (OPNsense) .2 - .19 Infraestructura (switches, APs, NAS) .20 - .49 Servidores y servicios .50 - .99 Dispositivos con IP fija (impresoras, cámaras) .100 - .254 Pool DHCP dinámico Esto hace que con solo ver la IP de un dispositivo ya sepas en qué categoría cae.\nZenarmor (Sensei) Zenarmor es un plugin de deep packet inspection (DPI) para OPNsense. Va más allá de lo que hacen Suricata o CrowdSec porque inspecciona el tráfico a nivel de aplicación: puede distinguir entre Netflix y YouTube, entre Telegram y WhatsApp, entre tráfico legítimo y aplicaciones potencialmente peligrosas.\nQué hace exactamente Clasificación de tráfico por aplicación: identifica más de 300 aplicaciones y protocolos. Filtrado de contenido por categorías: permite bloquear categorías enteras (gambling, malware, adult content) sin necesidad de mantener listas manualmente. Análisis de tráfico cifrado (TLS): Zenarmor puede clasificar tráfico HTTPS sin descifrarlo, utilizando metadatos como SNI, JA3 fingerprints y patrones de conexión. Reporting detallado: dashboards con el consumo por dispositivo, aplicación y categoría. Instalación En System \u0026gt; Firmware \u0026gt; Plugins, buscar os-sunnyvalley e instalar. Tras la instalación, Zenarmor aparece en el menú principal.\nAl iniciar Zenarmor por primera vez, se ejecuta un asistente de configuración:\nModo de despliegue: elegir Routed Mode para inspeccionar todo el tráfico que pasa por OPNsense. El modo Bridge es para casos específicos. Motor de base de datos: Zenarmor usa una base de datos local para los logs. Para hardware modesto (N100), seleccionar SQLite. Para hardware más potente, Elasticsearch da mejor rendimiento en las consultas. Interfaces a proteger: seleccionar las interfaces LAN que se quieren inspeccionar. Política por defecto: empezar con una política permisiva (solo monitorizar) y ajustar después de ver el tráfico real. Configuración de políticas En Zenarmor \u0026gt; Policies:\nLas políticas se aplican por interfaz o por grupo de dispositivos. Una configuración razonable:\nPolítica general (LAN principal):\nBloquear categorías: Malware, Phishing, Cryptomining, C2 (Command \u0026amp; Control). Monitorizar pero permitir: Streaming, Social Media, Gaming. Permitir todo lo demás. Política para IoT (la crearemos con VLANs más adelante):\nBloquear todo excepto los dominios necesarios para cada dispositivo. Los dispositivos IoT no deberían poder acceder a internet libremente. Política para invitados:\nBloquear: P2P, Tor, VPN (para evitar bypass del filtrado). Limitar ancho de banda por dispositivo. Diferencia con Suricata y CrowdSec Característica Suricata (IDS/IPS) CrowdSec Zenarmor Inspección Paquetes y firmas Logs y patrones Aplicación (DPI) Qué detecta Exploits, malware, C2 Fuerza bruta, escaneos Aplicaciones, categorías Bloqueo Por firma/regla Por IP (ban temporal) Por aplicación/categoría Recurso principal CPU (alto) CPU (bajo) CPU (medio) + RAM Complementarios Sí Sí Sí Los tres se complementan. Suricata busca amenazas conocidas en el tráfico. CrowdSec detecta comportamientos maliciosos en los logs y comparte inteligencia. Zenarmor clasifica y filtra a nivel de aplicación. Usarlos juntos da una cobertura de seguridad difícil de superar en un equipo doméstico.\nDeshabilitar SSH inseguro SSH es la forma habitual de acceder a la consola de OPNsense de forma remota. Pero la configuración por defecto tiene aspectos que conviene cambiar.\nConfiguración segura de SSH En System \u0026gt; Settings \u0026gt; Administration, sección SSH:\nDeshabilitar el login de root por SSH. Crear un usuario específico con acceso SSH y permisos de sudo. Cambiar el puerto por defecto. El puerto 22 es el primero que escanean los bots. Cambiar a un puerto alto (por ejemplo, 2222 o algo menos predecible). Deshabilitar autenticación por contraseña. Usar exclusivamente claves SSH: 1 2 3 4 5 # En tu máquina local, generar un par de claves si no tienes uno ssh-keygen -t ed25519 -C \u0026#34;opnsense-admin\u0026#34; # Copiar la clave pública cat ~/.ssh/id_ed25519.pub Pegar la clave pública en el perfil del usuario en System \u0026gt; Access \u0026gt; Users \u0026gt; [usuario] \u0026gt; Authorized Keys. En la configuración SSH, desmarcar Permit Password Login. Restricción de acceso SSH por firewall Crear una regla de firewall que solo permita SSH desde IPs específicas:\nEn Firewall \u0026gt; Rules \u0026gt; LAN, crear una regla:\nAcción: Pass Protocolo: TCP Origen: alias con las IPs de administración Destino: This Firewall Puerto destino: el puerto SSH configurado Y otra regla que bloquee SSH desde cualquier otro origen.\nVLANs: segmentación de red La segmentación con VLANs es probablemente el cambio más importante que se puede hacer en la seguridad de una red doméstica. Sin segmentación, una bombilla WiFi comprometida tiene acceso directo al NAS con las fotos familiares. Con VLANs, cada tipo de dispositivo vive en su propio segmento aislado.\nDiseño de VLANs VLAN ID Nombre Subred Propósito 10 Main 192.168.10.0/24 Dispositivos de confianza: portátiles, sobremesas, móviles personales 20 Guests 192.168.20.0/24 Dispositivos de invitados, sin acceso a la red interna 30 IoT 192.168.30.0/24 Dispositivos IoT: cámaras, sensores, bombillas, aspiradoras 40 Servers 192.168.40.0/24 Servidores, NAS, servicios auto-alojados 50 Management 192.168.50.0/24 Gestión de infraestructura: switches, APs, el propio OPNsense Creación de VLANs en OPNsense Para cada VLAN:\nIr a Interfaces \u0026gt; Other Types \u0026gt; VLAN. Crear una nueva VLAN: Parent interface: la interfaz física a la que se conecta el switch gestionable (por ejemplo, igb1). VLAN tag: el ID de la tabla anterior (10, 20, 30, 40, 50). Description: el nombre de la VLAN. Ir a Interfaces \u0026gt; Assignments y asignar cada VLAN como una nueva interfaz. Configurar cada interfaz: Habilitar la interfaz. Asignar IP estática: la IP del gateway para esa subred (por ejemplo, 192.168.10.1/24 para VLAN 10). Configurar DHCP en Services \u0026gt; DHCPv4 para cada VLAN con su rango correspondiente. Configuración del switch El switch gestionable necesita configurarse para que entienda las VLANs:\nEl puerto troncal (trunk) que va a OPNsense debe ser tagged para todas las VLANs (10, 20, 30, 40, 50). Los puertos de acceso se configuran como untagged en la VLAN correspondiente. Por ejemplo, el puerto donde se conecta un AP para invitados se pone untagged en VLAN 20. Si el AP soporta múltiples SSIDs con VLANs (como los Ubiquiti o TP-Link Omada), se puede crear un SSID por VLAN y el AP se encarga de tagear el tráfico. Reglas de firewall entre VLANs Este es el punto donde se define realmente la segmentación. Sin reglas de firewall, las VLANs comparten el mismo router y pueden comunicarse entre sí. Hay que crear reglas explícitas.\nPrincipio general: denegar todo entre VLANs por defecto y permitir solo lo necesario.\nVLAN 10 (Main):\nAcción Origen Destino Puerto Descripción Pass Main net * * Acceso completo a internet Pass Main net Servers net * Acceso a servicios internos Block Main net Management net * No acceder directamente a gestión Block Main net IoT net * Aislamiento de IoT VLAN 20 (Guests):\nAcción Origen Destino Puerto Descripción Pass Guests net * 80, 443, 53 Solo navegación web y DNS Block Guests net RFC1918 * Sin acceso a redes internas VLAN 30 (IoT):\nAcción Origen Destino Puerto Descripción Pass IoT net * 443, 8883 Solo HTTPS y MQTT para cloud Pass IoT net IoT gateway 53 DNS Block IoT net RFC1918 * Sin acceso a redes internas VLAN 40 (Servers):\nAcción Origen Destino Puerto Descripción Pass Servers net * 80, 443, 53 Acceso a internet para actualizaciones Pass Servers net Servers net * Comunicación entre servicios Block Servers net Main net * Los servidores no inician conexiones a Main VLAN 50 (Management):\nAcción Origen Destino Puerto Descripción Pass Management net * * Acceso total (solo admins) Para implementar la regla de bloqueo de redes RFC1918 (que cubre todas las subredes privadas), crear un alias en Firewall \u0026gt; Aliases:\nNombre: RFC1918 Tipo: Network Contenido: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 Este alias se usa como destino en las reglas de bloqueo para evitar que VLANs como Guests o IoT accedan a cualquier red interna.\nHardening y buenas prácticas Actualizaciones Lo primero y lo más básico: mantener OPNsense actualizado. Las actualizaciones de seguridad se publican con regularidad y los parches se aplican rápido.\nConfigurar notificaciones de actualización por email. Aplicar las actualizaciones en horarios de bajo uso. Antes de actualizar, hacer un backup (ya está automatizado si se siguió la primera sección). DNS sobre TLS (DoT) Configurar Unbound (el resolver DNS de OPNsense) para usar DNS sobre TLS:\nEn Services \u0026gt; Unbound DNS \u0026gt; General:\nHabilitar DNS over TLS. En Custom forwarding, añadir servidores DNS que soporten DoT: 1 2 3 4 5 6 7 # Quad9 (filtrado de malware incluido) 9.9.9.9@853#dns.quad9.net 149.112.112.112@853#dns.quad9.net # Cloudflare 1.1.1.1@853#cloudflare-dns.com 1.0.0.1@853#cloudflare-dns.com Esto cifra las consultas DNS entre OPNsense y el resolver, evitando que el ISP vea qué dominios consulta cada dispositivo.\nDeshabilitar servicios innecesarios En System \u0026gt; Settings \u0026gt; Administration:\nDeshabilitar UPnP salvo que sea estrictamente necesario (y aun así, limitarlo a interfaces específicas). Deshabilitar SNMP si no se usa para monitorización. Revisar los plugins instalados y desinstalar los que no se usen. Logging centralizado OPNsense puede enviar logs a un servidor syslog externo. Si se tiene un stack de monitorización (Grafana + Loki, o ELK), configurar el envío en System \u0026gt; Settings \u0026gt; Logging \u0026gt; Remote:\nServidor: la IP del servidor syslog. Protocolo: TCP con TLS si es posible. Facility: seleccionar qué logs enviar (firewall, sistema, IDS). Auditoría regular Establecer una rutina de revisión:\nSemanal: revisar los logs de IDS/IPS y CrowdSec. Buscar patrones recurrentes. Mensual: revisar las reglas de firewall. ¿Hay reglas que ya no tienen sentido? ¿Se ha añadido algún dispositivo nuevo que necesita reglas específicas? Trimestral: revisar los usuarios y permisos. ¿Sigue siendo necesario cada usuario? ¿Las claves SSH están vigentes? En el tercer y último post de la serie repasaremos todo lo configurado, revisaremos la postura de seguridad en conjunto y veremos prácticas avanzadas.\n","date":"2026-04-03T00:00:00Z","permalink":"/p/opnsense-segmentaci%C3%B3n-de-red-vlans-y-hardening/","title":"OPNsense: segmentación de red, VLANs y hardening"},{"content":"Qué hardware necesita OPNsense Antes de abrir el instalador conviene saber qué pide OPNsense y qué merece la pena comprar. La documentación oficial distingue entre mínimos y recomendados, pero en la práctica hay matices que importan bastante.\nRequisitos mínimos oficiales Recurso Mínimo Recomendado CPU x86-64 de 64 bits, 1 GHz Multi-core reciente con AES-NI RAM 2 GB 8 GB Almacenamiento 40 GB SSD 120 GB SSD NICs 2 interfaces de red 2+ interfaces Intel AES-NI es obligatorio desde OPNsense 24.1. Sin esta instrucción el instalador ni arranca. Cualquier procesador Intel de sexta generación o posterior la incluye, y en AMD está presente desde Ryzen en adelante.\nOpciones económicas que funcionan La opción más barata con la que he tenido buena experiencia es un mini PC con procesador Intel N100 o N200. Están pensados para bajo consumo y tienen AES-NI, lo que cubre el requisito principal. Se encuentran con cuatro puertos Ethernet Intel i226-V por menos de 150 euros.\nAlgunos modelos concretos que cumplen:\nTopton N100/N200 con 4x i226-V: entre 120 y 170 euros según la configuración. Vienen sin RAM ni SSD, que se compran aparte. Un módulo de 8 GB DDR5 y un SSD de 128 GB añaden unos 30 euros más. Protectli VP2420 o VP2410: más caros (en torno a 300 euros), pero con soporte oficial y carcasa de aluminio que disipa bien. Buena opción si prefieres algo con garantía seria. Hardware reciclado con dos NICs: un Dell OptiPlex o Lenovo ThinkCentre con una tarjeta Intel dual-port PCIe funciona perfectamente. Se encuentran por 50-80 euros en mercados de segunda mano. Lo que realmente importa: que las interfaces de red sean Intel. Las Realtek funcionan, pero dan problemas con offloading y rendimiento bajo carga. Merece la pena pagar la diferencia.\nInstalación La instalación de OPNsense es directa. Se descarga la imagen ISO desde la web oficial, se graba en un USB con dd o con Rufus en Windows, y se arranca desde el USB.\n1 2 # Grabar la imagen en un USB (cuidado con seleccionar el dispositivo correcto) dd if=OPNsense-24.7-dvd-amd64.iso of=/dev/sdX bs=4M status=progress Al arrancar aparece un entorno live con la opción de probar antes de instalar. El usuario por defecto es installer con contraseña opnsense.\nDurante la instalación:\nSeleccionar el disco destino para la instalación (el SSD interno, no el USB). Elegir el sistema de ficheros. UFS es la opción simple y estable. ZFS tiene ventajas (snapshots, compresión), pero para un firewall con un solo disco UFS es suficiente. Definir la contraseña de root. Retirar el USB y reiniciar. Tras el reinicio, OPNsense arranca directamente y presenta una consola de texto con un menú básico. Desde ahí se puede asignar interfaces y configurar la dirección IP de la LAN para acceder a la interfaz web.\nConfiguración de PPPoE en WAN Si tu ISP utiliza PPPoE (como ocurre con muchas conexiones de fibra en España y Latinoamérica), hay que configurarlo en la interfaz WAN.\nEn Interfaces \u0026gt; WAN:\nCambiar el tipo de configuración IPv4 a PPPoE. Introducir el usuario y contraseña que proporciona el ISP. En la mayoría de proveedores no hace falta tocar el MTU, pero si notas problemas de fragmentación, ajustarlo a 1492 (el estándar para PPPoE sobre Ethernet con MTU 1500). Guardar y aplicar. Si la conexión no levanta, verificar que el cable del ONT va directamente al puerto asignado como WAN. Algunos ONT del ISP necesitan estar en modo bridge para que OPNsense negocie la sesión PPPoE directamente.\nLAN en modo bridge Hay situaciones en las que interesa agrupar varios puertos físicos en un mismo segmento de red, por ejemplo cuando el mini PC tiene cuatro puertos y queremos que tres de ellos funcionen como un switch sin necesidad de hardware adicional.\nPara configurar un bridge en OPNsense:\nIr a Interfaces \u0026gt; Other Types \u0026gt; Bridge. Crear un nuevo bridge y añadir las interfaces que quieres agrupar (por ejemplo, igb1, igb2, igb3). Ir a Interfaces \u0026gt; Assignments y asignar el bridge recién creado como la interfaz LAN. Configurar la IP estática de la LAN sobre la interfaz bridge (por ejemplo, 192.168.1.1/24). Habilitar el servidor DHCP en Services \u0026gt; DHCPv4 apuntando a la interfaz bridge. Con esto los tres puertos comparten el mismo segmento de red y el DHCP sirve direcciones para todos ellos.\nInterfaz wireless y firmware OPNsense soporta algunas tarjetas WiFi, pero el soporte es limitado comparado con Linux. Las tarjetas Atheros son las que mejor funcionan, pero muchas necesitan firmware adicional que no viene incluido por defecto.\nPara instalar el firmware necesario:\n1 2 3 4 # Desde la consola de OPNsense (opción 8 del menú para shell) pkg install wifi-firmware-atheros # O para tarjetas Intel: pkg install wifi-firmware-intel Después de instalar el firmware, reiniciar el sistema. La interfaz wireless debería aparecer en Interfaces \u0026gt; Assignments.\nPara configurar el punto de acceso:\nIr a Interfaces \u0026gt; Wireless y crear un nuevo dispositivo en modo Access Point. Seleccionar el estándar (802.11ac/ax si la tarjeta lo soporta). Configurar el SSID y la seguridad WPA2/WPA3. Asignar la interfaz wireless y darle una IP en un rango diferente al de la LAN cableada, o añadirla al bridge existente si se quiere que esté en el mismo segmento. Una advertencia honesta: el WiFi integrado en OPNsense funciona, pero no esperes el rendimiento ni la estabilidad de un access point dedicado. Para un uso serio es mejor usar un AP externo (Ubiquiti, TP-Link Omada) y dejar que OPNsense se encargue solo del routing y el firewall.\nIDS e IPS: detección y prevención de intrusiones OPNsense incluye Suricata como motor de IDS/IPS. La diferencia entre ambos modos es simple: IDS detecta y registra, IPS detecta y bloquea.\nConfiguración inicial En Services \u0026gt; Intrusion Detection:\nHabilitar IDS: marcar la casilla de activación. Modo IPS: si se quiere que bloquee tráfico, cambiar el modo a IPS. Esto requiere que Suricata funcione en modo inline, que es el comportamiento por defecto en OPNsense. Interfaces: seleccionar WAN como mínimo. Si se quiere inspeccionar también tráfico interno, añadir LAN, pero esto consume bastante más CPU. Pattern matcher: seleccionar Hyperscan si el hardware lo soporta (procesadores con SSSE3). Es significativamente más rápido que el matcher por defecto. Conjuntos de reglas recomendados en 2026 No se trata de activar todas las reglas disponibles. Eso consume recursos y genera falsos positivos. Una selección razonable:\nConjunto de reglas Para qué sirve Recomendación ET Open (Emerging Threats) Amenazas conocidas, malware, C2 Activar. Es la base Abuse.ch SSL Blacklist Certificados asociados a malware Activar Abuse.ch URLhaus URLs de distribución de malware Activar ET Open Compromised IPs comprometidas conocidas Activar Feodo Tracker Botnets bancarias Activar ET Open Tor Tráfico Tor Solo si quieres bloquear Tor Snort VRT Reglas comerciales de Snort Requiere suscripción, no imprescindible Buenas prácticas para IDS/IPS en 2026 No activar todas las reglas. Seleccionar las que tengan sentido para tu entorno. Una red doméstica no necesita reglas de SCADA o de servidores SQL. Actualización automática de reglas: configurar la descarga programada de reglas. En Schedule dentro de IDS, establecer una actualización diaria. Revisar los logs antes de pasar a modo IPS. Dejar el sistema en modo IDS durante al menos una semana para identificar falsos positivos. Si algo legítimo dispara alertas, crear una excepción antes de empezar a bloquear. Monitorizar el consumo de CPU. Suricata puede consumir mucho en hardware modesto. Si el procesador se mantiene por encima del 80% de uso con IPS activo, reducir el número de reglas o limitar la inspección a la interfaz WAN. Usar EVE JSON logging para exportar eventos a un SIEM o a una herramienta de análisis. El formato JSON facilita la integración con Elasticsearch, Grafana o Wazuh. No confiar únicamente en IDS/IPS. Es una capa más de defensa. No sustituye unas buenas reglas de firewall, segmentación de red ni actualizaciones regulares. CrowdSec CrowdSec complementa a Suricata con un enfoque diferente: análisis de logs y decisiones compartidas con la comunidad. Mientras que Suricata inspecciona paquetes en tiempo real, CrowdSec analiza los logs de los servicios y aplica bans basados en patrones de comportamiento.\nInstalación CrowdSec tiene un plugin oficial para OPNsense:\nIr a System \u0026gt; Firmware \u0026gt; Plugins. Buscar os-crowdsec e instalarlo. Tras la instalación, aparece en Services \u0026gt; CrowdSec. Configuración y colecciones recomendadas (Opcional) Después de la instalación, registrar la instancia en la consola central de CrowdSec:\n1 2 # Desde la shell de OPNsense cscli console enroll \u0026lt;tu-enrollment-key\u0026gt; Las colecciones definen qué patrones de ataque detecta CrowdSec. Las recomendadas para un firewall doméstico o de pequeña oficina:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # Colección base para firewalls (ya viene instalada normalmente) cscli collections install crowdsecurity/freebsd # Detección de escaneo de puertos y fuerza bruta SSH cscli collections install crowdsecurity/sshd cscli collections install crowdsecurity/iptables # Protección HTTP si expones servicios web cscli collections install crowdsecurity/nginx cscli collections install crowdsecurity/base-http-scenarios # Detección de escaneos agresivos cscli collections install crowdsecurity/http-cve # Listas de bloqueo comunitarias (IPs maliciosas conocidas) cscli collections install crowdsecurity/whitelist-good-actors Habilitar el bouncer de firewall para que CrowdSec pueda crear reglas de bloqueo directamente en el firewall de OPNsense:\n1 cscli bouncers add opnsense-firewall El token generado se introduce en la configuración del plugin en la interfaz web, en Services \u0026gt; CrowdSec \u0026gt; Bouncer.\nLa ventaja real de CrowdSec es la inteligencia compartida. Cuando un miembro de la comunidad detecta una IP atacante, esa información se distribuye a todos los demás. Es como tener un sistema de reputación de IPs colaborativo.\nWireGuard WireGuard es la opción más limpia para VPN en 2026. Más rápido, más simple y con mejor criptografía que OpenVPN o IPsec.\nConfiguración del servidor En VPN \u0026gt; WireGuard:\nCrear una instancia: ir a la pestaña Instances (o Local en versiones anteriores) y añadir una nueva.\nGenerar un par de claves (se hace automáticamente al crear la instancia). Puerto de escucha: 51820 (o el que prefieras). Dirección del túnel: 10.10.10.1/24. Añadir un peer: en la pestaña Peers, crear un nuevo par.\nClave pública del cliente (se genera en el dispositivo cliente). Allowed IPs: 10.10.10.2/32 (la IP que tendrá el cliente dentro del túnel). Asignar la interfaz: ir a Interfaces \u0026gt; Assignments, asignar la interfaz WireGuard (wg0 o wg1), habilitarla y no tocar la configuración de IP (ya está definida en WireGuard).\nConfiguración del cliente En el cliente (móvil, portátil), la configuración es un archivo sencillo:\n1 2 3 4 5 6 7 8 9 10 [Interface] PrivateKey = \u0026lt;clave-privada-del-cliente\u0026gt; Address = 10.10.10.2/24 DNS = 10.10.10.1 [Peer] PublicKey = \u0026lt;clave-publica-del-servidor\u0026gt; Endpoint = \u0026lt;ip-publica-o-ddns\u0026gt;:51820 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25 Con AllowedIPs = 0.0.0.0/0 todo el tráfico del cliente pasa por el túnel. Si solo se quiere acceder a la red local, cambiar a AllowedIPs = 192.168.1.0/24, 10.10.10.0/24.\nReglas de firewall De nada sirve configurar servicios si las reglas de firewall no permiten el tráfico correcto. OPNsense bloquea todo por defecto en WAN, lo cual es correcto. El trabajo está en permitir lo necesario en LAN y WireGuard.\nReglas para LAN En Firewall \u0026gt; Rules \u0026gt; LAN:\nAcción Protocolo Origen Destino Puerto destino Descripción Pass IPv4+6 LAN net * * Permitir salida LAN Pass IPv4 LAN net LAN address 53 DNS al firewall Pass IPv4 LAN net LAN address 443 Acceso WebUI La primera regla es la más permisiva y permite que la LAN salga a internet. En el segundo post de la serie veremos cómo restringir esto con VLANs.\nReglas para WireGuard En Firewall \u0026gt; Rules \u0026gt; WireGuard (o la interfaz asignada):\nAcción Protocolo Origen Destino Puerto destino Descripción Pass IPv4 WireGuard net LAN net * Acceso a LAN desde VPN Pass IPv4 WireGuard net * * Salida a internet desde VPN Regla en WAN para WireGuard En Firewall \u0026gt; Rules \u0026gt; WAN, añadir una regla para permitir la conexión entrante al puerto de WireGuard:\nAcción Protocolo Origen Destino Puerto destino Descripción Pass UDP * WAN address 51820 WireGuard entrante Offloading y tunning de hardware Cuando todo está funcionando, llega el momento de exprimir el rendimiento. OPNsense corre sobre FreeBSD, y tiene varias opciones de offloading que pueden marcar una diferencia notable.\nQué es el offloading Offloading significa delegar ciertas operaciones de red al hardware de la tarjeta de red en lugar de procesarlas por software en la CPU. Esto libera ciclos de CPU para otras tareas (como Suricata o CrowdSec) y reduce la latencia.\nOpciones disponibles En Interfaces \u0026gt; Settings:\nHardware CRC (Checksum Offloading): delega el cálculo de checksums TCP/UDP/IP a la tarjeta de red. Activar si la NIC lo soporta (las Intel i210/i225/i226 sí). Reduce carga de CPU de forma medible. Hardware TSO (TCP Segmentation Offloading): la tarjeta de red se encarga de dividir los paquetes TCP grandes en segmentos más pequeños. Mejora el throughput en transferencias grandes. Puede causar problemas con algunas configuraciones de IPS, así que probar y verificar. Hardware LRO (Large Receive Offloading): agrupa paquetes pequeños entrantes en bloques más grandes antes de pasarlos a la CPU. Reduce interrupciones. No activar si se usa IPS en modo inline, ya que interfiere con la inspección de paquetes. VLAN Hardware Filtering: si se usan VLANs (lo veremos en el segundo post), dejar que la NIC filtre por VLAN ID en hardware. Tunning adicional del sistema En System \u0026gt; Settings \u0026gt; Tunables, algunos ajustes útiles:\n1 2 3 4 5 6 7 8 9 # Aumentar los buffers de red net.inet.tcp.recvspace=65536 net.inet.tcp.sendspace=65536 # Habilitar RACK y BBR si el hardware lo soporta (FreeBSD 14+) net.inet.tcp.functions_default=bbr # Ajustar el número de colas de la NIC hw.igb.num_queues=4 No hay que obsesionarse con el tunning. En la mayoría de conexiones domésticas (hasta 1 Gbps simétrico), un N100 con las opciones por defecto ya da el rendimiento máximo. El tunning empieza a ser relevante cuando se quiere exprimir conexiones de 2.5 Gbps o más, o cuando Suricata consume demasiada CPU.\nGestión de usuarios y seguridad de la interfaz web Usar root para el día a día en la interfaz web es una mala práctica. Si alguien compromete esas credenciales, tiene control total.\nCrear un nuevo usuario administrador En System \u0026gt; Access \u0026gt; Users:\nCrear un nuevo usuario con nombre descriptivo (no admin, algo menos predecible). Asignar una contraseña fuerte. Mínimo 16 caracteres, generada con un gestor de contraseñas. En Effective Privileges, asignar el grupo admins. Activar la autenticación OTP si es posible. OPNsense soporta TOTP nativo, así que se puede usar con cualquier app de autenticación. Cambiar la contraseña de root En System \u0026gt; Access \u0026gt; Users, seleccionar root y cambiar la contraseña a algo largo y aleatorio. Guardar esta contraseña en un lugar seguro (gestor de contraseñas) y no usarla para el acceso diario.\nOtra opción más radical: deshabilitar el login de root en la interfaz web. Esto se puede hacer quitando los privilegios de acceso web al usuario root, dejando solo el acceso por consola física como último recurso.\nRestringir el acceso a la interfaz web Por defecto, la interfaz web es accesible desde toda la LAN. Esto se puede restringir:\nCambiar el puerto HTTPS: en System \u0026gt; Settings \u0026gt; Administration, cambiar el puerto de 443 a otro no estándar (por ejemplo, 8443). Restringir por IP de origen: crear un alias en Firewall \u0026gt; Aliases con las IPs desde las que se permite el acceso a la interfaz web. Luego, en las reglas de firewall de la LAN, crear una regla que permita el acceso al puerto de la WebUI solo desde ese alias, y una regla de bloqueo para el resto. Habilitar HTTPS con un certificado propio: en System \u0026gt; Trust \u0026gt; Certificates, generar un certificado autofirmado o importar uno de Let\u0026rsquo;s Encrypt. Esto elimina las advertencias del navegador y asegura que la conexión está cifrada correctamente. Protección contra fuerza bruta: en System \u0026gt; Settings \u0026gt; Administration, configurar el número máximo de intentos fallidos y el tiempo de bloqueo. Deshabilitar HTTP: asegurarse de que solo HTTPS está habilitado. El acceso HTTP sin cifrar a la interfaz de administración de un firewall no tiene sentido. En el siguiente post de la serie veremos cómo llevar la seguridad más lejos con backups cifrados, VLANs, Zenarmor y hardening del sistema.\n","date":"2026-04-01T00:00:00Z","permalink":"/p/opnsense-del-hardware-al-firewall-funcional/","title":"OPNsense: del hardware al firewall funcional"},{"content":"Por qué estas dos herramientas y no otras La oferta de herramientas de seguridad para pipelines es enorme, y es fácil acabar con un pipeline que tarda veinte minutos solo en escaneos. Después de probar varias combinaciones, me quedo con Trivy y Semgrep por una razón sencilla: cubren dos superficies de ataque distintas con mínima fricción.\nSemgrep analiza tu código fuente buscando patrones peligrosos — inyecciones SQL, deserialización insegura, secretos hardcodeados. Lo hace rápido y sin necesitar compilar nada. Trivy, por su parte, se encarga de todo lo que no es tu código: dependencias con CVEs conocidos, imágenes base desactualizadas, configuraciones de IaC problemáticas. Entre los dos cubres código propio y código ajeno.\nAmbas son open-source, se ejecutan sin servidor externo y producen salida JSON que puedes parsear fácilmente en CI. No necesitas licencias ni dashboards de terceros para empezar.\nEstructura del pipeline La idea es que la seguridad no sea una etapa aislada al final, sino algo que se ejecuta en paralelo con el resto de checks. Este es el esquema general:\n1 2 3 4 5 6 7 8 9 stages: - test - security - build - deploy variables: TRIVY_SEVERITY: \u0026#34;HIGH,CRITICAL\u0026#34; SEMGREP_RULES: \u0026#34;p/owasp-top-ten p/security-audit\u0026#34; La etapa security corre al mismo nivel que test. Si algún escaneo falla, el pipeline se detiene antes de construir la imagen o desplegar nada.\nConfigurando Semgrep Job básico 1 2 3 4 5 6 7 8 9 10 11 12 semgrep: stage: security image: semgrep/semgrep:latest script: - semgrep ci --config \u0026#34;$SEMGREP_RULES\u0026#34; --json --output semgrep-results.json artifacts: paths: - semgrep-results.json when: always rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;merge_request_event\u0026#34; - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH Esto ejecuta Semgrep en cada merge request y en cada push a la rama principal. Los resultados se guardan siempre como artefacto, incluso si el pipeline falla — querrás poder revisarlos después.\nReglas personalizadas Los rulesets genéricos están bien para empezar, pero en cuanto tengas patrones propios que quieras detectar, necesitarás reglas custom. Crea un directorio .semgrep/ en la raíz del proyecto:\n1 2 3 4 5 6 7 8 9 10 11 # .semgrep/no-env-secrets.yml rules: - id: no-os-environ-secrets patterns: - pattern: os.environ[$KEY] - metavariable-regex: metavariable: $KEY regex: \u0026#34;.*(SECRET|PASSWORD|TOKEN|KEY).*\u0026#34; message: \u0026#34;Acceso directo a secretos desde variables de entorno. Usa el gestor de secretos.\u0026#34; languages: [python] severity: WARNING Y referéncialo en el pipeline:\n1 2 variables: SEMGREP_RULES: \u0026#34;p/owasp-top-ten p/security-audit .semgrep/\u0026#34; Gestionando falsos positivos Va a haber falsos positivos. Es inevitable. Lo que importa es cómo los gestionas. La peor reacción es desactivar la regla entera o poner allow_failure: true. En su lugar, usa anotaciones inline:\n1 2 # nosemgrep: python.lang.security.audit.hardcoded-password TEST_PASSWORD = \u0026#34;dummy\u0026#34; # fixture de tests, no se usa en producción Cada supresión debería tener un comentario que explique por qué es seguro ignorarla. Sin excepción. Si no puedes justificarlo, no lo suprimas.\nPara supresiones más amplias, usa .semgrepignore:\n1 2 3 4 # Excluir fixtures de test tests/fixtures/ # Excluir código generado automáticamente *_generated.py Configurando Trivy Escaneo de dependencias 1 2 3 4 5 6 7 8 9 10 11 12 13 14 trivy-fs: stage: security image: name: aquasec/trivy:latest entrypoint: [\u0026#34;\u0026#34;] script: - trivy fs --severity \u0026#34;$TRIVY_SEVERITY\u0026#34; --exit-code 1 --format json --output trivy-fs.json . artifacts: paths: - trivy-fs.json when: always rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;merge_request_event\u0026#34; - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH Trivy examina los lockfiles del proyecto (package-lock.json, requirements.txt, go.sum, etc.) y cruza las versiones con bases de datos de vulnerabilidades. El flag --exit-code 1 hace que el job falle si encuentra algo HIGH o CRITICAL.\nEscaneo de imágenes de contenedor Si construyes imágenes Docker, escanéalas antes de publicarlas en el registry:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 trivy-image: stage: security image: name: aquasec/trivy:latest entrypoint: [\u0026#34;\u0026#34;] needs: - job: build-image artifacts: true script: - trivy image --severity \u0026#34;$TRIVY_SEVERITY\u0026#34; --exit-code 1 --format json --output trivy-image.json \u0026#34;$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA\u0026#34; artifacts: paths: - trivy-image.json when: always rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH Este job depende del build de la imagen (con needs) y solo se ejecuta en la rama principal, no en cada MR. Escanear imágenes es más lento que escanear el filesystem, así que reserva eso para lo que realmente se va a desplegar.\nEscaneo de IaC Una ventaja de Trivy que a menudo se pasa por alto es que también analiza configuraciones de infraestructura:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 trivy-iac: stage: security image: name: aquasec/trivy:latest entrypoint: [\u0026#34;\u0026#34;] script: - trivy config --severity \u0026#34;$TRIVY_SEVERITY\u0026#34; --exit-code 1 --format json --output trivy-iac.json . artifacts: paths: - trivy-iac.json when: always rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;merge_request_event\u0026#34; changes: - \u0026#34;**/*.tf\u0026#34; - \u0026#34;**/Dockerfile\u0026#34; - \u0026#34;**/*.yml\u0026#34; - \u0026#34;**/*.yaml\u0026#34; Detecta Dockerfiles que corren como root, archivos de Terraform con security groups demasiado abiertos, y configuraciones de Kubernetes sin límites de recursos. El bloque changes hace que solo se ejecute cuando se modifican archivos relevantes, evitando escaneos innecesarios.\nPolíticas de bloqueo No empieces bloqueando todo desde el primer día. Eso genera frustración, workarounds creativos y al final alguien pone allow_failure: true en todos los jobs de seguridad.\nMejor hacerlo por fases:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # Fase 1: Solo informar semgrep: allow_failure: true # Fase 2: Bloquear solo críticos semgrep: script: - semgrep ci --config \u0026#34;$SEMGREP_RULES\u0026#34; --json --output semgrep-results.json - | CRITICAL=$(jq \u0026#39;[.results[] | select(.extra.severity == \u0026#34;ERROR\u0026#34;)] | length\u0026#39; semgrep-results.json) if [ \u0026#34;$CRITICAL\u0026#34; -gt 0 ]; then echo \u0026#34;Bloqueado: $CRITICAL hallazgos críticos\u0026#34; exit 1 fi allow_failure: false # Fase 3: Bloquear high + critical # ... ajustar el filtro jq Lo mismo aplica para Trivy. El flag --severity ya te permite controlar qué niveles bloquean el pipeline. Empieza solo con CRITICAL, y cuando el equipo se haya adaptado, añade HIGH.\nEl pipeline completo Poniendo todo junto:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 stages: - test - security - build - deploy variables: TRIVY_SEVERITY: \u0026#34;HIGH,CRITICAL\u0026#34; SEMGREP_RULES: \u0026#34;p/owasp-top-ten p/security-audit\u0026#34; semgrep: stage: security image: semgrep/semgrep:latest script: - semgrep ci --config \u0026#34;$SEMGREP_RULES\u0026#34; --json --output semgrep-results.json - | CRITICAL=$(jq \u0026#39;[.results[] | select(.extra.severity == \u0026#34;ERROR\u0026#34;)] | length\u0026#39; semgrep-results.json) echo \u0026#34;Hallazgos críticos: $CRITICAL\u0026#34; if [ \u0026#34;$CRITICAL\u0026#34; -gt 0 ]; then echo \u0026#34;Pipeline bloqueado\u0026#34; exit 1 fi artifacts: paths: - semgrep-results.json when: always rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;merge_request_event\u0026#34; - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH trivy-fs: stage: security image: name: aquasec/trivy:latest entrypoint: [\u0026#34;\u0026#34;] script: - trivy fs --severity \u0026#34;$TRIVY_SEVERITY\u0026#34; --exit-code 1 --format json --output trivy-fs.json . artifacts: paths: - trivy-fs.json when: always rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;merge_request_event\u0026#34; - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH trivy-config: stage: security image: name: aquasec/trivy:latest entrypoint: [\u0026#34;\u0026#34;] script: - trivy config --severity \u0026#34;$TRIVY_SEVERITY\u0026#34; --exit-code 1 --format json --output trivy-iac.json . artifacts: paths: - trivy-iac.json when: always rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;merge_request_event\u0026#34; changes: - \u0026#34;**/*.tf\u0026#34; - \u0026#34;**/Dockerfile\u0026#34; - \u0026#34;**/*.yml\u0026#34; trivy-image: stage: security image: name: aquasec/trivy:latest entrypoint: [\u0026#34;\u0026#34;] needs: - job: build artifacts: true script: - trivy image --severity \u0026#34;$TRIVY_SEVERITY\u0026#34; --exit-code 1 --format json --output trivy-image.json \u0026#34;$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA\u0026#34; artifacts: paths: - trivy-image.json when: always rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH Semgrep y los escaneos de Trivy corren en paralelo dentro de la etapa security. Si cualquiera falla, el pipeline se detiene antes de construir o desplegar.\nIntegrando resultados en merge requests Los reportes JSON están bien para auditoría, pero los desarrolladores necesitan feedback visible directamente en el MR. GitLab soporta reportes de seguridad nativos si usas las plantillas oficiales, pero con herramientas externas puedes parsear el JSON y comentar en el MR:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 comment-results: stage: .post image: alpine:latest script: - apk add --no-cache curl jq - | SEMGREP_COUNT=$(jq \u0026#39;.results | length\u0026#39; semgrep-results.json 2\u0026gt;/dev/null || echo \u0026#34;0\u0026#34;) TRIVY_COUNT=$(jq \u0026#39;.Results[]?.Vulnerabilities // [] | length\u0026#39; trivy-fs.json 2\u0026gt;/dev/null || echo \u0026#34;0\u0026#34;) BODY=\u0026#34;### Resumen de seguridad\\n- Semgrep: ${SEMGREP_COUNT} hallazgos\\n- Trivy: ${TRIVY_COUNT} vulnerabilidades\u0026#34; curl --request POST \\ --header \u0026#34;PRIVATE-TOKEN: ${GITLAB_API_TOKEN}\u0026#34; \\ --header \u0026#34;Content-Type: application/json\u0026#34; \\ --data \u0026#34;{\\\u0026#34;body\\\u0026#34;: \\\u0026#34;$BODY\\\u0026#34;}\u0026#34; \\ \u0026#34;${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/merge_requests/${CI_MERGE_REQUEST_IID}/notes\u0026#34; rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;merge_request_event\u0026#34; allow_failure: true No es lo más elegante, pero funciona. Si usas GitLab Ultimate tienes los reportes de seguridad integrados. Si no, esto da visibilidad suficiente.\nCaché y rendimiento Los escaneos añaden tiempo al pipeline, y si ese tiempo es excesivo el equipo los acabará desactivando. Algunas cosas que ayudan:\n1 2 3 4 5 6 7 8 trivy-fs: variables: TRIVY_CACHE_DIR: \u0026#34;.trivycache/\u0026#34; cache: key: trivy-db paths: - .trivycache/ # ...resto del job Cachear la base de datos de vulnerabilidades de Trivy evita descargarla en cada ejecución. Son unos 40MB que se descarga de GitHub, y en runners compartidos esa descarga puede tardar bastante.\nPara Semgrep, el propio binario ya es rápido, pero si tu repositorio es grande, limita los paths:\n1 2 3 semgrep: script: - semgrep ci --config \u0026#34;$SEMGREP_RULES\u0026#34; --include=\u0026#34;src/\u0026#34; --include=\u0026#34;app/\u0026#34; --json --output semgrep-results.json No pierdas tiempo escaneando node_modules/, vendor/ o directorios de assets.\nLo que aprendí configurando esto Llevo un tiempo con esta configuración en producción y hay cosas que solo se ven con el uso:\nTrivy detecta muchos CVEs en imágenes base que no tienen fix disponible. Si no filtras por --ignore-unfixed, vas a tener ruido constante. Mejor añadir ese flag y centrarte en lo que puedes corregir:\n1 trivy image --ignore-unfixed --severity HIGH,CRITICAL mi-imagen:latest Con Semgrep, los rulesets de comunidad son un buen punto de partida, pero las reglas que más valor aportan son las que escribes tú, adaptadas a los patrones de tu proyecto. Una regla que detecta que alguien usa el ORM sin parametrizar queries vale más que cien reglas genéricas.\nY lo más importante: no intentes tapar todos los agujeros a la vez. Empieza con los escaneos en modo informativo, revisa qué sale, ajusta las reglas, y solo entonces empieza a bloquear. Si el primer día bloqueas todo, el segundo día alguien habrá puesto allow_failure: true en cada job.\n","date":"2026-03-16T00:00:00Z","permalink":"/p/seguridad-shift-left-integrando-trivy-y-semgrep-en-gitlab-ci/","title":"Seguridad shift-left: integrando Trivy y Semgrep en GitLab CI"},{"content":"sdm es un gestor de imágenes de tarjetas SD para Raspberry Pi que te permite automatizar y repetir todo lo que normalmente harías a mano: usuarios, claves SSH, paquetes, cifrado y más. En lugar de configurar cada tarjeta manualmente, personalizas una imagen base una sola vez y luego grabas tantas tarjetas idénticas como necesites.\nEn esta publicación muestro cómo instalar y usar sdm para crear una imagen de RaspiOS cifrada que puedes desbloquear por SSH, y luego grabarla en una tarjeta SD.\nRequisitos Para ejecutar sdm necesitas:\nLa última versión de systemd-nspawn La imagen de RaspiOS que deseas personalizar, por ejemplo: 2025-12-04-raspios-trixie-arm64-lite.img. Instalación Una instalación típica se ve así:\n1 2 3 4 5 6 7 # 1. Clona el repositorio de sdm git clone [https://github.com/gitbls/sdm.git](https://github.com/gitbls/sdm.git) cd sdm # 2. Opcionalmente agrega sdm a tu PATH sudo cp sdm /usr/local/bin/ sudo chmod +x /usr/local/bin/sdm Personalizar la imagen Después de leer la documentación sobre Cifrado de Disco y plugins, realizo la siguiente personalización:\n1 2 3 4 5 6 7 8 9 10 sudo sdm --customize --host rpi-1 --plugin-debug --expand-root --regen-ssh-host-keys \\ --plugin swap:\u0026#34;filesize=2048|zramsize=1024\u0026#34; \\ --plugin user:\u0026#34;deluser=pi|adduser=user|uid=1234|password=12345|addgroup=sudo\u0026#34; \\ --plugin copyfile:\u0026#34;from=/home/user/.ssh/rpi-1.user.ed25519.pub|to=/home/user/.ssh/authorized_keys|chown=user:user|chmod=600|mkdirif\u0026#34; \\ --plugin sshd:\u0026#34;password-authentication=yes|port=22222\u0026#34; \\ --plugin cryptroot:\u0026#34;ssh|authkeys=/home/user/.ssh/initramfs_authorized_keys|crypto=xchacha|ipaddr=192.168.1.20|gateway=192.168.1.1|netmask=255.255.255.0|dns=1.1.1.1\u0026#34; \\ --plugin network:\u0026#34;ifname=eth0|ipv4-static-ip=192.168.1.20|ipv4-static-gateway=192.168.20.1\u0026#34; \\ --plugin disables:piwiz \\ --restart \\ 2025-12-04-raspios-trixie-arm64-lite.img Este comando sdm --customize personaliza una imagen de RasPiOS Trixie ARM64 lite de la siguiente forma:\nExpande el sistema de archivos raíz y regenera las claves host de SSH Configura el swap, crea un usuario, instala una clave SSH y ajusta los parámetros del demonio SSH Configura el cifrado completo del sistema de archivos raíz con desbloqueo SSH en initramfs y red estática Desactiva piwiz y reinicia después de la personalización Desglose detallado Parámetros globales:\ncustomize: Personaliza el archivo de imagen especificado. host rpi-1: Establece el nombre de host como rpi-1. plugin-debug: Habilita la salida de depuración de los plugins. expand-root: Expande el sistema de archivos raíz al primer arranque. regen-ssh-host-keys: Regenera las claves host SSH en el primer arranque para que cada dispositivo tenga claves únicas. restart: Reinicia la imagen después de finalizar la personalización. Imagen objetivo: 2025-12-04-raspios-trixie-arm64-lite.img. Plugins swap:\u0026quot;filesize=2048|zramsize=1024\u0026quot;: Configura un archivo swap de 2 GB y un dispositivo zram de 1 GB mediante el plugin de swap. user:\u0026quot;deluser=pi|adduser=user|uid=4321|password=12345|addgroup=sudo\u0026quot;: Elimina el usuario por defecto pi, crea un nuevo usuario user con UID 4321, establece su contraseña y lo agrega al grupo sudo. copyfile:\u0026quot;from=...|to=...|chown=user:user|chmod=600|mkdirif\u0026quot;: Copia una clave pública SSH dentro de la imagen como authorized_keys para la cuenta del usuario, creando el directorio .ssh si es necesario, y ajustando los permisos. sshd:\u0026quot;password-authentication=yes|port=62626\u0026quot;: Configura el daemon SSH para permitir autenticación por contraseña y escuchar en el puerto 62626. cryptroot:\u0026quot;ssh|authkeys=...|crypto=xchacha|ipaddr=...|gateway=...|netmask=...|dns=...\u0026quot;: Configura el cifrado completo del sistema de archivos raíz con LUKS, habilita el desbloqueo SSH en initramfs, usa cifrado xchacha y define red estática para el initramfs. network:\u0026quot;ifname=eth0|ipv4-static-ip=...|ipv4-static-gateway=...\u0026quot;: Establece una IP estática para eth0 en el sistema en ejecución. disables:piwiz: Desactiva el asistente de primer inicio piwiz para que no solicite teclado ni usuario al arrancar. Cifrar la tarjeta SD (rootfs) Durante la personalización invocamos el plugin cryptroot, por lo tanto, ahora solo es necesario grabar la imagen en la tarjeta SD situada en /dev/sdb:\n1 sudo sdm --burn /dev/sdb 2025-12-04-raspios-trixie-arm64-lite.img Primer arranque: se ejecuta sdm-auto-encrypt y el sistema se reinicia.\nEl servicio ejecuta sdm-cryptconfig --sdm ... --reboot, que actualiza initramfs, cmdline.txt, fstab y crypttab. Segundo arranque: se abre el prompt de initramfs; ejecuta sdmcryptfs.\nEl sistema cae a (initramfs). Conecta un disco auxiliar mayor al espacio usado y ejecuta: 1 (initramfs) sdmcryptfs /dev/mmcblk0 /dev/sdY Sustituye /dev/mmcblk0 por el disco del sistema y /dev/sdY por el disco auxiliar. Sigue las instrucciones para cifrar y desbloquear el rootfs. Luego escribe exit para continuar el arranque. Arranque final: rootfs cifrado activo.\nEl sistema ahora pedirá la contraseña en cada inicio.\nSi SSH está habilitado, puedes desbloquear remotamente iniciando sesión como root al IP del initramfs durante el arranque.\n","date":"2025-12-21T00:00:00Z","permalink":"/p/personalizando-un-raspberry-pi-os-cifrado-con-sdm/","title":"Personalizando un Raspberry Pi OS cifrado con sdm"},{"content":"DevSecOps se usa mucho en ofertas de trabajo y charlas. Pero detrás del buzzword hay lecciones reales que solo vienen de hacer el trabajo. De construir pipelines que se rompen cuando añades seguridad, de ver equipos ignorar herramientas que pasaste meses desplegando, hasta finalmente encontrar qué funciona.\nEstas son lecciones que aprendimos a base de golpes. Son opiniones fundamentadas, prácticas, moldeadas por experiencia real.\nLa seguridad es responsabilidad de todos Suena a póster, pero es la lección más importante. Si la seguridad es solo del equipo de seguridad, ya perdiste.\nLos desarrolladores toman decisiones de seguridad cada vez que escriben código, lo sepan o no. Cómo validan entrada. Cómo manejan secretos. Cómo configuran acceso de red. Cada PR es un evento de seguridad.\nLo que funciona: haz seguridad parte del flujo de desarrollo normal, no una puerta al final. Los desarrolladores aprenden cuando reciben feedback rápido sobre problemas de seguridad en su PR. Lo resientan cuando se enteran tres semanas después de un auditor.\nLo hemos visto repetidamente: equipos que tratan seguridad como responsabilidad compartida encuentran menos vulnerabilidades críticas. Los que la aíslan las encuentran en las noticias.\nAutomatiza todo lo que puedas Los procesos de seguridad manuales no escalan. Punto. Si tu revisión de seguridad es un humano leyendo una checklist, se saltará bajo presión de plazos, se aplicará de forma inconsistente y será odiada por todos los involucrados.\nAutomatiza las cosas que se pueden automatizar:\nEscaneo de dependencias en cada build de CI (Dependabot, Snyk, Trivy) Análisis estático en cada pull request (Semgrep, SonarQube) Detección de secretos como pre-commit hook y check de CI (gitleaks, detect-secrets) Escaneo de imágenes de contenedores antes del despliegue (Trivy, Grype) Escaneo de Infrastructure as Code (tfsec, Checkov, KICS) Compliance as Code para cumplimiento de políticas en runtime (OPA, Kyverno) El objetivo no es capturarlo todo automáticamente. El objetivo es capturar lo fácil automáticamente para que los revisores humanos puedan centrarse en lo difícil: fallos en la lógica de negocio, problemas de seguridad a nivel de diseño, modelado de amenazas.\nEmpieza pequeño Uno de los mayores errores que hemos cometido es intentar asegurar todo de golpe. Despliegas SAST, DAST, SCA, escaneo de contenedores, escaneo de IaC y protección en runtime en un trimestre. El resultado: fatiga de alertas, rebelión de los desarrolladores y un muro de hallazgos sin resolver que nadie mira.\nEmpieza con una herramienta, un pipeline, un equipo. Haz que funcione bien. Que los desarrolladores se sientan cómodos con ello. Resuelve los falsos positivos. Ajusta las reglas. Después expande.\nUna progresión práctica:\nMes 1: Detección de secretos en pre-commit hooks y CI. Esto es poco controvertido y captura problemas reales. Mes 2: Escaneo de dependencias con creación automatizada de PRs para actualizaciones. Los desarrolladores ven el valor inmediatamente. Mes 3: Escaneo de imágenes de contenedores bloqueando despliegues con vulnerabilidades críticas/altas. Mes 4+: Análisis estático, expandiendo conjuntos de reglas gradualmente. Cada paso debe ser estable antes de pasar al siguiente. Ir con prisas crea ruido, y el ruido enseña a la gente a ignorar alertas.\nLa cultura blameless importa Cuando ocurre un incidente de seguridad porque alguien subió un secreto a un repo público, o porque una vulnerabilidad no se parcheó a tiempo, la respuesta importa más que el propio incidente.\nSi se culpa a la gente, ocultan cosas. No reportan casi-incidentes. Tapan errores. Y el siguiente incidente será peor porque nadie compartió las lecciones del anterior.\nLas postmortems blameless no consisten en librar a la gente de responsabilidad. Consisten en entender fallos sistémicos. Por qué fue posible subir un secreto? Por qué no había escaneo? Por qué el proceso de parcheo era lento? Arregla el sistema, no a la persona.\nHemos comprobado que los equipos con culturas genuinamente blameless tienen posturas de seguridad significativamente mejores. La gente reporta cosas sospechosas. Piden ayuda pronto. Señalan riesgos antes de que se conviertan en incidentes.\nLas herramientas no bastan sin cambio cultural Una vez desplegamos un pipeline de escaneo de seguridad completo con dashboards bonitos, notificaciones de Slack, creación de tickets en Jira, todo el paquete. Seis meses después, había 3.000 hallazgos sin resolver y el canal de Slack estaba silenciado por todos los desarrolladores.\nLas herramientas estaban bien. La cultura no estaba preparada.\nAntes de desplegar herramientas, invierte en:\nFormación: Los desarrolladores necesitan entender por qué existe la herramienta y cómo actuar sobre sus hallazgos. Ownership: Alguien necesita ser dueño del backlog de hallazgos y hacer triaje. Si nadie es dueño, nadie lo hace. SLAs: Define plazos claros para remediar hallazgos por severidad. Críticos en 48 horas. Altos en una semana. Medios en un sprint. Bajos en un trimestre. Bucles de feedback: Cuando una herramienta produce un falso positivo, debe haber una forma fácil de reportarlo y que se ajuste la regla. De lo contrario, los desarrolladores aprenden a ignorar todo. Invierte en la experiencia de desarrollador de las herramientas de seguridad Si tu herramienta de seguridad hace la vida de los desarrolladores más difícil, encontrarán la forma de esquivarla. Esto no es un defecto de carácter. Es naturaleza humana y buen instinto de ingeniería: eliminar obstáculos para entregar.\nLas herramientas de seguridad que se adoptan son las que:\nEjecutan rápido: Un escaneo SAST que tarda 20 minutos será esquivado. Uno que tarda 30 segundos será tolerado. Se integran nativamente: Muestra resultados en la PR, no en un portal separado. Nadie quiere hacer login en otro dashboard. Tienen baja tasa de falsos positivos: Cada falso positivo erosiona la confianza. Invierte tiempo en el ajuste. Proporcionan guía accionable: \u0026ldquo;Vulnerabilidad de SQL injection en la línea 42\u0026rdquo; es inútil sin \u0026ldquo;así es como se arregla.\u0026rdquo; Fallan de forma elegante: Si el escáner está caído, el pipeline debe avisar, no bloquear. La disponibilidad del pipeline de desarrollo no es negociable. Lo pensamos así: si un desarrollador tiene que cambiar su flujo de trabajo para acomodar una herramienta de seguridad, la herramienta ha fallado. Las mejores herramientas de seguridad son invisibles.\nMonitorización y observabilidad no son negociables No puedes asegurar lo que no puedes ver. La monitorización de seguridad no es opcional, y no es algo que se añade después.\nQué significa esto en la práctica:\nLogging centralizado: Todos los logs de aplicación, infraestructura y herramientas de seguridad en un solo lugar. Si tienes que hacer SSH a una máquina para leer logs, ya vas por detrás. Audit trails: Quién hizo qué, cuándo y desde dónde. Cada despliegue, cada cambio de configuración, cada solicitud de acceso. Alertas sobre anomalías: No solo \u0026ldquo;está el servicio arriba?\u0026rdquo; sino \u0026ldquo;es este patrón de acceso normal?\u0026rdquo; Volúmenes inusuales de llamadas a API, accesos desde nuevas ubicaciones, escalaciones de privilegios. Seguridad en runtime: Herramientas como Falco para monitorización de runtime de contenedores. Saber cuándo algo inesperado ocurre en producción. La monitorización también es cómo demuestras a auditores y clientes que tus controles de seguridad funcionan. \u0026ldquo;Confía en nosotros\u0026rdquo; no es una estrategia de cumplimiento.\nEl open source es tu aliado Algunas de las mejores herramientas de seguridad disponibles son open source. Trivy, Falco, OPA, Semgrep, gitleaks, cosign, KICS, Checkov. El ecosistema es rico y madura rápidamente.\nBeneficios de las herramientas de seguridad open source:\nTransparencia: Puedes leer las reglas y entender exactamente qué se está comprobando. Comunidad: Miles de contribuidores encontrando casos límite y añadiendo reglas de detección. Sin vendor lock-in: Puedes cambiar de herramienta sin renegociar un contrato. Coste: Empieza gratis, escala según necesites. Esto no significa que las herramientas comerciales no tengan su lugar. Algunas proporcionan agregación, gestión y soporte valiosos. Pero puedes construir un pipeline de seguridad muy sólido solo con herramientas open source, y creemos que todos los equipos deberían empezar por ahí.\nEl aprendizaje continuo es esencial El panorama de amenazas cambia constantemente. Las herramientas cambian. Las mejores prácticas evolucionan. Lo que se consideraba seguro hace dos años puede tener un CVE hoy.\nLo que hacemos para mantenernos al día:\nDedicar tiempo al aprendizaje: Al menos unas horas por sprint para que el equipo lea sobre nuevas vulnerabilidades, herramientas y técnicas. Esto no es un nice-to-have. Es un requisito profesional. Organizar CTFs internos y ejercicios de mesa: Nada enseña seguridad como intentar romper cosas. Los ejercicios regulares mantienen las habilidades afiladas y revelan brechas en tus defensas. Participar en la comunidad: Asistir a meetups, contribuir a open source, leer advisories. La comunidad de seguridad es generosa con el conocimiento. Aprovéchalo. Revisar y actualizar: Revisiones trimestrales de tu tooling de seguridad, políticas y procedimientos de respuesta a incidentes. Lo que funcionó el trimestre pasado puede no funcionar el próximo. Reflexiones finales DevSecOps no es un destino. No hay un punto donde digas \u0026ldquo;terminamos, somos seguros.\u0026rdquo; Es una práctica continua de reducir riesgo, mejorar visibilidad, construir una cultura donde seguridad sea tan natural como escribir tests.\nLa lección más importante: lo perfecto es enemigo de lo bueno. Un pipeline básico que los desarrolladores usan de verdad vale infinitamente más que uno completo que esquivan. Empieza donde estás, mejora iterativamente, nunca pares.\n","date":"2025-10-20T00:00:00Z","permalink":"/p/lecciones-aprendidas-en-devsecops/","title":"Lecciones aprendidas en DevSecOps"},{"content":"Los LLMs han ido más allá de chatbots. Ahora se integran en flujos de trabajo de ingeniería donde automatizan tareas tediosas, aceleran respuesta a incidentes y potencian productividad. Pero desplegar un LLM en un pipeline de DevOps en producción es fundamentalmente diferente a usar ChatGPT en un navegador.\nEsta guía cubre qué significa LLMOps en la práctica, dónde encajan los LLMs en DevOps, patrones de arquitectura que funcionan y trampas que debes evitar.\nQué es LLMOps LLMOps es el conjunto de prácticas, herramientas e infraestructura necesarios para operacionalizar LLMs. Extiende MLOps pero aborda desafíos únicos de los modelos de lenguaje:\nSelección de modelo vs. entrenamiento de modelo: La mayoría de equipos consumen modelos pre-entrenados (mediante APIs o inferencia auto-alojada) en lugar de entrenar desde cero. El foco operacional se desplaza hacia prompt engineering, fine-tuning y generación aumentada por recuperación (RAG). Gestión de costes: La inferencia con LLMs es cara. La tarificación por tokens significa que los costes escalan con el uso de formas más difíciles de predecir que el cómputo tradicional. No determinismo: Los LLMs producen salidas variables para la misma entrada, lo que complica las pruebas, la validación y la reproducibilidad. Latencia: Tiempos de respuesta de segundos (no milisegundos) requieren patrones arquitectónicos diferentes a los microservicios tradicionales. LLMOps no es una disciplina separada. Es una extensión de tus prácticas existentes de DevOps y MLOps, adaptada a las características operacionales específicas de los modelos de lenguaje.\nCasos de uso prácticos en DevOps Aquí es donde los LLMs están aportando valor real en flujos de trabajo DevOps hoy en día:\nRevisión automatizada de código Los LLMs pueden proporcionar una primera pasada de revisión de pull requests, detectando problemas comunes como manejo de errores ausente, anti-patrones de seguridad, nomenclatura inconsistente o tests faltantes. No reemplazan a los revisores humanos, pero reducen la carga del feedback repetitivo.\nResumen de incidentes Cuando un incidente salta a las 3 de la mañana, la persona de guardia necesita contexto rápido. Un LLM puede ingerir datos de alertas, logs de despliegues recientes, runbooks relacionados e informes de incidentes anteriores para producir un resumen conciso de lo que probablemente está fallando y qué se hizo la última vez.\nAnálisis de logs Los LLMs son sorprendentemente efectivos en el reconocimiento de patrones en datos de logs no estructurados. Aliméntalos con un bloque de logs de error y pueden identificar la causa raíz más rápido que sesiones manuales de grep, especialmente para sistemas con los que no estás familiarizado.\nGeneración de documentación Generar borradores de documentación a partir de código, esquemas de API o módulos de Terraform. El resultado necesita revisión humana, pero elimina el problema de la página en blanco y mantiene la documentación más cercana al estado actual.\nGeneración de Infrastructure as Code Dada una descripción en lenguaje natural de la infraestructura deseada, los LLMs pueden generar manifiestos de Terraform, Ansible o Kubernetes como punto de partida. Útil para scaffolding, no para código listo para producción sin revisión.\nPatrones de arquitectura para integración de LLMs Patrón 1: API gateway a LLM externo El enfoque más simple. Tu aplicación llama a una API de LLM externa (OpenAI, Anthropic, etc.) a través de un gateway centralizado que gestiona autenticación, rate limiting, logging y seguimiento de costes.\n1 2 3 4 5 [Pipeline CI/CD] --\u0026gt; [API Gateway] --\u0026gt; [API LLM Externa] | [Logging y Métricas] | [Seguimiento de Costes] Pros: Sin infraestructura que gestionar, acceso a los modelos más capaces, rápido de implementar. Contras: Los datos salen de tu red, dependencia del proveedor, latencia variable, costes continuos de API.\nPatrón 2: Inferencia auto-alojada Ejecutar modelos de pesos abiertos (Llama, Mistral, etc.) en tu propia infraestructura usando servidores de inferencia como vLLM u Ollama.\n1 2 3 [Pipeline CI/CD] --\u0026gt; [Load Balancer] --\u0026gt; [Instancia(s) vLLM / Ollama] | [Pool de Nodos GPU] Pros: Los datos permanecen internos, costes predecibles a escala, sin dependencia de proveedor, control total sobre versiones del modelo. Contras: Requiere infraestructura GPU, sobrecarga operacional, modelos más pequeños pueden ser menos capaces.\nPatrón 3: Pipeline mejorado con RAG Combinar un LLM con un sistema de recuperación que proporciona contexto relevante de tu propia base de conocimiento (runbooks, documentación, incidentes pasados). Esto mejora drásticamente la calidad de las respuestas para tareas específicas del dominio.\n1 2 3 4 [Consulta] --\u0026gt; [Modelo Embedding] --\u0026gt; [Búsqueda Vector DB] --\u0026gt; [Contexto + Consulta] --\u0026gt; [LLM] --\u0026gt; [Respuesta] | [Tu Base de Conocimiento] (runbooks, docs, etc.) Este patrón es particularmente potente para respuesta a incidentes y tareas de documentación donde el LLM necesita el contexto específico de tu organización.\nConsideraciones clave Coste Los costes de API de LLMs pueden sorprender. Un pipeline de revisión de código que procesa 50 PRs al día con diffs grandes puede fácilmente alcanzar cientos de dólares al mes. Estrategias para controlar costes:\nEstablecer límites de tokens por petición Cachear consultas y respuestas comunes Usar modelos más pequeños para tareas simples (triaje con un modelo pequeño, escalar a uno mayor) Monitorizar el uso de tokens por pipeline y configurar alertas Latencia Las respuestas de LLMs tardan segundos, no milisegundos. Diseña tus integraciones como procesos asíncronos:\nPublicar comentarios de revisión de código después del hecho, no bloquear la PR Procesar datos de incidentes en segundo plano, enviar resultados a un canal de Slack Usar streaming de respuestas donde sea posible para mejorar el rendimiento percibido Alucinaciones Los LLMs generarán con confianza información que suena plausible pero es incorrecta. Esta es una preocupación crítica para tareas de DevOps donde un mal consejo puede causar caídas.\nMitigaciones:\nSiempre presentar la salida del LLM como sugerencias, nunca como acciones autoritativas Requerir aprobación humana antes de aplicar cualquier cambio generado por LLM Usar RAG para anclar las respuestas en documentación verificada Implementar validación de salida (por ejemplo, lint del IaC generado antes de presentarlo) Seguridad Exposición de datos: Cualquier cosa que envíes a una API de LLM externa puede ser usada para entrenamiento o almacenada. Nunca envíes secretos, credenciales o datos sensibles de clientes. Prompt injection: Contenido malicioso en código, logs o entrada de usuario puede manipular el comportamiento del LLM. Sanitiza las entradas y valida las salidas. Cadena de suministro: El código generado por LLM puede introducir vulnerabilidades. Pasa todo el código generado por tu pipeline de escaneo de seguridad existente. Herramientas y plataformas LangChain Un framework para construir aplicaciones potenciadas por LLMs. Útil para orquestar cadenas de múltiples pasos (por ejemplo, recuperar contexto, formatear prompt, llamar al LLM, parsear la salida). Soporta muchos proveedores de LLMs y tiene buen tooling para pipelines RAG.\n1 2 3 4 5 6 7 8 from langchain.chat_models import ChatOpenAI from langchain.prompts import ChatPromptTemplate prompt = ChatPromptTemplate.from_template( \u0026#34;Review this code diff for security issues and suggest fixes:\\n\\n{diff}\u0026#34; ) chain = prompt | ChatOpenAI(model=\u0026#34;gpt-4o\u0026#34;, temperature=0) result = chain.invoke({\u0026#34;diff\u0026#34;: code_diff}) vLLM Un motor de inferencia de alto rendimiento para modelos auto-alojados. Soporta PagedAttention para gestión eficiente de memoria y continuous batching para alto throughput.\n1 2 3 4 # Iniciar un servidor vLLM python -m vllm.entrypoints.openai.api_server \\ --model mistralai/Mistral-7B-Instruct-v0.2 \\ --port 8000 Expone una API compatible con OpenAI, así que puedes cambiar entre APIs auto-alojadas y externas con cambios mínimos de código.\nOllama La forma más fácil de ejecutar LLMs localmente para desarrollo y pruebas. Ideal para prototipar pipelines antes de comprometerte con infraestructura.\n1 2 3 4 5 6 7 # Descargar y ejecutar un modelo ollama pull llama3 ollama run llama3 \u0026#34;Summarize this error log: [paste log]\u0026#34; # Servir como API ollama serve # Luego llamar a http://localhost:11434/api/generate Ejemplo: Pipeline de revisión automatizada de PRs Aquí tienes un pipeline conceptual para revisión automatizada de PRs usando un LLM:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 # .github/workflows/llm-review.yml name: LLM Code Review on: pull_request: types: [opened, synchronize] jobs: llm-review: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Get diff id: diff run: | git diff origin/${{ github.base_ref }}...HEAD \u0026gt; diff.txt - name: Run LLM review env: LLM_API_KEY: ${{ secrets.LLM_API_KEY }} run: | python scripts/llm_review.py \\ --diff diff.txt \\ --model gpt-4o \\ --max-tokens 2000 \\ --output review.json - name: Post review comments uses: actions/github-script@v7 with: script: | const review = require(\u0026#39;./review.json\u0026#39;); await github.rest.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number, body: review.summary, event: \u0026#39;COMMENT\u0026#39;, comments: review.line_comments }); El script de revisión:\nLee el diff Divide diffs grandes en fragmentos que quepan en la ventana de contexto del modelo Para cada fragmento, construye un prompt pidiendo problemas de seguridad, bugs y problemas de estilo Agrega resultados y formatea como comentarios de revisión de GitHub Incluye puntuaciones de confianza y siempre marca la salida como generada por IA Guardrails y uso responsable Etiqueta claramente toda la salida del LLM como generada por IA. Los ingenieros deben saber cuándo están leyendo salida de una máquina. Nunca auto-mergees ni auto-apliques sugerencias del LLM. Mantén un humano en el bucle para todos los cambios. Registra todos los prompts y respuestas para depuración y auditoría. Establece límites de gasto y alertas sobre el uso de API de LLMs. Revisa las plantillas de prompts regularmente para asegurarte de que no filtran información sensible. Prueba sesgos y errores con muestras representativas antes de desplegar en flujos de trabajo de producción. Recomendaciones para empezar Elige un caso de uso - No intentes habilitar LLMs en todo. Empieza bajo riesgo: borradores, sugerencias de commits. Empieza con API externa - No inviertas en GPU hasta validar el caso. Usa OpenAI o Anthropic para prototipar. Mide todo - Registra coste por invocación, latencia, satisfacción, tasas de error desde el primer día. Construye un framework - Crea un suite de tests con entradas y salidas conocidas. Ejecútalo contra cada cambio de prompt o modelo. Planifica tu estrategia de datos - Decide qué datos enviarás a APIs externas. Documéntalo. Itera en prompts - El prompt engineering es iterativo. Versiona prompts, trátalos como código. Los LLMs son una herramienta potente para DevOps, pero son exactamente eso: una herramienta. Funcionan mejor cuando se integran de forma reflexiva en flujos existentes, con límites claros sobre qué pueden y no pueden hacer autonomamente.\n","date":"2025-06-15T00:00:00Z","permalink":"/p/llmops-integrando-llms-en-flujos-de-trabajo-devops/","title":"LLMOps: integrando LLMs en flujos de trabajo DevOps"},{"content":"Los ataques de cadena de suministro ya no son teóricos. La brecha SolarWinds de 2020 mostró cómo un pipeline de compilación comprometido podía golpear miles de organizaciones, incluyendo agencias gubernamentales. Log4Shell en 2021 probó que una vulnerabilidad profunda en una dependencia transitiva podía amenazar todas las apps Java de la noche a la mañana. El mensaje fue claro: necesitamos visibilidad sobre qué hay en nuestro software y garantías más fuertes de integridad.\nEsta guía cubre las herramientas prácticas: SBOMs, Sigstore y framework SLSA.\nPor qué importa la seguridad de la cadena de suministro La seguridad tradicional se centra en tu propio código: análisis estático, escaneo de dependencias, pruebas de penetración. La seguridad de la cadena de suministro extiende ese perímetro a todo de lo que depende tu software y a cada paso en el proceso de construcción y entrega.\nLa superficie de ataque incluye:\nRepositorios de código fuente: cuentas de desarrolladores comprometidas, commits maliciosos Dependencias: typosquatting, confusión de dependencias, paquetes upstream comprometidos Sistemas de compilación: pipelines de CI/CD manipulados, pasos de build inyectados Registros de artefactos: binarios reemplazados, paquetes sin firmar Pipelines de despliegue: manifiestos modificados, ataques man-in-the-middle Un solo eslabón débil en cualquiera de estas etapas puede comprometer toda la cadena.\nSoftware Bill of Materials (SBOM) Un SBOM es un inventario formal y legible por máquinas de todos los componentes de un software. Piensa en ello como la lista de ingredientes de tu aplicación. Incluye dependencias directas, dependencias transitivas, sus versiones, licencias y relaciones.\nPor qué lo necesitas Respuesta ante vulnerabilidades: Cuando aparece un nuevo CVE (como Log4Shell), puedes comprobar al instante si alguna de tus aplicaciones está afectada. Cumplimiento de licencias: Saber exactamente qué licencias estás distribuyendo. Requisitos regulatorios: La Orden Ejecutiva 14028 de EE.UU. y la Ley de Ciberresiliencia de la UE empujan hacia SBOMs obligatorios. Transparencia: Clientes y partners pueden verificar lo que están ejecutando. Formatos de SBOM Dos formatos principales dominan:\nSPDX (Software Package Data Exchange): Un estándar ISO (ISO/IEC 5962:2021), originalmente centrado en cumplimiento de licencias, ahora integral. Soporta formatos JSON, RDF, YAML y tag-value. CycloneDX: Un proyecto de OWASP, diseñado desde cero para casos de uso de seguridad. Soporta JSON y XML. Más ligero y con opiniones más definidas. Ambos son opciones sólidas. CycloneDX tiende a ser más fácil de usar para flujos de trabajo centrados en seguridad. SPDX tiene mayor adopción en industrias con requisitos de cumplimiento estrictos.\nGenerando SBOMs con Syft Syft de Anchore es una de las mejores herramientas para generar SBOMs. Soporta imágenes de contenedores, sistemas de archivos y archivos comprimidos.\nInstalar syft:\n1 curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin Generar un SBOM desde una imagen de contenedor:\n1 2 3 4 5 # Formato CycloneDX (JSON) syft packages registry.example.com/myapp:v1.2.3 -o cyclonedx-json \u0026gt; sbom.cdx.json # Formato SPDX (JSON) syft packages registry.example.com/myapp:v1.2.3 -o spdx-json \u0026gt; sbom.spdx.json Generar un SBOM desde un directorio local:\n1 syft packages dir:/path/to/project -o cyclonedx-json \u0026gt; sbom.cdx.json Después puedes escanear el SBOM en busca de vulnerabilidades usando Grype:\n1 grype sbom:sbom.cdx.json El ecosistema Sigstore Sigstore es un proyecto open source que hace accesible la firma y verificación criptográfica. Elimina la necesidad de gestionar claves de firma de larga duración, que históricamente ha sido la principal barrera para la adopción de la firma de artefactos.\nEl ecosistema tiene tres componentes centrales:\ncosign: Firma y verifica imágenes de contenedores y otros artefactos OCI. Fulcio: Una autoridad certificadora que emite certificados de corta duración basados en identidad OIDC (tu proveedor de identidad existente). Rekor: Un log de transparencia que crea un registro inmutable y resistente a manipulaciones de los eventos de firma. Cómo funciona Te autentificas con un proveedor OIDC (GitHub, Google, Microsoft, etc.). Fulcio emite un certificado de corta duración vinculado a tu identidad. cosign usa ese certificado para firmar tu artefacto. El evento de firma se registra en el log de transparencia de Rekor. Cualquiera puede verificar la firma usando el log de transparencia, sin necesitar tu clave pública. Esto se conoce como firma \u0026ldquo;keyless\u0026rdquo;. Sin claves que rotar, sin secretos que gestionar, sin infraestructura PKI que mantener.\nFirmando imágenes de contenedores con Cosign Instalar cosign:\n1 2 3 4 5 6 # Usando Go go install github.com/sigstore/cosign/v2/cmd/cosign@latest # O descargar un release curl -sSfL https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64 -o /usr/local/bin/cosign chmod +x /usr/local/bin/cosign Firmar una imagen (modo keyless):\n1 cosign sign registry.example.com/myapp:v1.2.3 Esto abrirá un navegador para autenticación OIDC. En CI, puedes usar identidad de carga de trabajo (por ejemplo, el token OIDC de GitHub Actions) para firma no interactiva.\nVerificar una imagen:\n1 2 3 cosign verify registry.example.com/myapp:v1.2.3 \\ --certificate-identity=user@example.com \\ --certificate-oidc-issuer=https://accounts.google.com Adjuntar un SBOM a una imagen y firmarlo:\n1 2 3 4 5 # Adjuntar el SBOM cosign attach sbom --sbom sbom.cdx.json registry.example.com/myapp:v1.2.3 # Firmar el adjunto del SBOM cosign sign --attachment sbom registry.example.com/myapp:v1.2.3 El framework SLSA SLSA (Supply-chain Levels for Software Artifacts, pronunciado \u0026ldquo;salsa\u0026rdquo;) es un framework que define niveles crecientes de garantías de integridad en la cadena de suministro.\nNiveles SLSA Level 0: Sin garantías. Aquí es donde empiezan la mayoría de proyectos. Level 1: El proceso de compilación está documentado y produce provenance (metadatos sobre cómo se construyó un artefacto). Level 2: La compilación se ejecuta en un servicio de build alojado que genera provenance autenticado. Level 3: La plataforma de compilación proporciona builds reforzados con provenance resistente a manipulaciones. El entorno de build es aislado y efímero. Cada nivel se construye sobre el anterior. El objetivo no es saltar al Level 3 inmediatamente, sino mejorar tu postura de forma incremental.\nSLSA Provenance El provenance responde a las preguntas críticas: Quién construyó esto? Qué código fuente se usó? Qué proceso de build se siguió? Era el entorno de build a prueba de manipulaciones?\nEl SLSA provenance es una attestation firmada en formato in-toto que captura esta información.\nIntegración CI/CD: Ejemplo con GitHub Actions Aquí tienes un workflow práctico de GitHub Actions que construye una imagen, genera un SBOM, firma todo y genera SLSA provenance:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 name: Build, Sign, and Attest on: push: tags: - \u0026#39;v*\u0026#39; permissions: contents: read packages: write id-token: write # Requerido para firma keyless env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build-sign-attest: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Log in to GHCR uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push image id: build uses: docker/build-push-action@v5 with: push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }} - name: Install cosign uses: sigstore/cosign-installer@v3 - name: Install syft uses: anchore/sbom-action/download-syft@v0 - name: Sign the image run: | cosign sign --yes \\ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}@${{ steps.build.outputs.digest }} - name: Generate SBOM run: | syft packages \\ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}@${{ steps.build.outputs.digest }} \\ -o cyclonedx-json \u0026gt; sbom.cdx.json - name: Attach and sign SBOM run: | cosign attach sbom --sbom sbom.cdx.json \\ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}@${{ steps.build.outputs.digest }} cosign sign --yes --attachment sbom \\ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}@${{ steps.build.outputs.digest }} - name: Verify signature run: | cosign verify \\ --certificate-identity-regexp=\u0026#34;https://github.com/${{ github.repository }}/*\u0026#34; \\ --certificate-oidc-issuer=https://token.actions.githubusercontent.com \\ ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.ref_name }}@${{ steps.build.outputs.digest }} El permiso id-token: write es lo que habilita la firma keyless en GitHub Actions. El token OIDC de GitHub se usa automáticamente por cosign sin ninguna gestión manual de claves.\nHoja de ruta práctica para la adopción No necesitas hacer todo de golpe. Aquí tienes una progresión sensata:\nSemana 1-2: Visibilidad\nEmpieza a generar SBOMs para tus aplicaciones más críticas usando syft. Integra Grype en tu pipeline de CI para escaneo de vulnerabilidades contra el SBOM. Semana 3-4: Firma\nConfigura la firma keyless con cosign en tus pipelines de CI/CD. Firma tus imágenes de contenedores en cada build. Mes 2: Verificación\nAplica verificación de firmas en tus pipelines de despliegue (por ejemplo, controladores de admisión de Kubernetes como Kyverno o Sigstore policy-controller). Adjunta SBOMs a las imágenes y fírmalos. Mes 3+: SLSA Provenance\nAñade generación de SLSA provenance usando slsa-github-generator. Trabaja hacia SLSA Level 2, después Level 3. Automatiza la verificación de provenance en tu tooling de despliegue. Conclusiones clave SBOMs dan visibilidad - No aseguras lo que no ves. Genera SBOMs para cada artefacto. Sigstore elimina excusas - La firma keyless elimina la sobrecarga de gestión de claves. Sin buena razón para no firmar. SLSA es un modelo de madurez - Úsalo para mejorar la integridad de forma incremental, no como todo o nada. Automatiza todo - Estas herramientas son para integración CI/CD. Lo manual no escala. El ecosistema de seguridad de cadena de suministro madura rápido. Las herramientas están listas para producción, los estándares se consolidan, la presión regulatoria sigue subiendo. El mejor momento fue ayer. El segundo mejor es ahora.\n","date":"2025-02-10T00:00:00Z","permalink":"/p/seguridad-en-la-cadena-de-suministro-sbom-y-sigstore/","title":"Seguridad en la cadena de suministro: SBOM y Sigstore"},{"content":"Superficie de Ataque de Kubernetes Kubernetes por defecto no es seguro. El cluster expone múltiples vectores de ataque que necesitan atención sistemática:\nAPI Server - Punto de control central; acceso no autorizado = compromiso total etcd - Almacena todo el estado incluyendo secretos en base64 (sin cifrar por defecto) Kubelet - Agente del nodo; API expuesto filtra info de pods y permite ejecutar comandos Container runtime - Vulnerabilidades de escape dan acceso al host Red - Los pods se comunican libremente con otros por defecto Cadena de suministro - Imágenes maliciosas o vulnerables introducen backdoors Esta guía cubre las medidas clave organizadas por vector de ataque.\nBastionado del API Server El API server es el componente más crítico. Asegúralo primero:\nDeshabilitar autenticación anónima: establece --anonymous-auth=false Habilitar audit logging: rastrea quién hizo qué (cubierto en detalle más adelante) Restringir acceso: usa reglas de firewall o security groups para limitar quien puede alcanzar el API server Habilitar admission controllers: PodSecurity, NodeRestriction, ResourceQuota y LimitRanger deben estar activos Usar OIDC para autenticación: integra con tu proveedor de identidad en lugar de depender de certificados de cliente 1 2 # Comprobar los flags actuales del API server (en clusters kubeadm) kubectl -n kube-system get pod kube-apiserver-\u0026lt;node\u0026gt; -o jsonpath=\u0026#39;{.spec.containers[0].command}\u0026#39; | tr \u0026#39;,\u0026#39; \u0026#39;\\n\u0026#39; Buenas Prácticas de RBAC RBAC es tu mecanismo de autorización principal. Aplica el mínimo privilegio rigurosamente.\nReglas Clave Nunca usar cluster-admin para workloads \u0026ndash; otorga acceso ilimitado Usar Roles (con namespace) sobre ClusterRoles siempre que sea posible Evitar wildcards en especificaciones de recursos o verbos Vincular a ServiceAccounts, no a usuarios para workloads automatizados Revisar bindings regularmente \u0026ndash; los permisos se acumulan con el tiempo Ejemplo: Rol Restringido para Despliegues 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: production name: deployment-manager rules: # Puede gestionar deployments - apiGroups: [\u0026#34;apps\u0026#34;] resources: [\u0026#34;deployments\u0026#34;] verbs: [\u0026#34;get\u0026#34;, \u0026#34;list\u0026#34;, \u0026#34;watch\u0026#34;, \u0026#34;create\u0026#34;, \u0026#34;update\u0026#34;, \u0026#34;patch\u0026#34;] # Puede ver pods y logs - apiGroups: [\u0026#34;\u0026#34;] resources: [\u0026#34;pods\u0026#34;, \u0026#34;pods/log\u0026#34;] verbs: [\u0026#34;get\u0026#34;, \u0026#34;list\u0026#34;, \u0026#34;watch\u0026#34;] # Puede ver services - apiGroups: [\u0026#34;\u0026#34;] resources: [\u0026#34;services\u0026#34;] verbs: [\u0026#34;get\u0026#34;, \u0026#34;list\u0026#34;, \u0026#34;watch\u0026#34;] # Explicitamente SIN acceso a secrets, escritura de configmaps, o exec --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: namespace: production name: deployment-manager-binding subjects: - kind: ServiceAccount name: ci-deployer namespace: production roleRef: kind: Role name: deployment-manager apiGroup: rbac.authorization.k8s.io Audita el RBAC existente con:\n1 2 3 4 5 6 # Listar todos los bindings de cluster-admin kubectl get clusterrolebindings -o json | \\ jq \u0026#39;.items[] | select(.roleRef.name == \u0026#34;cluster-admin\u0026#34;) | {name: .metadata.name, subjects: .subjects}\u0026#39; # Comprobar que puede hacer una service account especifica kubectl auth can-i --list --as=system:serviceaccount:production:ci-deployer -n production Pod Security Standards Los PSS (Pod Security Standards) de Kubernetes definen tres niveles de restricciones. Desde 1.25, Pod Security Admission (PSA) es el mecanismo integrado (reemplaza PodSecurityPolicy).\nLos Tres Niveles Nivel Descripción Caso de Uso Privileged Sin restricciones Workloads de sistema (CNI, drivers de almacenamiento) Baseline Bloquea escalaciones de privilegios conocidas Workloads generales Restricted Bastionado máximo Workloads sensibles, clusters multi-tenant Aplicacion de Pod Security Standards Aplica los estandares a nivel de namespace usando labels:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 apiVersion: v1 kind: Namespace metadata: name: production labels: # Enforce restricted: rechazar pods que violen pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/enforce-version: latest # Warn en violaciones baseline (muestra aviso pero permite) pod-security.kubernetes.io/warn: restricted pod-security.kubernetes.io/warn-version: latest # Audit: registrar violaciones pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/audit-version: latest Ejemplo de Pod Conforme Un pod que pasa el nivel restricted:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 apiVersion: v1 kind: Pod metadata: name: secure-app namespace: production spec: securityContext: runAsNonRoot: true seccompProfile: type: RuntimeDefault containers: - name: app image: myregistry.com/app:v1.2.3@sha256:abc123... securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsUser: 1000 runAsGroup: 1000 capabilities: drop: - ALL resources: limits: memory: \u0026#34;256Mi\u0026#34; cpu: \u0026#34;500m\u0026#34; requests: memory: \u0026#34;128Mi\u0026#34; cpu: \u0026#34;250m\u0026#34; Configuraciones de seguridad clave que siempre incluir:\nrunAsNonRoot: true \u0026ndash; nunca ejecutar contenedores como root readOnlyRootFilesystem: true \u0026ndash; prevenir modificaciones del sistema de archivos allowPrivilegeEscalation: false \u0026ndash; bloquear setuid/setgid capabilities.drop: [\u0026quot;ALL\u0026quot;] \u0026ndash; eliminar todas las capabilities de Linux seccompProfile.type: RuntimeDefault \u0026ndash; aplicar perfil seccomp por defecto Siempre especificar limites de recursos para prevenir DoS NetworkPolicies Por defecto, todos los pods pueden comunicarse con todos los demas pods en un cluster. Las NetworkPolicies restringen esto a solo el trafico necesario.\nDenegacion Total por Defecto Comienza cada namespace con una política de denegacion por defecto:\n1 2 3 4 5 6 7 8 9 10 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: production spec: podSelector: {} policyTypes: - Ingress - Egress Permitir Trafico Especifico Luego permite explicitamente solo lo que se necesita:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-api-to-db namespace: production spec: podSelector: matchLabels: app: database policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: app: api-server ports: - protocol: TCP port: 5432 --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: api-server-egress namespace: production spec: podSelector: matchLabels: app: api-server policyTypes: - Egress egress: # Permitir resolucion DNS - to: [] ports: - protocol: UDP port: 53 - protocol: TCP port: 53 # Permitir conexion a la base de datos - to: - podSelector: matchLabels: app: database ports: - protocol: TCP port: 5432 # Permitir HTTPS externo - to: - ipBlock: cidr: 0.0.0.0/0 except: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 ports: - protocol: TCP port: 443 Nota: las NetworkPolicies requieren un plugin CNI que las soporte (Calico, Cilium, Weave Net). El kubenet por defecto no aplica NetworkPolicies.\nGestion de Secretos Los Secrets de Kubernetes estan codificados en base64, no cifrados. Cualquiera con acceso de lectura a Secrets en un namespace puede decodificarlos trivialmente. La gestion adecuada de secretos requiere herramientas adicionales.\nOpcion 1: Sealed Secrets Sealed Secrets (de Bitnami) cifra secretos del lado del cliente para que puedan almacenarse de forma segura en Git:\n1 2 3 4 5 6 7 8 9 10 # Instalar CLI kubeseal # Cifrar un secreto kubectl create secret generic db-creds \\ --from-literal=password=supersecret \\ --dry-run=client -o yaml | \\ kubeseal --format yaml \u0026gt; sealed-db-creds.yaml # El sealed secret puede commitearse en Git # Solo el controlador del cluster puede descifrarlo kubectl apply -f sealed-db-creds.yaml Opcion 2: External Secrets Operator External Secrets Operator sincroniza secretos desde proveedores externos (AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager) en Kubernetes:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: db-credentials namespace: production spec: refreshInterval: 1h secretStoreRef: name: aws-secrets-manager kind: ClusterSecretStore target: name: db-credentials data: - secretKey: password remoteRef: key: production/database property: password Habilitar Cifrado en Reposo Asegurate de que etcd cifre los secretos en reposo:\n1 2 3 4 5 6 7 8 9 10 11 12 # /etc/kubernetes/encryption-config.yaml apiVersion: apiserver.config.k8s.io/v1 kind: EncryptionConfiguration resources: - resources: - secrets providers: - aescbc: keys: - name: key1 secret: \u0026lt;base64-encoded-32-byte-key\u0026gt; - identity: {} Audit Logging Los audit logs de Kubernetes registran cada peticion al API server, proporcionando un rastro detallado de quien hizo que y cuando.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # audit-policy.yaml apiVersion: audit.k8s.io/v1 kind: Policy rules: # Registrar todas las peticiones a secrets a nivel Metadata - level: Metadata resources: - group: \u0026#34;\u0026#34; resources: [\u0026#34;secrets\u0026#34;] # Registrar pod exec/attach a nivel RequestResponse - level: RequestResponse resources: - group: \u0026#34;\u0026#34; resources: [\u0026#34;pods/exec\u0026#34;, \u0026#34;pods/attach\u0026#34;] # Registrar todas las operaciones de escritura a nivel Request - level: Request verbs: [\u0026#34;create\u0026#34;, \u0026#34;update\u0026#34;, \u0026#34;patch\u0026#34;, \u0026#34;delete\u0026#34;] # Registrar todo lo demas a nivel Metadata - level: Metadata omitStages: - RequestReceived Habilita en el API server con:\n1 2 3 4 5 --audit-policy-file=/etc/kubernetes/audit-policy.yaml --audit-log-path=/var/log/kubernetes/audit.log --audit-log-maxage=30 --audit-log-maxbackup=10 --audit-log-maxsize=100 Envia los audit logs a tu SIEM o sistema de agregacion de logs (Loki, Elasticsearch) para analisis y alertas.\nPoliticas de Imagenes con Kyverno Kyverno es un motor de políticas para Kubernetes que valida, muta y genera recursos basándose en políticas. Es mas sencillo de adoptar que OPA Gatekeeper porque las políticas se escriben como recursos de Kubernetes en lugar de Rego.\nRequerir Digest de Imagen y Registro de Confianza 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: require-image-digest spec: validationFailureAction: Enforce rules: - name: require-digest match: any: - resources: kinds: - Pod validate: message: \u0026#34;Las imágenes deben usar un digest (@sha256:...) en lugar de un tag\u0026#34; pattern: spec: containers: - image: \u0026#34;*@sha256:*\u0026#34; - name: require-trusted-registry match: any: - resources: kinds: - Pod validate: message: \u0026#34;Las imágenes deben provenir del registro de confianza\u0026#34; pattern: spec: containers: - image: \u0026#34;myregistry.com/*\u0026#34; Esta política asegura que solo se desplieguen imágenes de tu registro de confianza con digests fijados, previniendo tanto ataques a la cadena de suministro como problemas de mutabilidad de tags.\nCIS Kubernetes Benchmark El CIS Kubernetes Benchmark proporciona un conjunto completo de recomendaciones de seguridad. Ejecuta comprobaciones automatizadas con kube-bench:\n1 2 3 4 5 # Ejecutar comprobaciones del benchmark CIS kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml # Ver resultados kubectl logs job/kube-bench Aborda los hallazgos por prioridad: elementos criticos primero (autenticacion del API server, cifrado de etcd), luego altos (RBAC, network policies), despues medios y bajos.\nChecklist de Bastionado Usa esta checklist como punto de partida para asegurar tu cluster:\nAPI server: autenticacion anonima deshabilitada, audit logging habilitado etcd: cifrado en reposo, acceso restringido solo al API server RBAC: sin bindings innecesarios de cluster-admin, minimo privilegio aplicado Pod Security: PSS restricted aplicado en namespaces de produccion NetworkPolicies: denegacion por defecto en todos los namespaces, reglas de permiso explicitas Secretos: gestor de secretos externo o sealed secrets, cifrado en reposo Imagenes: imágenes firmadas, aplicación de registro de confianza, fijación de digest Nodos: actualizaciones de seguridad automaticas, SO bastionado segun CIS Auditoria: audit logs del API server enviados al SIEM Monitorizacion: alertas sobre cambios de RBAC, creacion de pods privilegiados, exec en pods Cadena de suministro: escaneo de vulnerabilidades en CI/CD, escaneo de imágenes en tiempo de admisión Red: TLS entre todos los componentes, service mesh para mTLS entre pods El bastionado de seguridad no es una actividad puntual. Programa revisiones trimestrales para reevaluar tu postura, ejecutar benchmarks CIS, revisar bindings RBAC y actualizar políticas a medida que tu cluster evoluciona.\n","date":"2024-11-03T00:00:00Z","permalink":"/p/gu%C3%ADa-de-bastionado-de-seguridad-en-kubernetes/","title":"Guía de bastionado de seguridad en Kubernetes"},{"content":"Los Tres Pilares de la Observabilidad La observabilidad es la capacidad de entender qué está ocurriendo dentro de tus sistemas examinando sus salidas externas. Se apoya en tres pilares:\nMétricas son mediciones numéricas recopiladas a lo largo del tiempo: uso de CPU, latencia de peticiones, tasas de error, profundidad de colas. Son baratas de almacenar, rápidas de consultar e ideales para dashboards y alertas. Prometheus es la herramienta dominante aquí.\nLogs son registros de texto con marca de tiempo de eventos discretos: errores de aplicación, logs de acceso, pistas de auditoría. Proporcionan contexto detallado que las métricas no pueden. Loki, Elasticsearch y Fluentd gestionan la agregación de logs.\nTrazas siguen una petición individual mientras atraviesa múltiples servicios, mostrando la latencia en cada salto. Jaeger y Tempo son las principales opciones open-source. Las trazas son esenciales para depurar sistemas distribuidos, pero son las más complejas de instrumentar.\nEsta guía se centra en métricas y logs usando el stack Prometheus + Grafana + Loki, que cubre la mayoría de las necesidades de observabilidad para la mayoría de equipos.\nArquitectura de Prometheus Prometheus usa un modelo pull: en lugar de que las aplicaciones empujen métricas a un colector central, Prometheus escanea endpoints HTTP a intervalos regulares. Este diseño tiene algunas ventajas claras:\nLos servicios no necesitan conocer el sistema de monitorizacion Prometheus controla la tasa de escaneo y detecta cuando los targets estan caidos Es facil ejecutarlo localmente contra cualquier servicio que exponga un endpoint /metrics Componentes Principales Prometheus Server: escanea targets, almacena datos de series temporales, evalua reglas de alerta Exporters: traducen metricas de sistemas de terceros (node_exporter para Linux, mysqld_exporter para MySQL) Pushgateway: acepta metricas enviadas por trabajos batch de corta duracion Alertmanager: recibe alertas de Prometheus y las enruta a tus canales de notificacion Configuracion de Scraping Una configuracion basica de prometheus.yml:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 global: scrape_interval: 15s evaluation_interval: 15s rule_files: - \u0026#34;alert_rules.yml\u0026#34; alerting: alertmanagers: - static_configs: - targets: - \u0026#34;alertmanager:9093\u0026#34; scrape_configs: - job_name: \u0026#34;prometheus\u0026#34; static_configs: - targets: [\u0026#34;localhost:9090\u0026#34;] - job_name: \u0026#34;node-exporter\u0026#34; static_configs: - targets: [\u0026#34;node-exporter:9100\u0026#34;] - job_name: \u0026#34;application\u0026#34; metrics_path: \u0026#34;/metrics\u0026#34; static_configs: - targets: [\u0026#34;app:8080\u0026#34;] # Service discovery en Kubernetes - job_name: \u0026#34;kubernetes-pods\u0026#34; kubernetes_sd_configs: - role: pod relabel_configs: - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape] action: keep regex: true - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path] action: replace target_label: __metrics_path__ regex: (.+) En Kubernetes, el service discovery encuentra automaticamente los pods anotados con prometheus.io/scrape: \u0026quot;true\u0026quot;. Ya no necesitas listar cada target manualmente.\nFundamentos de PromQL PromQL es el lenguaje de consulta de Prometheus. Aqui tienes los patrones mas utiles:\nVectores Instantaneos y Rate 1 2 3 4 5 6 7 8 # Uso actual de CPU por core node_cpu_seconds_total{mode=\u0026#34;idle\u0026#34;} # Tasa por segundo de peticiones HTTP en los ultimos 5 minutos rate(http_requests_total[5m]) # Tasa de peticiones por codigo de estado sum(rate(http_requests_total[5m])) by (status_code) Percentiles de Latencia con Histogramas 1 2 3 4 5 # Latencia del percentil 95 histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) # Percentil 99 por endpoint histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket[5m])) by (le, handler)) Tasas de Error 1 2 3 4 5 6 7 8 9 10 11 12 # Tasa de error como porcentaje sum(rate(http_requests_total{status_code=~\u0026#34;5..\u0026#34;}[5m])) / sum(rate(http_requests_total[5m])) * 100 # Disponibilidad (inversa de la tasa de error) 1 - ( sum(rate(http_requests_total{status_code=~\u0026#34;5..\u0026#34;}[5m])) / sum(rate(http_requests_total[5m])) ) Utilizacion de Recursos 1 2 3 4 5 # Porcentaje de uso de memoria (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 # Porcentaje de uso de disco (1 - node_filesystem_avail_bytes{mountpoint=\u0026#34;/\u0026#34;} / node_filesystem_size_bytes{mountpoint=\u0026#34;/\u0026#34;}) * 100 Dashboards de Grafana Grafana se conecta a Prometheus como fuente de datos y permite construir dashboards con paneles para graficos, tablas, indicadores y heatmaps.\nConfiguracion Anade Prometheus como fuente de datos en Grafana ya sea por la UI o mediante provisioning:\n1 2 3 4 5 6 7 8 9 10 11 12 13 # grafana/provisioning/datasources/prometheus.yml apiVersion: 1 datasources: - name: Prometheus type: prometheus access: proxy url: http://prometheus:9090 isDefault: true - name: Loki type: loki access: proxy url: http://loki:3100 Provisioning de Dashboards En lugar de crear dashboards manualmente en la UI, almacenalos como archivos JSON y aprovisionarlos automaticamente:\n1 2 3 4 5 6 7 8 9 10 11 12 # grafana/provisioning/dashboards/default.yml apiVersion: 1 providers: - name: \u0026#34;Default\u0026#34; orgId: 1 folder: \u0026#34;\u0026#34; type: file disableDeletion: false updateIntervalSeconds: 30 options: path: /var/lib/grafana/dashboards foldersFromFilesStructure: true Coloca tus archivos JSON de dashboard en el directorio montado. Exporta dashboards existentes desde la UI de Grafana usando la funcion compartir/exportar y commitealos en Git. Esto te da dashboards versionados y reproducibles.\nConsejo útil: al exportar dashboards para provisioning, reemplaza UIDs de datasource hardcodeados con la variable ${DS_PROMETHEUS} para que funcionen en diferentes entornos.\nLoki para Agregacion de Logs Loki es el sistema de agregacion de logs de Grafana. Esta disenado para ser eficiente en coste indexando solo metadatos (labels) en lugar del contenido completo de los logs. Se integra naturalmente con Grafana, permitiendo correlacionar logs y metricas en el mismo dashboard.\nArquitectura Loki usa el mismo enfoque basado en labels que Prometheus. Los logs se etiquetan con labels como {job=\u0026quot;myapp\u0026quot;, namespace=\u0026quot;production\u0026quot;} y se consultan usando LogQL:\n1 2 3 4 5 6 7 8 # Todos los logs de error del servicio de pagos {job=\u0026#34;payment-service\u0026#34;} |= \u0026#34;error\u0026#34; # Logs estructurados en JSON, filtrar por nivel y extraer campos {job=\u0026#34;api\u0026#34;} | json | level=\u0026#34;error\u0026#34; | line_format \u0026#34;{{.msg}}\u0026#34; # Contar errores por servicio a lo largo del tiempo sum(count_over_time({job=~\u0026#34;.+\u0026#34;} |= \u0026#34;error\u0026#34; [5m])) by (job) Recopilacion de Logs con Promtail Promtail es el agente que envia logs a Loki. Una configuracion basica:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 server: http_listen_port: 9080 positions: filename: /tmp/positions.yaml clients: - url: http://loki:3100/loki/api/v1/push scrape_configs: - job_name: containers static_configs: - targets: - localhost labels: job: containers __path__: /var/log/containers/*.log En Kubernetes, despliega Promtail como un DaemonSet para recopilar logs de todos los nodos automaticamente.\nAlerting con Alertmanager Alertmanager gestiona el enrutamiento de alertas, agrupacion, deduplicacion y silenciado. Prometheus evalua reglas de alerta y dispara alertas a Alertmanager, que luego entrega las notificaciones.\nReglas de Alerta Define reglas de alerta en un archivo referenciado por prometheus.yml:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 # alert_rules.yml groups: - name: application rules: - alert: HighErrorRate expr: | sum(rate(http_requests_total{status_code=~\u0026#34;5..\u0026#34;}[5m])) / sum(rate(http_requests_total[5m])) \u0026gt; 0.05 for: 5m labels: severity: critical annotations: summary: \u0026#34;Tasa de error alta detectada\u0026#34; description: \u0026#34;La tasa de error es {{ $value | humanizePercentage }} en los ultimos 5 minutos\u0026#34; - alert: HighLatency expr: | histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket[5m])) by (le)) \u0026gt; 1.0 for: 10m labels: severity: warning annotations: summary: \u0026#34;Latencia p95 alta\u0026#34; description: \u0026#34;La latencia del percentil 95 es {{ $value }}s\u0026#34; - alert: DiskSpaceLow expr: | (1 - node_filesystem_avail_bytes{mountpoint=\u0026#34;/\u0026#34;} / node_filesystem_size_bytes{mountpoint=\u0026#34;/\u0026#34;}) * 100 \u0026gt; 85 for: 15m labels: severity: warning annotations: summary: \u0026#34;Espacio en disco superior al 85%\u0026#34; description: \u0026#34;El uso de disco en {{ $labels.instance }} es {{ $value }}%\u0026#34; Configuracion de Alertmanager 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 # alertmanager.yml global: resolve_timeout: 5m route: group_by: [\u0026#34;alertname\u0026#34;, \u0026#34;severity\u0026#34;] group_wait: 30s group_interval: 5m repeat_interval: 4h receiver: \u0026#34;default\u0026#34; routes: - match: severity: critical receiver: \u0026#34;pagerduty-critical\u0026#34; repeat_interval: 1h - match: severity: warning receiver: \u0026#34;slack-warnings\u0026#34; receivers: - name: \u0026#34;default\u0026#34; slack_configs: - api_url: \u0026#34;https://hooks.slack.com/services/XXX/YYY/ZZZ\u0026#34; channel: \u0026#34;#alerts\u0026#34; title: \u0026#39;{{ .GroupLabels.alertname }}\u0026#39; text: \u0026#39;{{ range .Alerts }}{{ .Annotations.description }}{{ end }}\u0026#39; - name: \u0026#34;pagerduty-critical\u0026#34; pagerduty_configs: - service_key: \u0026#34;\u0026lt;pagerduty-service-key\u0026gt;\u0026#34; - name: \u0026#34;slack-warnings\u0026#34; slack_configs: - api_url: \u0026#34;https://hooks.slack.com/services/XXX/YYY/ZZZ\u0026#34; channel: \u0026#34;#warnings\u0026#34; Despliegue con Docker Compose Aqui tienes un docker-compose.yml completo para levantar el stack de observabilidad localmente:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 version: \u0026#34;3.8\u0026#34; services: prometheus: image: prom/prometheus:latest volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml - ./prometheus/alert_rules.yml:/etc/prometheus/alert_rules.yml - prometheus_data:/prometheus ports: - \u0026#34;9090:9090\u0026#34; command: - \u0026#34;--config.file=/etc/prometheus/prometheus.yml\u0026#34; - \u0026#34;--storage.tsdb.retention.time=30d\u0026#34; alertmanager: image: prom/alertmanager:latest volumes: - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml ports: - \u0026#34;9093:9093\u0026#34; grafana: image: grafana/grafana:latest volumes: - ./grafana/provisioning:/etc/grafana/provisioning - ./grafana/dashboards:/var/lib/grafana/dashboards - grafana_data:/var/lib/grafana ports: - \u0026#34;3000:3000\u0026#34; environment: - GF_SECURITY_ADMIN_PASSWORD=changeme loki: image: grafana/loki:latest volumes: - loki_data:/loki ports: - \u0026#34;3100:3100\u0026#34; promtail: image: grafana/promtail:latest volumes: - ./promtail/config.yml:/etc/promtail/config.yml - /var/log:/var/log:ro command: -config.file=/etc/promtail/config.yml node-exporter: image: prom/node-exporter:latest ports: - \u0026#34;9100:9100\u0026#34; volumes: - /proc:/host/proc:ro - /sys:/host/sys:ro - /:/rootfs:ro command: - \u0026#34;--path.procfs=/host/proc\u0026#34; - \u0026#34;--path.sysfs=/host/sys\u0026#34; - \u0026#34;--path.rootfs=/rootfs\u0026#34; volumes: prometheus_data: grafana_data: loki_data: Levanta el stack con:\n1 docker-compose up -d Accede a Grafana en http://localhost:3000, Prometheus en http://localhost:9090 y Alertmanager en http://localhost:9093.\nConsejos para Produccion Usa recording rules para consultas PromQL costosas que los dashboards ejecutan frecuentemente. Pre-calcula y almacena el resultado como una nueva metrica para reducir la carga de consultas.\nConfigura la retencion segun la resolucion: mantener datos de alta resolucion (intervalos de 15s) durante 15 dias, luego downsample a 5m durante 90 dias usando Thanos o Cortex para almacenamiento a largo plazo.\nLa cardinalidad de labels importa: evita labels con valores ilimitados (IDs de usuario, IDs de peticion). Labels de alta cardinalidad dispararan el uso de memoria de Prometheus.\nUsa carpetas y equipos en Grafana para organizar dashboards por servicio o equipo. Omite el mega-dashboard que intenta mostrar todo.\nAlerta sobre sintomas, no causas: alerta sobre \u0026ldquo;la tasa de error es alta\u0026rdquo; en lugar de \u0026ldquo;el Pod se reinicio.\u0026rdquo; Los usuarios se preocupan por el impacto, no por el mecanismo interno.\nImplementa runbooks de alertas: cada alerta debe enlazar a un runbook describiendo que comprobar y como mitigar. Anade el enlace en la anotacion de la alerta.\nTestea tus alertas: usa promtool check rules alert_rules.yml para validar la sintaxis de las reglas. Usa tests unitarios para expresiones PromQL complejas.\nAsegura tu stack: pon Grafana detras de SSO/OAuth, restringe el acceso a Prometheus a redes internas, habilita TLS entre componentes en produccion.\nEl stack Prometheus + Grafana + Loki proporciona una base solida de observabilidad que escala bien para la mayoria de organizaciones. Empieza con metricas y alertas, anade agregacion de logs cuando necesites correlacionar eventos, e introduce trazas cuando depurar latencia entre servicios se convierta en algo habitual.\n","date":"2024-08-25T00:00:00Z","permalink":"/p/stack-de-observabilidad-prometheus-grafana-y-alertas/","title":"Stack de observabilidad: Prometheus, Grafana y alertas"},{"content":"SAST vs DAST: Entendiendo la Diferencia Las pruebas de seguridad se dividen en dos enfoques fundamentales, y saber cuándo usar cada uno importa para tu postura.\nSAST (Static Application Security Testing) lee código fuente, bytecode o binarios sin ejecutar la app. Busca patrones que coincidan con vulnerabilidades conocidas (SQL injection, XSS, credenciales hardcodeadas, deserialización insegura). Piensa en ello como un linter de seguridad que marca patrones peligrosos.\nDAST (Dynamic Application Security Testing) prueba una aplicación en ejecución enviando peticiones crafteadas y analizando respuestas. Simula lo que haría un atacante: sondeando endpoints, testeando autenticación, buscando misconfiguraciones. DAST ve la app desde afuera, como un atacante real.\nAspecto SAST DAST Cuando se ejecuta Build time, sobre código fuente Runtime, contra app desplegada Qué encuentra Fallos de código, secretos hardcodeados, patrones inseguros Vulnerabilidades en runtime, misconfiguraciones, problemas de autenticación Tasa de falsos positivos Mayor (sin contexto de ejecución) Menor (testea comportamiento real) Dependencia de lenguaje Sí (necesita reglas específicas) No (testea capa HTTP/API) Cobertura Todas las rutas de código (incluso código muerto) Solo endpoints alcanzables Velocidad Rápido (segundos a minutos) Más lento (minutos a horas) Mejor etapa Cada commit/PR Staging o pre-producción Respuesta corta: usa ambos. SAST detecta temprano y barato. DAST detecta lo que solo aparece en runtime. Se complementan.\nComparativa de Herramientas Herramientas SAST Herramienta Lenguajes Fortalezas Licencia Semgrep 30+ lenguajes Rápido, reglas personalizadas, gran integración CI OSS + Comercial SonarQube 25+ lenguajes Ecosistema amplio, quality gates, dashboard Community + Comercial Bandit Solo Python Específico para Python, ligero, fácil configuración OSS (Apache 2.0) CodeQL 10+ lenguajes Analisis semantico profundo, nativo en GitHub Gratis para OSS Herramientas DAST Herramienta Tipo Fortalezas Licencia OWASP ZAP Escaner basado en proxy Completo, scriptable, reglas de la comunidad OSS (Apache 2.0) Burp Suite Escaner basado en proxy Lo mejor para testing manual + automatizado Comercial Nuclei Escaner basado en templates Rapido, enorme biblioteca de templates, CI-friendly OSS (MIT) Para la mayoria de equipos, Semgrep + OWASP ZAP proporciona una excelente base open-source que cubre tanto SAST como DAST sin costes de licencia.\nIntegracion en Pipeline de GitLab CI Aqui tienes un ejemplo completo de .gitlab-ci.yml que integra tanto SAST como DAST en un pipeline con gating apropiado:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 stages: - build - test - sast - deploy-staging - dast - deploy-production variables: SEMGREP_RULES: \u0026#34;p/owasp-top-ten p/security-audit\u0026#34; ZAP_TARGET_URL: \u0026#34;https://staging.example.com\u0026#34; # --- Etapa SAST --- semgrep-scan: stage: sast image: semgrep/semgrep:latest script: - semgrep ci --config \u0026#34;$SEMGREP_RULES\u0026#34; --json --output semgrep-results.json - | # Bloquear pipeline si los hallazgos altos/criticos superan el umbral HIGH_COUNT=$(cat semgrep-results.json | jq \u0026#39;[.results[] | select(.extra.severity == \u0026#34;ERROR\u0026#34;)] | length\u0026#39;) echo \u0026#34;High severity findings: $HIGH_COUNT\u0026#34; if [ \u0026#34;$HIGH_COUNT\u0026#34; -gt 0 ]; then echo \u0026#34;Pipeline blocked: $HIGH_COUNT high severity findings\u0026#34; exit 1 fi artifacts: paths: - semgrep-results.json when: always allow_failure: false bandit-scan: stage: sast image: python:3.11-slim script: - pip install bandit - bandit -r src/ -f json -o bandit-results.json --severity-level medium || true - | HIGH_COUNT=$(cat bandit-results.json | jq \u0026#39;.results | map(select(.issue_severity == \u0026#34;HIGH\u0026#34;)) | length\u0026#39;) echo \u0026#34;Bandit high severity findings: $HIGH_COUNT\u0026#34; if [ \u0026#34;$HIGH_COUNT\u0026#34; -gt 3 ]; then exit 1 fi artifacts: paths: - bandit-results.json when: always only: - merge_requests - main # --- Despliegue Staging --- deploy-staging: stage: deploy-staging script: - echo \u0026#34;Deploying to staging...\u0026#34; - ./deploy.sh staging environment: name: staging url: https://staging.example.com # --- Etapa DAST --- owasp-zap-scan: stage: dast image: ghcr.io/zaproxy/zaproxy:stable script: - mkdir -p /zap/wrk - | zap-full-scan.py \\ -t \u0026#34;$ZAP_TARGET_URL\u0026#34; \\ -r zap-report.html \\ -J zap-results.json \\ -l WARN \\ -d - | # Parsear resultados y aplicar politica HIGH_ALERTS=$(cat zap-results.json | jq \u0026#39;[.site[].alerts[] | select(.riskcode == \u0026#34;3\u0026#34;)] | length\u0026#39;) echo \u0026#34;High risk alerts: $HIGH_ALERTS\u0026#34; if [ \u0026#34;$HIGH_ALERTS\u0026#34; -gt 0 ]; then echo \u0026#34;Pipeline blocked: $HIGH_ALERTS high risk vulnerabilities found\u0026#34; exit 1 fi artifacts: paths: - zap-report.html - zap-results.json when: always dependencies: - deploy-staging # --- Despliegue Produccion --- deploy-production: stage: deploy-production script: - echo \u0026#34;Deploying to production...\u0026#34; - ./deploy.sh production environment: name: production when: manual only: - main Las decisiones de diseno clave en este pipeline:\nSAST se ejecuta en cada merge request, detectando problemas antes de que el codigo se fusione DAST se ejecuta contra staging, testeando la aplicacion desplegada Los umbrales son configurables: tolerancia cero para hallazgos SAST altos/criticos, pero cierta flexibilidad para severidades menores Los informes siempre se guardan como artefactos, incluso cuando el pipeline pasa El despliegue a produccion es manual, bloqueado detras de las etapas SAST y DAST Gestion de Falsos Positivos Los falsos positivos son la razon numero uno por la que los equipos abandonan el escaneo de seguridad. Gestionalos de forma sistematica:\nPara Semgrep Crea un archivo .semgrepignore o usa anotaciones inline:\n1 2 # nosemgrep: python.lang.security.audit.hardcoded-password DEFAULT_TEST_PASSWORD = \u0026#34;test123\u0026#34; # Solo usado en fixtures de test Para falsos positivos persistentes, crea un semgrep-exclusions.yml:\n1 2 3 4 5 6 7 rules: - id: ignore-test-passwords pattern: $X = \u0026#34;...\u0026#34; paths: exclude: - tests/ - fixtures/ Para OWASP ZAP Usa un archivo de contexto para excluir falsos positivos conocidos:\n1 2 3 4 5 6 7 \u0026lt;alertFilter\u0026gt; \u0026lt;ruleId\u0026gt;10038\u0026lt;/ruleId\u0026gt; \u0026lt;url\u0026gt;https://staging.example.com/api/health\u0026lt;/url\u0026gt; \u0026lt;urlIsRegex\u0026gt;false\u0026lt;/urlIsRegex\u0026gt; \u0026lt;enabled\u0026gt;true\u0026lt;/enabled\u0026gt; \u0026lt;newRisk\u0026gt;-1\u0026lt;/newRisk\u0026gt; \u0026lt;!-- -1 = Falso Positivo --\u0026gt; \u0026lt;/alertFilter\u0026gt; La regla de oro: cada supresion debe incluir un comentario de justificacion explicando por que es seguro ignorarlo. Revisa las supresiones trimestralmente.\nPoliticas de Umbrales y Gates Define politicas claras por entorno y severidad:\nSeveridad Gate PR/MR Gate Rama Principal Pre-Produccion Critica Bloquear Bloquear Bloquear Alta Bloquear Bloquear Avisar Media Avisar Avisar Info Baja Info Info Info Implementa estos como codigos de salida en tus scripts CI. Empieza de forma permisiva y endurece con el tiempo \u0026ndash; bloquear todo desde el primer dia creara frustracion y workarounds.\nInformes y Dashboards Agrega resultados de SAST y DAST en una vista centralizada:\nDefectDojo: plataforma open-source de gestion de vulnerabilidades que ingesta informes de Semgrep, ZAP, Bandit y docenas de otras herramientas GitLab Security Dashboard: integracion nativa si estas en GitLab Ultimate Dashboards personalizados: envia resultados de escaneo a Elasticsearch y visualiza en Grafana Rastrea estas metricas a lo largo del tiempo:\nTiempo medio de remediacion (MTTR) por severidad Total de vulnerabilidades abiertas por antiguedad Tasa de falsos positivos (supresiones vs total de hallazgos) Cobertura de escaneo (porcentaje de repos con escaneo de seguridad habilitado) IAST como Complemento IAST (Interactive Application Security Testing) combina elementos de SAST y DAST instrumentando la aplicacion en tiempo de ejecucion. Un agente se ejecuta dentro de la aplicacion durante el testing, correlacionando peticiones HTTP con rutas de ejecucion de codigo.\nHerramientas IAST como Contrast Security y Datadog Application Security proporcionan:\nTasas de falsos positivos mas bajas que SAST Contexto a nivel de codigo que DAST no tiene Feedback en tiempo real durante el testing de QA Considera IAST como una tercera capa una vez que SAST y DAST esten maduros en tu pipeline.\nEstrategia Practica de Despliegue Desplegar escaneo de seguridad en tu organización requiere fases:\nFase 1: Visibilidad (Semanas 1-4) Habilitar SAST en CI con allow_failure: true (no bloques) Generar informes, guardar como artefactos Encontrar principales categorías de vulnerabilidades Establecer métricas base Fase 2: Gating Selectivo (Semanas 5-8) Bloquear solo hallazgos SAST críticos/altos Añadir escaneos DAST a staging para apps clave Crear flujos de supresión y triaje Formar desarrolladores en interpretar y corregir hallazgos Fase 3: Integración Completa (Semanas 9-12) Aplicar gates SAST en todos los repos Aplicar gates DAST en todas las web apps Integrar con plataforma de vulnerabilidades Auto-crear tickets para hallazgos Fase 4: Mejora Continua (Continuo) Escribir reglas Semgrep personalizadas Afinar políticas de ZAP para reducir tiempo Rastrear MTTR, establecer objetivos Revisiones trimestrales de falsos positivos Mayor error: saltar a Fase 3. Empieza con visibilidad, construye confianza, endurece gradualmente. El escaneo debe ayudar, no bloquear.\n","date":"2024-05-12T00:00:00Z","permalink":"/p/integraci%C3%B3n-de-pruebas-sast/dast-en-pipelines-ci/cd/","title":"Integración de pruebas SAST/DAST en pipelines CI/CD"},{"content":"¿Qué es DataOps? DataOps aplica principios de DevOps (automatización, integración continua, monitorización, colaboración) a pipelines de datos y analítica. Mientras DevOps entrega software de forma fiable, DataOps entrega datos de forma fiable.\nLa diferencia: qué fluye por el pipeline. DevOps construye, testea, despliega código. DataOps construye, testea, despliega transformaciones de datos. El objetivo: asegurar que datos lleguen a dashboards, modelos de ML y sistemas downstream correctos, frescos, confiables.\nSi alguna vez tuviste un dashboard roto el lunes porque un esquema cambio el fin de semana, sabes por qué DataOps importa.\nPrincipios fundamentales 1. Automatización primero Cada paso en tu pipeline de datos \u0026ndash; extracción, transformación, carga, testing y despliegue \u0026ndash; debe estar automatizado. Scripts SQL manuales ejecutados desde el portátil de alguien son un riesgo. Codifica todo, versiona en Git y deja que los orquestadores se encarguen de la ejecución.\n2. Testing continuo El testing de datos no es opcional. Debes validar los datos en cada etapa:\nTests de esquema: tipos de columna, restricciones de nulabilidad Tests de volumen: conteos de filas dentro de rangos esperados Tests de frescura: los datos llegaron según lo programado Tests de reglas de negocio: los ingresos nunca son negativos, las fechas no están en el futuro 3. Monitorización y observabilidad Necesitas saber cuándo algo se rompe antes que tus stakeholders. Instrumenta tus pipelines con métricas de latencia, conteo de filas, tasas de error y puntuaciones de calidad de datos. Configura alertas que se disparen cuando se detecten anomalías.\n4. Colaboración y control de versiones Los pipelines de datos son código. Trátalos como tal. Usa pull requests, code reviews y CI/CD para tu lógica de transformación. Cada cambio en un pipeline debe ser revisable, testeable y reversible.\nArquitectura de pipelines: ETL vs ELT Los dos patrones dominantes para pipelines de datos son ETL y ELT. La elección depende de tu infraestructura y caso de uso.\nETL (Extract, Transform, Load) Los datos se extraen de las fuentes, se transforman en un motor de procesamiento (Spark, scripts Python) y luego se cargan en el sistema destino. Este patrón tiene sentido cuando:\nNecesitas reducir el volumen de datos antes de cargar (control de costes) Las transformaciones requieren computacion pesada no adecuada para tu warehouse Tienes requisitos estrictos de gobernanza que requieren transformacion antes del almacenamiento ELT (Extract, Load, Transform) Los datos se extraen y cargan en crudo en un data warehouse (BigQuery, Snowflake, Redshift), luego se transforman in situ usando SQL. Este es el enfoque moderno por defecto porque:\nLos warehouses en la nube tienen capacidad de computo masiva Las transformaciones basadas en SQL son más fáciles de revisar y testear Los datos en crudo se preservan, permitiendo reprocesamiento cuando la logica cambia Herramientas como dbt hacen de las transformaciones SQL ciudadanos de primera clase Para la mayoría de equipos que empiezan hoy, ELT es el enfoque recomendado a menos que tengas una razón específica para transformar antes de cargar.\nHerramientas clave Apache Airflow \u0026ndash; orquestación Airflow es el orquestador open-source más ampliamente adoptado para pipelines de datos. Te permite definir flujos de trabajo como Directed Acyclic Graphs (DAGs) en Python, con planificación integrada, reintentos, gestión de dependencias y una interfaz web para monitorización.\nAquí tienes un ejemplo práctico de un DAG que orquesta un pipeline ELT:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 from airflow import DAG from airflow.operators.python import PythonOperator from airflow.providers.common.sql.operators.sql import SQLExecuteQueryOperator from airflow.utils.dates import days_ago from datetime import timedelta default_args = { \u0026#34;owner\u0026#34;: \u0026#34;data-team\u0026#34;, \u0026#34;retries\u0026#34;: 2, \u0026#34;retry_delay\u0026#34;: timedelta(minutes=5), \u0026#34;email_on_failure\u0026#34;: True, \u0026#34;email\u0026#34;: [\u0026#34;data-alerts@company.com\u0026#34;], } with DAG( dag_id=\u0026#34;elt_sales_pipeline\u0026#34;, default_args=default_args, schedule_interval=\u0026#34;@daily\u0026#34;, start_date=days_ago(1), catchup=False, tags=[\u0026#34;elt\u0026#34;, \u0026#34;sales\u0026#34;], ) as dag: extract_load = PythonOperator( task_id=\u0026#34;extract_and_load_raw\u0026#34;, python_callable=extract_and_load_sales_data, # tu funcion de extraccion ) transform = SQLExecuteQueryOperator( task_id=\u0026#34;transform_sales\u0026#34;, conn_id=\u0026#34;warehouse_conn\u0026#34;, sql=\u0026#34;sql/transform_sales.sql\u0026#34;, ) run_quality_checks = PythonOperator( task_id=\u0026#34;data_quality_checks\u0026#34;, python_callable=run_great_expectations_suite, ) extract_load \u0026gt;\u0026gt; transform \u0026gt;\u0026gt; run_quality_checks Patrones clave a seguir en Airflow:\nTareas idempotentes: ejecutar la misma tarea dos veces debe producir el mismo resultado Escrituras atomicas: usa tablas staging e intercambia al completarse Fechas parametrizadas: usa variables template {{ ds }} para particionamiento por fecha Tareas pequeñas: cada tarea debe hacer una sola cosa, facilitando el diagnóstico de fallos dbt \u0026ndash; transformacion dbt (data build tool) es el estandar para gestionar transformaciones basadas en SQL en un pipeline ELT. Proporciona:\nSQL modular: divide transformaciones complejas en modelos referenciables Testing integrado: tests de esquema, tests personalizados y chequeos de frescura Documentacion: documentacion auto-generada a partir de las descripciones de tus modelos Linaje: DAG visual mostrando como los modelos dependen unos de otros Una estructura tipica de proyecto dbt:\n1 2 3 4 5 6 7 8 models/ staging/ stg_sales.sql -- limpiar datos en crudo stg_customers.sql marts/ fct_daily_revenue.sql -- agregaciones a nivel de negocio dim_customers.sql schema.yml -- tests y documentacion Great Expectations \u0026ndash; calidad de datos Great Expectations es un framework Python para definir, ejecutar y documentar chequeos de calidad de datos. Va mas alla de simples aserciones generando documentacion de datos legible por humanos.\nAqui tienes un ejemplo de configuración de expectations para una tabla de ventas:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import great_expectations as gx context = gx.get_context() # Conectar a tu fuente de datos datasource = context.sources.add_or_update_pandas(\u0026#34;sales_source\u0026#34;) data_asset = datasource.add_csv_asset(\u0026#34;daily_sales\u0026#34;, filepath_or_buffer=\u0026#34;data/daily_sales.csv\u0026#34;) batch_request = data_asset.build_batch_request() # Crear una suite de expectations suite = context.add_or_update_expectation_suite(\u0026#34;sales_quality_suite\u0026#34;) validator = context.get_validator( batch_request=batch_request, expectation_suite_name=\u0026#34;sales_quality_suite\u0026#34;, ) # Definir expectations validator.expect_column_to_exist(\u0026#34;order_id\u0026#34;) validator.expect_column_values_to_be_unique(\u0026#34;order_id\u0026#34;) validator.expect_column_values_to_not_be_null(\u0026#34;customer_id\u0026#34;) validator.expect_column_values_to_be_between(\u0026#34;amount\u0026#34;, min_value=0, max_value=100000) validator.expect_column_values_to_be_in_set(\u0026#34;status\u0026#34;, [\u0026#34;pending\u0026#34;, \u0026#34;completed\u0026#34;, \u0026#34;refunded\u0026#34;]) # Ejecutar validacion results = validator.validate() validator.save_expectation_suite(discard_failed_expectations=False) if not results.success: raise Exception(f\u0026#34;Data quality checks failed: {results.statistics}\u0026#34;) Integra esto en tu DAG de Airflow para que las puertas de calidad se ejecuten despues de cada paso de transformacion. Si los chequeos fallan, el pipeline se detiene y las alertas se disparan.\nMonitorizacion y observabilidad Un pipeline de datos en producción necesita observabilidad en varias dimensiones:\nDimension Que Rastrear Herramientas Salud del pipeline Tasas de exito/fallo de tareas, tendencias de duracion Metricas de Airflow, Prometheus Frescura de datos Tiempo desde la ultima carga exitosa dbt source freshness, chequeos personalizados Volumen de datos Conteo de filas por tabla por ejecucion Great Expectations, SQL personalizado Calidad de datos Tasas de tests aprobados/fallidos, puntuaciones de anomalias Great Expectations, Monte Carlo Coste Uso de computo del warehouse, crecimiento del almacenamiento Dashboards del proveedor cloud Configura alertas para:\nCualquier fallo de tarea del pipeline Frescura de datos excediendo umbrales de SLA Desviaciones de conteo de filas mas alla de 2 desviaciones estandar de la media movil Fallos en tests de calidad de datos Envia metricas de Airflow a Prometheus y construye dashboards de Grafana que den a tu equipo una vista unificada de la salud del pipeline.\nBuenas prácticas Trata los pipelines como código: todo el SQL, definiciones de DAGs y configuración viven en Git Usa entornos: dev, staging, producción \u0026ndash; igual que el código de aplicacion Implementa CI/CD: ejecuta tests de dbt y linting en cada pull request Disena para el fallo: cada tarea debe ser reintentable e idempotente Documenta contratos de datos: define y publica esquemas acordados entre equipos upstream y downstream Empieza con testing: anade chequeos de calidad de datos antes de anadir nuevas funcionalidades Alerta sobre SLAs, no solo fallos: un pipeline que tiene exito pero tarda 3x mas de lo habitual sigue siendo un problema Mantener los datos en crudo inmutables: nunca modifiques datos fuente; transforma en tablas separadas DataOps no es una herramienta. Es un conjunto de prácticas que hacen tu infraestructura fiable, testeable, mantenible. Empieza con orquestación y testing, luego añade monitorización y chequeos conforme madures.\n","date":"2024-02-18T00:00:00Z","permalink":"/p/dataops-construyendo-pipelines-de-datos-confiables/","title":"DataOps: construyendo pipelines de datos confiables"},{"content":"El detonante Hace un par de meses estuve bastionando el cluster K3s. Pasé un fin de semana entero cambiando configuraciones, ajustando parámetros del kernel, instalando Cilium en lugar de Flannel, escribiendo políticas de red. Al final el cluster quedó bastante mejor de lo que estaba.\nPero lo había hecho todo a mano.\nSi mañana tengo que recrear ese nodo desde cero, ¿cuánto tardo? Probablemente dos o tres días buscando en mis propias notas dispersas entre archivos de texto, el historial del terminal y comentarios en el chat. Y aun así me dejaría cosas. Eso no es sostenible.\nAsí que decidí construir un repositorio de infraestructura real. No una demo, no una prueba de concepto: el repositorio donde vive la definición de todo lo que corro en casa, sanitizado para poder publicarlo.\nQué hay en el homelab Antes de hablar de la estructura del repositorio, conviene explicar lo que hay que gestionar. El setup es:\nUn servidor principal con Proxmox donde corren varias VMs Dos nodos físicos adicionales que forman el cluster K3s Un router con OpenWrt Un NAS con TrueNAS No es un entorno enorme, pero tiene suficiente variedad como para que gestionar todo a mano sea un problema real. Especialmente porque Proxmox, las VMs, el cluster y el NAS tienen configuraciones que interactúan entre sí: IPs, DNS interno, certificados, usuarios.\nEstructura del repositorio Después de unas pruebas, esta es la organización que me funciona:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 homelab-infra/ ├── terraform/ │ ├── modules/ │ │ ├── proxmox-vm/ │ │ ├── dns-record/ │ │ └── network-vlan/ │ └── environments/ │ ├── main.tf │ ├── variables.tf │ └── terraform.tfvars.example ├── ansible/ │ ├── inventory/ │ │ ├── hosts.yml │ │ └── group_vars/ │ ├── playbooks/ │ │ ├── bootstrap.yml │ │ ├── k3s-server.yml │ │ ├── k3s-agent.yml │ │ └── hardening.yml │ └── roles/ │ ├── common/ │ ├── cis-level1/ │ └── k3s/ ├── kubernetes/ │ ├── base/ │ ├── apps/ │ │ ├── monitoring/ │ │ ├── storage/ │ │ └── networking/ │ └── policies/ │ ├── gatekeeper/ │ └── seccomp/ ├── .gitlab-ci.yml ├── .sops.yaml └── README.md Tres capas bien separadas: provisioning (Terraform), configuración de nodos (Ansible) y workloads de Kubernetes. Las políticas de seguridad viven dentro de kubernetes/policies/ porque son recursos de Kubernetes, pero conceptualmente las considero una capa aparte.\nTerraform: provisioning con Proxmox El proveedor de Proxmox para Terraform es el de Telmate (telmate/proxmox). No es oficial, pero es el más usado y funciona razonablemente bien.\nEl módulo proxmox-vm encapsula la creación de VMs con los parámetros que uso habitualmente:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 # terraform/modules/proxmox-vm/main.tf resource \u0026#34;proxmox_vm_qemu\u0026#34; \u0026#34;vm\u0026#34; { name = var.name target_node = var.target_node clone = var.template full_clone = true cores = var.cores memory = var.memory sockets = 1 disk { size = var.disk_size type = \u0026#34;virtio\u0026#34; storage = var.storage_pool discard = \u0026#34;on\u0026#34; } network { model = \u0026#34;virtio\u0026#34; bridge = var.network_bridge tag = var.vlan_tag } ipconfig0 = \u0026#34;ip=${var.ip_address}/24,gw=${var.gateway}\u0026#34; nameserver = var.nameserver searchdomain = var.searchdomain ciuser = var.ssh_user sshkeys = var.ssh_public_key lifecycle { ignore_changes = [ network, ] } } Las variables sensibles — la contraseña de la API de Proxmox, las claves SSH — no están en el repositorio. Uso SOPS para cifrar el fichero terraform.tfvars con age:\n1 2 3 4 5 6 # .sops.yaml creation_rules: - path_regex: .*\\.tfvars$ age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - path_regex: ansible/inventory/group_vars/.*\\.yml$ age: age1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx El fichero cifrado (terraform.tfvars) sí está en Git. Descifrarlo requiere la clave privada de age, que está en el servidor de CI y en mi máquina local, nunca en el repositorio.\nAnsible: configuración de nodos Una vez que Terraform provisiona las VMs, Ansible se encarga de configurarlas. El playbook bootstrap.yml hace lo mínimo necesario para que un nodo recién creado esté en condiciones:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 # ansible/playbooks/bootstrap.yml --- - name: Bootstrap new nodes hosts: all become: true roles: - common - cis-level1 - name: Configure K3s server nodes hosts: k3s_servers become: true roles: - k3s El rol common instala los paquetes base, configura NTP, ajusta SSH, establece los parámetros de sysctl y crea los usuarios del sistema. El rol cis-level1 aplica las recomendaciones del CIS Benchmark Level 1 para Debian.\nEl rol CIS no lo escribí desde cero. Partí del rol de la comunidad dev-sec/ansible-collection-hardening y lo adapté. Hay bastantes tareas que el rol por defecto hace que no encajan en un homelab — cosas pensadas para servidores de producción con requisitos de auditoría muy estrictos. Lo que hice fue revisar cada tarea, entender qué hacía y decidir si aplicaba a mi caso.\nAlgunas cosas que desactivé:\n1 2 3 4 5 # ansible/roles/cis-level1/defaults/main.yml os_auth_pam_pwquality_enable: false # No tengo usuarios locales con contraseña os_security_users_allow: [\u0026#34;vagrant\u0026#34;] # En el entorno de dev os_filesystem_whitelist: - vfat # Necesario para arranque UEFI Y algunas que añadí específicamente para K3s:\n1 2 3 4 5 6 7 8 # Parámetros kernel requeridos por K3s con protect-kernel-defaults kernel_parameters: - { name: \u0026#34;kernel.panic\u0026#34;, value: \u0026#34;10\u0026#34; } - { name: \u0026#34;kernel.panic_on_oops\u0026#34;, value: \u0026#34;1\u0026#34; } - { name: \u0026#34;vm.overcommit_memory\u0026#34;, value: \u0026#34;1\u0026#34; } - { name: \u0026#34;vm.panic_on_oom\u0026#34;, value: \u0026#34;0\u0026#34; } - { name: \u0026#34;fs.inotify.max_user_watches\u0026#34;, value: \u0026#34;524288\u0026#34; } - { name: \u0026#34;fs.inotify.max_user_instances\u0026#34;, value: \u0026#34;512\u0026#34; } Kubernetes: manifiestos con Kustomize Para los manifiestos de Kubernetes uso Kustomize en lugar de Helm cuando puedo. Helm es más potente para cosas complejas, pero para mis propias aplicaciones Kustomize es suficiente y produce YAML legible.\nLa estructura básica con Kustomize:\n1 2 3 4 5 6 7 8 9 10 11 kubernetes/apps/monitoring/ ├── base/ │ ├── kustomization.yaml │ ├── namespace.yaml │ ├── prometheus-deployment.yaml │ └── grafana-deployment.yaml └── overlays/ └── homelab/ ├── kustomization.yaml └── patches/ └── resource-limits.yaml El overlay homelab añade los ajustes específicos de mi entorno sin modificar los manifiestos base:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 # kubernetes/apps/monitoring/overlays/homelab/patches/resource-limits.yaml apiVersion: apps/v1 kind: Deployment metadata: name: prometheus namespace: monitoring spec: template: spec: containers: - name: prometheus resources: requests: memory: \u0026#34;256Mi\u0026#34; cpu: \u0026#34;100m\u0026#34; limits: memory: \u0026#34;512Mi\u0026#34; cpu: \u0026#34;500m\u0026#34; OPA/Gatekeeper: políticas como código Gatekeeper es un admission controller para Kubernetes que usa OPA (Open Policy Agent) para evaluar políticas escritas en Rego. En lugar de dejar que cualquier pod se despliegue con cualquier configuración, las políticas rechazan los manifiestos que no cumplen los requisitos de seguridad.\nLas políticas que tengo activas:\nNo contenedores como root 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 # kubernetes/policies/gatekeeper/no-root-containers.yaml apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sPSPAllowedUsers metadata: name: psp-pods-allowed-user-ranges spec: match: kinds: - apiGroups: [\u0026#34;\u0026#34;] kinds: [\u0026#34;Pod\u0026#34;] excludedNamespaces: - kube-system - falco parameters: runAsUser: rule: MustRunAsNonRoot runAsGroup: rule: MustRunAs ranges: - min: 1000 max: 65535 Límites de recursos obligatorios Sin límites de recursos, un pod puede consumir toda la memoria del nodo y tumbar el cluster. Esta política lo impide:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 # kubernetes/policies/gatekeeper/require-resource-limits.yaml apiVersion: templates.gatekeeper.sh/v1 kind: ConstraintTemplate metadata: name: k8srequiredresources spec: crd: spec: names: kind: K8sRequiredResources targets: - target: admission.k8s.gatekeeper.sh rego: | package k8srequiredresources violation[{\u0026#34;msg\u0026#34;: msg}] { container := input.review.object.spec.containers[_] not container.resources.limits.memory msg := sprintf(\u0026#34;El contenedor \u0026#39;%v\u0026#39; no tiene límite de memoria definido\u0026#34;, [container.name]) } violation[{\u0026#34;msg\u0026#34;: msg}] { container := input.review.object.spec.containers[_] not container.resources.limits.cpu msg := sprintf(\u0026#34;El contenedor \u0026#39;%v\u0026#39; no tiene límite de CPU definido\u0026#34;, [container.name]) } --- apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sRequiredResources metadata: name: require-resource-limits spec: match: kinds: - apiGroups: [\u0026#34;\u0026#34;] kinds: [\u0026#34;Pod\u0026#34;] excludedNamespaces: - kube-system Registro de imágenes de confianza 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 # kubernetes/policies/gatekeeper/allowed-registries.yaml apiVersion: templates.gatekeeper.sh/v1 kind: ConstraintTemplate metadata: name: k8sallowedrepos spec: crd: spec: names: kind: K8sAllowedRepos validation: openAPIV3Schema: type: object properties: repos: type: array items: type: string targets: - target: admission.k8s.gatekeeper.sh rego: | package k8sallowedrepos violation[{\u0026#34;msg\u0026#34;: msg}] { container := input.review.object.spec.containers[_] not any_repo_matches(container.image) msg := sprintf(\u0026#34;Imagen \u0026#39;%v\u0026#39; no proviene de un registro autorizado\u0026#34;, [container.image]) } any_repo_matches(image) { repo := input.parameters.repos[_] startswith(image, repo) } --- apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sAllowedRepos metadata: name: allowed-registries spec: match: kinds: - apiGroups: [\u0026#34;\u0026#34;] kinds: [\u0026#34;Pod\u0026#34;] excludedNamespaces: - kube-system parameters: repos: - \u0026#34;registry.homelab.internal/\u0026#34; - \u0026#34;ghcr.io/mi-usuario/\u0026#34; - \u0026#34;quay.io/prometheus/\u0026#34; - \u0026#34;grafana/\u0026#34; Perfiles seccomp Los perfiles seccomp limitan las llamadas al sistema que un contenedor puede realizar. Kubernetes tiene un perfil por defecto (RuntimeDefault) que ya es razonable, pero para aplicaciones que conozco bien defino perfiles más restrictivos.\nLos perfiles viven en el repositorio y se despliegan como ConfigMaps o directamente en los nodos:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 // kubernetes/policies/seccomp/web-app-profile.json { \u0026#34;defaultAction\u0026#34;: \u0026#34;SCMP_ACT_ERRNO\u0026#34;, \u0026#34;architectures\u0026#34;: [\u0026#34;SCMP_ARCH_X86_64\u0026#34;], \u0026#34;syscalls\u0026#34;: [ { \u0026#34;names\u0026#34;: [ \u0026#34;accept4\u0026#34;, \u0026#34;bind\u0026#34;, \u0026#34;brk\u0026#34;, \u0026#34;clone\u0026#34;, \u0026#34;close\u0026#34;, \u0026#34;connect\u0026#34;, \u0026#34;epoll_create1\u0026#34;, \u0026#34;epoll_ctl\u0026#34;, \u0026#34;epoll_wait\u0026#34;, \u0026#34;execve\u0026#34;, \u0026#34;exit_group\u0026#34;, \u0026#34;fcntl\u0026#34;, \u0026#34;fstat\u0026#34;, \u0026#34;futex\u0026#34;, \u0026#34;getdents64\u0026#34;, \u0026#34;getpid\u0026#34;, \u0026#34;getsockname\u0026#34;, \u0026#34;getsockopt\u0026#34;, \u0026#34;listen\u0026#34;, \u0026#34;lstat\u0026#34;, \u0026#34;mmap\u0026#34;, \u0026#34;mprotect\u0026#34;, \u0026#34;munmap\u0026#34;, \u0026#34;nanosleep\u0026#34;, \u0026#34;newfstatat\u0026#34;, \u0026#34;openat\u0026#34;, \u0026#34;poll\u0026#34;, \u0026#34;prctl\u0026#34;, \u0026#34;read\u0026#34;, \u0026#34;recvfrom\u0026#34;, \u0026#34;rt_sigaction\u0026#34;, \u0026#34;rt_sigprocmask\u0026#34;, \u0026#34;rt_sigreturn\u0026#34;, \u0026#34;sendto\u0026#34;, \u0026#34;set_robust_list\u0026#34;, \u0026#34;setsockopt\u0026#34;, \u0026#34;sigaltstack\u0026#34;, \u0026#34;socket\u0026#34;, \u0026#34;stat\u0026#34;, \u0026#34;write\u0026#34; ], \u0026#34;action\u0026#34;: \u0026#34;SCMP_ACT_ALLOW\u0026#34; } ] } Y se referencia desde el pod:\n1 2 3 4 5 spec: securityContext: seccompProfile: type: Localhost localhostProfile: \u0026#34;web-app-profile.json\u0026#34; Construir un perfil seccomp desde cero es tedioso. Lo que hago es arrancar primero con RuntimeDefault, usar strace para ver qué syscalls hace la aplicación, y luego elaborar un perfil más ajustado para las aplicaciones que quiero restringir más.\nPipeline de CI/CD El repositorio tiene un pipeline de GitLab CI que automatiza la aplicación de los cambios. El flujo es:\nEn merge requests: terraform plan y ansible-lint para detectar problemas antes de mergear Al mergear a main: terraform apply y, si hay cambios en Ansible, el playbook correspondiente 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 # .gitlab-ci.yml (fragmento) stages: - validate - plan - apply variables: TF_ROOT: \u0026#34;${CI_PROJECT_DIR}/terraform/environments\u0026#34; ANSIBLE_CONFIG: \u0026#34;${CI_PROJECT_DIR}/ansible/ansible.cfg\u0026#34; terraform-validate: stage: validate image: hashicorp/terraform:1.6 script: - cd \u0026#34;$TF_ROOT\u0026#34; - terraform init -backend=false - terraform validate rules: - changes: - terraform/**/* terraform-plan: stage: plan image: hashicorp/terraform:1.6 script: - cd \u0026#34;$TF_ROOT\u0026#34; - terraform init - terraform plan -out=tfplan artifacts: paths: - \u0026#34;${TF_ROOT}/tfplan\u0026#34; expire_in: 1 week rules: - if: $CI_PIPELINE_SOURCE == \u0026#34;merge_request_event\u0026#34; changes: - terraform/**/* terraform-apply: stage: apply image: hashicorp/terraform:1.6 script: - cd \u0026#34;$TF_ROOT\u0026#34; - terraform init - terraform apply -auto-approve rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH changes: - terraform/**/* when: manual ansible-lint: stage: validate image: python:3.11-slim script: - pip install ansible ansible-lint - ansible-lint ansible/ rules: - changes: - ansible/**/* El terraform apply es manual — no quiero que la infraestructura cambie automáticamente sin que yo lo apruebe. El plan se ejecuta automáticamente en el MR para tener visibilidad.\nLo que saniticé Publicar el repositorio requirió revisar qué no debía estar ahí:\nIPs internas: reemplazadas por rangos de ejemplo (192.168.1.x) Nombres de dominio: el dominio interno del homelab (homelab.internal en el repo, algo diferente en producción) Usuarios: los nombres de usuario reales no están en el repo Claves públicas SSH: sustituidas por placeholders Hashes de contraseñas: eliminados del inventario de Ansible Secretos de aplicaciones: cifrados con SOPS o eliminados, con un .example en su lugar La regla que seguí: si alguien con acceso a mi red local pudiera usar esa información para atacar algo, no va al repositorio en claro. Todo lo demás puede estar.\nLo que quedó pendiente Todavía hay cosas que gestiono a mano que debería codificar:\nOpenWrt: la configuración del router es la más difícil de meter en IaC. Hay un módulo de Terraform para OpenWrt que no está muy mantenido. Por ahora lo gestiono con un script de Ansible que hace backup de la configuración y otro que la restaura. No es idempotente, pero funciona.\nTrueNAS: tiene una API REST bastante completa. Hay un proveedor de Terraform en desarrollo. Lo tengo en el radar para la siguiente iteración.\nBackups: tengo backups, pero el proceso no está codificado en el repositorio. Está en otro script suelto que algún día llegará aquí.\nEl repositorio nunca está \u0026ldquo;terminado\u0026rdquo;. Lo que importa es que el estado actual del homelab esté representado en él, y que cualquier cambio pase por Git.\n","date":"2023-11-20T00:00:00Z","permalink":"/p/montando-un-repositorio-de-iac-para-el-homelab/","title":"Montando un repositorio de IaC para el homelab"},{"content":"Por qué un modelo de madurez ayuda La mayoría de los equipos saben que deberían \u0026ldquo;desplazar la seguridad a la izquierda\u0026rdquo;, pero saber por dónde empezar es la parte difícil. Un modelo de madurez proporciona una forma estructurada de evaluar el estado actual, identificar brechas y planificar una hoja de ruta realista para mejorar.\nSin un modelo, las mejoras de seguridad tienden a ser reactivas (desencadenadas por incidentes o hallazgos de auditoría en lugar de por una planificación deliberada). Un modelo de madurez convierte la seguridad de un simulacro de incendio en una disciplina de ingeniería con progreso medible.\nEl modelo descrito aquí tiene cinco niveles. El objetivo no es correr al nivel más alto, sino hacer un progreso constante y sostenible. Cada nivel se construye sobre el anterior.\nLos cinco niveles de madurez Nivel 1: Ad-Hoc En este nivel, la seguridad es algo secundario. No existen procesos formales y las actividades de seguridad ocurren de forma esporádica, si es que ocurren.\nCómo se ve:\nSin pruebas de seguridad en los pipelines de CI/CD. Las vulnerabilidades se descubren en producción o por terceros. Sin herramientas de seguridad dedicadas. Los desarrolladores tienen poca o ninguna formación en seguridad. La respuesta a incidentes es improvisada. El cumplimiento normativo se aborda manualmente antes de las auditorías. Herramientas típicas: Ninguna específica de seguridad. Quizás un firewall y un antivirus.\nNivel 2: Reactivo La seguridad se reconoce como importante, pero el enfoque es reactivo. El equipo responde a vulnerabilidades e incidentes pero no los previene de manera proactiva.\nCómo se ve:\nEl análisis estático básico (SAST) se ejecuta ocasionalmente, pero los hallazgos no siempre se abordan. El escaneo de dependencias se hace de forma manual o ad-hoc. Hay documentación de seguridad, pero está desactualizada. La respuesta a incidentes existe como un proceso documentado, aunque se practica raramente. Las revisiones de seguridad ocurren tarde en el ciclo de desarrollo (justo antes del lanzamiento). Herramientas típicas: SonarQube (reglas básicas), OWASP Dependency-Check, pruebas de penetración manuales.\nNivel 3: Proactivo La seguridad está integrada en el flujo de trabajo de desarrollo. El equipo busca activamente prevenir vulnerabilidades en lugar de solo reaccionar ante ellas.\nCómo se ve:\nSAST y DAST se ejecutan automáticamente en los pipelines de CI/CD. Escaneo de dependencias con alertas automáticas para vulnerabilidades conocidas. Escaneo de imágenes de contenedores antes del despliegue (Trivy, Grype). La Infrastructure as Code se escanea en busca de configuraciones incorrectas (Checkov, tfsec). Se realiza threat modeling para nuevas funcionalidades y cambios de arquitectura. Existen security champions dentro de los equipos de desarrollo. Se realizan postmortems sin culpa después de incidentes de seguridad. Formación regular en seguridad para desarrolladores. Herramientas típicas: Semgrep, Trivy, Checkov, OWASP ZAP, HashiCorp Vault, Falco.\nNivel 4: Optimizado La seguridad está profundamente integrada en cada etapa del ciclo de vida del software. Las métricas guían las decisiones y el equipo mejora continuamente basándose en datos.\nCómo se ve:\nPuertas de seguridad en los pipelines que bloquean el despliegue si se encuentran problemas críticos. El tiempo medio de remediación (MTTR) se rastrea y se reduce continuamente. Se genera un Software Bill of Materials (SBOM) para cada release. Artefactos firmados y cadena de suministro verificada. Comprobaciones de cumplimiento automatizadas mapeadas a frameworks (SOC2, ISO 27001, PCI-DSS). Monitorización de seguridad en runtime con respuesta automatizada (Falco + reglas personalizadas). Ejercicios regulares de red team y chaos engineering para seguridad. Las métricas de seguridad forman parte de los dashboards de ingeniería. Herramientas típicas: Sigstore/cosign, OPA/Gatekeeper, Kyverno, integración con SIEM, plataformas de cumplimiento automatizado.\nNivel 5: Innovador La seguridad es una ventaja competitiva. El equipo contribuye a la comunidad de seguridad en general y empuja el estado del arte.\nCómo se ve:\nProgramas de bug bounty gestionados activamente. Herramientas de seguridad personalizadas desarrolladas para riesgos específicos de la organización. Machine learning aplicado a detección de anomalías y threat hunting. La seguridad es una característica que se vende a los clientes (certificaciones, informes de transparencia). Participación activa en proyectos de seguridad open-source. Arquitectura zero-trust completamente implementada. Policy as code gobierna toda la seguridad de infraestructura y aplicaciones. Herramientas típicas: Plataformas construidas a medida, herramientas de seguridad basadas en eBPF, SIEM avanzado con ML, service mesh zero-trust.\nDimensiones clave Un modelo de madurez no es unidimensional. Evalúa tu organización en estas dimensiones, ya que el progreso rara vez es parejo:\nSeguridad del código Nivel Prácticas Ad-Hoc Sin escaneo de código Reactivo SAST ocasional, revisiones de código manuales orientadas a seguridad Proactivo SAST/DAST automatizado en CI, directrices de revisión de código enfocadas en seguridad Optimizado Reglas personalizadas para patrones específicos de la organización, MTTR rastreado Innovador Revisión de código asistida por IA, sugerencias automáticas de corrección Seguridad de la infraestructura Nivel Prácticas Ad-Hoc Configuración manual de servidores, sin estándares de hardening Reactivo Checklists básicas de hardening, auditorías ocasionales Proactivo Escaneo de IaC, hardening automatizado, CIS benchmarks Optimizado Policy as code (OPA), detección de drift, remediación automatizada Innovador Infraestructura auto-reparable, redes zero-trust Monitorización y detección Nivel Prácticas Ad-Hoc Sin monitorización de seguridad Reactivo Recopilación básica de logs, revisión manual después de incidentes Proactivo Logging centralizado, alertas sobre patrones conocidos, monitorización en runtime Optimizado SIEM con reglas de correlación, playbooks de respuesta automatizada Innovador Detección de anomalías basada en ML, programas de threat hunting Respuesta a incidentes Nivel Prácticas Ad-Hoc Sin proceso, respuesta improvisada Reactivo Runbooks documentados, raramente probados Proactivo Ejercicios regulares de simulación, postmortems sin culpa, rotación de guardia Optimizado Clasificación automatizada de incidentes, tiempos de respuesta basados en SLA Innovador Chaos engineering para seguridad, contención automatizada Cumplimiento normativo Nivel Prácticas Ad-Hoc Recopilación manual de evidencias antes de auditorías Reactivo Seguimiento en hojas de cálculo, revisiones periódicas Proactivo Recopilación automatizada de evidencias, monitorización continua Optimizado Compliance as code, dashboards en tiempo real, informes automatizados Innovador Certificación continua, informes públicos de transparencia Checklist de autoevaluación Califica tu organización en cada punto (Sí / Parcial / No):\nFase de build:\nSAST se ejecuta automáticamente en cada pull request. El escaneo de dependencias alerta sobre CVEs conocidos. Las imágenes de contenedores se escanean antes de publicarse en un registry. Las plantillas de IaC se escanean en busca de configuraciones incorrectas. La detección de secretos impide que se hagan commit de credenciales. Fase de despliegue:\nLas puertas de seguridad pueden bloquear el despliegue por hallazgos críticos. Los artefactos están firmados y las firmas se verifican. Se genera un SBOM para cada release. Los cambios de infraestructura pasan por validación de policy-as-code. Fase de ejecución:\nLa monitorización de seguridad en runtime está activa (Falco, Sysdig, etc.). Logging centralizado con alertas relevantes para seguridad. La segmentación de red limita el radio de impacto. Los secretos se gestionan a través de un vault dedicado. Cultura y procesos:\nLos desarrolladores reciben formación regular en seguridad. Hay security champions integrados en los equipos de desarrollo. Se realizan postmortems sin culpa después de los incidentes. El threat modeling es parte del proceso de diseño de nuevas funcionalidades. Las métricas de seguridad se rastrean y revisan regularmente. Hoja de ruta para la progresión Subir de nivel de madurez no ocurre de la noche a la mañana. Aquí tienes una hoja de ruta práctica:\nDe Ad-Hoc a Reactivo (3-6 meses) Añade una herramienta SAST a tu pipeline de CI (empieza con Semgrep, tiene buenos valores por defecto y es rápido). Habilita el escaneo de dependencias (GitHub Dependabot, o trivy fs en CI). Documenta tu proceso de respuesta a incidentes, aunque sea básico. Realiza una sesión de formación en seguridad para el equipo. De Reactivo a Proactivo (6-12 meses) Añade escaneo de imágenes de contenedores y escaneo de IaC a los pipelines. Implementa detección de secretos en pre-commit hooks (gitleaks, detect-secrets). Nombra security champions en cada equipo. Comienza a hacer threat modeling para funcionalidades importantes. Realiza tu primer postmortem sin culpa después de un incidente. Despliega monitorización en runtime (Falco). De Proactivo a Optimizado (12-18 meses) Implementa puertas de seguridad que puedan bloquear despliegues. Rastrea el MTTR y establece objetivos de reducción. Genera SBOMs y firma los artefactos. Implementa policy-as-code para infraestructura (OPA/Gatekeeper). Mapea las comprobaciones automatizadas a frameworks de cumplimiento. Integra las métricas de seguridad en los dashboards de ingeniería. De Optimizado a Innovador (18+ meses) Lanza un programa de bug bounty. Construye herramientas de seguridad personalizadas para riesgos específicos de la organización. Implementa arquitectura zero-trust. Realiza ejercicios regulares de red team. Contribuye a proyectos de seguridad open-source. Aspectos culturales Las herramientas y los procesos son necesarios pero insuficientes. La cultura determina si las prácticas de seguridad realmente se mantienen.\nPostmortems sin culpa Cuando ocurre un incidente de seguridad, el instinto suele ser buscar a alguien a quien culpar. Esto lleva a la gente a ocultar errores y encubrir casi-incidentes. Los postmortems sin culpa le dan la vuelta a esto: se centran en los fallos sistémicos y las mejoras de procesos en lugar de la responsabilidad individual. La pregunta cambia de \u0026ldquo;quién cometió este error\u0026rdquo; a \u0026ldquo;qué permitió que este error ocurriera y cómo lo prevenimos\u0026rdquo;.\nSecurity Champions Un security champion es un desarrollador que asume responsabilidad adicional en materia de seguridad dentro de su equipo. No son ingenieros de seguridad a tiempo completo \u0026mdash; son desarrolladores que actúan como puente entre el equipo de seguridad y el equipo de desarrollo. Su papel incluye:\nRevisar pull requests relevantes para seguridad. Mantenerse al día en temas de seguridad y compartir conocimiento. Participar en sesiones de threat modeling. Ser el primer punto de contacto para preguntas de seguridad. Este modelo escala mucho mejor que tener un equipo central de seguridad revisando todo.\nHacer la seguridad fácil Si las prácticas de seguridad son dolorosas, la gente buscará atajos. El objetivo es hacer que la seguridad sea el camino más fácil:\nProporciona plantillas seguras y proyectos de inicio. Automatiza tanto como sea posible para que los desarrolladores no tengan que recordar pasos manuales. Da feedback rápido. Un escaneo SAST que tarda 30 minutos será ignorado; uno que tarda 30 segundos será utilizado. Celebra las mejoras de seguridad igual que celebras la entrega de funcionalidades. Conclusión Un modelo de madurez DevSecOps es una brújula, no un destino. El valor viene de una autoevaluación honesta, establecer objetivos realistas y hacer un progreso constante. Empieza donde estás, elige la dimensión donde la mejora tendrá mayor impacto y construye a partir de ahí. La seguridad es un deporte de equipo. Las mejores culturas de seguridad se construyen de forma incremental, una práctica a la vez.\n","date":"2023-10-08T10:00:00+01:00","permalink":"/p/modelo-de-madurez-de-devsecops/","title":"Modelo de madurez de DevSecOps"},{"content":"Punto de partida Llevo un tiempo corriendo K3s en un par de máquinas físicas en casa. Al principio lo instalé para aprender Kubernetes sin montar algo pesado, y lo fui usando para proyectos pequeños: algunas aplicaciones web, servicios de monitorización, cosas así. La instalación era perfectamente funcional pero nunca me había sentado a pensar en la seguridad con calma.\nHace unos meses decidí hacer ese ejercicio. Sin prisa, sin checklist genérica de internet. Solo mirar lo que tenía, entender qué estaba mal y arreglarlo.\nLo que encontré no era catastrófico, pero había bastantes cosas que no me gustaron. Lo escribo aquí porque K3s tiene particularidades respecto a un cluster Kubernetes estándar, y la mayoría de guías de bastionado hablan de kubeadm o clusters gestionados, no de instalaciones caseras con un binario único.\nLo que K3s tiene de diferente Antes de entrar en lo que hice, vale la pena entender qué hace distinto a K3s desde el punto de vista de seguridad.\nK3s empaqueta todo en un único binario: el API server, el scheduler, el controller manager, kubelet, kube-proxy y containerd. En lugar de etcd usa SQLite por defecto. El CNI por defecto es Flannel. El ingress controller por defecto es Traefik. Todo esto simplifica mucho la instalación, pero también significa que hay componentes activos que quizás no necesitas, y que algunas decisiones de diseño están pensadas para facilitar el uso, no para maximizar la seguridad.\nEl archivo de configuración está en /etc/rancher/k3s/config.yaml. Ahí es donde vive la mayoría de lo que voy a tocar.\nEl nodo antes que el cluster Antes de tocar nada de Kubernetes, el sistema operativo. El cluster corre en Debian, así que empecé por ahí.\nSSH Tenía autenticación por contraseña activa. Es lo primero que hay que quitar:\n1 2 3 4 # /etc/ssh/sshd_config PasswordAuthentication no PermitRootLogin no AllowUsers miusuario También cambié el puerto por defecto. No evita que alguien determinado te encuentre, pero sí elimina una cantidad enorme de ruido en los logs.\nFirewall con nftables La máquina tenía las interfaces de red completamente abiertas. Con un cluster K3s en casa, el API server (puerto 6443) no debería ser accesible desde fuera de tu red local. Mis reglas básicas con nftables:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 # Listar reglas activas nft list ruleset # Política por defecto restrictiva nft add chain inet filter input { type filter hook input priority 0 \\; policy drop \\; } # Permitir loopback y conexiones establecidas nft add rule inet filter input iifname lo accept nft add rule inet filter input ct state established,related accept # SSH solo desde red local nft add rule inet filter input ip saddr 192.168.1.0/24 tcp dport 22 accept # API server K3s solo desde red local nft add rule inet filter input ip saddr 192.168.1.0/24 tcp dport 6443 accept # Kubernetes node ports nft add rule inet filter input tcp dport 30000-32767 accept # Traefik (si lo usas como ingress) nft add rule inet filter input tcp dport { 80, 443 } accept # ICMP nft add rule inet filter input icmp type echo-request accept Lo que me sorprendió al revisar esto: el API server estaba escuchando en todas las interfaces y era alcanzable directamente desde la WAN porque el router tenía un port forward de otro servicio que arrastraba algo de tráfico. Pequeño susto, nada explotado, pero no era algo que quería dejar.\nParámetros del kernel K3s con el flag --protect-kernel-defaults verifica que ciertos parámetros del kernel estén configurados correctamente. Si no los tienes bien, el arranque falla con un mensaje claro. Mejor configurarlos antes:\n1 2 3 4 5 6 7 # /etc/sysctl.d/90-k3s-hardening.conf kernel.panic = 10 kernel.panic_on_oops = 1 vm.overcommit_memory = 1 vm.panic_on_oom = 0 fs.inotify.max_user_watches = 524288 fs.inotify.max_user_instances = 512 1 sysctl --system Configuración de K3s Con el nodo en orden, al cluster.\nArchivo de configuración base 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # /etc/rancher/k3s/config.yaml write-kubeconfig-mode: \u0026#34;0600\u0026#34; protect-kernel-defaults: true secrets-encryption: true kube-apiserver-arg: - \u0026#34;anonymous-auth=false\u0026#34; - \u0026#34;audit-log-path=/var/log/k3s/audit.log\u0026#34; - \u0026#34;audit-log-maxage=30\u0026#34; - \u0026#34;audit-policy-file=/etc/rancher/k3s/audit-policy.yaml\u0026#34; kube-controller-manager-arg: - \u0026#34;terminated-pod-gc-threshold=10\u0026#34; kubelet-arg: - \u0026#34;streaming-connection-idle-timeout=5m\u0026#34; - \u0026#34;protect-kernel-defaults=true\u0026#34; - \u0026#34;make-iptables-util-chains=true\u0026#34; Las tres líneas más importantes aquí:\nsecrets-encryption: true habilita el cifrado en reposo de los secrets de Kubernetes. Con K3s es un flag de primera clase, no hay que configurar un EncryptionConfiguration manual como en kubeadm. anonymous-auth=false elimina el acceso anónimo al API server. write-kubeconfig-mode: \u0026quot;0600\u0026quot; fuerza permisos restrictivos en el kubeconfig que K3s genera en /etc/rancher/k3s/k3s.yaml. Política de auditoría Sin audit logs, no sabes qué pasa en el cluster. Este es el mínimo razonable:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 # /etc/rancher/k3s/audit-policy.yaml apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: Metadata resources: - group: \u0026#34;\u0026#34; resources: [\u0026#34;secrets\u0026#34;] - level: RequestResponse resources: - group: \u0026#34;\u0026#34; resources: [\u0026#34;pods/exec\u0026#34;, \u0026#34;pods/attach\u0026#34;] - level: Request verbs: [\u0026#34;create\u0026#34;, \u0026#34;update\u0026#34;, \u0026#34;patch\u0026#34;, \u0026#34;delete\u0026#34;] - level: None users: [\u0026#34;system:kube-proxy\u0026#34;] verbs: [\u0026#34;watch\u0026#34;] resources: - group: \u0026#34;\u0026#34; resources: [\u0026#34;endpoints\u0026#34;, \u0026#34;services\u0026#34;, \u0026#34;services/status\u0026#34;] - level: Metadata omitStages: - RequestReceived Los logs van a /var/log/k3s/audit.log. En mi caso los recojo con Promtail y los mando a Loki, así puedo hacer queries desde Grafana cuando necesito revisar algo.\nKubeconfig El kubeconfig que genera K3s en /etc/rancher/k3s/k3s.yaml tiene credenciales de administrador. Un error que vi en mi propia configuración: tenía ese archivo copiado en ~/.kube/config con permisos 644. Cualquier proceso corriendo bajo mi usuario podía leerlo.\n1 2 # Permisos correctos chmod 600 ~/.kube/config Si tienes usuarios adicionales que necesitan acceso al cluster, crea ServiceAccounts o usa certificados de cliente con RBAC limitado. No distribuyas el kubeconfig de admin.\nCNI: de Flannel a Cilium Flannel viene por defecto en K3s. Funciona, pero no soporta NetworkPolicies por defecto. Eso significa que todos los pods se comunican entre sí sin restricciones.\nCambié a Cilium. El proceso con K3s requiere deshabilitar Flannel primero:\n1 2 3 # /etc/rancher/k3s/config.yaml (añadir) flannel-backend: none disable-network-policy: true Y luego instalar Cilium con Helm:\n1 2 3 4 5 6 7 8 9 helm repo add cilium https://helm.cilium.io/ helm install cilium cilium/cilium \\ --namespace kube-system \\ --set operator.replicas=1 \\ --set ipam.mode=kubernetes \\ --set kubeProxyReplacement=strict \\ --set k8sServiceHost=192.168.1.10 \\ --set k8sServicePort=6443 Con kubeProxyReplacement=strict Cilium también reemplaza kube-proxy, lo que da mejor rendimiento con eBPF y mejor visibilidad del tráfico de red.\nDespués del cambio, empecé a aplicar NetworkPolicies. La primera y más importante: denegación por defecto en todos los namespaces de aplicaciones:\n1 2 3 4 5 6 7 8 9 10 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all namespace: apps spec: podSelector: {} policyTypes: - Ingress - Egress A partir de ahí, permitir solo lo necesario explícitamente.\nSecrets: qué hacer cuando solo tienes K3s En un entorno corporativo usarías Vault o External Secrets Operator con AWS Secrets Manager o similar. En un homelab eso es overkill. Mi solución fue más simple:\nEl cifrado en reposo de K3s ya protege los secrets en la base de datos. Para los manifiestos en Git, uso age para cifrar los valores sensibles antes de commitearlos:\n1 2 # Cifrar un valor echo \u0026#34;mi-contraseña-real\u0026#34; | age -r $(cat ~/.config/age/recipient.txt) | base64 Y el valor cifrado va al repositorio. Para desplegarlo hay un paso manual de descifrado. No es tan cómodo como un operador automático, pero para un homelab es suficiente y no añade complejidad operativa.\nFalco para detección en tiempo de ejecución Todo lo anterior es prevención. Falco es detección: monitoriza las llamadas al sistema y genera alertas cuando algo sospechoso ocurre en un contenedor.\nLo instalé con Helm:\n1 2 3 4 5 helm repo add falcosecurity https://falcosecurity.github.io/charts helm install falco falcosecurity/falco \\ --namespace falco \\ --create-namespace \\ --set driver.kind=ebpf Las reglas por defecto ya cubren bastante: ejecución de shells en contenedores, escrituras en directorios del sistema, cambios de privilegios, conexiones de red inesperadas. Añadí algunas reglas propias para mi caso de uso específico.\nLas alertas van a Loki también. Así tengo en el mismo lugar los audit logs del API server y las alertas de Falco.\nPod Security Standards Con K3s en versión \u0026gt;= 1.25 puedes usar Pod Security Admission directamente. Apliqué el nivel baseline en los namespaces de aplicaciones y restricted donde era posible:\n1 2 3 4 5 6 7 apiVersion: v1 kind: Namespace metadata: name: apps labels: pod-security.kubernetes.io/enforce: baseline pod-security.kubernetes.io/warn: restricted El nivel restricted es estricto: requiere que los contenedores no corran como root, que el sistema de archivos raíz sea de solo lectura, y que se eliminen todas las capabilities de Linux. Algunas aplicaciones que tenía desplegadas no cumplían. Fui arreglándolo de una en una antes de subir el nivel de enforce.\nLo que dejé para después No todo está perfecto. Hay cosas que sé que debería hacer y todavía no he hecho:\nRootless K3s: se puede correr K3s completamente sin root, lo que reduce el impacto de una posible escalada de privilegios. Lo he mirado, tiene algunas limitaciones con ciertas características de red, pero para mi caso de uso debería funcionar.\nVerificación de imágenes con cosign: firmar y verificar imágenes antes de desplegarlas. Tengo un registro privado para mis imágenes y las de terceros que uso, pero no estoy verificando firmas todavía.\nCIS Benchmark: K3s tiene documentación oficial para el benchmark CIS K3s. Lo he revisado parcialmente pero no he pasado kube-bench de forma sistemática para ver qué queda pendiente.\nLo que aprendí La instalación por defecto de K3s es sorprendentemente razonable para lo que es: una distribución pensada para ser fácil de desplegar. Pero \u0026ldquo;razonable\u0026rdquo; no es lo mismo que \u0026ldquo;bastionada\u0026rdquo;.\nLo que más me sorprendió fue lo fácil que resultó hacer la mayoría de cambios. K3s tiene flags de primera clase para muchas cosas que en kubeadm requieren configuración manual. El secrets-encryption, el protect-kernel-defaults, la política de auditoría directamente en el archivo de configuración. No es tan difícil si te sientas a leer la documentación.\nEl mayor riesgo en un homelab no es que alguien en internet te ataque directamente. Es que tienes un montón de servicios corriendo en la misma red que tu vida personal, y si alguno se compromete, el radio de explosión puede ser mayor de lo que parece. Vale la pena tomárselo en serio aunque sea un entorno de juguete.\n","date":"2023-09-14T00:00:00Z","permalink":"/p/c%C3%B3mo-bastion%C3%A9-mi-homelab-con-k3s/","title":"Cómo bastioné mi homelab con K3s"},{"content":"La superficie de ataque de los contenedores Los contenedores dan aislamiento de procesos, no de seguridad. Un contenedor mal configurado puede exponer el kernel, filtrar secretos o servir como punto de pivote. Primero, entiende la superficie de ataque:\nImágenes - Librerías vulnerables, credenciales hardcodeadas, herramientas innecesarias Runtime - Vulnerabilidades que permiten escapes Orquestador (RBAC de Kubernetes, network policies) - Servicios expuestos, permisos excesivos Cadena de suministro - Imágenes base o dependencias comprometidas Secretos - En imágenes o variables de entorno que cualquier proceso puede leer La seguridad requiere defensa en profundidad: build, ship, run.\nSeguridad de las imágenes Usa imágenes base mínimas Cada paquete adicional en una imagen de contenedor es una vulnerabilidad potencial. Prefiere imágenes base mínimas:\n1 2 3 4 # Preferir distroless o Alpine sobre distribuciones completas FROM gcr.io/distroless/static-debian11 # o FROM alpine:3.18 Las imágenes distroless contienen solo tu aplicación y sus dependencias de runtime \u0026mdash; sin shell, sin gestor de paquetes, sin binarios innecesarios. Esto reduce drásticamente la superficie de ataque.\nMulti-Stage Builds Los multi-stage builds permiten compilar en una etapa y copiar solo el artefacto final a una imagen de runtime mínima:\n1 2 3 4 5 6 7 8 9 10 11 12 13 # Build stage FROM golang:1.21 AS builder WORKDIR /app COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -o /app/server # Runtime stage FROM gcr.io/distroless/static-debian11 COPY --from=builder /app/server /server USER nonroot:nonroot ENTRYPOINT [\u0026#34;/server\u0026#34;] Las herramientas de compilación, el código fuente y los archivos intermedios nunca llegan a la imagen final.\nNunca ejecutes como root Ejecutar contenedores como root significa que un escape del contenedor le da al atacante acceso root en el host. Siempre especifica un usuario no-root:\n1 2 3 # Crear un usuario no-root RUN addgroup -S appgroup \u0026amp;\u0026amp; adduser -S appuser -G appgroup USER appuser En Kubernetes, esto se refuerza con Pod Security Standards (más detalles abajo).\nComparación de Dockerfile seguro vs. inseguro Aquí hay una comparación lado a lado de errores comunes frente a prácticas seguras:\n1 2 3 4 5 6 7 8 # INSEGURO - NO hagas esto FROM ubuntu:latest RUN apt-get update \u0026amp;\u0026amp; apt-get install -y curl wget vim COPY . /app RUN echo \u0026#34;DB_PASSWORD=supersecret\u0026#34; \u0026gt; /app/.env EXPOSE 22 80 443 USER root CMD [\u0026#34;python3\u0026#34;, \u0026#34;/app/main.py\u0026#34;] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # SEGURO - Sigue este patrón FROM python:3.11-slim AS builder WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir --user -r requirements.txt FROM python:3.11-slim RUN groupadd -r appgroup \u0026amp;\u0026amp; useradd -r -g appgroup appuser WORKDIR /app COPY --from=builder /root/.local /home/appuser/.local COPY --chown=appuser:appgroup . . ENV PATH=/home/appuser/.local/bin:$PATH EXPOSE 8080 USER appuser HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:8080/health || exit 1 CMD [\u0026#34;python3\u0026#34;, \u0026#34;main.py\u0026#34;] Diferencias clave: imagen base mínima, multi-stage build, sin secretos en la imagen, usuario no-root, solo los puertos necesarios expuestos, health check incluido.\nEscaneo de imágenes con Trivy Trivy es un escáner de vulnerabilidades open-source que analiza imágenes de contenedores, sistemas de archivos y configuraciones de IaC. Intégralo en tu pipeline de CI para detectar vulnerabilidades antes del despliegue.\nEscaneo básico de imagen 1 2 3 4 5 6 7 8 # Escanear una imagen en busca de vulnerabilidades trivy image python:3.11-slim # Escanear con filtro de severidad trivy image --severity HIGH,CRITICAL myapp:latest # Fallar el CI si se encuentran vulnerabilidades críticas trivy image --exit-code 1 --severity CRITICAL myapp:latest Escaneo en CI/CD Añade Trivy a tu pipeline para que ninguna imagen con vulnerabilidades críticas llegue a producción:\n1 2 3 4 5 6 7 8 # Ejemplo de paso en GitHub Actions - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: image-ref: \u0026#39;myapp:${{ github.sha }}\u0026#39; format: \u0026#39;table\u0026#39; exit-code: \u0026#39;1\u0026#39; severity: \u0026#39;CRITICAL,HIGH\u0026#39; Escaneo de IaC y sistemas de archivos Trivy va más allá de las imágenes de contenedores:\n1 2 3 4 5 # Escanear manifiestos de Kubernetes en busca de configuraciones incorrectas trivy config ./k8s-manifests/ # Escanear un sistema de archivos en busca de secretos y vulnerabilidades trivy fs --security-checks vuln,secret ./ Seguridad en runtime con Falco Mientras que el escaneo detecta vulnerabilidades en tiempo de build, Falco monitoriza los contenedores en tiempo de ejecución. Utiliza instrumentación a nivel de kernel para detectar comportamientos sospechosos:\nEjecuciones inesperadas de shell dentro de contenedores. Procesos que leen archivos sensibles (/etc/shadow, /etc/passwd). Conexiones de red salientes a destinos inesperados. Intentos de escalada de privilegios. Ejemplo de reglas Falco 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 - rule: Terminal shell in container desc: Detect a shell being spawned in a container condition: \u0026gt; spawned_process and container and proc.name in (bash, sh, zsh, dash) output: \u0026gt; Shell spawned in container (user=%user.name container=%container.name shell=%proc.name parent=%proc.pname) priority: WARNING - rule: Read sensitive file in container desc: Detect reads of sensitive files condition: \u0026gt; open_read and container and fd.name in (/etc/shadow, /etc/passwd) output: \u0026gt; Sensitive file read in container (user=%user.name file=%fd.name container=%container.name) priority: ERROR Despliega Falco como un DaemonSet en tu cluster de Kubernetes para obtener visibilidad sobre el comportamiento en runtime en todos los nodos.\nSeguridad en Kubernetes Pod Security Standards Los Pod Security Standards de Kubernetes definen tres niveles de restricción:\nPrivileged \u0026mdash; Sin restricciones (solo para cargas de trabajo a nivel de sistema). Baseline \u0026mdash; Previene escaladas de privilegios conocidas. Restricted \u0026mdash; Altamente restringido, siguiendo las mejores prácticas de seguridad. Aplícalos a nivel de namespace:\n1 2 3 4 5 6 7 8 apiVersion: v1 kind: Namespace metadata: name: production labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/audit: restricted pod-security.kubernetes.io/warn: restricted NetworkPolicies Por defecto, todos los pods en Kubernetes pueden comunicarse entre sí. Las NetworkPolicies permiten restringir el tráfico:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: api-allow namespace: production spec: podSelector: matchLabels: app: api policyTypes: - Ingress - Egress ingress: - from: - podSelector: matchLabels: app: frontend ports: - protocol: TCP port: 8080 egress: - to: - podSelector: matchLabels: app: database ports: - protocol: TCP port: 5432 Esta política asegura que el pod de la API solo recibe tráfico del frontend y solo envía tráfico a la base de datos.\nRBAC Sigue el principio de mínimo privilegio. Evita dar cluster-admin a service accounts. Crea roles específicos:\n1 2 3 4 5 6 7 8 9 apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: namespace: production name: deployment-manager rules: - apiGroups: [\u0026#34;apps\u0026#34;] resources: [\u0026#34;deployments\u0026#34;] verbs: [\u0026#34;get\u0026#34;, \u0026#34;list\u0026#34;, \u0026#34;watch\u0026#34;, \u0026#34;update\u0026#34;, \u0026#34;patch\u0026#34;] Audita regularmente los RBAC bindings con herramientas como kubectl-who-can o rbac-tool.\nGestión de secretos Nunca almacenes secretos en imágenes de contenedores, variables de entorno en Dockerfiles en texto plano ni en control de versiones. En su lugar:\nUsa Kubernetes Secrets (cifrados en reposo con KMS). Usa gestores de secretos externos: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault. Usa el External Secrets Operator para sincronizar secretos de proveedores externos en Kubernetes. Rota los secretos regularmente y audita el acceso. Seguridad de la cadena de suministro Imágenes firmadas Firma tus imágenes de contenedores con cosign (parte del proyecto Sigstore) y verifica las firmas antes del despliegue:\n1 2 3 4 5 # Firmar una imagen cosign sign --key cosign.key myregistry/myapp:v1.0 # Verificar una firma cosign verify --key cosign.pub myregistry/myapp:v1.0 SBOM (Software Bill of Materials) Genera un SBOM para cada imagen para poder verificar rápidamente si un CVE recién publicado afecta a tus contenedores en ejecución:\n1 2 3 4 5 # Generar SBOM con Trivy trivy image --format spdx-json --output sbom.json myapp:latest # O usar syft syft myapp:latest -o spdx-json \u0026gt; sbom.json Checklist de seguridad de contenedores Usa esta checklist para evaluar tu postura de seguridad en contenedores:\nLas imágenes base son mínimas (distroless o Alpine). Se usan multi-stage builds para excluir herramientas de compilación. Los contenedores se ejecutan como usuarios no-root. Las imágenes se escanean en busca de vulnerabilidades en CI/CD. No se almacenan secretos en imágenes ni en variables de entorno en texto plano. Los Pod Security Standards de Kubernetes están habilitados. Las NetworkPolicies restringen la comunicación entre pods. RBAC sigue el mínimo privilegio. La monitorización de seguridad en runtime está activa (Falco o equivalente). Las imágenes están firmadas y las firmas se verifican antes del despliegue. Se generan y almacenan SBOMs para todas las imágenes en producción. Los secretos se gestionan a través de un gestor de secretos externo. Las políticas de pull de imágenes están configuradas como Always para tags mutables. Se realizan auditorías de seguridad y pruebas de penetración de forma regular. Conclusión La seguridad en contenedores es una práctica continua, no una tarea puntual. Empieza con lo básico: imágenes mínimas, usuarios no-root, escaneo. Luego añade monitorización en runtime, network policies, verificación de cadena de suministro, aplicación automatizada. Cada capa reduce el impacto y te acerca a seguridad real.\n","date":"2023-07-14T10:00:00+01:00","permalink":"/p/buenas-pr%C3%A1cticas-de-seguridad-en-contenedores/","title":"Buenas prácticas de seguridad en contenedores"},{"content":"Qué es MLOps y por qué importa MLOps trata de desplegar y mantener modelos en producción de forma fiable y eficiente. Conecta la experimentación en ciencia de datos con la ingeniería de producción. Sin MLOps, chocas con los mismos problemas: modelos que funcionan en notebooks pero fallan en producción, sin reproducibilidad, traspasos dolorosos entre equipos, cero visibilidad una vez desplegados.\nLa idea: trata sistemas de ML con el mismo rigor que software. Control de versiones, pruebas automatizadas, entrega continua, monitorización. Solo reconoce que datos y modelos introducen desafíos únicos.\nEl ciclo de vida de ML Antes de entrar en los patrones, conviene entender las etapas por las que pasa todo sistema de ML:\nIngesta y validación de datos \u0026mdash; Recopilar, limpiar y validar los datos de entrada. Ingeniería de features \u0026mdash; Transformar los datos en bruto en features que el modelo pueda consumir. Entrenamiento del modelo \u0026mdash; Ejecutar experimentos, ajustar hiperparámetros, seleccionar algoritmos. Evaluación del modelo \u0026mdash; Validar la calidad del modelo con datos de prueba y métricas de negocio. Despliegue del modelo \u0026mdash; Servir predicciones en producción (batch o tiempo real). Monitorización y retroalimentación \u0026mdash; Seguimiento del rendimiento, detección de drift, activación de reentrenamiento. Cada etapa tiene sus propios modos de fallo, y los patrones que se presentan a continuación los abordan de forma sistemática.\nPatrones de diseño clave Feature store Un feature store es un repositorio centralizado para almacenar, compartir y servir features de ML. En lugar de que cada equipo recalcule features desde cero, un feature store proporciona:\nConsistencia entre entrenamiento y serving (evitando el training-serving skew). Reutilización entre equipos y modelos. Corrección temporal para valores históricos de features. Herramientas como Feast, Tecton y Hopsworks implementan este patrón. Si varios equipos están duplicando pipelines de features, un feature store probablemente merezca la inversión.\nModel registry Un model registry actúa como catálogo versionado de modelos entrenados. Almacena artefactos del modelo, metadatos (hiperparámetros, métricas, versión de los datos de entrenamiento) y etapa del ciclo de vida (staging, producción, archivado).\nMLflow Model Registry es una de las soluciones más adoptadas. Permite promover modelos a través de etapas con flujos de aprobación y rastrear la trazabilidad desde el experimento hasta producción.\nCT/CI/CD para ML Los pipelines tradicionales de CI/CD construyen y despliegan código. Los pipelines de ML necesitan tres bucles:\nContinuous Training (CT) \u0026mdash; Reentrenar modelos automáticamente cuando cambian los datos o el rendimiento se degrada. Continuous Integration (CI) \u0026mdash; Validar no solo el código sino también esquemas de datos, expectativas de features y umbrales de calidad del modelo. Continuous Delivery (CD) \u0026mdash; Desplegar modelos validados a la infraestructura de serving de forma automática. Un flujo típico podría ser: llegan datos nuevos al data lake, CT lanza el reentrenamiento, CI ejecuta las pruebas de validación y CD publica el modelo en producción si todas las verificaciones pasan.\nA/B Testing El A/B testing para modelos consiste en dirigir un porcentaje del tráfico a un modelo nuevo mientras el resto sigue llegando al modelo actual en producción. Se miden métricas de negocio (tasa de conversión, clicks, ingresos) en lugar de solo métricas de ML (accuracy, F1). Este patrón es esencial porque un modelo que puntúa bien en offline puede funcionar mal en producción debido a bucles de retroalimentación, latencia o diferencias en la distribución.\nShadow Deployment En el modo shadow, el modelo nuevo recibe tráfico de producción y genera predicciones, pero esas predicciones no se sirven a los usuarios. En su lugar, se registran junto a las predicciones del modelo actual para una comparación offline. Es una forma de bajo riesgo de validar un modelo con tráfico real antes de exponerlo a los usuarios.\nCanary releases para modelos Similar a los canary deployments en software, se despliega un nuevo modelo a una pequeña fracción del tráfico (por ejemplo, el 5%), se monitorizan las métricas clave y se aumenta gradualmente el tráfico si todo se mantiene saludable. Si las métricas se degradan, se realiza un rollback automático. Este patrón se combina bien con A/B testing pero se centra más en la mitigación de riesgos que en la experimentación.\nPanorama de herramientas Herramienta Uso principal Punto fuerte MLflow Tracking de experimentos, model registry Flexible, independiente del proveedor Kubeflow Pipelines de ML de extremo a extremo en Kubernetes Escalable, cloud-native DVC Versionado de datos y modelos Flujo de trabajo similar a Git para datos Weights \u0026amp; Biases Tracking de experimentos, visualización Excelente interfaz y colaboración Feast Feature store Open-source, listo para producción Seldon Core Model serving en Kubernetes Estrategias de despliegue avanzadas No existe una herramienta que cubra todo. La mayoría de las configuraciones en producción combinan varias, eligiendo según la experiencia del equipo y las restricciones de infraestructura.\nEjemplo: tracking de experimentos con MLflow Este es un ejemplo mínimo de cómo registrar un experimento con MLflow:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import mlflow import mlflow.sklearn from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score, f1_score from sklearn.model_selection import train_test_split # Start an MLflow run with mlflow.start_run(run_name=\u0026#34;rf-baseline\u0026#34;): # Log parameters n_estimators = 100 max_depth = 10 mlflow.log_param(\u0026#34;n_estimators\u0026#34;, n_estimators) mlflow.log_param(\u0026#34;max_depth\u0026#34;, max_depth) # Train model model = RandomForestClassifier( n_estimators=n_estimators, max_depth=max_depth, random_state=42 ) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2) model.fit(X_train, y_train) # Log metrics predictions = model.predict(X_test) mlflow.log_metric(\u0026#34;accuracy\u0026#34;, accuracy_score(y_test, predictions)) mlflow.log_metric(\u0026#34;f1_score\u0026#34;, f1_score(y_test, predictions, average=\u0026#34;weighted\u0026#34;)) # Log model artifact mlflow.sklearn.log_model(model, \u0026#34;random-forest-model\u0026#34;) Cada ejecución queda registrada con sus parámetros, métricas y artefactos, lo que facilita comparar experimentos y reproducir resultados.\nAnti-patrones a evitar No versionar datos ni modelos. Si no puedes reproducir un entrenamiento de hace seis meses, tienes un problema. Versiona todo: código, datos, configuración y artefactos del modelo.\nTraining-serving skew. Cuando la lógica de cálculo de features difiere entre entrenamiento y serving, las predicciones se degradan de forma silenciosa. Un feature store o una librería compartida de cálculo de features ayuda a eliminar esto.\nDespliegue manual. Copiar archivos del modelo a un servidor es una receta para incidentes. Automatiza el despliegue mediante pipelines con puertas de validación adecuadas.\nIgnorar la monitorización del modelo. Los modelos se degradan con el tiempo a medida que cambian las distribuciones de entrada. Sin monitorización, solo te enteras cuando un usuario se queja o una métrica de negocio cae. Configura alertas para cambios en la distribución de predicciones, latencia y calidad de datos.\nPipelines monolíticos. Un pipeline único que hace todo desde la ingesta de datos hasta el serving del modelo es frágil y difícil de depurar. Divide los pipelines en etapas modulares e independientemente testeables.\nSobreingeniería prematura. No todos los proyectos de ML necesitan Kubeflow y un feature store desde el día uno. Empieza simple, identifica cuellos de botella y adopta patrones a medida que la complejidad del sistema crece.\nNiveles de madurez MLOps Las organizaciones suelen progresar a través de varios niveles de madurez:\nNivel 0: Manual Modelos entrenados en notebooks. Despliegue manual (copia de archivos, reinicio manual de la API). Sin tracking de experimentos. Sin monitorización. Nivel 1: automatización del pipeline de ML Pipelines de entrenamiento automatizados. Tracking de experimentos con herramientas como MLflow. Validación básica del modelo antes del despliegue. Algo de monitorización de las predicciones del modelo. Nivel 2: CI/CD para ML Testing automatizado de datos, features y calidad del modelo. Continuous training activado por cambios en los datos o por programación. Despliegue automatizado con canary o shadow releases. Monitorización completa con alertas y rollback automático. Nivel 3: MLOps completo Feature store para la gestión consistente de features. Model registry con gobernanza y flujos de aprobación. A/B testing integrado en el proceso de despliegue. Trazabilidad de datos y modelos de extremo a extremo. Pipelines auto-reparables que detectan y responden al drift automáticamente. La mayoría de los equipos se encuentran entre el Nivel 0 y el Nivel 1. El objetivo no es saltar al Nivel 3 de inmediato, sino progresar de forma incremental, abordando primero los cuellos de botella más dolorosos.\nConclusión MLOps consiste en aplicar patrones de ingeniería a los desafíos únicos de ML. Empieza con tracking de experimentos y automatización básica, luego añade feature stores, registries y estrategias avanzadas conforme crezcas. La clave: trata modelos como artefactos de producción. Versiona, prueba, monitoriza, mejora.\n","date":"2023-03-22T10:00:00+01:00","permalink":"/p/patrones-de-dise%C3%B1o-para-pipelines-mlops/","title":"Patrones de diseño para pipelines MLOps"},{"content":"¿Qué es AIOps? AIOps (Artificial Intelligence for IT Operations) aplica machine learning y analítica de datos a los datos operativos (logs, métricas, eventos, trazas) para automatizar y mejorar flujos de trabajo. Gartner acuñó el término en 2017, pero la idea es simple: usar algoritmos para gestionar el volumen y la complejidad que los humanos no pueden manejar manualmente.\nEn términos prácticos, las plataformas AIOps ingieren datos de herramientas de monitorización, sistemas APM, agregadores de logs y fuentes de eventos. Aplican modelos de ML para detectar anomalías, correlacionar eventos, identificar causas raíz y, en algunos casos, desencadenar remediación automatizada. El objetivo es reducir el tiempo medio de detección (MTTD) y el tiempo medio de resolución (MTTR) mientras se libera a los equipos de operaciones de la fatiga por alertas.\nPor qué la monitorización tradicional se queda corta La monitorización funcionaba bien cuando los sistemas eran simples. Tenías pocos servidores, unas pocas apps y un número limitado de métricas. Un umbral estático de CPU o un regex en logs era suficiente.\nLa infraestructura moderna rompió ese modelo:\nEscala: Un clúster de Kubernetes genera millones de métricas y logs por minuto. No puedes vigilar dashboards a esa escala. Complejidad: Los microservicios crean dependencias enredadas. Una petición puede atravesar docenas de servicios. Encontrar qué causó una latencia significa correlacionar datos entre todos. Entornos dinámicos: Auto-scaling, contenedores efímeros, serverless. Las baselines cambian constantemente y los umbrales estáticos explotan con falsos positivos. Fatiga por alertas: Los equipos se hunden en alertas. Cuando el 90% es ruido, ese crítico 10% desaparece. Los ingenieros empiezan a ignorar todo. AIOps no reemplaza la monitorización. Se sitúa encima de lo que ya tienes y lo hace más inteligente.\nCapacidades clave 1. Detección de anomalías En lugar de umbrales estáticos, AIOps usa modelos de ML (frecuentemente análisis de series temporales, clustering o autoencoders) para aprender qué aspecto tiene lo \u0026ldquo;normal\u0026rdquo; para cada métrica y servicio. Cuando el comportamiento se desvía significativamente de la línea base aprendida, se marca una anomalía.\nEsto maneja el problema de la línea base dinámica. Si tu aplicación normalmente ve un pico de tráfico cada lunes a las 9 de la mañana, el modelo aprende ese patrón y no alerta por ello. Pero un pico inesperado a las 3 de la madrugada de un miércoles sí se marca.\n2. Correlación de eventos Un único problema de infraestructura puede generar cientos o miles de alertas relacionadas en diferentes herramientas de monitorización. AIOps correlaciona estos eventos — agrupándolos por tiempo, topología y relaciones causales — para presentar un único incidente en lugar de un muro de alertas.\nPor ejemplo, un fallo en un switch de red podría disparar alertas en: el propio switch, todos los servidores conectados (conectividad perdida), todas las aplicaciones en esos servidores (fallos en health checks), y servicios downstream (errores de timeout). Una plataforma AIOps correlaciona todos estos en un incidente: \u0026ldquo;Switch de red X ha fallado.\u0026rdquo;\n3. Análisis de causa raíz Más allá de la correlación, AIOps intenta identificar la causa raíz de un incidente. Al comprender la topología de tu infraestructura y la cadena causal de eventos, puede sugerir que el fallo del switch de red es la causa raíz, en lugar de presentar el timeout de la aplicación como un problema independiente.\nAquí es donde el valor se vuelve tangible. En lugar de que un ingeniero de guardia pase 30 minutos rastreando a través de dashboards y logs, la plataforma muestra la causa raíz probable inmediatamente.\n4. Auto-remediación Las implementaciones más maduras de AIOps cierran el ciclo disparando acciones de remediación automatizadas. Si se detecta un patrón conocido (disco llenándose, un pod en CrashLoopBackOff, un proceso descontrolado consumiendo memoria), la plataforma puede ejecutar runbooks predefinidos automáticamente.\nEjemplos:\nReiniciar un pod o servicio caído. Escalar un deployment cuando se detecta carga anómala. Limpiar un directorio de logs cuando el uso de disco supera un umbral dinámico. Disparar un failover cuando una base de datos primaria deja de responder. La auto-remediación requiere un diseño cuidadoso. Empieza con acciones de bajo riesgo y amplía conforme crece la confianza.\nPlataformas y herramientas comunes El panorama de AIOps incluye tanto plataformas comerciales como bloques de construcción open-source:\nPlataformas comerciales Plataforma Fortalezas Dynatrace Auto-descubrimiento robusto, motor de IA (Davis), observabilidad full-stack Datadog Monitorización unificada + alertas con ML, detección de anomalías Watchdog Splunk ITSI Analítica de logs potente + toolkit de ML, bueno para correlación de eventos Moogsoft Pionero en el espacio AIOps, fuerte correlación de eventos y reducción de ruido BigPanda Enfocado en correlación de eventos y automatización, se integra con herramientas existentes PagerDuty Gestión de incidentes con reducción de ruido por ML y agrupación inteligente Bloques de construcción open-source Puedes ensamblar un stack similar a AIOps con componentes open-source:\nRecolección de datos: Prometheus, Grafana Agent, OpenTelemetry Collector, Fluentd/Fluent Bit. Almacenamiento de datos: Prometheus (métricas), Elasticsearch/OpenSearch (logs), Jaeger/Tempo (trazas). Detección de anomalías: Facebook Prophet, Isolation Forest (scikit-learn), luminol, Grafana ML. Correlación de eventos: Lógica personalizada sobre streams de eventos, o StackStorm para automatización dirigida por eventos. Alertas y automatización: Alertmanager, Grafana OnCall, StackStorm, Rundeck. Construir un stack AIOps personalizado es significativamente más trabajo que usar una plataforma comercial, pero te da control total y evita el vendor lock-in. Un punto medio razonable es usar una plataforma comercial para las capacidades core de AIOps mientras mantienes tu pipeline de datos en open-source.\nCasos de uso prácticos Reducción de ruido en gestión de alertas Un equipo que recibe más de 500 alertas al día implementa correlación de eventos AIOps. Las alertas relacionadas se agrupan en incidentes, los duplicados se suprimen y las alertas fluctuantes se silencian. El volumen de alertas baja un 80%, y el ingeniero de guardia puede enfocarse en incidentes reales.\nPlanificación proactiva de capacidad Los modelos AIOps analizan tendencias históricas de uso de recursos y predicen cuándo se alcanzarán los límites de capacidad. En lugar de reaccionar a una alerta de disco lleno a las 2 de la madrugada, la plataforma predice el problema con dos semanas de antelación y crea un ticket para que el equipo lo aborde en horario laboral.\nRespuesta a incidentes más rápida Durante una caída de producción, la plataforma AIOps correlaciona alertas de todo el stack de monitorización, identifica la causa raíz (un despliegue reciente que introdujo una fuga de memoria) y muestra el commit del despliegue relevante. El MTTR baja de 45 minutos a 10 minutos.\nEscalado automático La plataforma detecta patrones de tráfico anómalos que se desvían de la línea base aprendida. En lugar de esperar a que la CPU alcance el 80% (el umbral estático), dispara una acción de scale-up basada en la tasa de cambio, asegurando que la capacidad está lista antes de que los usuarios experimenten degradación.\nCómo encaja AIOps en los flujos de trabajo DevOps AIOps no es un reemplazo de las prácticas DevOps. Es una capa de mejora:\n1 2 3 4 5 Código ──\u0026gt; CI/CD Pipeline ──\u0026gt; Deploy ──\u0026gt; Observar ──\u0026gt; Capa AIOps ──\u0026gt; Actuar │ │ Monitoring Stack Modelos ML (métricas, logs, (detección de anomalías, trazas, eventos) correlación, RCA) Los desarrolladores se benefician de una identificación más rápida de la causa raíz cuando su código causa problemas en producción. Los equipos de operaciones se benefician de la reducción de ruido, remediación automatizada y alertas proactivas. Los equipos SRE se benefician del seguimiento de SLOs basado en datos y el análisis de tasa de consumo del error budget. AIOps funciona mejor cuando tu base de observabilidad es sólida. Si no estás recolectando buenos datos (logs estructurados, métricas significativas, trazas distribuidas), los modelos de ML no producirán insights significativos. Arregla primero tu observabilidad, luego añade AIOps encima.\nPrimeros pasos: Un camino pragmático Si estás considerando AIOps, aquí tienes un enfoque práctico:\nAudita tu stack de observabilidad actual. ¿Qué datos estás recolectando? ¿Los logs están estructurados? ¿Las métricas están etiquetadas de forma consistente? ¿Las trazas se propagan entre servicios? AIOps es tan bueno como los datos que ingiere.\nEmpieza con la reducción de ruido. Esta es la fruta que cuelga más baja. Implementa agrupación y deduplicación de alertas. Incluso una correlación básica basada en reglas (antes de cualquier ML) reducirá la fatiga por alertas significativamente.\nAñade detección de anomalías a métricas clave. Elige 3-5 métricas críticas de negocio e infraestructura. Aplica un modelo de detección de anomalías de series temporales. Facebook Prophet o recording rules de Prometheus con ajustes estacionales son buenos puntos de partida.\nImplementa remediación automatizada para problemas conocidos. Identifica los 5 incidentes recurrentes principales. Escribe runbooks para ellos. Automatiza los runbooks usando StackStorm, Rundeck o el motor de automatización de tu plataforma.\nEvalúa una plataforma comercial cuando la complejidad lo requiera. Si tienes cientos de servicios, múltiples herramientas de monitorización y un equipo de operaciones creciente, la inversión en una plataforma AIOps comercial puede justificarse solo por la reducción en MTTR.\nMide el impacto. Sigue MTTD, MTTR, ratio alerta-a-incidente y tasa de falsos positivos. Sin métricas, no puedes probar que AIOps vale la pena.\nAIOps no es magia. Es un conjunto de técnicas que, aplicadas a buenos datos operativos, pueden reducir la carga sobre los equipos y mejorar la fiabilidad. Empieza pequeño, mide todo, y escala lo que funcione.\n","date":"2022-12-05T00:00:00Z","permalink":"/p/introducci%C3%B3n-a-aiops-operaciones-de-ti-inteligentes/","title":"Introducción a AIOps: operaciones de TI inteligentes"},{"content":"Por qué importa la infraestructura como código Gestionar infraestructura manualmente a través de consolas web o scripts ad-hoc crea problemas que se acumulan con el tiempo: entornos inconsistentes, cambios sin documentar, rollbacks imposibles y el clásico \u0026ldquo;funciona en mi máquina\u0026rdquo; extendido a servidores enteros.\nLa Infraestructura como Código (IaC) resuelve esto tratando la infraestructura como el código de aplicación: se escribe, versiona, revisa, prueba y aplica mediante flujos de trabajo automatizados. Los beneficios llegan rápidamente:\nReproducibilidad: Levanta entornos idénticos en minutos, no en días. Control de versiones: Cada cambio de infraestructura pasa por un PR con revisión de código. Documentación por defecto: El código es la documentación de cómo es tu infraestructura. Recuperación ante desastres: Reconstruye todo desde código si una región cae. Visibilidad de costes: Revisa los cambios de infraestructura antes de aplicarlos (y antes de que empiecen a costar dinero). Terraform vs otras herramientas Existen varias herramientas de IaC. Así es como Terraform se compara con las principales alternativas:\nCaracterística Terraform Pulumi CloudFormation Ansible Lenguaje HCL (declarativo) Python, TypeScript, Go, etc. JSON/YAML YAML (procedural) Soporte cloud Multi-cloud Multi-cloud Solo AWS Multi-cloud (vía módulos) Gestión de estado Fichero de estado explícito Gestionado por servicio Pulumi Gestionado por AWS Sin estado Curva de aprendizaje Moderada Varía según lenguaje Moderada Baja Ecosistema Enorme ecosistema de providers En crecimiento Solo AWS pero profundo Enorme ecosistema de roles Ideal para Infra multi-cloud Equipos que prefieren lenguajes de propósito general Entornos solo AWS Gestión de configuración El punto fuerte de Terraform es el aprovisionamiento de infraestructura multi-cloud con un enfoque declarativo. Si estás solo en AWS y quieres integración estrecha, CloudFormation es razonable. Si tu equipo prefiere escribir Python en lugar de HCL, Pulumi merece una mirada. Pero para la mayoría de equipos que gestionan infraestructura entre distintos proveedores, Terraform es la elección pragmática.\nConceptos fundamentales Providers Los providers son plugins que permiten a Terraform interactuar con APIs — AWS, Azure, GCP, Kubernetes, GitHub, Cloudflare y cientos más.\n1 2 3 4 5 6 7 8 9 10 11 12 terraform { required_providers { aws = { source = \u0026#34;hashicorp/aws\u0026#34; version = \u0026#34;~\u0026gt; 5.0\u0026#34; } } } provider \u0026#34;aws\u0026#34; { region = \u0026#34;eu-west-1\u0026#34; } Resources Los resources son los bloques de construcción fundamentales. Cada bloque resource describe un objeto de infraestructura.\n1 2 3 4 5 6 7 8 resource \u0026#34;aws_instance\u0026#34; \u0026#34;web\u0026#34; { ami = \u0026#34;ami-0c55b159cbfafe1f0\u0026#34; instance_type = \u0026#34;t3.micro\u0026#34; tags = { Name = \u0026#34;web-server\u0026#34; } } State Terraform mantiene un fichero de estado que mapea tu configuración a recursos del mundo real. Así es como Terraform sabe qué existe, qué necesita cambiar y qué destruir. El fichero de estado es crítico. Perderlo significa que Terraform pierde la pista de tu infraestructura.\nModules Los modules son paquetes reutilizables de configuración Terraform. Piensa en ellos como funciones: reciben entradas (variables), crean recursos y producen salidas.\n1 2 3 4 5 6 7 8 9 10 11 12 13 module \u0026#34;vpc\u0026#34; { source = \u0026#34;terraform-aws-modules/vpc/aws\u0026#34; version = \u0026#34;5.1.0\u0026#34; name = \u0026#34;my-vpc\u0026#34; cidr = \u0026#34;10.0.0.0/16\u0026#34; azs = [\u0026#34;eu-west-1a\u0026#34;, \u0026#34;eu-west-1b\u0026#34;] private_subnets = [\u0026#34;10.0.1.0/24\u0026#34;, \u0026#34;10.0.2.0/24\u0026#34;] public_subnets = [\u0026#34;10.0.101.0/24\u0026#34;, \u0026#34;10.0.102.0/24\u0026#34;] enable_nat_gateway = true } Ejemplo práctico: VPC + EC2 Aquí hay un ejemplo completo que aprovisiona una VPC con una subred pública y una instancia EC2:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 terraform { required_version = \u0026#34;\u0026gt;= 1.5.0\u0026#34; required_providers { aws = { source = \u0026#34;hashicorp/aws\u0026#34; version = \u0026#34;~\u0026gt; 5.0\u0026#34; } } } provider \u0026#34;aws\u0026#34; { region = \u0026#34;eu-west-1\u0026#34; } # --- Networking --- resource \u0026#34;aws_vpc\u0026#34; \u0026#34;main\u0026#34; { cidr_block = \u0026#34;10.0.0.0/16\u0026#34; enable_dns_support = true enable_dns_hostnames = true tags = { Name = \u0026#34;main-vpc\u0026#34; } } resource \u0026#34;aws_subnet\u0026#34; \u0026#34;public\u0026#34; { vpc_id = aws_vpc.main.id cidr_block = \u0026#34;10.0.1.0/24\u0026#34; availability_zone = \u0026#34;eu-west-1a\u0026#34; map_public_ip_on_launch = true tags = { Name = \u0026#34;public-subnet\u0026#34; } } resource \u0026#34;aws_internet_gateway\u0026#34; \u0026#34;gw\u0026#34; { vpc_id = aws_vpc.main.id tags = { Name = \u0026#34;main-igw\u0026#34; } } resource \u0026#34;aws_route_table\u0026#34; \u0026#34;public\u0026#34; { vpc_id = aws_vpc.main.id route { cidr_block = \u0026#34;0.0.0.0/0\u0026#34; gateway_id = aws_internet_gateway.gw.id } tags = { Name = \u0026#34;public-rt\u0026#34; } } resource \u0026#34;aws_route_table_association\u0026#34; \u0026#34;public\u0026#34; { subnet_id = aws_subnet.public.id route_table_id = aws_route_table.public.id } # --- Security Group --- resource \u0026#34;aws_security_group\u0026#34; \u0026#34;web\u0026#34; { name = \u0026#34;web-sg\u0026#34; description = \u0026#34;Allow HTTP and SSH\u0026#34; vpc_id = aws_vpc.main.id ingress { from_port = 80 to_port = 80 protocol = \u0026#34;tcp\u0026#34; cidr_blocks = [\u0026#34;0.0.0.0/0\u0026#34;] } ingress { from_port = 22 to_port = 22 protocol = \u0026#34;tcp\u0026#34; cidr_blocks = [\u0026#34;YOUR_IP/32\u0026#34;] # Restringir a tu IP } egress { from_port = 0 to_port = 0 protocol = \u0026#34;-1\u0026#34; cidr_blocks = [\u0026#34;0.0.0.0/0\u0026#34;] } } # --- EC2 Instance --- resource \u0026#34;aws_instance\u0026#34; \u0026#34;web\u0026#34; { ami = \u0026#34;ami-0c55b159cbfafe1f0\u0026#34; instance_type = \u0026#34;t3.micro\u0026#34; subnet_id = aws_subnet.public.id vpc_security_group_ids = [aws_security_group.web.id] tags = { Name = \u0026#34;web-server\u0026#34; } } # --- Outputs --- output \u0026#34;instance_public_ip\u0026#34; { value = aws_instance.web.public_ip } output \u0026#34;vpc_id\u0026#34; { value = aws_vpc.main.id } El flujo plan/apply Terraform sigue un flujo de trabajo predecible:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # 1. Inicializar - descargar providers y modules terraform init # 2. Formatear - asegurar estilo de código consistente terraform fmt # 3. Validar - comprobar sintaxis y configuración terraform validate # 4. Plan - previsualizar qué cambiará (¡paso crítico!) terraform plan -out=tfplan # 5. Apply - ejecutar el plan terraform apply tfplan # 6. Destroy - destruir todos los recursos (cuando sea necesario) terraform destroy El paso terraform plan es el más importante. Nunca te lo saltes. Siempre revisa la salida del plan antes de aplicar, especialmente en producción. El plan te muestra exactamente qué se creará, modificará o destruirá.\n1 2 # Ejemplo de salida del plan Plan: 6 to add, 0 to change, 0 to destroy. En pipelines CI/CD, guarda el plan en un fichero (-out=tfplan) y aplica ese plan exacto. Esto previene condiciones de carrera donde la infraestructura cambia entre el plan y el paso de apply.\nBuenas prácticas de gestión de estado La gestión de estado es donde se originan la mayoría de problemas con Terraform. Sigue estas prácticas:\nUsa un backend remoto Nunca almacenes el estado localmente o en Git. Usa un backend remoto con cifrado y bloqueo:\n1 2 3 4 5 6 7 8 9 terraform { backend \u0026#34;s3\u0026#34; { bucket = \u0026#34;my-terraform-state\u0026#34; key = \u0026#34;prod/networking/terraform.tfstate\u0026#34; region = \u0026#34;eu-west-1\u0026#34; encrypt = true dynamodb_table = \u0026#34;terraform-locks\u0026#34; } } La tabla DynamoDB proporciona bloqueo de estado. Esto previene que dos personas o pipelines modifiquen la misma infraestructura al mismo tiempo.\nOrganiza el estado por componente No pongas toda tu infraestructura en un solo fichero de estado. Divídela por componente o equipo:\n1 2 3 4 5 6 7 8 9 10 environments/ ├── prod/ │ ├── networking/ # VPC, subnets, routes │ ├── compute/ # EC2, ASGs, load balancers │ ├── database/ # Instancias RDS │ └── monitoring/ # CloudWatch, alertas └── staging/ ├── networking/ ├── compute/ └── database/ Ficheros de estado más pequeños significan planes más rápidos, menor radio de explosión y menos equipos compitiendo por los bloqueos.\nUsa terraform_remote_state con moderación Puedes referenciar outputs de otros ficheros de estado, pero úsalo con cuidado. El uso excesivo de remote state crea acoplamiento fuerte entre componentes. Prefiere pasar valores a través de variables o un parameter store.\nConsejos para uso en producción Fija las versiones de los providers. Usa restricciones ~\u0026gt; para permitir actualizaciones de parche pero prevenir cambios incompatibles: version = \u0026quot;~\u0026gt; 5.0\u0026quot;.\nUsa workspaces con cuidado. Los workspaces son útiles para separación simple de entornos pero se vuelven confusos a escala. Directorios separados por entorno suele ser más claro.\nImplementa un pipeline CI/CD para Terraform. Ejecuta terraform plan en PRs y publica la salida como comentario en el PR. Ejecuta terraform apply solo después del merge y la aprobación.\nUsa prevent_destroy para recursos críticos. Esta regla de lifecycle evita la destrucción accidental de bases de datos o almacenamiento persistente:\n1 2 3 4 5 6 resource \u0026#34;aws_db_instance\u0026#34; \u0026#34;main\u0026#34; { # ... lifecycle { prevent_destroy = true } } Etiqueta todo. Usa un bloque default_tags en el provider para asegurar que cada recurso recibe tags estándar (entorno, equipo, proyecto).\nUsa tflint y checkov. Haz lint de tu código Terraform y escanea en busca de configuraciones inseguras antes de aplicar.\n1 2 3 tflint --init tflint checkov -d . Importa recursos existentes. Si tienes infraestructura creada manualmente, usa terraform import para traerla bajo gestión en lugar de recrearla.\nRevisa el diff del plan cuidadosamente. Un recurso que muestra \u0026ldquo;destroy and recreate\u0026rdquo; puede causar tiempo de inactividad. Entiende qué cambios son in-place versus destructivos.\nTerraform es una de esas herramientas que recompensa la disciplina. Cuanto más consistentemente sigas estas prácticas, con más confianza gestionará tu equipo la infraestructura a escala.\n","date":"2022-09-10T00:00:00Z","permalink":"/p/infraestructura-como-c%C3%B3digo-con-terraform-gu%C3%ADa-pr%C3%A1ctica/","title":"Infraestructura como código con Terraform: guía práctica"},{"content":"En esta entrada se definen los pasos a seguir para instalar y configurar Picroft en una Raspberry Pi.\nInstalación de la imagen Picroft en una tarjeta SD o un usb Mediante el siguiente comando se quema la imagen en una tarjeta SD o un USB.\n1 sudo dd bs=4M if=Picroft_v20.08_2020-09-07.img of=/dev/sda1 conv=fsync oflag=direct status=progress Una vez terminado, se introduce en una raspberry y se enciende conectada a un monitor, teclado, ratón y micrófono y auriculares (USB o jack, lo que se prefiera).\nConfiguración de Pycroft Se configura al inicio y es probable que no se escuche el audio por el auricular o altavoz debido a que por defecto está configurado ALSA en vez de pulseaudio. Para configurarlo correctamente, seguimos los siguientes pasos 1:\nConfiguramos picroft con el asistente de comandos mycroft-setup-wizard:\nLas opciones elegidas son: Salida: Altavoces vía 3.5 o USB Mic: Otro - No soportado\nLo más probable es que las pruebas fallen en esta etapa, esto es de esperar Una vez que llegue a la mycroft-cli y registre su dispositivo, es el momento de aplicar algunas actualizaciones.\na. Actualice la lista de paquetes 1 sudo apt update b. Actualice los paquetes 1 sudo apt upgrade -y c. Eliminar los paquetes no utilizados 1 sudo apt autoremove -y d. Reinicie 1 sudo reboot Cuando las cosas vuelvan a arrancar, es el momento de hacer funcionar el audio. Se puede hacer esto a través de SSH. a. Revise los dispositivos de audio por defecto 1 pactl info b. Establecer el dispositivo de salida por defecto a la toma de auriculares 1 pactl set-default-sink alsa_output.platform-bcm2835_audio.analog-stereo c. Verificar que los dispositivos por defecto son los correctos 1 pactl info d. Indique a MyCroft que utilice el sistema de pulsos por defecto 1 mycroft-config set listener.device_name \u0026#34;pulse\u0026#34; e. Reinicie 1 sudo reboot Actualice el archivo /etc/mycroft/mycroft.conf a. Actualice las siguientes líneas: \u0026ldquo;play_wav_cmdline\u0026rdquo;: \u0026ldquo;aplay -Dhw:0,0 %1\u0026rdquo;, \u0026ldquo;play_mp3_cmdline\u0026rdquo;: \u0026ldquo;mpg123 -a hw:0,0 %1\u0026rdquo;,\nb. Para que se vea así: \u0026ldquo;play_wav_cmdline\u0026rdquo;: \u0026ldquo;aplay %1\u0026rdquo;, \u0026ldquo;play_mp3_cmdline\u0026rdquo;: \u0026ldquo;mpg123 %1\u0026rdquo;,\nActualiza la habilidad de DuckDuckGo 1 msm install https://github.com/JarbasSkills/skill-ddg Cuando el sistema vuelva a estar en línea, ejecuta una prueba de mycroft-mic 1 mycroft-mic-test Instalar habilidades adicionales 1 2 3 mycroft-msm install fallback-aiml mycroft-msm install skill-finished-booting mycroft-msm install mycroft-spotify Asegúrese de que MyCroft emita un pitido cuando escuche la palabra \u0026ldquo;wake\u0026rdquo; - Debería devolver \u0026ldquo;true\u0026rdquo; 1 mycroft-config set confirm_listening true Se puede ver la configuración por defecto de Mycroft en GitHub - MycroftAI/mycroft-core .\nInstalar raspotify (todavía tengo que conseguir que funcione) 1 curl -sL https://dtcooper.github.io/raspotify/install.sh | sh Paquetes opcionales 1 sudo apt install rustc libpulse-dev python3-venv libatlas-base-dev -y Picroft Setup Steps - Quick Setup - USB Mic/Headphones Output\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2022-09-03T00:00:00Z","permalink":"/p/instalaci%C3%B3n-y-configuraci%C3%B3n-de-mycroft-en-una-raspberry-mediante-picroft/","title":"Instalación y configuración de Mycroft en una Raspberry mediante Picroft"},{"content":"¿Qué es la seguridad shift-left? La seguridad shift-left consiste en adelantar las prácticas de seguridad en el ciclo de vida del desarrollo de software. En lugar de tratar la seguridad como una puerta final antes de producción (o peor, como algo que se piensa después), integras comprobaciones de seguridad directamente en tus pipelines CI/CD. Así las vulnerabilidades se detectan cuando son más baratas de corregir: en tiempo de desarrollo.\nEl modelo tradicional de \u0026ldquo;constrúyelo primero, audítalo después\u0026rdquo; no escala. Las aplicaciones modernas se despliegan docenas de veces al día. Si tu revisión de seguridad es un proceso manual que ocurre una vez al trimestre, estás desplegando código vulnerable la mayoría del tiempo.\nVectores de amenaza en pipelines CI/CD Antes de securizar tu pipeline, entiende contra qué te estás defendiendo. Los sistemas CI/CD son objetivos de alto valor porque tienen acceso a credenciales de producción, código fuente y artefactos de build.\nLos vectores de amenaza comunes incluyen:\nDependencias comprometidas: Un paquete malicioso en tu árbol de dependencias (ataque a la cadena de suministro). Secretos filtrados: Claves API, tokens o contraseñas commiteados en el código fuente o expuestos en logs de build. Vulnerabilidades en el código: Inyección SQL, XSS, deserialización insegura y otros problemas del OWASP Top 10 introducidos en el código de la aplicación. Configuración insegura del pipeline: Acceso excesivamente permisivo en runners, reglas de protección de ramas ausentes o puertas de aprobación faltantes. Vulnerabilidades en imágenes de contenedor: Imágenes base con CVEs conocidos que se propagan a producción. Manipulación de artefactos de build: Artefactos no firmados o no verificados que pueden ser reemplazados por un atacante. Integrando SAST en tu pipeline Static Application Security Testing (SAST) analiza el código fuente sin ejecutarlo. Detecta vulnerabilidades temprano, antes de que el código siquiera se ejecute.\nHerramientas recomendadas Semgrep: Rápido, flexible, soporta reglas personalizadas. Funciona con muchos lenguajes. Mi principal recomendación para la mayoría de equipos. Bandit: Específico para Python. Excelente para proyectos Python ya que entiende patrones de seguridad propios de Python. SonarQube: Alcance más amplio (calidad de código + seguridad). Más pesado de configurar pero útil si quieres un panel unificado. Ejecutando Semgrep localmente 1 2 3 4 5 6 7 8 # Instalar pip install semgrep # Ejecutar con rulesets por defecto semgrep --config auto . # Ejecutar con reglas OWASP Top 10 específicamente semgrep --config \u0026#34;p/owasp-top-ten\u0026#34; . Ejecutando Bandit para proyectos Python 1 2 pip install bandit bandit -r ./src -f json -o bandit-report.json La clave es ejecutar estas herramientas en cada pull request, no solo en la rama principal. Los desarrolladores deberían ver los hallazgos antes de que el código se fusione.\nIntegrando DAST en tu pipeline Dynamic Application Security Testing (DAST) prueba la aplicación en ejecución desde el exterior, simulando un atacante. Detecta problemas que SAST no puede — errores de configuración, fallos de autenticación y vulnerabilidades en tiempo de ejecución.\nOWASP ZAP OWASP ZAP es la herramienta DAST de código abierto estándar. Puedes ejecutarla en tu pipeline contra un despliegue de staging:\n1 2 3 4 5 6 7 # Descargar la imagen Docker de ZAP docker pull ghcr.io/zaproxy/zaproxy:stable # Ejecutar un escaneo baseline contra una URL objetivo docker run -t ghcr.io/zaproxy/zaproxy:stable zap-baseline.py \\ -t https://staging.example.com \\ -r zap-report.html DAST es típicamente más lento que SAST. Ejecútalo después del despliegue en un entorno de staging en lugar de en cada commit. Una cadencia nocturna o por release funciona bien para la mayoría de equipos.\nEscaneo de secretos Los secretos filtrados son uno de los fallos de seguridad más comunes y dañinos. Una vez que un secreto está en el historial de Git, considéralo comprometido — incluso si lo eliminas en un commit posterior.\nHerramientas gitleaks: Escanea repositorios Git en busca de secretos usando regex y detección basada en entropía. trufflehog: Busca en el historial de Git cadenas de alta entropía y patrones de secretos conocidos. Ejecutando gitleaks 1 2 3 4 5 6 7 8 # Instalar brew install gitleaks # o descargar el binario desde GitHub releases # Escanear el repo actual gitleaks detect --source . --report-path gitleaks-report.json # Escanear en CI (detectar solo nuevas fugas en el PR) gitleaks detect --source . --log-opts=\u0026#34;origin/main..HEAD\u0026#34; Hook de pre-commit Bloquea secretos antes de que lleguen al remoto:\n1 2 3 4 5 6 # .pre-commit-config.yaml repos: - repo: https://github.com/gitleaks/gitleaks rev: v8.16.1 hooks: - id: gitleaks Escaneo de dependencias Tu aplicación es tan segura como su dependencia más débil. Los ataques a la cadena de suministro están en aumento y debes escanear tu árbol de dependencias regularmente.\nHerramientas Trivy: Escanea imágenes de contenedor, sistemas de archivos y repos Git en busca de vulnerabilidades. Rápido y completo. Snyk: Opción comercial con un tier gratuito generoso. Buena experiencia de desarrollador. OWASP Dependency-Check: Maduro, código abierto, soporta múltiples ecosistemas. 1 2 3 4 5 # Escanear una imagen de contenedor con Trivy trivy image my-app:latest # Escanear el sistema de archivos en busca de dependencias vulnerables trivy fs --severity HIGH,CRITICAL . Workflow de GitHub Actions con etapas de seguridad Aquí tienes un workflow práctico de GitHub Actions que integra todas las etapas de seguridad discutidas:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 name: Secure CI/CD Pipeline on: pull_request: branches: [main] push: branches: [main] jobs: secret-scan: name: Secret Scanning runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Run gitleaks uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} sast: name: Static Analysis runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Semgrep uses: returntocorp/semgrep-action@v1 with: config: \u0026gt;- p/security-audit p/owasp-top-ten - name: Run Bandit (Python) run: | pip install bandit bandit -r ./src -f json -o bandit-report.json || true - name: Upload SAST reports uses: actions/upload-artifact@v4 with: name: sast-reports path: \u0026#34;*.json\u0026#34; dependency-scan: name: Dependency Scanning runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run Trivy filesystem scan uses: aquasecurity/trivy-action@master with: scan-type: fs severity: HIGH,CRITICAL exit-code: 1 build-and-scan-image: name: Build \u0026amp; Scan Image needs: [secret-scan, sast, dependency-scan] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build Docker image run: docker build -t my-app:${{ github.sha }} . - name: Scan image with Trivy uses: aquasecurity/trivy-action@master with: image-ref: my-app:${{ github.sha }} severity: HIGH,CRITICAL exit-code: 1 deploy-staging: name: Deploy to Staging needs: [build-and-scan-image] runs-on: ubuntu-latest environment: staging steps: - name: Deploy to staging run: echo \u0026#34;Deploy to staging environment\u0026#34; dast: name: Dynamic Analysis needs: [deploy-staging] runs-on: ubuntu-latest steps: - name: OWASP ZAP Baseline Scan uses: zaproxy/action-baseline@v0.9.0 with: target: \u0026#34;https://staging.example.com\u0026#34; Observa el orden deliberado: el escaneo de secretos, SAST y escaneo de dependencias se ejecutan en paralelo (feedback rápido). El escaneo de imagen se ejecuta después del build. DAST se ejecuta después del despliegue en staging.\nChecklist de buenas prácticas Aquí tienes una checklist para evaluar la madurez de seguridad de tu pipeline CI/CD:\nEl escaneo de secretos se ejecuta en cada PR y bloquea el merge ante hallazgos. Los hooks de pre-commit previenen que se commiteen secretos localmente. SAST se ejecuta en cada PR con reglas que cubren OWASP Top 10. El escaneo de dependencias se ejecuta en cada PR y marca CVEs HIGH/CRITICAL. El escaneo de imágenes de contenedor se ejecuta antes de publicar imágenes en un registry. DAST se ejecuta contra staging en cada release (o como mínimo cada noche). La protección de ramas requiere que pasen las comprobaciones de seguridad antes del merge. El principio de mínimo privilegio se aplica en permisos de CI runners y acceso a secretos. Los commits firmados y artefactos firmados se exigen para releases de producción. Los logs de build se revisan para asegurar que no se filtran secretos en la salida. Se usa pinning de dependencias (versiones exactas, no rangos) para prevenir ataques a la cadena de suministro. Se realiza rotación regular de todos los secretos de CI/CD y claves de cuentas de servicio. Reflexiones finales La seguridad shift-left no se trata de comprar una herramienta, sino de cambiar la cultura. Las comprobaciones de seguridad en CI/CD deben ser rápidas, automatizadas e innegociables. Empieza con el escaneo de secretos (tiene el mayor ROI), añade SAST, y luego incorpora el escaneo de dependencias y DAST.\nEl objetivo no es detectar todo en el pipeline. Lo importante es elevar el listón lo suficiente para que los problemas obvios nunca lleguen a producción, liberando a tu equipo de seguridad para enfocarse en las amenazas sutiles y de alto impacto que requieren juicio humano.\n","date":"2022-06-20T00:00:00Z","permalink":"/p/seguridad-en-pipelines-ci/cd-enfoque-shift-left/","title":"Seguridad en pipelines CI/CD: enfoque shift-left"},{"content":"En esta entrada se exponen varias aplicaciones android de software libre que pueden descargar desde F-Droid.\nF-Droid AntennaPod\nAurora Store\nArchivos\nCalendario\nContactos\nF-Droid: repositorios\nF-Droid Archive\nF-Droid\nGuardian Project Archive\nGuardiann Project Official Releases\nPartido Interdimensional Pirata: https://fdroid.partidopirata.com.ar/fdroid/repo?fingerprint=3DF6969EA3A2186D8A5DB00884B3F42F164931E8CFAFD7CC48263CAD1361A1D5\narchive.newpipe.net/fdroid/repo: https://archive.newpipe.net/fdroid/repo?fingerprint=E2402C78F9B97C6C89E97DB914A2751FDA1D02FE2039CC0897A462BDB57E7501\nFedilab\nGalería\nGitFox\nGitNex\nGrabadora\nHacker\u0026rsquo;s Keyboard\nIceCatMobile\nJami\nK-9 Mail\nLibreOffice Viewer\nLibrera\nMarkor\nMoneyBuster\nMusica\nNewPipe\nNextcloud\nOpenkeyChain\nOpenTrack\nOSM DashBoard\nOsmAnd~\nProtonmail\nRiseUpVPN\nStandart Notes\nTutanota\nUntrackme\nVLC\n","date":"2022-06-03T00:00:00Z","permalink":"/p/aplicaciones-de-m%C3%B3vil/","title":"Aplicaciones de móvil"},{"content":"¿Qué es GitOps? GitOps es un marco operativo que aplica las mejores prácticas de DevOps — como el control de versiones, la colaboración y CI/CD — a la automatización de infraestructura. En resumen, GitOps utiliza Git como fuente única de verdad tanto para la infraestructura como para la configuración de aplicaciones.\nEn lugar de aplicar cambios manualmente a tus clústeres o infraestructura, declaras el estado deseado en repositorios Git. Agentes automatizados se encargan de que el estado real de tus sistemas converja con ese estado declarado. Si algo se desvía, el sistema se autocorrige.\nEsto no es simplemente una moda. GitOps cambia fundamentalmente la forma en que los equipos operan entornos Kubernetes, aportando previsibilidad, auditabilidad y velocidad a los despliegues.\nPrincipios fundamentales GitOps se apoya en cuatro principios fundacionales. Si tu flujo de trabajo no cumple los cuatro, probablemente estés haciendo \u0026ldquo;ops con sabor a Git\u0026rdquo; en lugar de verdadero GitOps.\n1. Configuración declarativa Todo el estado deseado del sistema debe describirse de forma declarativa. Para Kubernetes, esto significa manifiestos YAML, charts de Helm u overlays de Kustomize almacenados en Git. No debería haber comandos imperativos kubectl apply ejecutados manualmente desde el portátil de alguien.\n2. Versionado e inmutable Dado que Git es la fuente de verdad, cada cambio queda versionado. Obtienes un registro de auditoría completo de forma gratuita: quién cambió qué, cuándo y por qué. Revertir es tan simple como hacer revert de un commit. Se acabó el adivinar cuál era el estado anterior de producción.\n3. Extracción automática Los cambios aprobados son extraídos y aplicados automáticamente por agentes que se ejecutan dentro del clúster. Esta es una distinción clave: en lugar de que un pipeline de CI empuje cambios al clúster (lo cual requiere dar credenciales de CI al clúster), el agente dentro del clúster extrae los cambios desde Git. Este es el modelo pull-based y mejora significativamente la seguridad.\n4. Reconciliación continua (auto-reparación) El agente compara continuamente el estado deseado en Git con el estado real en el clúster. Si alguien modifica manualmente un recurso (o si un nodo falla y los recursos se reprograman), el agente detecta la desviación y la reconcilia. El sistema se auto-repara por diseño.\nFlujo de trabajo de GitOps Aquí tienes un diagrama simplificado en texto de un flujo de trabajo GitOps típico:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Desarrollador ──\u0026gt; Git Push ──\u0026gt; Application Repo │ ▼ CI Pipeline (build, test, push image) │ ▼ Config Repo (actualizar image tag en manifiestos) │ ▼ GitOps Agent (ArgoCD / Flux) observa el Config Repo │ ▼ Kubernetes Cluster (estado deseado aplicado) │ ▼ Reconciliación continua (detección de drift + auto-reparación) Puntos clave:\nEl Application Repo contiene el código fuente. CI construye y publica imágenes de contenedor. El Config Repo (a veces llamado \u0026ldquo;environment repo\u0026rdquo;) contiene los manifiestos de Kubernetes. CI o un proceso automatizado actualiza el image tag aquí tras una build exitosa. El GitOps Agent observa el Config Repo y aplica los cambios al clúster. Separar el código de la aplicación de la configuración de despliegue es una buena práctica. Mantiene las responsabilidades aisladas y permite versionado independiente.\nArgoCD vs Flux: comparación práctica Las dos herramientas dominantes de GitOps para Kubernetes son ArgoCD y Flux. Ambas son proyectos de la CNCF y ambas están listas para producción. Aquí va una comparación honesta basada en experiencia real.\nCaracterística ArgoCD Flux UI Interfaz web completa con visualización Sin UI integrada (usar Weave GitOps o similar) Arquitectura Servidor centralizado con API Descentralizada, basada en controladores Multi-tenancy AppProjects con RBAC Controladores con ámbito de namespace Soporte Helm Renderizado nativo CRD HelmRelease con HelmController Kustomize Nativo Nativo Notificaciones Notification controller integrado notification-controller separado Automatización de imágenes No integrada (usar Argo Image Updater) Controladores de image automation integrados Curva de aprendizaje Menor (la UI ayuda) Ligeramente más pronunciada (CLI/CRD primero) GitOps Toolkit Monolítico Modular (elige lo que necesites) Cuándo elegir ArgoCD Tu equipo valora un panel visual para el estado del clúster. Necesitas multi-tenancy robusto con control de acceso basado en roles. Quieres una barrera de entrada más baja para miembros del equipo nuevos en GitOps. Cuándo elegir Flux Prefieres una arquitectura modular y componible. Necesitas automatización de imágenes integrada (actualizar automáticamente los tags en Git). Favoreces un enfoque CLI-first, infraestructura como código, sin depender de una UI. Sinceramente, ambas son opciones sólidas. Me inclino por ArgoCD para equipos que necesitan visibilidad y por Flux para equipos de plataforma que prefieren componibilidad.\nEjemplo de manifiesto Application de ArgoCD Aquí hay un recurso Application mínimo de ArgoCD que despliega una aplicación desde un repositorio Git:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: my-app namespace: argocd spec: project: default source: repoURL: https://github.com/my-org/my-app-config.git targetRevision: main path: overlays/production destination: server: https://kubernetes.default.svc namespace: my-app syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true Estos son los campos que importan:\nsource.repoURL: Apunta al repositorio Git que contiene tus manifiestos. source.targetRevision: La rama o tag a seguir. source.path: El directorio dentro del repo que contiene los manifiestos (útil con overlays de Kustomize). destination.server: El servidor API del clúster Kubernetes destino. syncPolicy.automated: Habilita la sincronización automática. prune: true elimina recursos que ya no están en Git. selfHeal: true re-aplica el estado deseado cuando se detecta drift. Para aplicar este manifiesto después de instalar ArgoCD:\n1 kubectl apply -f application.yaml ArgoCD comenzará inmediatamente a sincronizar el estado declarado con el clúster.\nBeneficios para los equipos Adoptar GitOps no es solo una mejora técnica. Cambia cómo trabaja tu equipo:\nIncorporación más rápida: Los nuevos miembros del equipo pueden entender el estado completo del sistema leyendo el config repo. Sin necesidad de conocimiento tribal. Rollbacks fiables: Revierte un commit en Git y el clúster sigue. No necesitas recordar los comandos exactos de kubectl que se ejecutaron. Mejor postura de seguridad: Los desarrolladores nunca necesitan acceso directo con kubectl a producción. Todos los cambios pasan por PRs de Git con revisión de código. Cumplimiento de auditoría: Cada cambio es un commit de Git con autor, timestamp y justificación. Esto satisface muchos requisitos de cumplimiento de forma nativa. Menor carga cognitiva: Los desarrolladores se centran en escribir código y actualizar manifiestos. El agente GitOps se encarga del resto. Recuperación ante desastres: Si un clúster se destruye, puedes recrear todo el estado desde Git. El config repo es tu backup. Primeros pasos Si eres nuevo en GitOps, aquí tienes un camino pragmático:\nEmpieza con un entorno no crítico. Configura ArgoCD o Flux en un clúster de staging primero. Migra una aplicación a la vez. No intentes convertir todo de la noche a la mañana. Establece una convención para el config repo desde el principio. Decide la estructura de directorios, nomenclatura y estrategia de ramas antes de escalar. Usa Kustomize o Helm para las diferencias entre entornos. Evita copiar manifiestos entre directorios staging/ y production/. Configura notificaciones. Conecta ArgoCD o Flux a Slack o tu canal preferido para que el equipo vea los eventos de sincronización. GitOps es una de esas prácticas donde la inversión se amortiza rápidamente. Una vez que tu equipo experimenta la confianza de saber que Git refleja la realidad, no hay marcha atrás.\n","date":"2022-03-15T00:00:00Z","permalink":"/p/principios-y-flujo-de-trabajo-de-gitops-gu%C3%ADa-pr%C3%A1ctica/","title":"Principios y flujo de trabajo de GitOps: guía práctica"},{"content":"En esta entrada se instalará y se configurará un arranque dual de múltiples distribuciones de GNU/Linux (Debian y ParrotOS) mediante rEFInd. Si usas GRUB para arrancar múltiples distribuciones y nunca has oído hablar de rEFInd entonces esta publicación es para ti. Hemos seguido las indicación de este artículo.\nNota importante: la instalación que se describe a continuación se ha realizado sobre un disco de almacenamiento limpio. Si tienes datos que quieras guardar, se recomienda encarecidamente hacer una copia de seguridad de todos los datos para realizar la instalaciones sobre un disco vacío.\nRequisitos Disco de almacenamiento limpio. USB flasheado con Debian y posteriormente con Parrot Revisar los conceptos básicos Conceptos básicos Debian GNU/Linux es un sistema operativo libre, desarrollado por miles de voluntarios de todo el mundo, que colaboran a través de Internet.\nLa dedicación de Debian al software libre, su base de voluntarios, su naturaleza no comercial y su modelo de desarrollo abierto la distingue de otras distribuciones del sistema operativo GNU1.\nLVM es una implementación de un gestor de volúmenes lógicos para el núcleo Linux. LVM incluye muchas de las características que se esperan de un administrador de volúmenes, incluyendo:\nRedimensionado de grupos lógicos Redimensionado de volúmenes lógicos Instantáneas de sólo lectura (LVM2 ofrece lectura y escritura) RAID0 de volúmenes lógicos. LVM no implementa RAID1 o RAID5, por lo que se recomienda usar software específico de RAID para estas operaciones, teniendo las LV por encima del RAID2. En esta configuración no se usará RAID.\nLUKS es una especificación de cifrado de disco creado por Clemens Fruhwirth, originalmente destinado para Linux. Mientras la mayoría del software de cifrado de discos implementan diferentes e incompatibles formatos no documentados, LUKS especifica un formato estándar en disco, independiente de plataforma, para usar en varias herramientas. Esto no sólo facilita la compatibilidad y la interoperabilidad entre los diferentes programas, sino que también garantiza que todas ellas implementen gestión de contraseñas en un lugar seguro y de manera documentada. La implementación de referencia funciona en Linux y se basa en una versión mejorada de cryptsetup, utilizando dm-crypt como la interfaz de cifrado de disco3.\nUn boot loader carga un kernel del sistema operativo en la memoria y lo ejecuta. Un boot manager entrega el control a otro programa de arranque. GRUB es tanto un boot loader como un boot manager. Refind es sólo un boot manager.\nOtro concepto fundamental es conocer la diferencia entre EFI/UEFI y BIOS.\nLVM es una implementación de un gestor de volúmenes lógicos para el núcleo Linux. LVM incluye muchas de las características que se esperan de un administrador de volúmenes, incluyendo:\nRedimensionado de grupos lógicos Redimensionado de volúmenes lógicos Instantáneas de sólo lectura (LVM2 ofrece lectura y escritura) RAID0 de volúmenes lógicos. LVM no implementa RAID1 o RAID5, por lo que se recomienda usar software específico de RAID para estas operaciones, teniendo las LV por encima del RAID2. En esta configuración no se usará RAID.\nLUKS es una especificación de cifrado de disco creado por Clemens Fruhwirth, originalmente destinado para Linux. Mientras la mayoría del software de cifrado de discos implementan diferentes e incompatibles formatos no documentados, LUKS especifica un formato estándar en disco, independiente de plataforma, para usar en varias herramientas. Esto no sólo facilita la compatibilidad y la interoperabilidad entre los diferentes programas, sino que también garantiza que todas ellas implementen gestión de contraseñas en un lugar seguro y de manera documentada. La implementación de referencia funciona en Linux y se basa en una versión mejorada de cryptsetup, utilizando dm-crypt como la interfaz de cifrado de disco3.\nEn la tabla de particiones Tabla de particiones se utiliza el formato ext4 para las particiones porque mejora la velocidad de entrada y salida y utiliza menos CPU que los formatos ext3 y ext2. Se recomiendan como mínimo los siguientes valores:\nParticion Tamaño recomendado Asignado Debian Asignado Propio Contiene / \u0026gt;= 750MB 22GB 64GB /etc, /bin, /sbin, /lib, /dev, /usr /usr \u0026gt;= 4-6GB 0 0 Programas de usuario, lib y docs /var \u0026gt;= 2-3GB 32GB 112GB Variables de datos como emails /tmp \u0026gt;= 100MB 16GB 32GB Páginas web, caché de paquetes, datos temporales /home \u0026gt;= 100MB 200GB 288GB Directorio con Documentos, Descargas, \u0026hellip; /boot \u0026gt;= 256MB 500MB 512GB Partición Primaria, ext4 o ext2, no se recomienda cifrarla /boot/efi \u0026gt;= 100MB 250MB 0 No se recomienda cifrarla y bootable flag: on /swap \u0026gt;= 8GB 16GB 16GB Área de intercambio GParted Mediante GParted ejecutado desde un USB live, se eliminan todas las particiones y se crea una nueva tabla de particiones GPT(GUID Partition Table). GPT es un formato utilizado por los sistemas con EFI y es una alternativa moderna al formato MBR(Master Boot Record) que se utiliza en los sistemas con BIOS.\nUEFI requiere que cada disco de arranque tenga una partición especial llamada EFI System Partion (ESP). El ESP es una simple partición FAT16 o FAT32 con los flags de partición boot y esp. El ESP almacena archivos ejecutables EFI, a pesar que son de un tamaño inferior a 100MB, algunos sistemas operativos requieren que la partición tenga una capacidad de 500MB. Por lo tanto, se procede a crear una partición de 550MB de tipo primaria, fat32, con la etiqueta ESP y efi como el nombre de la partición. Se aplican los cambios y en la opción de manage flags se selecionan boot y esp.\nEl siguiente paso es crear dos particiones ext4 para los sistemas operativos Debian y ParrotOS. Por ejemplo, se puede asignar 250GB a Debian, 150GB a Parrot y el resto puede ser una partición de datos que sea compartida. A cada partición se recomienda asignar su correspondiente etiqueta.\nInstalación de Debian Accedemos a la instalación en modo experto con gráfica y avanzamos hasta la detección de discos y particiones. Creamos las siguientes particiones:\n500MB para una partición EFI común. 500MB para la partición boot de Debian. 500MB para la partición boot de ParrotOS. El resto en una partición donde irán los distintos sistemas operativos. Primero se crea un volumen cifrado en la partición con la etiqueta all-Operative-Systems indicando que no se formatee o se borre la partición. Después se crea un volumen LVM de grupo y los siguientes volúmenes lógicos:\nVolúmenes Debian: 8GB para SWAP. 250GB para root. 100GB para home. Volúmenes ParrotOS: 8GB para SWAP. 250GB para root. 100GB para home. Volúmenes datos comunes: El resto para datos comunes. Se asigna a cada volumen lógico de Debian el punto de montaje correspondiente y se termina la instalación eligendo el entorno de escritorio al gusto del consumidor.\nInstalación de ParrotOS Como ParrotOS es una distribución derivada de Debian, la instalación se realiza igual que en el apartado anterior. Se accede al modo experto de instalación gráfica y se avanza hasta el punto de detección de discos. Como la partición de los sistemas operativos está cifrada, es necesario descifrarla y detectar el grupo de volúmenes LVM. Para ello, saldremos de la sección de detección de discos y iremos a la sección de abrir una terminal o shell. Lo primero será desencriptar la partición cifrada con:\nNota: la partición /dev/sdaX debe corresponder a la cifrada y el nombre debe ser el asignado en la etiqueta.\n1 cryptsetup luksOpen /dev/sdaX all-Operative-Systems Posteriormente detectaremos el grupo de los volúmenes LVM con:\n1 vgchange -a y Nota: es probable que los siguientes pasos no funcionen a la primera y sea necesario completarlos con la siguiente sección. Por lo que se podría obviar el final de esta sección e instalar el grub directamente.\nUna vez ejecutados los comandos anteriores, seguir con la instalación hasta la instalación del GRUB. Volvemos a abrir una terminal e identificamos el UUID de la partición cifrada con:\n1 blkid /dev/sdaX Lo siguiente es modificar el archivo /etc/crypttab:\n1 nano /etc/crypttab Y se añade el siguiente contenido, donde el UUID es el obtenido del comando blkid:\n1 all-Operative-Systems UUID=524c1ad6-fabe-4f32-9bb0-c8db1286b262 none luks Terminamos la instalación y reiniciamos el sistema operativo. Si todo funciona correctamente, ya estaría terminado. Lo más habitual es que al intentar arrancar el sistema operativo no pueda abrir la partición cifrada, ni los volúmenes cifrados. Entonces, abrirá una terminal de initramfs y tendremos que configurar los siguientes pasos.\nNo abre la partición cifrada y salta una terminal de initramfs En caso de obtener una terminal con initramfs, será necesario volver a repetir los pasos de descifrar la partición y abrir el grupo de volúmenes cifrados como se menciona anteriormente.\nAbrimos la partición cifrada con:\n1 cryptsetup luksOpen /dev/sdaX all-Operative-Systems Posteriormente detectaremos el grupo de los volúmenes LVM con:\n1 vgchange -a y Para arrancar el sistema, simplemente utilizamos el siguiente comando:\n1 exit Nos llevará al login y entraremos con las credenciales creadas en la instalación. Una vez iniciado el sistema operativo, abrimos una terminal y detectamos el UUID de la partición cifrada. La X de sdaX corresponde al número de la partición cifrada, si no se conoce simplemente utilizar el comando blkid.\n1 blkid /dev/sdaX Editamos el archivo /etc/crypttab con nano:\n1 sudo nano /etc/crypttab Añadimos lo siguiente:\n1 all-Operative-Systems UUID=524c1ad6-fabe-4f32-9bb0-c8db1286b262 none luks Una vez terminado se utiliza el siguiente comando para actualizar initramfs:\n1 sudo update-initramfs -u Reiniciamos el sistema operativo con:\n1 sudo reboot Instalación rEFInd La instalación de rEFInd se realiza con el siguiente comando:\n1 sudo apt install refind Wikipedia, Debian\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, Logical Volume Manager (Linux)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, LUKS (Linux Unified Key Setup)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2022-01-06T00:00:00Z","permalink":"/p/instalaci%C3%B3n-de-debian-y-parrotos-con-arranque-dual-en-una-partici%C3%B3n-cifrada-con-luks-vol%C3%BAmenes-lvm-y-refind/","title":"Instalación de Debian y ParrotOS con arranque dual en una partición cifrada con LUKS, volúmenes LVM y rEFInd"},{"content":"En esta entrada se definen los pasos a seguir para configurar un servidor multimedia en una Raspberry Pi y hacerla accesible desde internet. La instalación se realizará en contenedoes mediante docker-comnpose.\n¿Qué es Jellyfin? Jellyfin es la solución construida por voluntarios permite el control de contenidos multimedia. Transmite a cualquier dispositivo desde un servidor propio, sin ataduras. Tus medios, tu servidor, a tu manera. Es un sistema multimedia de software libre que permite controlar la gestión y el streaming de archivos multimedia. Es una alternativa a los sistemas propietarios Emby y Plex, para proporcionar medios desde un servidor dedicado a los dispositivos de los usuarios finales a través de múltiples aplicaciones. 1.\nRequisitos Instalar:\nDocker\nDocker-compose\nInstalación en docker-compose básica En la documentación de Jellyfin, se recomienda utilizar la imagen de LinuxServer.io [^2] para la instalación en una raspberry pi. El archivo inicial docker-compose.yml es el siguiente:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 --- version: \u0026#34;2.1\u0026#34; services: jellyfin: image: lscr.io/linuxserver/jellyfin container_name: jellyfin environment: - PUID=1000 - PGID=1000 - TZ=Europe/London - JELLYFIN_PublishedServerUrl=192.168.0.5 #optional volumes: - /path/to/library:/config - /path/to/tvseries:/data/tvshows - /path/to/movies:/data/movies - /opt/vc/lib:/opt/vc/lib #optional - /media/pi/Cineteca:/data/movies/Cineteca ports: - 8096:8096 - 8920:8920 #optional - 7359:7359/udp #optional - 1900:1900/udp #optional devices: # - /dev/dri:/dev/dri #optional # - /dev/vcsm:/dev/vcsm #optional # - /dev/vchiq:/dev/vchiq #optional - /dev/video10:/dev/video10 #optional - /dev/video11:/dev/video11 #optional - /dev/video12:/dev/video12 #optional restart: unless-stopped Nota: Hemos añadido el volumen /media/pi/Cineteca porque es un disco duro externo que se monta en la raspberry pi con el comando:\n1 udisksctl mount -b /dev/sdb1 Arrancar el docker-compose Utilizamos el siguiente comando para levantar el escenario:\n1 docker-compose up Una vez levantado, es accesible en la dirección http://\u0026lt;ip-raspberry\u0026gt;:8096.\nInstalación en docker-compose con traefik y certificados Let\u0026rsquo;s Encrypt Primero, añadimos la variable de entorno con el nombre del dominio:\n1 export $DOMINIO=dominioejemplo.org En segundo lugar creamos un fichero docker-compose.yml y añadimos el siguiente contenido:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 version: \u0026#34;3.3\u0026#34; services: traefik: image: \u0026#34;traefik:v2.5\u0026#34; container_name: \u0026#34;traefik\u0026#34; command: - \u0026#34;--log.level=DEBUG\u0026#34; - \u0026#34;--api.insecure=true\u0026#34; - \u0026#34;--providers.docker=true\u0026#34; - \u0026#34;--providers.docker.exposedbydefault=false\u0026#34; - \u0026#34;--entrypoints.websecure.address=:443\u0026#34; - \u0026#34;--certificatesresolvers.myresolver.acme.tlschallenge=true\u0026#34; - \u0026#34;--certificatesresolvers.myresolver.acme.caserver=https://acme-v02.api.letsencrypt.org/directory\u0026#34; - \u0026#34;--certificatesresolvers.myresolver.acme.email=hello@email-example.org\u0026#34; - \u0026#34;--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json\u0026#34; ports: - \u0026#34;443:443\u0026#34; - \u0026#34;8080:8080\u0026#34; volumes: - \u0026#34;./letsencrypt:/letsencrypt\u0026#34; - \u0026#34;/var/run/docker.sock:/var/run/docker.sock:ro\u0026#34; # extra_hosts: # - host.docker.internal:172.17.0.1 # Needed to avoid Bad Gateway. whoami: image: \u0026#34;traefik/whoami\u0026#34; container_name: \u0026#34;simple-service\u0026#34; labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.whoami.rule=Host(`whoami.${DOMAIN}`)\u0026#34; - \u0026#34;traefik.http.routers.whoami.entrypoints=websecure\u0026#34; - \u0026#34;traefik.http.routers.whoami.tls.certresolver=myresolver\u0026#34; jellyfin: image: lscr.io/linuxserver/jellyfin container_name: jellyfin environment: - PUID=1000 - PGID=1000 - TZ=Europe/London - JELLYFIN_PublishedServerUrl=jellyfin.${DOMAIN} #optional volumes: - /path/to/library:/config - /path/to/tvseries:/data/tvshows - /path/to/movies:/data/movies - /opt/vc/lib:/opt/vc/lib #optional ports: - 8096:8096 - 8920:8920 #optional # - 7359:7359/udp #optional # - 1900:1900/udp #optional devices: # - /dev/dri:/dev/dri #optional # - /dev/vcsm:/dev/vcsm #optional # - /dev/vchiq:/dev/vchiq #optional - /dev/video10:/dev/video10 #optional - /dev/video11:/dev/video11 #optional - /dev/video12:/dev/video12 #optional restart: unless-stopped labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)\u0026#34; - \u0026#34;traefik.http.routers.jellyfin.entrypoints=websecure\u0026#34; - \u0026#34;traefik.http.routers.jellyfin.tls.certresolver=myresolver\u0026#34; Una vez levantado, es accesible en la dirección http://\u0026lt;ip-raspberry\u0026gt;:8096.\nDocumentación, Jellyfin)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-12-26T12:40:37+01:00","permalink":"/p/despliegue-de-un-servidor-multimedia-jellyfin/","title":"Despliegue de un servidor multimedia Jellyfin"},{"content":"En esta entrada se definen los pasos a seguir para configurar el playmouth en Debian teniendo todas las particiones cifradas con LUKS, menos la partición /boot. Se utiliza como refencia el repositorio plymouth-themes.\n¿Qué es el Playmouth? Plymouth es una aplicación que se inicia muy temprano en el proceso de booteo o inicio (incluso antes de que el sistema de archivos esté montado) que proporcional una animación gráfica de booteo o inicio mientas el proceso de inicio ocurre en segundo plano.\nEsta diseñado para trabajar en sistemas que tengan drivers DRM modesetting. La idea es que muy temprano en el proceso de booteo o inicio se configure de forma nativa el modesetting, Plymouth usa este modo, este modo debe mantenerse durante todo el proceso de booteo o inicio incluso después de iniciar el servidor gráfico X. El máximo propósito es evitar los parpadeos durante el proceso de inicio 1.\nInstalación de Playmouth 1 sudo apt install plymouth Modificación del Grub Modificar el archivo grub que viene por defecto:\n1 sudo nano /etc/default/grub Modificamos la línea 9 añadiendo splash:\n1 GRUB_CMDLINE_LINUX_DEFAULT=\u0026#34;quiet splash\u0026#34; Temas para el plymouth Clonamos el repositorio de temas:\n1 git clone https://github.com/adi1090x/plymouth-themes.git Nos movemos dentro de algún directorio llamado pack_X, por ejemplo el pack_3:\n1 cd plymouth-themes/pack_3 Seleccionamos el tema que queremos, por ejemplo `lone:\n1 sudo cp -r lone /usr/share/plymouth/themes/ Plymouth - Debian\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-11-25T13:21:56+01:00","permalink":"/p/configuraci%C3%B3n-del-plymouth/","title":"Configuración del Plymouth"},{"content":"En esta entrada se definen los pasos a seguir para configurar un servidor DNS en una Raspberry Pi.\nInstalación de DNSMasq 1 sudo apt install -y dnsmasq Configuración de dnsmasq 1 sudo nano /etc/dnsmasq.conf Buscamos (CTRL+W) y descomentamos las siguientes líneas eliminando el signo de almohadilla (#):\ndomain-needed - Configuramos el servidor DNS para que no reenvíe los nombres sin un punto (.) o un nombre de dominio a los servidores upstream. Los nombres sin punto o dominio se quedan en la red local. bogus-priv - Impide que el servidor DNS reenvíe las consultas de búsqueda inversa del rango de IP local a los servidores DNS ascendentes. Esto previene la filtración de la red local a los servidores upstream. no-resolv - Deja de leer los servidores de nombres upstream del archivo /etc/resolv.conf, confiando en cambio en los de la configuración de DNSMasq. Buscamos (CTRL+W) y eliminamos la siguiente línea:\n1 #sever=/localnet/192.168.0.1 La sustitimos por las DNS de Cloudflare:\n1 2 3 server=1.1.1.1 server=1.0.0.1 Este paso hace uso de los servidores DNS de Google para los servidores de nombres ascendentes.\nBuscamos (CTRL+W) la siguiente línea:\n1 #cache-size=150 Descomentamos y cambiamos el tamaño de la caché a 1000:\n1 cache-size=1000 Aumentar el tamaño de la caché ahorra un mayor número de peticiones DNS a la caché de DNSMasq. El rendimiento de la red mejora porque el tiempo de búsqueda de DNS se reduce.\nGuardamos el archivo con CTRL+X, luego presionamos Y y pulsamos Enter para guardar los cambios.\nReiniciamos DNSMasq para aplicar los cambios:\n1 sudo systemctl restart dnsmasq Comprobamos el estado del servidor DNS con:\n1 sudo systemctl status dnsmasq Añadir una url 1 sudo nano /etc/dnsmasq.d/example.conf Añadimos la ip local asociada a un nombre de dominio, por ejemplo home.localhost.\n1 address=home.localhost/192.168.1.130 Probar el servidor DNS en una 1 sudo apt install -y dnsutils ","date":"2021-11-21T00:00:00Z","permalink":"/p/configuraci%C3%B3n-de-servidor-dns-en-una-raspbery-pi/","title":"Configuración de servidor DNS en una Raspbery Pi"},{"content":"En esta entrada se definen los pasos a seguir para configurar una Raspberry Pi y hacerla accesible desde internet.\nAsignar IP fija a raspberry pi Para configurar una IP estática en derivados de Debian, debemos editar el fichero /etc/dhcpcd.conf con el comando:\n1 sudo nano /etc/dhcpcd.conf Descomentamos y modificamos las líneas que están comentandas para la IP estática de manera que nos quedaría lo siguiente:\n1 2 3 4 interface eth0 static ip_address=192.168.1.200/24 static routers=192.168.1.1 static domain_name_servers=192.168.1.1 Una vez guardado, reseteamos la raspberry:\n1 sudo reboot Y una vez encendida lo comprobamos con:\n1 ip a Mapeo de IP a nombres más legibles Modificamos el archivo /etc/hosts en cada máquina que se quiera mapear la dirección IP a un nombre más legible con:\n1 sudo nano /etc/hosts Y añadimos al final:\n1 192.168.1.200 pi.local pi Seguridad Configuración SSH Una opción para hardenizar la configuración SSH es mediante la colección de ansible [ssh_hardening]](https://github.com/dev-sec/ansible-collection-hardening/tree/master/roles/ssh_hardening). Para la simplicación de esta sección, editaremos el archivo /etc/ssh/sshd_config y añadiremos lo siguiente.\n1 2 3 4 5 6 7 8 9 10 Port 2251 PermitRootLogin no ChallengeResponseAuthentication no PasswordAuthentication no UsePAM no AuthenticationMethods publickey PubkeyAuthentication yes AllowUsers pi X11Forwarding no Banner /etc/issue Validamos la configuración del fichero sshd_config es correcta con los siguientes comandos:\n1 2 3 4 #Versión simple sudo sshd -t #Versión extendida sudo sshd -T Se guardan los cambios y se reinicia el servicio con:\n1 sudo systemctl restart ssh Ahora el comando para conectarnos es:\n1 ssh -p 2251 pi@192.168.1.200 En caso de olvidar el puerto escogido, se puede hallar mediante un escaneo de puertos con el comando:\n1 sudo nmap -p 1-65535 -T4 -A -v \u0026lt;ip-servidora\u0026gt; Configuración de fail2ban Se instala con los siguientes comandos:\n1 2 sudo apt-get update sudo apt-get install fail2ban Fail2ban trae un archivo de configuración de ejemplo: /etc/fail2ban/jail.conf. Es recomendable copiarlo y guardarlo en el mismo directorio con el nombre jail.local.\n1 sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local Editamos el archivo jail.local y modificamos lo siguiente:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # \u0026#34;bantime\u0026#34; is the number of seconds that a host is banned. bantime = 604800 # 7 days # A host is banned if it has generated \u0026#34;maxretry\u0026#34; during the last \u0026#34;findtime\u0026#34; # seconds. findtime = 3600 # \u0026#34;maxretry\u0026#34; is the number of failures before a host get banned. maxretry = 3 [sshd] # To use more aggressive sshd modes set filter parameter \u0026#34;mode\u0026#34; in jail.local: # normal (default), ddos, extra or aggressive (combines all). # See \u0026#34;tests/files/logs/sshd\u0026#34; or \u0026#34;filter.d/sshd.conf\u0026#34; for usage example and details. #mode = normal enable = true port = 2251 logpath = %(sshd_log)s backend = %(sshd_backend)s [traefik-auth] # to use \u0026#39;traefik-auth\u0026#39; filter you have to configure your Traefik instance, # see `filter.d/traefik-auth.conf` for details and service example. enable = true port = http,https logpath = /var/log/traefik/access.log Como se puede apreciar, hemos activado los módulos de sshd y traefik con enable = true.\nUna vez modificado, reiniciamos el servicio con:\n1 sudo service fail2ban restart Para ver qué IPs han sido bloqueadas, se puede utilizar el siguiente comando:\n1 sudo cat /var/log/fail2ban.log | grep \u0026#39;Ban\u0026#39; Para comprobar los módulos o jaulas activas, se utiliza:\n1 sudo fail2ban-client status Configuración del firewall UFW Se instala con:\n1 sudo apt-get install ufw Por defecto está desactivado, entonces, empezaremos configurando que deniegue cualquier tipo de conexión por cualquier puerto con el comando:\n1 sudo ufw default deny incoming Por otro lado, permitiremos las salidas de paquetes para cualquier puerto:\n1 sudo ufw default allow outgoing Ahora, permitiremos las conexiones de entrada de SSH en el puerto 2251 y para los servicios web en los puertos 80 (protocolo HTTP) y el 443 (protocolo HTTPS).\n1 sudo ufw allow 80,443,2251/tcp Para ver la regla añadida, se utiliza el comando:\n1 sudo ufw show added Se activan las reglas con el comando:\n1 sudo ufw enable Para ver el estado del cortafuegos se puede ejecutar:\n1 sudo ufw status verbose Mantener el sistema actualizado Automatizaremos la actualización de paquetes utilizando la herramienta crontab. Por ejemplo, actualizaremos el paquete ssh todos los días a las 7 de la mañana y que se guarden los logs en el archivo /var/log/ssh_update.txt.\n1 sudo crontab -e Añadimos la siguiente línea:\n1 0 7 * * * sudo apt update \u0026amp;\u0026amp; sudo apt-get install ssh -y \u0026gt;\u0026gt; /var/log/ssh_update.txt 2\u0026gt;\u0026amp;1 Configuración del router Entramos en la configuración del router buscando la IP 192.168.1.1 en un navegador. Cambiaremos la contraseña por defecto de administración y la SSID y contraseña del Wi-Fi.\nRecomendamos seguir la entrada de Configuración de seguridad y privacidad un router\n","date":"2021-11-01T00:00:00Z","permalink":"/p/configurar-una-raspberry-pi-para-hacerla-accesible-desde-internet/","title":"Configurar una Raspberry Pi para hacerla accesible desde internet"},{"content":"En esta entrada se definen los pasos a seguir para configurar una Raspberry Pi y hacerla accesible desde internet.\nAsignar IP fija a raspberry pi Para configurar una IP estática en derivados de Debian, debemos editar el fichero /etc/dhcpcd.conf con el comando:\n1 sudo nano /etc/dhcpcd.conf Descomentamos y modificamos las líneas que están comentandas para la IP estática de manera que nos quedaría lo siguiente:\n1 2 3 4 interface eth0 static ip_address=192.168.1.200/24 static routers=192.168.1.1 static domain_name_servers=192.168.1.1 Una vez guardado, reseteamos la raspberry:\n1 sudo reboot Y una vez encendida lo comprobamos con:\n1 ip a Mapeo de IP a nombres más legibles Modificamos el archivo /etc/hosts en cada máquina que se quiera mapear la dirección IP a un nombre más legible con:\n1 sudo nano /etc/hosts Y añadimos al final:\n1 192.168.1.200 pi.local pi Seguridad Configuración SSH Una opción para hardenizar la configuración SSH es mediante la colección de ansible [ssh_hardening]](https://github.com/dev-sec/ansible-collection-hardening/tree/master/roles/ssh_hardening). Para la simplicación de esta sección, editaremos el archivo /etc/ssh/sshd_config y añadiremos lo siguiente.\n1 2 3 4 5 6 7 8 9 10 Port 2251 PermitRootLogin no ChallengeResponseAuthentication no PasswordAuthentication no UsePAM no AuthenticationMethods publickey PubkeyAuthentication yes AllowUsers pi X11Forwarding no Banner /etc/issue Validamos la configuración del fichero sshd_config es correcta con los siguientes comandos:\n1 2 3 4 #Versión simple sudo sshd -t #Versión extendida sudo sshd -T Se guardan los cambios y se reinicia el servicio con:\n1 sudo systemctl restart ssh Ahora el comando para conectarnos es:\n1 ssh -p 2251 pi@192.168.1.200 En caso de olvidar el puerto escogido, se puede hallar mediante un escaneo de puertos con el comando:\n1 sudo nmap -p 1-65535 -T4 -A -v \u0026lt;ip-servidora\u0026gt; Configuración de fail2ban Se instala con los siguientes comandos:\n1 2 sudo apt-get update sudo apt-get install fail2ban Fail2ban trae un archivo de configuración de ejemplo: /etc/fail2ban/jail.conf. Es recomendable copiarlo y guardarlo en el mismo directorio con el nombre jail.local.\n1 sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local Editamos el archivo jail.local y modificamos lo siguiente:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # \u0026#34;bantime\u0026#34; is the number of seconds that a host is banned. bantime = 604800 # 7 days # A host is banned if it has generated \u0026#34;maxretry\u0026#34; during the last \u0026#34;findtime\u0026#34; # seconds. findtime = 3600 # \u0026#34;maxretry\u0026#34; is the number of failures before a host get banned. maxretry = 3 [sshd] # To use more aggressive sshd modes set filter parameter \u0026#34;mode\u0026#34; in jail.local: # normal (default), ddos, extra or aggressive (combines all). # See \u0026#34;tests/files/logs/sshd\u0026#34; or \u0026#34;filter.d/sshd.conf\u0026#34; for usage example and details. #mode = normal enable = true port = 2251 logpath = %(sshd_log)s backend = %(sshd_backend)s [traefik-auth] # to use \u0026#39;traefik-auth\u0026#39; filter you have to configure your Traefik instance, # see `filter.d/traefik-auth.conf` for details and service example. enable = true port = http,https logpath = /var/log/traefik/access.log Como se puede apreciar, hemos activado los módulos de sshd y traefik con enable = true.\nUna vez modificado, reiniciamos el servicio con:\n1 sudo service fail2ban restart Para ver qué IPs han sido bloqueadas, se puede utilizar el siguiente comando:\n1 sudo cat /var/log/fail2ban.log | grep \u0026#39;Ban\u0026#39; Para comprobar los módulos o jaulas activas, se utiliza:\n1 sudo fail2ban-client status Configuración del firewall UFW Se instala con:\n1 sudo apt-get install ufw Por defecto está desactivado, entonces, empezaremos configurando que deniegue cualquier tipo de conexión por cualquier puerto con el comando:\n1 sudo ufw default deny incoming Por otro lado, permitiremos las salidas de paquetes para cualquier puerto:\n1 sudo ufw default allow outgoing Ahora, permitiremos las conexiones de entrada de SSH en el puerto 2251 y para los servicios web en los puertos 80 (protocolo HTTP) y el 443 (protocolo HTTPS).\n1 sudo ufw allow 80,443,2251/tcp Para ver la regla añadida, se utiliza el comando:\n1 sudo ufw show added Se activan las reglas con el comando:\n1 sudo ufw enable Para ver el estado del cortafuegos se puede ejecutar:\n1 sudo ufw status verbose Mantener el sistema actualizado Automatizaremos la actualización de paquetes utilizando la herramienta crontab. Por ejemplo, actualizaremos el paquete ssh todos los días a las 7 de la mañana y que se guarden los logs en el archivo /var/log/ssh_update.txt.\n1 sudo crontab -e Añadimos la siguiente línea:\n1 0 7 * * * sudo apt update \u0026amp;\u0026amp; sudo apt-get install ssh -y \u0026gt;\u0026gt; /var/log/ssh_update.txt 2\u0026gt;\u0026amp;1 Configuración del router Entramos en la configuración del router buscando la IP 192.168.1.1 en un navegador. Cambiaremos la contraseña por defecto de administración y la SSID y contraseña del Wi-Fi.\nRecomendamos seguir la entrada de Configuración de seguridad y privacidad un router\n","date":"2021-11-01T00:00:00Z","permalink":"/p/configurar-una-raspberry-pi-para-hacerla-accesible-desde-internet/","title":"Configurar una Raspberry Pi para hacerla accesible desde internet"},{"content":"En esta entrada se definen varios comandos útiles en la administración de sistemas.\nConsultar la información de red 1 ip a Monitorizar el tráfico TCP 1 sudo tcpdump -i \u0026lt;device\u0026gt; Eliminar ruta por defecto 1 sudo ip route del default via 192.168.1.1 ","date":"2021-10-21T00:00:00Z","permalink":"/p/comandos-%C3%BAtiles-para-administrar-sistemas-gnu/linux/","title":"Comandos útiles para administrar sistemas GNU/linux"},{"content":"En esta entrada se definen los pasos a seguir para configurar un servidor DNS en una Raspberry Pi.\nInstalación de DNSMasq 1 sudo apt install -y dnsmasq Configuración de dnsmasq 1 sudo nano /etc/dnsmasq.conf Buscamos (CTRL+W) y descomentamos las siguientes líneas eliminando el signo de almohadilla (#):\ndomain-needed - Configuramos el servidor DNS para que no reenvíe los nombres sin un punto (.) o un nombre de dominio a los servidores upstream. Los nombres sin punto o dominio se quedan en la red local. bogus-priv - Impide que el servidor DNS reenvíe las consultas de búsqueda inversa del rango de IP local a los servidores DNS ascendentes. Esto previene la filtración de la red local a los servidores upstream. no-resolv - Deja de leer los servidores de nombres upstream del archivo /etc/resolv.conf, confiando en cambio en los de la configuración de DNSMasq. Buscamos (CTRL+W) y eliminamos la siguiente línea:\n1 #sever=/localnet/192.168.0.1 La sustitimos por las DNS de Cloudflare:\n1 2 3 server=1.1.1.1 server=1.0.0.1 Este paso hace uso de los servidores DNS de Google para los servidores de nombres ascendentes.\nBuscamos (CTRL+W) la siguiente línea:\n1 #cache-size=150 Descomentamos y cambiamos el tamaño de la caché a 1000:\n1 cache-size=1000 Aumentar el tamaño de la caché ahorra un mayor número de peticiones DNS a la caché de DNSMasq. El rendimiento de la red mejora porque el tiempo de búsqueda de DNS se reduce.\nGuardamos el archivo con CTRL+X, luego presionamos Y y pulsamos Enter para guardar los cambios.\nReiniciamos DNSMasq para aplicar los cambios:\n1 sudo systemctl restart dnsmasq Comprobamos el estado del servidor DNS con:\n1 sudo systemctl status dnsmasq Añadir una url 1 sudo nano /etc/dnsmasq.d/example.conf Añadimos la ip local asociada a un nombre de dominio, por ejemplo home.localhost.\n1 address=home.localhost/192.168.1.130 Probar el servidor DNS en una 1 sudo apt install -y dnsutils ","date":"2021-10-21T00:00:00Z","permalink":"/p/configuraci%C3%B3n-de-servidor-dns-en-una-raspbery-pi/","title":"Configuración de servidor DNS en una Raspbery Pi"},{"content":"En esta entrada se definen los pasos a seguir para hacer hardening de OS y SSH una Raspberry Pi y posteriormente poder desplegar una serie de servicios securizados.\n1. Configuración SSH En el siguiente paso es necesario copiar la clave pública al archivo ~/.ssh/authorized_keys de la RaspberryPi. Para ello se utilizará el siguiente comando:\n1 ssh-copy-id -i \u0026lt;identity.pub\u0026gt; pi@\u0026lt;ip de la raspberry o node-1\u0026gt; Ahora nos pedirá la contraseña de nuestra clave SSH y nos conectaremos a la RaspberryPi mediante:\n1 ssh pi@node-1 2. Instalación de Ansible Debian 1 sudo apt install -y ansible Arch: 1 sudo pacman -Sy ansible 3. Configuración OS y SSH usando Ansible 3.1. Usando una colección Instalación: 1 2 ansible-galaxy install dev-sec.os-hardening ansible-galaxy install dev-sec.ssh-hardening Crea un playbook para cada rol de ansible llamado ansible-os-hardening.yaml y ansible-ssh-hardening.yaml.\nEjecuta estos playbooks con los siguientes comandos:\n1 2 ansible-playbook ansible-os-hardening.yaml --ask-become-pass ansible-playbook ansible-ssh-hardening.yaml --ask-become-pass 3.2. Usando un playbook básico Añade tu clave ssh en un ssh-agent usando zsh (o bash): 1 2 ssh-agent zsh ssh-add ~/.ssh/id_ed25519 Ejecutar el playbook de ansible con la contraseña sudo requerida para los comandos: 1 ansible-playbook playbook.yaml --ask-become-pass ","date":"2021-10-21T00:00:00Z","permalink":"/p/hardening-de-os-y-ssh/","title":"Hardening de OS y SSH"},{"content":"¿Qué es LineageOS? Instalación de LineageOS en Xiami Mi A1 Requerimientos Material utilizado en el escenario:\nXiaomi Mi A1 LineageOS16 oficial (nightly=en desarrollo) LineageOS17 Unofficial TWRP Recovery Descargas Descargar e instalar los archivos de desarrollo android(SDK platform) adb y fastboot(en mi caso: minimal_adb_fastboot_v1.4.3).\nActivar EOEM Se activa el EOEM y la depuración USB en los ajustes del teléfono.\nDesbloqueo del bootloader Se utilizan los siguientes comandos para desbloaquear bootloader. Se ejecutan en la carpeta de abd y fastboot:\n1 2 3 4 5 6 7 8 adb devices # Se reinicia el móvil en modo fastboot adb reboot bootloader # Se comprueba el estado del dispositivo fastboot oem device-info # Se desbloquea el bootloader fastboot oem unlock #Se reinicia el móvil Se comprueba que se ha desbloqueado correctamente con:\n1 2 3 adb devices adb reboot bootloader fastboot oem device-info Instalación del modo recovery Después de haber activado modo depuración USB y desbloqueado la eoem, se instala el modo recovery con el archivo .img en la misma carpeta que abd y fastboot:\n1 fastboot flash recovery twrp-installer-3.3.1-0-tissot.img Se obtiene el siguiente error:\n1 2 3 4 5 6 target reported max download size of 534773760 bytes sending \u0026#39;recovery\u0026#39; (29348 KB)... OKAY [ 0.683s] writing \u0026#39;recovery\u0026#39;... FAILED (remote: partition table doesn\u0026#39;t exist) finished. total time: 0.699s Entonces descubrimos que se soluciona con:\n1 fastboot flash boot twrp-3.3.1-0-tissot.img Obtenemos el siguiente resultado:\n1 2 3 4 5 6 7 8 RESULTADO: fastboot flash boot twrp-3.3.1-0-tissot.img target reported max download size of 534773760 bytes sending \u0026#39;boot\u0026#39; (29348 KB)... OKAY [ 0.679s] writing \u0026#39;boot\u0026#39;... OKAY [ 0.181s] finished. total time: 0.860s Instalación de la imagen Se reinicia en modo recovery con botón power + vol arriba y se siguen los siguientes pasos:\nWipe-\u0026gt; Format Data Advanced Wipe-\u0026gt; Dalvikk, system y data Install -\u0026gt; lineage-1-\u0026hellip;-tissot.zip Wipe Dalvik t reboot sistem. Una vez seguidos, ya está instalado LineageOS. Por defecto no viene con Google Play instalado. En caso de dar algún error, se pueden instalar las GApps en su versión mínima, por ejemplo open_gapps-arm-9.0-pico-20200408.zip.\n","date":"2021-10-21T00:00:00Z","permalink":"/p/instalaci%C3%B3n-de-lineageos/","title":"Instalación de LineageOS"},{"content":"En esta entrada se definen los pasos a seguir para instalar y configurar una Raspberry Pi para desplegar una serie de servicios.\n1. Instalación del SO 1.1. Ubuntu, RaspberryPiOS o LibreElec Usando el programa Raspberry Pi Imager se puede quemar la imagen de Ubuntu, RaspberryPiOS, LibreElec o que prefieras, en cualquier tarjeta micro SD o USB 1. Por ejemplo elegiremos la imagen de Raspbian OS con escritorio y la quemaremos en un USB de 64GB.\nOtra forma de quemar una imagen en una tarjeta SD o un USB sería usando los siguientes comandos:\n1 2 3 4 5 6 7 8 9 10 11 # See the partitions lsblk # Umount the USB partition umount /dev/sdc1 # Format in vFAT mkfs.vfat -F 32 /dev/sdc -I # Flash the ISO into USB dd status=progress if=NAME.iso of=/dev/sdc 1.2. Arch En caso de instalar Arch, se ha seguido los pasos de la instalación de Arch con la versión de AArch64 2. We reproduced those steps for AArch64.\nStart fdisk to partition the SD card: 1 fdisk /dev/sdX At the fdisk prompt, delete old partitions and create a new one:\nType o. This will clear out any partitions on the drive. Type p to list partitions. There should be no partitions left. Type n, then p for primary, 1 for the first partition on the drive, press ENTER to accept the default first sector, then type +200M for the last sector. Type t, then c to set the first partition to type W95 FAT32 (LBA). Type n, then p for primary, 2 for the second partition on the drive, and then press ENTER twice to accept the default first and last sector. Write the partition table and exit by typing w. Create and mount the FAT filesystem: 1 2 3 mkfs.vfat /dev/sdX1 mkdir boot mount /dev/sdX1 boot Create and mount the ext4 filesystem: 1 2 3 mkfs.ext4 /dev/sdX2 mkdir root mount /dev/sdX2 root Download and extract the root filesystem (as root, not via sudo): 1 2 3 wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz bsdtar -xpf ArchLinuxARM-rpi-aarch64-latest.tar.gz -C root sync Move boot files to the first partition: 1 mv root/boot/* boot Before unmounting the partitions, update /etc/fstab for the different SD block device compared to the Raspberry Pi 3: 1 sed -i \u0026#39;s/mmcblk0/mmcblk1/g\u0026#39; root/etc/fstab Unmount the two partitions: 1 umount boot root Insert the SD card into the Raspberry Pi, connect ethernet, and apply 5V power.\nUse the serial console or SSH to the IP address given to the board by your router.\nLogin as the default user alarm with the password alarm. The default root password is root. Initialize the pacman keyring and populate the Arch Linux ARM package signing keys: 1 2 pacman-key --init pacman-key --populate archlinuxarm 2. Configuración Básica Una vez esté instalado el sistema operativo, existen varias opciones para configurar la raspi. La más sencilla es realizar un analisis de red con sudo nmap -f 192.168.1.0/24 para identificar la IP ue tiene la Raspberry y ha sido proporcionada por el router. Haremos ssh pi@192.168.10.250 (si es raspbian) o ssh alarm@192.168.10.250 (si es arch)). También se puede configurar sin necesidad de una pantalla, teclado y ratón extra como se explicó en un post anterior o usando estos tres periféricos externos. En este caso, usaremos una pantalla, un teclado y un ratón externo para simplificar la publicación. Por lo tanto, una vez encendida la raspi con el USB o la tarjeta SD conectada, aparecerá un dialogo para configurar el idioma, el wifi y una contraseña (por ejemplo: usar KeepassXC para generar una contraseña aleatoria).\n2.1 Actualización del sistema Una vez tengamos una consola con un usuario sin privilegios de root, abriremos una nueva consola como el usuario root:\n1 su - La contraseña por defecto suele ser root o similar.\nBasados en Debian: 1 2 # Update and upgrade packages system apt-get update -y \u0026amp;\u0026amp; sudo apt-get upgrade -y Basados en Arch: 1 2 # Update and upgrade packages system pacman -Syu 2.2 Actualización horaria Seguimos esta guía con los primeros pasos después de haber instalado Arch 3 o alguna distribución minimalista como HypriotOS. Cambiamos la hora al ue nos corresponde con:\n1 timedatectl set-timezone Europe/London Actualizamos el reloj con internet:\n1 timedatectl set-ntp true 2.3 Actualización del idioma Descomentamos el idioma deseado en el archivo locale.gen (por ejemplo: en_US.UTF-8) :\n1 nano /etc/locale.gen Ejecutamos:\n1 locale-gen Y ejecutamos:\n1 localectl set-locale LANG=en_US.UTF-8 2.4 Cambio de hostname Cambiamos el hostname con:\n1 hostnamectl set-hostname \u0026lt;nombre\u0026gt; Añadimos un alias par el hostname en el archivo /etc/hosts del oredenador que estemos utilizando para la configuración. Usamos nano /etc/hosts:\n1 2 127.0.0.1\tlocalhost.localdomain\t\u0026lt;nombre\u0026gt;\tlocalhost ::1\tlocalhost.localdomain\t\u0026lt;nombre\u0026gt;\tlocalhost (Opcional) Cambiar el color a la salida de pacman Si utilizamos Arch, ejecutamos:\n1 sed -i \u0026#39;s/#Color/Color/\u0026#39; /etc/pacman.conf (Opcional) Añadimos 8GB de memoria SWAP Si utilizamos Arch, ejecutamos:\n1 fallocate -l 8192M /swapfile (Opcional) Nuevo usuario con permisos sudo Si utilizamos Arch, ahora usaremos la utilidad visudo para editar los permisos de grupo para ejecutar comandos administrativos con sudo.\n1 2 pacman -S sudo EDITOR=nano visudo Descomentamos la siguiente línea:\n1 2 ## Uncomment to allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL Creamos un nuevo grupo sudo con:\n1 sudo groupadd sudo Creamos un nuevo usuario con:\n1 useradd -m -G sudo nombre_usuario Ponemos una contraseña al nuevo usuario:\n1 passwd nombre_usuario Una vez tengamos el nuevo usuario, borraremos el usuario alarm.\n1 userdel alarm En Debian o derivados modificamos los permisos del usuario que habíamos creado durante la instalació y lo añadidos al grupo sudo con el siguiente comando:\n1 2 su - usermod -aG sudo username Reiniciamos el sistema:\n1 reboot 2.5 SSH En el siguiente paso es necesario copiar la clave pública al archivo ~/.ssh/authorized_keys de la RaspberryPi. Para ello se utilizará el siguiente comando:\n1 ssh-copy-id -i \u0026lt;identity.pub\u0026gt; pi@\u0026lt;ip de la raspberry o node-1\u0026gt; Ahora nos pedirá la contraseña de nuestra clave SSH y nos conectaremos a la RaspberryPi mediante:\n1 ssh pi@node-1 (Optional) Configuración Wi-Fi Reproducido de la guía: los primeros pasos después de haber instalado Arch 3\nkarog, on ArchLinux ARM forums provided a simple way to connect to Wi-Fi. As root, do the following steps:\nnano /etc/systemd/network/wlan0.network to configure the wlan0 interface: Add the following contents to the file: 1 2 3 4 5 [Match] Name=wlan0 [Network] DHCP=yes wpa_passphrase \u0026quot;\u0026lt;SSID\u0026gt;\u0026quot; \u0026quot;\u0026lt;PASSWORD\u0026gt;\u0026quot; \u0026gt; /etc/wpa_supplicant/wpa_supplicant-wlan0.conf. Replace and with your respective Wi-Fi network name and password. systemctl enable wpa_supplicant@wlan0 to enable the Wi-Fi when booting systemctl start wpa_supplicant@wlan0 to connect to Wi-Fi. You\u0026rsquo;re good to go!\nIf you ever want to remove Wi-Fi connection (e.g. when you want to make it connect only through ethernet):\nsystemctl stop wpa_supplicant@wlan0 systemctl disable wpa_supplicant@wlan0 rm /etc/wpa_supplicant/wpa_supplicant-wlan0.conf rm /etc/systemd/network/wlan0.network 3. Instalación de Programas 3.1. Paquetes básicos Debian: 1 sudo apt install -y software-properties-common git wget Arch: 1 sudo pacman -S -y git wget 3.2. Docker y docker compose Se recomienda instalar docker rootless.\n3.2.1. Instalación en Debian Instalamos docker con el script de instalación:\n1 2 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh Mientras que la instación de docker-compose lo realizamos a través de pithon3:\n1 2 3 4 sudo apt-get install libffi-dev libssl-dev sudo apt install python3-dev sudo apt-get install -y python3 python3-pip sudo pip3 install docker-compose Añadir usuario al grupo docker:\n1 sudo usermod -aG docker ${USER} 3.2.2. Instalación en Arch Instalamos docker y docker-compose desde los repositorios oficiales:\n1 2 sudo pacman -Sy docker sudo pacman -Sy docker-compose Se activa el servicio con:\n1 sudo systemctl start docker.service Se activa siempre que se reinicie:\n1 sudo systemctl start docker.service Añadir usuario al grupo docker\n1 sudo usermod -aG docker ${USER} 3.2.3 Docker rootless Arch: 1 2 sudo pacman -S shadow sudo pacman -S fuse-overlayfs Añade kernel.unprivileged_userns_clone=1 in /etc/sysctl.conf:\n1 2 sudo nano /etc/sysctl.conf sudo sysctl --system Común: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 sudo touch /etc/subuid \u0026amp;\u0026amp; sudo touch /etc/subgid su - echo \u0026#34;pi:100000:65536\u0026#34; \u0026gt;\u0026gt; /etc/subgid echo \u0026#34;pi:100000:65536\u0026#34; \u0026gt;\u0026gt; /etc/subuid exit sudo systemctl disable --now docker.service docker.socket curl -fsSL https://get.docker.com/rootless | sh systemctl --user start docker systemctl --user enable docker sudo loginctl enable-linger $(whoami) export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock Se prueba con docker run -d -p 8080:80 nginx.\nSi queremos que se arranque en el arranque, escribimos los siguientes comandos:\n1 2 sudo systemctl enable docker.service sudo systemctl enable containerd.service 3.3. Ansible Debian 1 sudo apt install -y ansible Arch: 1 sudo pacman -Sy ansible 3.3.1 Hardening de SSH usando Ansible Mediante las colecciones de Ansible devsec.hardening, proporcionamos mecanismos de seguridad y la comprobamos con los siguientes comandos.\nInstalación: 1 ansible-galaxy install dev-sec.ssh-hardening Crea un playbook para cada rol de ansible llamado ansible-ssh-hardening.yaml.\nEjecuta estos playbooks con los siguientes comandos:\n1 ansible-playbook ansible-ssh-hardening.yaml --ask-become-pass También se puede crear un playbook de ansible con los módulos que queramos incluir.\nAñade tu clave ssh en un ssh-agent usando zsh (o bash): 1 2 ssh-agent zsh ssh-add ~/.ssh/id_ed25519 Ejecutar el playbook de ansible con la contraseña sudo requerida para los comandos: 1 ansible-playbook playbook.yaml --ask-become-pass 3.4. Instalar zsh y Oh my zsh Debian4: 1 2 sudo apt install zsh sh -c \u0026#34;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34; Arch: 1 2 sudo pacman -Sy zsh zsh-completions sh -c \u0026#34;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34; 3.4.1. Instalar Powerlevel10k Descargar y pegar las 4 fuentes .ttf Meslo Nerd en /usr/local/share/fonts. Deben tener los permisos 644 (-rw-r\u0026ndash;r\u0026ndash;).5\nMesloLGS NF Regular.ttf MesloLGS NF Bold.ttf MesloLGS NF Italic.ttf MesloLGS NF Bold Italic.ttf Creamos la carpeta /usr/local/share/fonts: 1 2 sudo mkdir /usr/local/share/fonts cd /usr/local/share/fonts Descargamos las fuentes:\n1 sudo wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf Clonar el proyecto de powerlevel10k:\n1 2 3 git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/powerlevel10k echo \u0026#39;source ~/powerlevel10k/powerlevel10k.zsh-theme\u0026#39; \u0026gt;\u0026gt;~/.zshrc exec zsh Sustituir el siguiente valor en ~/.zshrc:\n1 ZSH_THEME=\u0026#34;powerlevel10k/powerlevel10k\u0026#34; 3.4.2. Instalar plugins para zsh Para añadir una serie de plugins interesantes, editamos el archivo ~/.zshrc con nano ~/.zshrc y modificamos lo siguiente:\n1 2 #plugins=(git) plugins=(git git-extras history ansible zsh-autosuggestions zsh-syntax-highlighting docker-helpers docker docker-compose kubectl kubectx colorize nmap pip ssh-agent sudo pipenv fzf fzf-docker) Necesitamos instalar los plugins de zsh-autosuggestions, zsh-syntax-highlightingm docker-helpers, fzf y fzf-docker.\nPara instalar zsh-autosuggestions:\n1 git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/plugins/zsh-autosuggestions Para instalar zsh-syntax-highlighting:\n1 git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ~/.oh-my-zsh/plugins/zsh-syntax-highlighting Para instalar fzf usamos los repositorios oficiales:\n1 sudo pacman -Sy fzf Para instalar fzf-docker:\n1 git clone https://github.com/pierpo/fzf-docker ~/.oh-my-zsh/plugins/fzf-docker Para instalar docker-helpers:\n1 git clone https://github.com/unixorn/docker-helpers.zshplugin ~/.oh-my-zsh/plugins/docker-helpers Configurar al gusto y actualizar los cambios del fichero ~/.zshrc:\n1 source ~/.zshrc Snapd Instalación Se instala los paquetes snapd y core:\n1 sudo apt install -y snapd core Añadir ruta de ejecutables al PATH de bash y Zhs Se añade la ruta de ejecutables snap al PATH:\n1 2 3 4 echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc Se comprueba que se ha añadido correctamente la ruta:\n1 echo $PATH Añadir lanzadores al menú de aplicaciones Se crea un enlace simbólico desde el directorio que almacena los lanzadores de snaps (/var/lib/snapd/desktop/applications) al directorio de aplicaciones del sistema (usr/share/applications/)\n1 sudo ln -s /var/lib/snapd/desktop/applications /usr/share/applications/snapd Flatpak Instalación De la documentación oficial de Flatpak, se siguen los siguientes pasos:\nInstalar Flatpak 1 sudo apt install flatpak -y Se instala el repositorio de Flatpak 1 flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo Se reinicia el sistema para aplicar los cambios. Añadir lanzadores al menú Se crea un enlace simbólico desde el directorio que almacena los lanzadores de flatpak (/var/lib/flatpak/exports/share/applications/) al directorio de aplicaciones del sistema (usr/share/applications/)\n1 sudo ln -s /var/lib/flatpak/exports/share/applications/ /usr/share/applications/flatpak KeePassXC Nota: se instala a través de Snap porque los repositorios oficiales tienen una versión desactualizada.\nSe instala a través de snap: 1 sudo snap install keepassxc Se descarga la extensión para el navegador.\nSe configura la extensión del navegador a través de un script oficial de KeePassXC. Guardar script y ejecutar:\n1 2 wget https://raw.githubusercontent.com/keepassxreboot/keepassxc/master/utils/keepassxc-snap-helper.sh zsh keepassxc-snap-helper.sh En caso de obtener el error Could not find keepassxc.proxy! Ensure the keepassxc snap is installed properly., esto se debe a que falta añadir la ruta de ejecutables snap al PATH mediante:\n1 2 3 4 echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc Volver a ejecutar el script:\n1 bash keepassxc-snap-helper.sh VSCodium 4 Añade la clave GPG del repositorio: 1 wget -qO - https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg | gpg --dearmor | sudo dd of=/etc/apt/trusted.gpg.d/vscodium.gpg Añade el repositorio: 1 2 3 4 echo \u0026#39;deb [ signed-by=/usr/share/keyrings/vscodium-archive-keyring.gpg ] https://paulcarroty.gitlab.io/vscodium-deb-rpm-repo/debs vscodium main\u0026#39; | sudo tee /etc/apt/sources.list.d/vscodium.list Actualización de repositorios e instalación de VSCodium: 1 sudo apt update \u0026amp;\u0026amp; sudo apt install codium Instalación de Ubuntu en la Raspberry - Atareao\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nArchLinux, Arch\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nsTheZoc, Raspberry Pi Setup Guide\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nDebian Documentation, Fonts\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nVSCodium Documentation, Installation\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-10-21T00:00:00Z","permalink":"/p/instalaci%C3%B3n-y-configuraci%C3%B3n-de-debian-ubuntu-raspberrypios-libreelec-o-arch-en-una-raspbery-pi/","title":"Instalación y configuración de Debian, Ubuntu, RaspberryPiOS, LibreElec o Arch en una Raspbery Pi"},{"content":"En esta entrada se definen los pasos a seguir para instalar y configurar una Raspberry Pi para desplegar una serie de servicios.\n1. Instalación del SO Usando el programa Raspberry Pi Imager se puede quemar la imagen de Ubuntu, RaspberryPiOS, LibreElec o que prefieras, en cualquier tarjeta micro SD o USB 1. Por ejemplo elegiremos la imagen de Raspbian OS con escritorio y la quemaremos en un USB de 64GB.\nOtra forma de quemar una imagen en una tarjeta SD o un USB sería usando los siguientes comandos:\n1 2 3 4 5 6 7 8 9 10 11 # See the partitions lsblk # Umount the USB partition umount /dev/sdc1 # Format in vFAT mkfs.vfat -F 32 /dev/sdc -I # Flash the ISO into USB dd status=progress if=NAME.iso of=/dev/sdc 2. Configuración Básica Una vez esté instalado el sistema operativo, existen varias opciones para configurar la raspi. Se puede configurar sin necesidad de una pantalla, teclado y ratón extra como se explicó en un post anterior o usando estos tres periféricos externos. En este caso, usaremos una pantalla, un teclado y un ratón externo para simplificar la publicación. Por lo tanto, una vez encendida la raspi con el USB o la tarjeta SD conectada, aparecerá un dialogo para configurar el idioma, el wifi y una contraseña (por ejemplo: 1234567890).\n1 2 # Update and upgrade packages system sudo apt-get update -y \u0026amp;\u0026amp; sudo apt-get upgrade -y Añadimos un alias par el hostname en el archivo /etc/hosts del oredenador que estemos utilizando para la configuración.\n1 \u0026lt;ip de la raspberry\u0026gt; node-1 En el siguiente paso es necesario copiar la clave pública al archivo ~/.ssh/authorized_keys de la RaspberryPi. Para ello se utilizará el siguiente comando:\n1 ssh-copy-id -i pi@\u0026lt;ip de la raspberry o node-1\u0026gt; Ahora nos pedirá la contraseña de nuestra clave SSH y nos conectaremos a la RaspberryPi mediante:\n1 ssh pi@node-1 3. Instalación de Programas Paquetes básicos 1 sudo apt install -y software-properties-common git wget Docker y docker compose Instalación Instalamos docker con el script de instalación:\n1 2 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh Mientras que la instación de docker-compose lo realizamos a través de pithon3:\n1 2 3 4 sudo apt-get install libffi-dev libssl-dev sudo apt install python3-dev sudo apt-get install -y python3 python3-pip sudo pip3 install docker-compose Añadir usuario al grupo docker 1 sudo usermod -aG docker ${USER} Ansible 1 sudo apt install -y ansible Instalar zsh y Oh my zsh2 1 2 sudo apt install zsh sh -c \u0026#34;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34; Instalar Powerlevel10k Descargar y pegar las 4 fuentes .ttf Meslo Nerd en /usr/local/share/fonts. Deben tener los permisos 644 (-rw-r\u0026ndash;r\u0026ndash;).3\nMesloLGS NF Regular.ttf MesloLGS NF Bold.ttf MesloLGS NF Italic.ttf MesloLGS NF Bold Italic.ttf Creamos la carpeta /usr/local/share/fonts:\n1 2 sudo mkdir /usr/local/share/fonts cd /usr/local/share/fonts Descargamos las fuentes:\n1 sudo wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf Clonar el proyecto de powerlevel10k:\n1 git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k Sustituir el siguiente valor en ~/.zshrc:\n1 ZSH_THEME=\u0026#34;powerlevel10k/powerlevel10k\u0026#34; Configurar al gusto y actualizar los cambios del fichero ~/.zshrc:\n1 source ~/.zshrc Snapd Instalación Se instala los paquetes snapd y core:\n1 sudo apt install -y snapd core Añadir ruta de ejecutables al PATH de bash y Zhs Se añade la ruta de ejecutables snap al PATH:\n1 2 3 4 echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc Se comprueba que se ha añadido correctamente la ruta:\n1 echo $PATH Añadir lanzadores al menú de aplicaciones Se crea un enlace simbólico desde el directorio que almacena los lanzadores de snaps (/var/lib/snapd/desktop/applications) al directorio de aplicaciones del sistema (usr/share/applications/)\n1 sudo ln -s /var/lib/snapd/desktop/applications /usr/share/applications/snapd Flatpak Instalación De la documentación oficial de Flatpak, se siguen los siguientes pasos:\nInstalar Flatpak 1 sudo apt install flatpak -y Se instala el repositorio de Flatpak 1 flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo Se reinicia el sistema para aplicar los cambios. Añadir lanzadores al menú Se crea un enlace simbólico desde el directorio que almacena los lanzadores de flatpak (/var/lib/flatpak/exports/share/applications/) al directorio de aplicaciones del sistema (usr/share/applications/)\n1 sudo ln -s /var/lib/flatpak/exports/share/applications/ /usr/share/applications/flatpak KeePassXC Nota: se instala a través de Snap porque los repositorios oficiales tienen una versión desactualizada.\nSe instala a través de snap: 1 sudo snap install keepassxc Se descarga la extensión para el navegador.\nSe configura la extensión del navegador a través de un script oficial de KeePassXC. Guardar script y ejecutar:\n1 2 wget https://raw.githubusercontent.com/keepassxreboot/keepassxc/master/utils/keepassxc-snap-helper.sh zsh keepassxc-snap-helper.sh En caso de obtener el error Could not find keepassxc.proxy! Ensure the keepassxc snap is installed properly., esto se debe a que falta añadir la ruta de ejecutables snap al PATH mediante:\n1 2 3 4 echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc Volver a ejecutar el script:\n1 bash keepassxc-snap-helper.sh VSCodium [^4] Añade la clave GPG del repositorio: 1 wget -qO - https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg | gpg --dearmor | sudo dd of=/etc/apt/trusted.gpg.d/vscodium.gpg Añade el repositorio: 1 2 3 4 echo \u0026#39;deb [ signed-by=/usr/share/keyrings/vscodium-archive-keyring.gpg ] https://paulcarroty.gitlab.io/vscodium-deb-rpm-repo/debs vscodium main\u0026#39; | sudo tee /etc/apt/sources.list.d/vscodium.list Actualización de repositorios e instalación de VSCodium: 1 sudo apt update \u0026amp;\u0026amp; sudo apt install codium Configuración usando Ansibles Usando una colección Instalación: 1 2 ansible-galaxy install dev-sec.os-hardening ansible-galaxy install dev-sec.ssh-hardening Crea un playbook para cada rol de ansible llamado ansible-os-hardening.yaml y ansible-ssh-hardening.yaml.\nEjecuta estos playbooks con los siguientes comandos:\n1 2 ansible-playbook ansible-os-hardening.yaml --ask-become-pass ansible-playbook ansible-ssh-hardening.yaml --ask-become-pass Usando un playbook básico Añade tu clave ssh en un ssh-agent usando zsh (o bash): 1 2 ssh-agent zsh ssh-add ~/.ssh/id_ed25519 Ejecutar el playbook de ansible con la contraseña sudo requerida para los comandos: 1 ansible-playbook playbook.yaml --ask-become-pass Instalación de Ubuntu en la Raspberry - Atareao\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nDebian Documentation, Fonts\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nVSCodium Documentation, Installation\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-10-21T00:00:00Z","permalink":"/p/instalaci%C3%B3n-y-configuraci%C3%B3n-de-una-raspbery-pi/","title":"Instalación y configuración de una Raspbery Pi"},{"content":"En esta entrada se definen los pasos a seguir para instalar y configurar WLED en una placa ESP8266.\nFlashear el ESP8266 NodeMCU es un firmware de código abierto basado en Lua para el SOC WiFi ESP8266 de Espressif y utiliza un sistema de archivos SPIFFS basado en la flash del módulo. NodeMCU está implementado en C y se basa en el SDK NON-OS de Espressif.\nEl firmware se desarrolló inicialmente como un proyecto complementario a los populares módulos para desarrollo NodeMCU basados en ESP8266, pero el proyecto está ahora apoyado por la comunidad, y el firmware puede ejecutarse en cualquier módulo ESP 1.\nPara flasear el ESP8266 intalams la herramienta esptool:\n1 pip install esptool Descargamos la última versión de WLED de su GitHub y flaseamos la placa con el siguiente comando:\n1 esptool.py write_flash 0x0 ./WLED_0.13.1_ESP8266.bin Documentación NodeMCU\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-10-21T00:00:00Z","permalink":"/p/instalaci%C3%B3n-y-configuraci%C3%B3n-de-wled-en-esp8266/","title":"Instalación y configuración de WLED en ESP8266"},{"content":"Purgar todos los recursos de Docker 1 2 docker system prune --all docker system prune --volumes Eliminar todas las imágenes 1 docker rmi -f $(docker images -a -q) ","date":"2021-06-20T00:00:00Z","permalink":"/p/comandos-%C3%BAtiles-de-docker/","title":"Comandos útiles de docker"},{"content":"Purgar todos los recursos de Docker 1 2 docker system prune --all docker system prune --volumes Eliminar todas las imágenes 1 docker rmi -f $(docker images -a -q) ","date":"2021-05-15T00:00:00Z","permalink":"/p/comandos-%C3%BAtiles-de-docker/","title":"Comandos útiles de docker"},{"content":"Hacking Awesome hacking Awesome Hacking Resources Administración de sistemas Snowflake SSH Client es una navaja suiza para los administradores de sistemas Análisis de red Subdominios Comparativa de herramientas de enumeración de subdominios:\nAmass: más lenta pero encuentra más subdominios válidos Findomain: más rápida con buen número de subdominios encontrados Subfinder Sublist3r DNSRecon dnssearch Knock SubBrute Programación segura Revisión de código De pago: Check Marx VeraCode Fortify AppScan-IBM Kiuwan Revisión de dependencias: Dependency check Kiuwan Sonatype SourceClear BlackDuck Snyk Secretos hardcodeados (contraseñas en el código) Gitleaks ","date":"2021-05-15T00:00:00Z","permalink":"/p/recopilaci%C3%B3n-de-herramientas-de-seguridad/","title":"Recopilación de herramientas de seguridad"},{"content":"Crear un grupo Se crea el grupo shared: 1 sudo groupadd shared Añadir usuario Se añade el usuario devops al grupo shared: 1 sudo usermod -a -G shared devops Para que los cambios surtan efecto se requiere cerrar sesión y volver a entrar en el usuario devops. Se comprobará con el comando:\n1 groups Cambiar el grupo de una carpeta y sus ficheros Se cambia el grupo de la carpeta wiki por shared: 1 sudo chgrp -R shared wiki Añadir permisos de escritura para el un grupo en una carpeta y sus ficheros Se añade los permisos de escritura w para el grupo de usuarios de la carpeta wiki.\n1 sudo chmod -R g+w wiki ","date":"2021-05-08T00:00:00Z","permalink":"/p/permisos-en-gnu/linux/","title":"Permisos en GNU/Linux"},{"content":"Libros recomendados:\nRamol y Cajal - Los tónicos de la voluntad Descartes - El método Ortega y Gasset - La universidad Objetivos de investigación Siglas SMART (específico, medibles, alcanzable, realístico, actual) Espresarlos en infinitivo.\nAlcance o metas Generales Intermedias Cualidades y precauciones Medibles Accesibles o realizables Coherencia Temática que sea de interes para el investigador Clasificación metodológica Variable dependiente Variable independiente. Aquella que se escoge para estudiar la dependiente. El objetivo que queremos perseguir. Variable extraña. Aquellas que en el caso concreto de estudio no son relevantes pero la literatura la incluye como una varible que afecta a la variable dependiente. Según su nivel control: Variable de control. Aquella que la literatura sabe que influye. Se sabe su efecto. Variable de moderadora. Cuando la literatura apunta que puede haber un impacto pero no se sabe cuanto afecta. Variable de intervinientes. Hipótesis Cómo impactan las variables independientes en las variables dependientes. Habitualmente se suele utilizar una hipótesis por objetivo. Incluir las VD y VI en la hipótesis. Tener coherencia con el problema planteado. En caso de no tener tanta coherencia, reformular el problema e incluir relaciones del problema en la propia hipótesis. Introducción y problemas de investigación Enganchar al lector desde el principio. Plantear el trabajo de manera atractiva. ","date":"2021-04-07T09:40:13+02:00","permalink":"/p/formaci%C3%B3n-de-doctorado/","title":"Formación de doctorado"},{"content":"En esta entrada se configurará el sistema operativo Debian.\n¿Qué es Debian? Debian GNU/Linux es un sistema operativo libre, desarrollado por miles de voluntarios de todo el mundo, que colaboran a través de Internet.\nLa dedicación de Debian al software libre, su base de voluntarios, su naturaleza no comercial y su modelo de desarrollo abierto la distingue de otras distribuciones del sistema operativo GNU1.\nAñadir drivers para la tarjeta de WiFi y NVIDIA Ejecutando los siguientes comandos se iniciará sesión como root y se añadirán los repositorios necesarios para añadir los drivers no incluidos en los repositorios totalmente libres:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # Log in as root su - # Install vim apt install -y vim # Add contrib and non-free reopositories ## Edit /etc/apt/sources.list vim /etc/apt/sources.list ## Add contrib and non-free at the end deb http://mirror.librelabucm.org/debian/ buster main contrib non-free deb http://security.debian.org/debian-security buster/updates main contrib non-free deb http://mirror.librelabucm.org/debian/ buster-updates main contrib non-free # Add non-free drivers for WiFi apt install -y firmware-iwlwifi firmware-atheros firmware-misc-nonfree firmware-intelwimax firmware-realtek firmware-linux firmware-linux-nonfree Comprobar que los paquetes han sido instalados:\n1 sudo apt list --installed | grep firmware Añadir a un usuario al grupo sudo 1 2 su - usermod -aG sudo username Comprobar que se ha añadido al grupo sudo 1 getent group sudo Iniciar sesión con el usuario del grupo sudo 1 su - username Instalar git y wget 1 sudo apt install git wget -y Instalar zsh y Oh my zsh2 1 2 sudo apt install zsh sh -c \u0026#34;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34; Instalar Powerlevel10k Descargar y pegar las 4 fuentes .ttf Meslo Nerd en /usr/local/share/fonts. Deben tener los permisos 644 (-rw-r\u0026ndash;r\u0026ndash;).3\nMesloLGS NF Regular.ttf MesloLGS NF Bold.ttf MesloLGS NF Italic.ttf MesloLGS NF Bold Italic.ttf Creamos la carpeta /usr/local/share/fonts:\n1 2 sudo mkdir /usr/local/share/fonts cd /usr/local/share/fonts Descargamos las fuentes:\n1 sudo wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf Clonar el proyecto de powerlevel10k:\n1 git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k Sustituir el siguiente valor en ~/.zshrc:\n1 ZSH_THEME=\u0026#34;powerlevel10k/powerlevel10k\u0026#34; Configurar al gusto y actualizar los cambios del fichero ~/.zshrc:\n1 source ~/.zshrc Añadir lanzadores al menú Utilizar el siguiente comando para emular en zsh las aplicaciones en /etc/profile.\n1 emulate sh -c \u0026#39;source /etc/profile\u0026#39; Instalación de programas recomendados Snapd Instalación Se instala los paquetes snapd y core:\n1 2 sudo apt install snapd sudo snap install core Añadir ruta de ejecutables al PATH de bash y Zhs Se añade la ruta de ejecutables snap al PATH:\n1 2 3 4 echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc Se comprueba que se ha añadido correctamente la ruta:\n1 echo $PATH Añadir lanzadores al menú de aplicaciones Se crea un enlace simbólico desde el directorio que almacena los lanzadores de snaps (/var/lib/snapd/desktop/applications) al directorio de aplicaciones del sistema (usr/share/applications/)\n1 sudo ln -s /var/lib/snapd/desktop/applications /usr/share/applications/snapd Flatpak Instalación De la documentación oficial de Flatpak, se siguen los siguientes pasos:\nInstalar Flatpak 1 sudo apt install flatpak -y Se instala el repositorio de Flatpak 1 flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo Se reinicia el sistema para aplicar los cambios. Añadir lanzadores al menú Se crea un enlace simbólico desde el directorio que almacena los lanzadores de flatpak (/var/lib/flatpak/exports/share/applications/) al directorio de aplicaciones del sistema (usr/share/applications/)\n1 sudo ln -s /var/lib/flatpak/exports/share/applications/ /usr/share/applications/flatpak Aptitude 1 sudo apt install aptitude Cliente de sincronización de Nextcloud Descargar el archivo AppImage desde Nextcloud, darle permisos de ejecución al usuario y ejecutarlo con:\n1 2 chmod u+x Nextcloud-3.3.5-x86_64.AppImage ./Nextcloud-3.3.5-x86_64.AppImage Sincronizar carpetas.\nKeePassXC Nota: se instala a través de Snap porque los repositorios oficiales tienen una versión desactualizada.\nSe instala a través de snap: 1 sudo snap install keepassxc Se descarga la extensión para el navegador.\nSe configura la extensión del navegador a través de un script oficial de KeePassXC. Guardar script y ejecutar:\n1 2 wget https://raw.githubusercontent.com/keepassxreboot/keepassxc/master/utils/keepassxc-snap-helper.sh zsh keepassxc-snap-helper.sh En caso de obtener el error Could not find keepassxc.proxy! Ensure the keepassxc snap is installed properly., esto se debe a que falta añadir la ruta de ejecutables snap al PATH mediante:\n1 2 3 4 echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc Volver a ejecutar el script:\n1 bash keepassxc-snap-helper.sh VSCodium 4 Añade la clave GPG del repositorio: 1 wget -qO - https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg | gpg --dearmor | sudo dd of=/etc/apt/trusted.gpg.d/vscodium.gpg Añade el repositorio: 1 2 3 4 echo \u0026#39;deb [ signed-by=/usr/share/keyrings/vscodium-archive-keyring.gpg ] https://paulcarroty.gitlab.io/vscodium-deb-rpm-repo/debs vscodium main\u0026#39; | sudo tee /etc/apt/sources.list.d/vscodium.list Actualización de repositorios e instalación de VSCodium: 1 sudo apt update \u0026amp;\u0026amp; sudo apt install codium Usar LaTeX con VSCodium En settings buscar por word wrap y activar para que las líneas no sean infinitas. Instalar la distibución de LaTeX Texlive (recomendada por la extensión LateX Workshop de VSCodium), ChkTex para comprobar la semántica de Latex y texlive-extra-utils para extensiones como latexindent. 1 apt-get install -y texlive texlive-latex-extra texlive-extra-utils chktex latexmk texlive-fonts-recommended texlive-fonts-extra texlive-science texlive-latex-base-doc Añadir la ruta 1 2 3 4 echo \u0026#39;export PATH=$PATH:/usr/share\u0026#39; \u0026gt;\u0026gt; ~/.bashrc echo \u0026#39;export PATH=$PATH:/usr/share\u0026#39; \u0026gt;\u0026gt; ~/.zshrc source ~/.bashrc source ~/.zshrc Inskape Instalar a través de los repositorios de flatpak.\n1 flatpak install org.inkscape.Inkscape Mattermost-Desktop Según la documentación oficial de Mattermost, para los sistemas operativos basados en Debian, los pasos a seguir son:\nSe descarga la última version de Mattermost (usar la página documentación oficial): 64-bit systems mattermost-desktop-4.6.2-linux-amd64.deb Zotero Los pasos que se han tomado de referencia son los que vienen en la wiki de Debian para instalar Zotero.\nSe instala Zotero a través de Flatpak:\n1 flatpak install flathub org.zotero.Zotero Se añade Zotero al PATH:\n1 echo \u0026#39;export PATH=$PATH:/var/lib/flatpak/exports/bin\u0026#39; \u0026gt;\u0026gt; ~/.bashrc Se ejecuta Zotero:\n1 flatpak run org.zotero.Zotero Se sincroniza la biblioblioteca y se instala el plugin BetterBibTex. Para instalar el plugin de BetterBibTex se sigue su documentación.\nUna vez instalado, añadir el siguiente script para que añada las keywords al exportarlo con\nOwnCloud Seguir la guía de installación para Debian.\nUna vez esté instalado, sincronizar carpetas.\nThunderbird Copiar y pegar la carpeta .thunderbird para hacer migración completa. Instalar con:\n1 sudo apt install thunderbird Pip 1 sudo apt install python3-pip Node y npm 1 2 sudo curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo bash - sudo apt-get install -y nodejs Kubernetes kubectl Install using native package management\nConfiguración de sonido HDMI Según este post, se debe añadir en /etc/pulse/default.pa lo siguiente:\n1 2 3 load-module module-alsa-sink device=hdmi:0 load-module module-combine-sink sink_name=combined set-default-sink combined Customización de xfce en Debian Tema Se descargan temas desde xfce-look, filtrando por rating. Alguno recomendado son Qogir-dark, Ultimate-dark o Nordic . Se descomprimen y se copian en la carpeta .themes, ubicada en /home/nombreUsuario/.themes.\nSe accede a Appeareance -\u0026gt; Themes -\u0026gt; Qogir-dark.\nIconos Se añaden los iconos Qogir-dark. Son descargados de xfce-look, se descomprimen y se copian en la carpeta .icons ubicada en /home/nombreUsuario/.icons.\nSe accede a Appeareance -\u0026gt; Icons -\u0026gt; Qogir-dark\nDock Instalación de Plank:\n1 sudo apt-get install plank Gestor de ventanas Instalar emerald:\n1 sudo apt install emerald Ejecutar el programa emerald-theme-manager y escoger un tema:\n1 emerald-theme-manager Correr en segundo plano:\n1 emerald --replace \u0026amp; Plymouth Pasos seguidos de la wiki oficial de Debian.\nGestor de ventanas i3wm 1 sudo apt install i3 i3status Wikipedia, Debian\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nOh My Zsh Documentation, Install oh-my-zsh\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nDebian Documentation, Fonts\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nVSCodium Documentation, Installation\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-04-02T00:00:00Z","permalink":"/p/configuraci%C3%B3n-de-debian/","title":"Configuración de Debian"},{"content":"En esta entrada se configurará el sistema operativo Debian.\n¿Qué es Debian? Debian GNU/Linux es un sistema operativo libre, desarrollado por miles de voluntarios de todo el mundo, que colaboran a través de Internet.\nLa dedicación de Debian al software libre, su base de voluntarios, su naturaleza no comercial y su modelo de desarrollo abierto la distingue de otras distribuciones del sistema operativo GNU1.\nAñadir drivers para la tarjeta de WiFi y NVIDIA Ejecutando los siguientes comandos se iniciará sesión como root y se añadirán los repositorios necesarios para añadir los drivers no incluidos en los repositorios totalmente libres:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 # Log in as root su - # Install vim apt install -y vim # Add contrib and non-free reopositories ## Edit /etc/apt/sources.list vim /etc/apt/sources.list ## Add contrib and non-free at the end deb http://mirror.librelabucm.org/debian/ buster main contrib non-free deb http://security.debian.org/debian-security buster/updates main contrib non-free deb http://mirror.librelabucm.org/debian/ buster-updates main contrib non-free # Add non-free drivers for WiFi apt install -y firmware-iwlwifi firmware-atheros firmware-misc-nonfree firmware-intelwimax firmware-realtek firmware-linux firmware-linux-nonfree Comprobar que los paquetes han sido instalados:\n1 sudo apt list --installed | grep firmware Añadir a un usuario al grupo sudo 1 2 su - usermod -aG sudo username Comprobar que se ha añadido al grupo sudo 1 getent group sudo Iniciar sesión con el usuario del grupo sudo 1 su - username Instalar git y wget 1 sudo apt install git wget -y Instalar zsh y Oh my zsh2 1 2 sudo apt install zsh sh -c \u0026#34;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34; Instalar Powerlevel10k Descargar y pegar las 4 fuentes .ttf Meslo Nerd en /usr/local/share/fonts. Deben tener los permisos 644 (-rw-r\u0026ndash;r\u0026ndash;).3\nMesloLGS NF Regular.ttf MesloLGS NF Bold.ttf MesloLGS NF Italic.ttf MesloLGS NF Bold Italic.ttf Creamos la carpeta /usr/local/share/fonts:\n1 2 sudo mkdir /usr/local/share/fonts cd /usr/local/share/fonts Descargamos las fuentes:\n1 sudo wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf Clonar el proyecto de powerlevel10k:\n1 git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k Sustituir el siguiente valor en ~/.zshrc:\n1 ZSH_THEME=\u0026#34;powerlevel10k/powerlevel10k\u0026#34; Configurar al gusto y actualizar los cambios del fichero ~/.zshrc:\n1 source ~/.zshrc Añadir lanzadores al menú Utilizar el siguiente comando para emular en zsh las aplicaciones en /etc/profile.\n1 emulate sh -c \u0026#39;source /etc/profile\u0026#39; Instalación de programas recomendados Snapd Instalación Se instala los paquetes snapd y core:\n1 2 sudo apt install snapd sudo snap install core Añadir ruta de ejecutables al PATH de bash y Zhs Se añade la ruta de ejecutables snap al PATH:\n1 2 3 4 echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc Se comprueba que se ha añadido correctamente la ruta:\n1 echo $PATH Añadir lanzadores al menú de aplicaciones Se crea un enlace simbólico desde el directorio que almacena los lanzadores de snaps (/var/lib/snapd/desktop/applications) al directorio de aplicaciones del sistema (usr/share/applications/)\n1 sudo ln -s /var/lib/snapd/desktop/applications /usr/share/applications/snapd Flatpak Instalación De la documentación oficial de Flatpak, se siguen los siguientes pasos:\nInstalar Flatpak 1 sudo apt install flatpak -y Se instala el repositorio de Flatpak 1 flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo Se reinicia el sistema para aplicar los cambios. Añadir lanzadores al menú Se crea un enlace simbólico desde el directorio que almacena los lanzadores de flatpak (/var/lib/flatpak/exports/share/applications/) al directorio de aplicaciones del sistema (usr/share/applications/)\n1 sudo ln -s /var/lib/flatpak/exports/share/applications/ /usr/share/applications/flatpak Aptitude 1 sudo apt install aptitude Cliente de sincronización de Nextcloud Descargar el archivo AppImage desde Nextcloud, darle permisos de ejecución al usuario y ejecutarlo con:\n1 2 chmod u+x Nextcloud-3.3.5-x86_64.AppImage ./Nextcloud-3.3.5-x86_64.AppImage Sincronizar carpetas.\nKeePassXC Nota: se instala a través de Snap porque los repositorios oficiales tienen una versión desactualizada.\nSe instala a través de snap: 1 sudo snap install keepassxc Se descarga la extensión para el navegador.\nSe configura la extensión del navegador a través de un script oficial de KeePassXC. Guardar script y ejecutar:\n1 2 wget https://raw.githubusercontent.com/keepassxreboot/keepassxc/master/utils/keepassxc-snap-helper.sh zsh keepassxc-snap-helper.sh En caso de obtener el error Could not find keepassxc.proxy! Ensure the keepassxc snap is installed properly., esto se debe a que falta añadir la ruta de ejecutables snap al PATH mediante:\n1 2 3 4 echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.zshrc source ~/.zshrc echo \u0026#34;export PATH=$PATH:/snap/bin\u0026#34; \u0026gt;\u0026gt; ~/.bashrc source ~/.bashrc Volver a ejecutar el script:\n1 bash keepassxc-snap-helper.sh VSCodium 4 Añade la clave GPG del repositorio: 1 wget -qO - https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg | gpg --dearmor | sudo dd of=/etc/apt/trusted.gpg.d/vscodium.gpg Añade el repositorio: 1 2 3 4 echo \u0026#39;deb [ signed-by=/usr/share/keyrings/vscodium-archive-keyring.gpg ] https://paulcarroty.gitlab.io/vscodium-deb-rpm-repo/debs vscodium main\u0026#39; | sudo tee /etc/apt/sources.list.d/vscodium.list Actualización de repositorios e instalación de VSCodium: 1 sudo apt update \u0026amp;\u0026amp; sudo apt install codium Usar LaTeX con VSCodium En settings buscar por word wrap y activar para que las líneas no sean infinitas. Instalar la distibución de LaTeX Texlive (recomendada por la extensión LateX Workshop de VSCodium), ChkTex para comprobar la semántica de Latex y texlive-extra-utils para extensiones como latexindent. 1 apt-get install -y texlive texlive-latex-extra texlive-extra-utils chktex latexmk texlive-fonts-recommended texlive-fonts-extra texlive-science texlive-latex-base-doc Añadir la ruta 1 2 3 4 echo \u0026#39;export PATH=$PATH:/usr/share\u0026#39; \u0026gt;\u0026gt; ~/.bashrc echo \u0026#39;export PATH=$PATH:/usr/share\u0026#39; \u0026gt;\u0026gt; ~/.zshrc source ~/.bashrc source ~/.zshrc Inskape Instalar a través de los repositorios de flatpak.\n1 flatpak install org.inkscape.Inkscape Mattermost-Desktop Según la documentación oficial de Mattermost, para los sistemas operativos basados en Debian, los pasos a seguir son:\nSe descarga la última version de Mattermost (usar la página documentación oficial): 64-bit systems mattermost-desktop-4.6.2-linux-amd64.deb Zotero Los pasos que se han tomado de referencia son los que vienen en la wiki de Debian para instalar Zotero.\nSe instala Zotero a través de Flatpak:\n1 flatpak install flathub org.zotero.Zotero Se añade Zotero al PATH:\n1 echo \u0026#39;export PATH=$PATH:/var/lib/flatpak/exports/bin\u0026#39; \u0026gt;\u0026gt; ~/.bashrc Se ejecuta Zotero:\n1 flatpak run org.zotero.Zotero Se sincroniza la biblioblioteca y se instala el plugin BetterBibTex. Para instalar el plugin de BetterBibTex se sigue su documentación.\nUna vez instalado, añadir el siguiente script para que añada las keywords al exportarlo con\nOwnCloud Seguir la guía de installación para Debian.\nUna vez esté instalado, sincronizar carpetas.\nThunderbird Copiar y pegar la carpeta .thunderbird para hacer migración completa. Instalar con:\n1 sudo apt install thunderbird Pip 1 sudo apt install python3-pip Node y npm 1 2 sudo curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo bash - sudo apt-get install -y nodejs Kubernetes kubectl Install using native package management\nConfiguración de sonido HDMI Según este post, se debe añadir en /etc/pulse/default.pa lo siguiente:\n1 2 3 load-module module-alsa-sink device=hdmi:0 load-module module-combine-sink sink_name=combined set-default-sink combined Customización de xfce en Debian Tema Se descargan temas desde xfce-look, filtrando por rating. Alguno recomendado son Qogir-dark, Ultimate-dark o Nordic . Se descomprimen y se copian en la carpeta .themes, ubicada en /home/nombreUsuario/.themes.\nSe accede a Appeareance -\u0026gt; Themes -\u0026gt; Qogir-dark.\nIconos Se añaden los iconos Qogir-dark. Son descargados de xfce-look, se descomprimen y se copian en la carpeta .icons ubicada en /home/nombreUsuario/.icons.\nSe accede a Appeareance -\u0026gt; Icons -\u0026gt; Qogir-dark\nDock Instalación de Plank:\n1 sudo apt-get install plank Gestor de ventanas Instalar emerald:\n1 sudo apt install emerald Ejecutar el programa emerald-theme-manager y escoger un tema:\n1 emerald-theme-manager Correr en segundo plano:\n1 emerald --replace \u0026amp; Plymouth Pasos seguidos de la wiki oficial de Debian.\nGestor de ventanas i3wm 1 sudo apt install i3 i3status Wikipedia, Debian\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nOh My Zsh Documentation, Install oh-my-zsh\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nDebian Documentation, Fonts\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nVSCodium Documentation, Installation\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-04-02T00:00:00Z","permalink":"/p/configuraci%C3%B3n-de-debian/","title":"Configuración de Debian"},{"content":"En esta entrada se instalará y se configurará el sistema operativo Debian con volúmenes LVM cifrados con LUKS.\n¿Qué es Debian? Debian GNU/Linux es un sistema operativo libre, desarrollado por miles de voluntarios de todo el mundo, que colaboran a través de Internet.\nLa dedicación de Debian al software libre, su base de voluntarios, su naturaleza no comercial y su modelo de desarrollo abierto la distingue de otras distribuciones del sistema operativo GNU1.\n¿Qué es LVM (Logical Volume Manager)? LVM es una implementación de un gestor de volúmenes lógicos para el núcleo Linux. LVM incluye muchas de las características que se esperan de un administrador de volúmenes, incluyendo:\nRedimensionado de grupos lógicos Redimensionado de volúmenes lógicos Instantáneas de sólo lectura (LVM2 ofrece lectura y escritura) RAID0 de volúmenes lógicos. LVM no implementa RAID1 o RAID5, por lo que se recomienda usar software específico de RAID para estas operaciones, teniendo las LV por encima del RAID2. En esta configuración no se usará RAID.\n¿Qué es LUKS (Linux Unified Key Setup)? LUKS es una especificación de cifrado de disco creado por Clemens Fruhwirth, originalmente destinado para Linux. Mientras la mayoría del software de cifrado de discos implementan diferentes e incompatibles formatos no documentados, LUKS especifica un formato estándar en disco, independiente de plataforma, para usar en varias herramientas. Esto no sólo facilita la compatibilidad y la interoperabilidad entre los diferentes programas, sino que también garantiza que todas ellas implementen gestión de contraseñas en un lugar seguro y de manera documentada. La implementación de referencia funciona en Linux y se basa en una versión mejorada de cryptsetup, utilizando dm-crypt como la interfaz de cifrado de disco3.\nTabla de particiones Se utiliza el formato ext4 para las particiones porque mejora la velocidad de entrada y salida y utiliza menos CPU que los formatos ext3 y ext2. Se recomiendan como mínimo los siguientes valores:\nParticion Tamaño recomendado Asignado Debian Asignado Propio Contiene / \u0026gt;= 750MB 22GB 64GB /etc, /bin, /sbin, /lib, /dev, /usr /usr \u0026gt;= 4-6GB 0 0 Programas de usuario, lib y docs /var \u0026gt;= 2-3GB 32GB 112GB Variables de datos como emails /tmp \u0026gt;= 100MB 16GB 32GB Páginas web, caché de paquetes, datos temporales /home \u0026gt;= 100MB 200GB 288GB Directorio con Documentos, Descargas, \u0026hellip; /boot \u0026gt;= 256MB 500MB 512GB Partición Primaria, ext4 o ext2, no se recomienda cifrarla /boot/efi \u0026gt;= 100MB 250MB 0 No se recomienda cifrarla y bootable flag: on /swap \u0026gt;= 8GB 16GB 16GB Área de intercambio Pasos seguidos Se recomienda conectar la máquina a través de ethernet para que se actualice el sistema durante la instalación.\nSe configura el idioma, región, teclado, etc. (Saltar paso) Se realiza unas particiones manuales, concretamente se realizan 3, una para /boot, otra para /boot/efi y otra para las demás particiones que irá cifrada a través de LUKS. Se cifra con LUKS y se elige una contraseña de más de 20 carácteres. Se crea un volumen LVM y posteriormente se realizan las particiones de volumen lógico para cada partición. Se asignan las etiquetas y se termina la configuración de las particiones. Se le da un hostname y se crea el usuario root y el usuario sin privilegios de administrador. Referencias recomendadas Arch Wiki, dm-crypt/Encrypting an entire system Debian Wiki, LVM Youtube, How to install Debian GNU/Linux with LUKS encrypted LVM Wikipedia, Debian\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, Logical Volume Manager (Linux)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, LUKS (Linux Unified Key Setup)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-04-02T00:00:00Z","permalink":"/p/instalaci%C3%B3n-de-debian-con-vol%C3%BAmenes-lvm-cifrados-con-luks/","title":"Instalación de Debian con volúmenes LVM cifrados con LUKS"},{"content":"En esta entrada se instalará y se configurará el sistema operativo Debian con volúmenes LVM cifrados con LUKS.\n¿Qué es Debian? Debian GNU/Linux es un sistema operativo libre, desarrollado por miles de voluntarios de todo el mundo, que colaboran a través de Internet.\nLa dedicación de Debian al software libre, su base de voluntarios, su naturaleza no comercial y su modelo de desarrollo abierto la distingue de otras distribuciones del sistema operativo GNU1.\n¿Qué es LVM (Logical Volume Manager)? LVM es una implementación de un gestor de volúmenes lógicos para el núcleo Linux. LVM incluye muchas de las características que se esperan de un administrador de volúmenes, incluyendo:\nRedimensionado de grupos lógicos Redimensionado de volúmenes lógicos Instantáneas de sólo lectura (LVM2 ofrece lectura y escritura) RAID0 de volúmenes lógicos. LVM no implementa RAID1 o RAID5, por lo que se recomienda usar software específico de RAID para estas operaciones, teniendo las LV por encima del RAID2. En esta configuración no se usará RAID.\n¿Qué es LUKS (Linux Unified Key Setup)? LUKS es una especificación de cifrado de disco creado por Clemens Fruhwirth, originalmente destinado para Linux. Mientras la mayoría del software de cifrado de discos implementan diferentes e incompatibles formatos no documentados, LUKS especifica un formato estándar en disco, independiente de plataforma, para usar en varias herramientas. Esto no sólo facilita la compatibilidad y la interoperabilidad entre los diferentes programas, sino que también garantiza que todas ellas implementen gestión de contraseñas en un lugar seguro y de manera documentada. La implementación de referencia funciona en Linux y se basa en una versión mejorada de cryptsetup, utilizando dm-crypt como la interfaz de cifrado de disco3.\nTabla de particiones Se utiliza el formato ext4 para las particiones porque mejora la velocidad de entrada y salida y utiliza menos CPU que los formatos ext3 y ext2. Se recomiendan como mínimo los siguientes valores:\nParticion Tamaño recomendado Asignado Debian Asignado Propio Contiene / \u0026gt;= 750MB 22GB 64GB /etc, /bin, /sbin, /lib, /dev, /usr /usr \u0026gt;= 4-6GB 0 0 Programas de usuario, lib y docs /var \u0026gt;= 2-3GB 32GB 112GB Variables de datos como emails /tmp \u0026gt;= 100MB 16GB 32GB Páginas web, caché de paquetes, datos temporales /home \u0026gt;= 100MB 200GB 288GB Directorio con Documentos, Descargas, \u0026hellip; /boot \u0026gt;= 256MB 500MB 512GB Partición Primaria, ext4 o ext2, no se recomienda cifrarla /boot/efi \u0026gt;= 100MB 250MB 0 No se recomienda cifrarla y bootable flag: on /swap \u0026gt;= 8GB 16GB 16GB Área de intercambio Pasos seguidos Se recomienda conectar la máquina a través de ethernet para que se actualice el sistema durante la instalación.\nSe configura el idioma, región, teclado, etc. (Saltar paso) Se realiza unas particiones manuales, concretamente se realizan 3, una para /boot, otra para /boot/efi y otra para las demás particiones que irá cifrada a través de LUKS. Se cifra con LUKS y se elige una contraseña de más de 20 carácteres. Se crea un volumen LVM y posteriormente se realizan las particiones de volumen lógico para cada partición. Se asignan las etiquetas y se termina la configuración de las particiones. Se le da un hostname y se crea el usuario root y el usuario sin privilegios de administrador. Referencias recomendadas Arch Wiki, dm-crypt/Encrypting an entire system Debian Wiki, LVM Youtube, How to install Debian GNU/Linux with LUKS encrypted LVM Wikipedia, Debian\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, Logical Volume Manager (Linux)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, LUKS (Linux Unified Key Setup)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-04-02T00:00:00Z","permalink":"/p/instalaci%C3%B3n-de-debian-con-vol%C3%BAmenes-lvm-cifrados-con-luks/","title":"Instalación de Debian con volúmenes LVM cifrados con LUKS"},{"content":"En esta entrada se configurará el sistema operativo Arch.\n1. Instalación de Arch 1.1. ¿Qué es Arch? Arch Linux es una distribución GNU/Linux de propósito general x86-64, desarrollada de forma independiente, que se esfuerza por ofrecer las últimas versiones estables de la mayoría del software siguiendo un modelo rolling-release. La instalación por defecto es un sistema base mínimo, configurado por el usuario para añadir sólo lo que se requiere a propósito 1.\n1.2. Conceptos básicos LVM es una implementación de un gestor de volúmenes lógicos para el núcleo Linux. LVM incluye muchas de las características que se esperan de un administrador de volúmenes, incluyendo:\nRedimensionado de grupos lógicos Redimensionado de volúmenes lógicos Instantáneas de sólo lectura (LVM2 ofrece lectura y escritura) RAID0 de volúmenes lógicos. LVM no implementa RAID1 o RAID5, por lo que se recomienda usar software específico de RAID para estas operaciones, teniendo las LV por encima del RAID 2. En esta configuración no se usará RAID.\nLUKS es una especificación de cifrado de disco creado por Clemens Fruhwirth, originalmente destinado para Linux. Mientras la mayoría del software de cifrado de discos implementan diferentes e incompatibles formatos no documentados, LUKS especifica un formato estándar en disco, independiente de plataforma, para usar en varias herramientas. Esto no sólo facilita la compatibilidad y la interoperabilidad entre los diferentes programas, sino que también garantiza que todas ellas implementen gestión de contraseñas en un lugar seguro y de manera documentada. La implementación de referencia funciona en Linux y se basa en una versión mejorada de cryptsetup, utilizando dm-crypt como la interfaz de cifrado de disco 3.\nUn boot loader carga un kernel del sistema operativo en la memoria y lo ejecuta. Un boot manager entrega el control a otro programa de arranque. GRUB es tanto un boot loader como un boot manager. Refind es sólo un boot manager.\nOtro concepto fundamental es conocer la diferencia entre EFI/UEFI y BIOS.\nLVM es una implementación de un gestor de volúmenes lógicos para el núcleo Linux. LVM incluye muchas de las características que se esperan de un administrador de volúmenes, incluyendo:\nRedimensionado de grupos lógicos Redimensionado de volúmenes lógicos Instantáneas de sólo lectura (LVM2 ofrece lectura y escritura) RAID0 de volúmenes lógicos. LVM no implementa RAID1 o RAID5, por lo que se recomienda usar software específico de RAID para estas operaciones, teniendo las LV por encima del RAID 2. En esta configuración no se usará RAID.\nLUKS es una especificación de cifrado de disco creado por Clemens Fruhwirth, originalmente destinado para Linux. Mientras la mayoría del software de cifrado de discos implementan diferentes e incompatibles formatos no documentados, LUKS especifica un formato estándar en disco, independiente de plataforma, para usar en varias herramientas. Esto no sólo facilita la compatibilidad y la interoperabilidad entre los diferentes programas, sino que también garantiza que todas ellas implementen gestión de contraseñas en un lugar seguro y de manera documentada. La implementación de referencia funciona en Linux y se basa en una versión mejorada de cryptsetup, utilizando dm-crypt como la interfaz de cifrado de disco 3.\nEn la tabla de particiones Tabla de particiones se utiliza el formato ext4 para las particiones porque mejora la velocidad de entrada y salida y utiliza menos CPU que los formatos ext3 y ext2. Se recomiendan como mínimo los siguientes valores:\nParticion Tamaño recomendado Asignado Debian Asignado Propio Contiene / \u0026gt;= 750MB 22GB 64GB /etc, /bin, /sbin, /lib, /dev, /usr /usr \u0026gt;= 4-6GB 0 0 Programas de usuario, lib y docs /var \u0026gt;= 2-3GB 32GB 112GB Variables de datos como emails /tmp \u0026gt;= 100MB 16GB 32GB Páginas web, caché de paquetes, datos temporales /home \u0026gt;= 100MB 200GB 288GB Directorio con Documentos, Descargas, \u0026hellip; /boot \u0026gt;= 256MB 500MB 512GB Partición Primaria, ext4 o ext2, no se recomienda cifrarla /boot/efi \u0026gt;= 100MB 250MB 0 No se recomienda cifrarla y bootable flag: on /swap \u0026gt;= 8GB 16GB 16GB Área de intercambio 1.3. Quemar la imagen de Arch Se ha seguido los pasos de la instalación de Arch 4.\nUna forma de quemar una imagen es con el comando dd como se muestra a continuación:\n1 2 # See the partitions lsblk -f 1 2 # Umount the USB partition umount /dev/sda1 1 2 # Flash the ISO into USB sudo dd bs=4M if=archlinux-2022.05.01-x86_64.iso of=/dev/sda conv=fsync oflag=direct status=progress 1.4. Arrancamos Arch Conectamos el USB, ethernet y mediante la BIOS, arrancamos Boot Arch Linux desde el USB.\n2. Configuración inicial 2.1. Definir la distribución del teclado en el entorno live Cambiamos el teclado a castellano:\n1 loadkeys es 2.2. Configurar la WiFi Si no está instalado el paquete iwd, lo instalamos con una conexión ethernet;\n1 sudo pacman -yS iwd Configuramos la interfaz WiFi con:\n: wlan0 : nombre de la WiFi : contraseña Para localizar dichos valores, podemos utilizar el comando iwctl y después device device show.\n1 iwctl --passphrase \u0026lt;passphrase\u0026gt; station \u0026lt;device\u0026gt; connect \u0026lt;SSID\u0026gt; Para ver las redes WiFi disponibles escribimos los siguientes comandos:\n1 2 3 iwctl station list iwctl station wlan0 scan iwctl station station get-networks Comprobamos que tenemos IP con:\n1 ip a Ahora si cambiamos la contraseña al usuario root, con el comando passwd, nos podremos conectar a la máquina con:\n1 ssh root@\u0026lt;IP-máquina\u0026gt; 2.3. Actualización horaria Seguimos esta guía con los primeros pasos después de haber instalado Arch 5. Cambiamos la hora a la que nos corresponde con:\n1 timedatectl set-timezone Europe/Madrid Actualizamos el reloj con internet:\n1 timedatectl set-ntp true 2.4. Desbloquear partición cifrada con LUKS y configurada con volúmenes lógicos LVM Desciframos la partición con:\n1 cryptsetup luksOpen /dev/sdaX all-Operative-Systems Posteriormente detectaremos el grupo de los volúmenes LVM con:\n1 vgchange -a y Nota: es probable que los siguientes pasos no funcionen a la primera y sea necesario completarlos con la siguiente sección. Por lo que se podría obviar el final de esta sección e instalar el grub directamente.\nUna vez ejecutados los comandos anteriores, seguir con la instalación hasta la instalación del GRUB. Volvemos a abrir una terminal e identificamos el UUID de la partición cifrada con:\n1 blkid /dev/sdaX \u0026gt;\u0026gt; nano /etc/crypttab Lo siguiente es modificar el archivo /etc/crypttab:\n1 nano /etc/crypttab Y se añade el siguiente contenido, donde el UUID es el obtenido del comando blkid:\n1 all-Operative-Systems UUID=524c1ad6-1111-2222-0000-c8db1286b262 none luks Parece que esta configuración es necesaria repetirla más adelante.\n2.5. Montar las particiones Según la documentación de Arch para crear sistemas de archivos y montar volúmnes, formateamos los volúmenes ya creados y montamos las siguientes particiones:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 # Formateamos y montamos la partición root mkfs.ext4 -L arch-root /dev/lvm-all-OS/lvm-arch-root mount /dev/lvm-all-OS/lvm-arch-root /mnt # Formateamos y montamos la partición home mkfs.ext4 -L arch-home /dev/lvm-all-OS/lvm-arch-home mount --mkdir /dev/lvm-all-OS/lvm-arch-home /mnt/home # Formateamos y montamos la partición EFI o ESP, y la BOOT # Si no está formateada la partición boot en FAT32, utilizamos el siguiente comando comentado # mkfs.fat -F 32 -n boot-arch /dev/sda4 mkfs.ext4 -L boot-arch /dev/sda4 mount --mkdir /dev/sda4 /mnt/boot mount --mkdir /dev/sda1 /mnt/boot/efi 2.6. Instalación de paquetes esenciales y recomendados Fuentes:\n[https://denovatoanovato.net/instalar-arch-linux/#uefi] [https://linuxhint.com/setup-luks-encryption-on-arch-linux/] Probar a seguirlo con encrypt en vez de lvm2 o poniendo ambas Paquetes esenciales:\n1 pacstrap /mnt base base-devel linux linux-firmware lvm2 nano vim intel-ucode iwd Paquetes recomendados (aunque alguno puede dar error):\n1 pacstrap /mnt grub networkmanager dhcpcd efibootmgr gvfs gvfs-mtp netctl wpa_supplicant dialog nano initramfs Para activar el touchpad, instalar el paquete xf86-input-synaptics.\nOtros paquetes adicionales podrían ser os-probes (parece que da error).\nDespués generaremos el archivo fstab, el encargado de contiener la tabla de particiones del sistema.\n1 genfstab -pU /mnt \u0026gt;\u0026gt; /mnt/etc/fstab 2.7. Entrar al sistema base Ya es momento que entremos al sistema base instalado, para seguir configurándolo desde dentro. Para acceder al sistema en chroot ejecutamos:\n1 arch-chroot /mnt 2.8 Actualizar hostname 1 echo nombredehost \u0026gt; /etc/hostname 2.9. Actualizar zona horaria 1 ln -sf /usr/share/zoneinfo/Europe/Madrid /etc/localtime 2.10. Ajustamos el reloj 1 hwclock --systohc 2.11. Configurar distibución de teclado 1 echo KEYMAP=es \u0026gt;\u0026gt; /etc/vconsole.conf 2.12. Configurar mkinitcpio Fuentes:\n[https://www.linuxserver.io/blog/2014-01-18-installing-arch-linux-with-root-on-an-lvm] [https://wiki.archlinux.org/title/LVM_(Espa%C3%B1ol)#Crear_sistemas_de_archivos_y_montar_los_vol%C3%BAmenes_l%C3%B3gicos] 1 nano /etc/mkinitcpio.conf Modificamos el HOOKS y añadimos lo siguiente:\n1 HOOKS=(base udev autodetect keyboard keymap consolefont modconf block encrypt lvm2 filesystems fsck) Y ejecutamos:\n1 mkinitcpio -p linux Ahora, ya podríamos desmontar la partición y reiniciar el sistema operativo con los siguientes comandos en caso de no haber instalado Arch en una partición cifrada. En caso de haberlo instalado en una partición cifrada, deberemos configurar el grub para indicar que está cifrado (paso 2.13).\n1 2 umount -R /mnt sudo reboot 2.13. Configurar Grub Instalamos grub con los siguientes comandos:\n1 grub-install --boot-directory=/boot --efi-directory=/boot/efi --target=x86_64-efi --recheck /dev/sda4 En /etc/default/grub editamos la línea GRUB_CMDLINE_LINUX por:\n1 GRUB_CMDLINE_LINUX=\u0026#34;cryptdevice=/dev/sda2:luks:allow-discards\u0026#34; [Consejo] Para buscar automáticamente otros sistemas operativos en su ordenador, instale os-prober (pacman -S os-prober) antes de ejecutar el siguiente comando.\nPor último, configuramos el grub con:\n1 2 grub-mkconfig -o /boot/grub/grub.cfg grub-mkconfig -o /boot/efi/EFI/arch/grub.cfg 2.14. Configuración para particición cifrada con LUKS Nota: los siguientes son los repetidos en la sección 2.4., por lo que fijarse bien si funcionó en ese paso o hay que repetirlos.\nDetectamos el UUID de la partición cifrada. La X de sdaX corresponde al número de la partición cifrada, si no se conoce simplemente utilizar el comando blkid.\n1 blkid /dev/sdaX \u0026gt;\u0026gt; /etc/crypttab Editamos el archivo /etc/crypttab con nano:\n1 sudo nano /etc/crypttab Añadimos lo siguiente:\n1 all-Operative-Systems UUID=524c1ad6-1111-2222-0000-c8db1286b262 none luks Instalamos initramfs:\n1 pacman -Sy initramfs Una vez terminado se utiliza el siguiente comando para actualizar initramfs:\n1 sudo update-initramfs -u 2.14 (Opcional) Inicialización del llavero de pacman Instalamos el llavero:\n1 pacman -Sy archlinux-keyring Inicializamos el llavero de pacman y rellenar las claves de firma de los paquetes de Arch Linux ARM (en caso de ser una raspberry):\n1 2 pacman-key --init pacman-key --populate archlinuxarm 2.15 Desmontar las particiones Desmontamos la partición mnt\n1 umount -R /mnt Reiniciamos el sistema operativo con:\n1 sudo reboot 3. Configuración Avanzada Volvemos a acceder por ssh a la máquina y seguimos los siguientes pasos.\n3.1. Actualización del sistema Una vez tengamos una consola con un usuario sin privilegios de root, abriremos una nueva consola como el usuario root:\n1 su - La contraseña por defecto suele ser root o la que ya se haya configurado previamente.\nActualizamos Arch: 1 pacman -Syu 3.2. Actualización del idioma Si no está configurado anteriormente, descomentamos el idioma deseado en el archivo locale.gen (por ejemplo: en_US.UTF-8) :\n1 nano /etc/locale.gen Ejecutamos:\n1 locale-gen Y ejecutamos:\n1 localectl set-locale LANG=en_US.UTF-8 3.3. Cambio de hostname Cambiamos el hostname con:\n1 hostnamectl set-hostname \u0026lt;nombre\u0026gt; Añadimos un alias par el hostname en el archivo /etc/hosts del oredenador que estemos utilizando para la configuración. Usamos nano /etc/hosts:\n1 2 127.0.0.1\tlocalhost.localdomain\t\u0026lt;nombre\u0026gt;\tlocalhost ::1\tlocalhost.localdomain\t\u0026lt;nombre\u0026gt;\tlocalhost 3.4. (Opcional) Cambiar el color a la salida de pacman Si utilizamos Arch, ejecutamos:\n1 sed -i \u0026#39;s/#Color/Color/\u0026#39; /etc/pacman.conf 3.5. (Opcional) Añadimos 8GB de memoria SWAP Si utilizamos Arch, ejecutamos:\n1 fallocate -l 8192M /swapfile 3.6. (Opcional) Nuevo usuario con permisos sudo Si utilizamos Arch, ahora usaremos la utilidad visudo para editar los permisos de grupo para ejecutar comandos administrativos con sudo.\n1 2 pacman -S sudo EDITOR=nano visudo Descomentamos la siguiente línea:\n1 2 ## Uncomment to allow members of group sudo to execute any command %sudo ALL=(ALL:ALL) ALL Creamos un nuevo grupo sudo con:\n1 sudo groupadd sudo Creamos un nuevo usuario con:\n1 useradd -m -G sudo nombre_usuario Ponemos una contraseña al nuevo usuario:\n1 passwd nombre_usuario Una vez tengamos el nuevo usuario, borraremos el usuario alarm o el usuario por defecto de la instalación (en caso de existir uno).\n1 userdel alarm Modificamos los permisos del usuario que habíamos creado durante la instalació y lo añadidos al grupo sudo con el siguiente comando:\n1 2 su - usermod -aG sudo username Reiniciamos el sistema:\n1 reboot 3.6. Claves SSH En el siguiente paso es necesario copiar la clave pública al archivo ~/.ssh/authorized_keys de la máquina. Para ello se utilizará el siguiente comando:\n1 ssh-copy-id -i \u0026lt;identity.pub\u0026gt; pi@\u0026lt;ip de la máquina\u0026gt; Ahora nos pedirá la contraseña de nuestra clave SSH y nos conectaremos a la máquina mediante:\n1 ssh pi@\u0026lt;ip de la máquina\u0026gt; 3.7. (Optional) Configuración Wi-Fi Reproducido de la guía: los primeros pasos después de haber instalado Arch 5.karog, on ArchLinux ARM forums provee una manera de conectarse al Wi-Fi es muy sencilla. Como root, haz los siguientes pasos:\nnano /etc/systemd/network/wlan0.network para configurar la interfaz wlan0: Añade el siguiente contenido al archivo: 1 2 3 4 5 [Match] Name=wlan0 [Network] DHCP=yes wpa_passphrase \u0026quot;\u0026lt;SSID\u0026gt;\u0026quot; \u0026quot;\u0026lt;PASSWORD\u0026gt;\u0026quot; \u0026gt; /etc/wpa_supplicant/wpa_supplicant-wlan0.conf. Sustituye y por el nombre y la contraseña de su red Wi-Fi. systemctl enable wpa_supplicant@wlan0 para habilitar el Wi-Fi al arrancar systemctl start wpa_supplicant@wlan0 para conectarse al Wi-Fi. Ya está todo listo. Aunque, si alguna vez quieres quitar la conexión Wi-Fi (por ejemplo, cuando quieras hacer que se conecte sólo a través de ethernet):\nsystemctl stop wpa_supplicant@wlan0 systemctl disable wpa_supplicant@wlan0 rm /etc/wpa_supplicant/wpa_supplicant-wlan0.conf rm /etc/systemd/network/wlan0.network 4. Instalación de paquetes y programas 4.1. Paquetes básicos git y wget: 1 sudo pacman -S -y git wget yay: Los ayudantes de AUR más utilizados en Arch Linux son Yaourt y Packer. Puede utilizarlos fácilmente para las tareas de gestión de paquetes de Arch Linux, como la instalación y actualización de paquetes. Sin embargo, los dos han sido descontinuados en favor de yay, abreviatura de Yet Another Yaourt. Yay es un moderno ayudante de AUR escrito en el lenguaje GO. Tiene muy pocas dependencias y soporta el completamiento de pestañas de AUR para que no tengas que escribir los comandos en su totalidad.\nLo instalamos con los siguientes comandos en el directorio opt por ser la carpeta destinada a almacenar los programas externos.\n1 2 3 4 cd /opt sudo git clone https://aur.archlinux.org/yay.git sudo chown -R $USER:$USER ./yay makepkg -si Actualizamos los repos con:\n1 sudo yay -Syu 4.2 Instalar zsh, Oh my zsh y Powerlevel10k Instalamos zsh y oh-my-zsh con los siguientes comandos:\n1 2 sudo pacman -S zsh sh -c \u0026#34;$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\u0026#34; Para instalar Powerlevel10k, necesitamos instalar las fuentes necesarias mediante el comando:\n1 2 yay -Sy --noconfirm ttf-meslo-nerd-font-powerlevel10k sudo pacman -S powerline-common awesome-terminal-fonts Como alternativa lo podremos hacer manualmente si se descarga y se pega las 4 fuentes .ttf Meslo Nerd en /usr/local/share/fonts. Deben tener los permisos 644 (-rw-r\u0026ndash;r\u0026ndash;)6.\nMesloLGS NF Regular.ttf MesloLGS NF Bold.ttf MesloLGS NF Italic.ttf MesloLGS NF Bold Italic.ttf Creamos la carpeta /usr/local/share/fonts:\n1 2 sudo mkdir /usr/local/share/fonts cd /usr/local/share/fonts Descargamos las fuentes:\n1 sudo wget https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf Instalamos y configuramos Powerlevel10k con:\n1 2 yay -S --noconfirm zsh-theme-powerlevel10k-git echo \u0026#39;source /usr/share/zsh-theme-powerlevel10k/powerlevel10k.zsh-theme\u0026#39; \u0026gt;\u0026gt;~/.zshrc 4.2. Docker y docker compose Se recomienda instalar docker rootless (4.2.2.) pero puede dar problemas con algunos contenedores docker. En caso de no que quieras pegarte con esos problemas o que estes configurando un servidor en producción que requiera seguridad, sigue el siguiente apartado (4.2.1.).\n4.2.1. Instalación en Arch Instalamos docker de los repositorios oficiales:\n1 sudo pacman -Sy docker docker-compose Añadir usuario al grupo docker:\n1 sudo usermod -aG docker ${USER} Activamos el demonio de docker:\n1 2 sudo systemctl enable docker.service sudo systemctl enable docker.socket Si da error reiniciamos la máquina.\n4.2.2 Docker rootless Arch: 1 2 sudo pacman -S shadow sudo pacman -S fuse-overlayfs Añade kernel.unprivileged_userns_clone=1 in /etc/sysctl.conf:\n1 2 sudo nano /etc/sysctl.conf sudo sysctl --system 1 2 3 4 5 6 7 8 9 10 11 12 13 14 sudo touch /etc/subuid \u0026amp;\u0026amp; sudo touch /etc/subgid su - echo \u0026#34;pi:100000:65536\u0026#34; \u0026gt;\u0026gt; /etc/subgid echo \u0026#34;pi:100000:65536\u0026#34; \u0026gt;\u0026gt; /etc/subuid exit sudo systemctl disable --now docker.service docker.socket curl -fsSL https://get.docker.com/rootless | sh systemctl --user start docker systemctl --user enable docker sudo loginctl enable-linger $(whoami) export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock Se prueba con docker run -d -p 8080:80 nginx.\nSi queremos que se arranque en el arranque, escribimos los siguientes comandos:\n1 2 sudo systemctl enable docker.service sudo systemctl enable containerd.service 4.3 Gestor de ventanas i3wm Siguiendo los pasos de Low Orbit Flux - Arch Linux How to Install i3 Gaps,instalamos el paquete xorg-xinit que instala xinit. El programa xinit permite al usuario iniciar manualmente un servidor de visualización Xorg. Instalamos el servidor de ventanas X xorg y xterm.\n1 sudo pacman -S xorg xorg-xinit xterm Instalamos unos extras opcionales:\n1 pacman -S xorg-xeyes xorg-xclock Instalamos todo el grupo de i3, priorizamos i3-gaps sobre i3-wm por ser un fork el primero del segundo.\n1 sudo apt install i3-w Instalamos los drivers necesarios para nuestra máquina.\n1 2 3 sudo pacman -S nvidia nvidia-utils # NVIDIA sudo pacman -S xf86-video-amdgpu mesa # AMD sudo pacman -S xf86-video-intel mesa # Intel Seguimos los pasos de Low Orbit Flux - Arch Linux How to Install i3 Gaps hasta terminarlos.\n5. Referencias ArchLinux, Arch\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, Logical Volume Manager (Linux)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, LUKS (Linux Unified Key Setup)\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nArchLinux, Installation Guide\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nGitHub - TheZoc/Setting up guide for ArchLinux on Raspberry Pi.md\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nDebian Documentation, Fonts\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-04-02T00:00:00Z","permalink":"/p/instalaci%C3%B3n-y-configuraci%C3%B3n-de-arch/","title":"Instalación y configuración de Arch"},{"content":"Crear un grupo Se crea el grupo shared: 1 sudo groupadd shared Añadir usuario Se añade el usuario devops al grupo shared: 1 sudo usermod -a -G shared devops Para que los cambios surtan efecto se requiere cerrar sesión y volver a entrar en el usuario devops. Se comprobará con el comando:\n1 groups Cambiar el grupo de una carpeta y sus ficheros Se cambia el grupo de la carpeta wiki por shared: 1 sudo chgrp -R shared wiki Añadir permisos de escritura para el un grupo en una carpeta y sus ficheros Se añade los permisos de escritura w para el grupo de usuarios de la carpeta wiki.\n1 sudo chmod -R g+w wiki ","date":"2021-04-02T00:00:00Z","permalink":"/p/permisos-en-gnu/linux/","title":"Permisos en GNU/Linux"},{"content":"Cloud Recursos de formación en Cloud Kubernetes Kube academy\nKatakoda\nGuía visual para la resolución de problemas en despliegues de Kubernetes\nTécnicas avanzadas de Scheduling\n","date":"2021-03-05T10:46:34+01:00","permalink":"/p/recursos-de-formaci%C3%B3n-en-devops-y-materiales-de-aprendizaje/","title":"Recursos de formación en DevOps y materiales de aprendizaje"},{"content":"Instalar requirements.txt Pipenv 1 2 3 4 5 6 7 8 9 10 11 # Install pip install pipenv # Install a packages for the project pipenv install \u0026lt;package\u0026gt; # Activate Virtual Env pipenv shell # Run a script in the virtual env pipenv run python \u0026lt;script.py\u0026gt; Generate requirements.txt:\n1 pipenv lock -r \u0026gt;\u0026gt; requirements.txt ","date":"2021-02-17T09:13:29+01:00","permalink":"/p/python/","title":"Python"},{"content":"MLOps con GitHub Vídeo de flujo de trabajo MLOps con Github Actions - O\u0026rsquo;Really ","date":"2021-02-15T13:00:14+01:00","permalink":"/p/recursos-de-formaci%C3%B3n-en-mlops-y-rutas-de-aprendizaje/","title":"Recursos de formación en MLOps y rutas de aprendizaje"},{"content":"Preparar los ficheros para hacer un USB boot Descarga la imagen 1 wget \u0026lt;url-iso\u0026gt; Quemar la imagen de Arch Una forma de quemar una imagen es con el comando dd como se muestra a continuación:\n1 2 3 4 5 6 7 8 # See the partitions lsblk # Umount the USB partition umount /dev/sda1 # Flash the ISO into USB sudo dd bs=4M if=archlinux-2022.05.01-x86_64.iso of=/dev/sda conv=fsync oflag=direct status=progress Random things Cómo crear USB Boot Con Multiples Sistemas Operativos | How to make a USB boot With Multiple OS ","date":"2021-01-11T00:00:00Z","permalink":"/p/creaci%C3%B3n-de-un-usb-bootable/","title":"Creación de un USB Bootable"},{"content":"En esta entrada se instalará y se configurará Nextcloud para una Raspberry Pi. Se utilizará la versión dockerizada nextcloudpi y se instalará sobre el sistema operativo HypriotOS.\n¿Qué es Nextcloud? Nextcloud es una serie de programas de código abierto, tanto el cliente como el servidor, con el objetivo de crear un servicio de alojamiento de archivos. Permite el alojamiento en un servidor propio, a modo de nube privada, para no tener la dependencia de nubes de terceros como Dropbox o Google Drive.\n¿Qué es Nextcloudpi? NextCloudPi es una instacia especial de Nextcloud que está adaptada y optimizada al hardware de las Raspberry Pi. De manera que garantiza la interacción más fluida posible de todos los componentes.\n¿Qué es HypriotOS? HypriotOS es un sistema operativo basado en Debian optimizado para ejecutar Docker en plataformas ARM como las Raspberry Pi.\nInstalación de HypriotOS En los siguientes pasos, se procede a quemar la imagen de HypriotOS en una tarjeta SD que esté conectada a un ordenador con sistema operativo GNU/Linux con distribuciones basadas en Debian o en Arch.\nFlasheo de la imagen Para quemar la imagen dentro de la tarjeta microSD, existen diversas maneras de hacerlo. Se recomienda utilizar la herramienta flash instalada de como se indica en su página de documentación:\nInstalación de la herramienta flash Distribuciones basadas en Debian: Se instala la herramienta con los siguientes comandos:\n1 2 3 curl -LO https://github.com/hypriot/flash/releases/download/2.7.0/flash chmod +x flash sudo mv flash /usr/local/bin/flash Se instalan las dependencias con:\n1 2 sudo apt-get install -y pv curl python-pip unzip hdparm sudo pip install awscli Distribuciones basadas en Arch: La instalación más cómoda es instalar el paquete desde los repositorios oficiales de Arch. Para encontrar el paquete en el programa de añadir software buscar flash hypriot.\nQuema de la imagen en la tarjeta SD Una vez instalada la herramienta para quemar la imagen, se copia el enlace de la imagen ISO comprimida desde la página oficial de HypriotOS o se descarga la imagen. Durante el flasheo de la imagen, se puede realizar la configuración inicial del usuario y de la conexión WiFi. En caso de descargar la imagen es necesario verificar que el checksum es el mismo con los siguientes comandos:\n1 2 sha256sum hypriotos-rpi-v1.12.3.img.zip cat hypriotos-rpi-v1.12.3.img.zip.sha256 Una vez verificado el checksum se puede flasear la imagen con el comando a continuación. Aunque se recomienda leer y seguir la opción de configurar el WiFi antes de quemar la imagen.\n1 sudo flash hypriotos-rpi-v1.10.0.img.zip Para quemar la imagen con el enlace directo, ejecutar:\n1 sudo flash https://github.com/hypriot/image-builder-rpi/releases/download/v1.12.3/hypriotos-rpi-v1.12.3.img.zip Solicitará la ubicación de la partición de la tarjeta SD y una confirmación. Una vez termine el proceso, se introducirá la SD en la Raspberry Pi y ya está lista para usar.\nConfiguración del usuario inicial y WiFi Primer creamos un archivo llamado wifi.yaml con la siguiente plantilla, donde es necesario modificar el SSID del WiFi y la clave precompartida en texto plano o cifrada con wpa_passphrase SSID passwordWiFi. En caso de añadir la clave en texto plano será necesario ponerla entre comillas psk=\u0026quot;ContraseñaWiFi\u0026quot;, mientras que si se añade cifrada no serán necesarias las comillas psk=jghXt58cfvfgbksFSJhoA. Para conseguir la contraseña cifrada es necesario ejecutar en un terminal wpa_passphrase \u0026quot;NOMBRE_WIFI\u0026quot; pedirá la contraseña en texto plano y devolverá la contraseña cifrada.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #cloud-config # vim: syntax=yaml # # Set your hostname here, the manage_etc_hosts will update the hosts file entries as well hostname: hypriot manage_etc_hosts: true # You could modify this for your own user information users: - name: pi gecos: \u0026#34;Hypriot Pirate\u0026#34; sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash groups: users,docker,video,input plain_text_passwd: hypriot lock_passwd: false ssh_pwauth: true chpasswd: { expire: false } # # Set the locale of the system locale: \u0026#34;es_ES.UTF-8\u0026#34; # # Set the timezone # # Value of \u0026#39;timezone\u0026#39; must exist in /usr/share/zoneinfo timezone: \u0026#34;Europe/Madrid\u0026#34; # # Update apt packages on first boot package_update: true package_upgrade: true package_reboot_if_required: true #package_upgrade: false # # Install any additional apt packages you need here packages: - software-properties-common # - python-software-properties # - xinput-calibrator # - console-data # - keyboard-configuration # - ntp # # WiFi connect to HotSpot # # - use `wpa_passphrase SSID PASSWORD` to encrypt the psk write_files: - content: | allow-hotplug wlan0 iface wlan0 inet dhcp wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf iface default inet dhcp path: /etc/network/interfaces.d/wlan0 - content: | country=es ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid=\u0026#34;NOMBRE_WIFI\u0026#34; psk=\u0026#34;ContraseñaWiFi\u0026#34; proto=RSN key_mgmt=WPA-PSK pairwise=CCMP auth_alg=OPEN } path: /etc/wpa_supplicant/wpa_supplicant.conf # These commands will be ran once on first boot only runcmd: # Pickup the hostname changes - \u0026#39;systemctl restart avahi-daemon\u0026#39; # # Activate WiFi interface - \u0026#39;ifup wlan0\u0026#39; Una vez se haya descargado la imagen de HypriotOS y se haya configurado la platilla de configuración inicial guardada como wifi.yaml. Desde el mismo directorio que almacena los dos archivos ejecutamos:\n1 sudo flash --hostname hypriot --userdata wifi.yaml hypriotos-rpi-v1.12.3.img.zip Donde el flag --hostname sirve para cambiar el nombre de la máquina y el flag --userdata sirve para cargar la configuración inicial.\nSolicitará la ubicación de la partición de la tarjeta SD y una confirmación. Una vez termine el proceso, se introducirá la SD en la Raspberry Pi y ya está lista para usar.\nEn caso de querer cambiar el hostname después de la instalación, usar el siguiente comando:\n1 sudo hostnamectl set-hostname --static nuevohostname Además, para que sea un cambio persistenten es necesario modificar el archivo sudo nano /etc/cloud/cloud.cfg con lo siguiente:\n1 preserve_hostname: true Después comprobar que se ha cambiado el hostname en /etc/hostname y en /etc/hosts, si no es así modificarlo manualmente. Por último, reiniciar el sistema. Todo lo anterior es necesario debido a un error a partir de la versión de Hypriot 1.11 1.\nPrimer arranque de Raspberry Pi con HypriotOS Una vez instalado HypriotOS en la tarjeta SD, se introduce en la tarjeta en la Raspberry Pi y se conecta a la corriente de alimentación. Si se siguieron correctamento los pasos para preconfigurar el WiFi, al arrancar (tardará varios minutos, aproximadamente entr 5-10mins) será posible conectarse mediante SSH a la Raspberry Pi sin necesidad de conectar un cable RJ-45 (Ethernet) al router ni un teclado y monitor directamente a la máquina. Aunque a pesar de haber seguido correctamente los pasos antiores, se recomienda utilizar un teclado, un monitor y una conexión a internet mediante un cable Ethernet al router en el primer arranque. En caso de no tener monitor ni teclado, saltar a los pasos del apartado Localización de de la IP local de la Rasberry Pi y Acceso mediante ssh, leyendo los pasos anteriores para conocer las credenciales por defecto.\nIniciar sesión En caso de no haber utilizado, durante la instalación de hypriot, el flag \u0026ndash;user-data con el fichero de configuración wifi.yaml, el usuario por defecto es pirate y la contraseña hypriot.\nEn caso de si haber utilizado el fichero de ejemplo, el usuario es pi y la contraseña hypriot.\nCambio de la contraseña por defecto Es obligatorio cambiar la contraseña del usuario por defecto (pirate) o del usuario creado con la configuración del archivo .yaml (pi) a partir de este punto.\nPara cambiar la contraseña se utiliza el comando:\n1 passwd Según el blog de HyriotOS 2, por motivos de seguridad no existe un usuario root construido por defecto.\nCambio de idioma de teclado Una vez conectado el monitor y el teclado USB, por defecto se ejecuta el teclado de US (Estados Unidos). Para cambiar al teclado ES (España), instalar el paquete console-data:\n1 sudo apt install console-data Se abrirá una pantalla gráfica con cuatro opciones, seleccionar la opción select keymap from full list. En la siguiente ventana seleccionar pc/qwerty/Spanish/Standard/CP850.\nAhora ya funcionarán todas las letras menos la ñ. Para poder usarla ejecutar:\n1 sudo loadkeys es Localización de la IP local de la Rasberry Pi Un método para conocer la IP de la Raspberry Pi, contectada a un monitor y un teclado, iniciar sesión con el usuario por defecto pirate(o el usuario de wifi.yaml, en el ejemplo es pi) y la contraseña por defecto hypriot. Una vez dentro, se ejecuta el comando:\n1 sudo ip addr show Primero ver a qué red local estamos conectados con el ordenador que queremos configurar la raspberry pi:\n1 sudo ip addr show ó\n1 sudo ifconfig Una vez que tengamos el rango de la subred (habitualmente siempre es por defecto la 192.168.1.0/24), realizamos un escaneo de red con nmap:\n1 sudo nmap -f 192.168.1.0/24 El flag -f es para realizar el escaneo rápido y poder averiguar la IP de la Raspberry mediante los dígitos fijos de la MAC del fabricante.\nUna vez terminado el escaneo, se mostrará una IP que la dirección MAC la identifique como un producto de la RaspberryPi Foundation.\nOtra opción para conocer la IP de la raspberry pi es a través de la interfaz web del router, accediendo mediante un navegador a http://192.168.1.1/. Solicitará la contraseña del router, por defecto siempre está escrita debajo del propio dispositivo o es admin o 1234). Dentro de la interfaz se debería de ver la IP asignada a la raspberry pi. Si se utiliza este método, se recomienda asignar una IP estática a la MAC de la raspberry pi para que siempre que se conecte al router se pueda acceder a través de la misma IP.\nAcceso mediante SSH Una vez se haya localizado la IP privada de la Raspberry y se conozca cuál es el usuario creado durante la instalación (usuario pirate y contraseña hypriot por defecto), ejecutamos lo siguiente:\n1 2 3 ssh \u0026lt;usuario\u0026gt;@\u0026lt;ip_privada_raspberry_pi\u0026gt; #Por ejemplo, en caso de haber usado el archivo wifi.yaml: ssh pi@192.168.1.50 Configuración de SSH a través de claves público-privada en vez de contraseña Desde el ordenador utilizado y desde la propia Raspberry Pi, al ejecutar el siguiente comando se generarán dos claves RSA, una pública y otra privada:\n1 ssh-keygen Pedirá una contraseña y una vez generadas las claves, copiar el contenido de la clave pública $HOME/.ssh/id_rsa.pub en el fichero /home/pi/.ssh/authorized_keys de cada nodo del clúster. Para ello, se recomienda utilizar el siguiente comando:\n1 ssh-copy-id -i $HOME/.ssh/id_rsa.pub pi@\u0026lt;ip de la raspberry\u0026gt; Solicitará la contraseña de la clave SSH y se conectará a la Raspberry Pi.\nA partir de ahora, cada vez que se acceda por SSH a algún nodo, por defecto se pedirá la contraseña de la clave privada SSH en vez de la contraseña de sesión del nodo.\nLo último, será restringir el acceso remoto con contraseñas. De manera que sólo se podrán conectar remotamente a las máquinas aquellas que hayan subido previamente su clave pública SSH a cada Rasberry Pi. Para realizarlo, es necesario editar el fichero de configuración sshd_config y modificar la línea PasswordAuthentication no.\n1 sudo nano /etc/ssh/sshd_config En la línea PasswordAuthentication se modifica a no:\n1 PasswordAuthentication no Se guardan los cambios y se reinicia el servicio con:\n1 sudo service ssh restart Cambio del puerto por defecto de las conexiones SSH Una práctica de seguridad habitual es cambiar el puerto por defecto de SSH (puerto 22). Esto es porque durante un ataque, probablemente se pruebe la conexión por ese puerto. De esta manera, al cambiar el puerto, se reducen el número de intentos de conexión por parte de posibles atacantes 3.\nSe puede escoger un puerto alto entre el 1024 hasta el 65535, para evitar los escaneos rápidos de red de los puertos más comunes. Antes de seleccionar un puerto, es necesario revisar que no haya otro servicio utilizando el mismo puerto. Para ello se ejecuta el comando:\n1 netstat -ltnp Donde los flags son:\nl muestra sólo los sockets a la escucha t muestra las conexiones tcp n muestra las direcciones de forma numérica p muestra los identificadores de procesos/programa Una vez comprobado que el puerto seleccionado no está en uso se modifica el archivo de configuración de SSH:\n1 sudo nano /etc/ssh/sshd_config Se cambia la línea #Port 22 por otro puerto, por ejemplo, Port 2251. Se guarda el fichero y se reinicia el servicio con:\n1 sudo service ssh restart En caso de haber un error en el proceso de cambio de puerto, se cerrará la sesión ssh de la máquina y se perderá el acceso. Por lo tanto, es recomendable estar físicamente cerca de la máquina.\nA partir de este momento, para acceder vía SSH a cada Raspberry Pi será necesario especificar el puerto modificado. El mandato a ejecutar será:\n1 ssh -p 2251 pi@\u0026lt;dirección ip\u0026gt; En caso de olvidar el puerto escogido, se puede hallar mediante un escaneo de puertos con el comando:\n1 sudo nmap -p 1-65535 -T4 -A -v \u0026lt;ip-servidora\u0026gt; Actualizar el sistema Utilizando la configuración del archivo wifi.yaml se actualizan todos los paquetes del sistema al iniciarlo, aunque para actualizar el sistema se utiliza en algún momento particular se utiliza:\n1 2 sudo apt update -y sudp apt upgrade -y Configurar cortafuegos ufw Para instalar el cortafuegos ufw ejecutar:\n1 sudo apt-get install ufw Permitimos las conexiones por el puerto 80 (HTTP), 443(HTTPS), 2251(SSH configurado) y 4443(puerto de configuración de nextcloud).\n1 2 3 4 sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 4443/tcp sudo ufw allow 2251/tcp Para activarlo:\n1 sudo ufw enable Para ver las reglas por defecto:\n1 sudo ufw show raw También se puede ver con un formato más legible:\n1 sudo ufw status verbose Apagar la Raspberry Pi de forma correcta Para apagar la Raspberry Pi evitando que se corrompa la tarjeta SD se ejecuta el siguiente comando:\n1 sudo shutdown -h now Esperar a que la luz verde deje de parpadear y ya desenchufar el cable de alimentación.\nObtener dominio Se requiere un dominio en caso de querer acceder desde el exterior de la red local, en otras palabras, desde Internet. Para ello existen varias páginas donde obtener dominios gratuitos o por menos de 1€ al año. Lo más importante es que el resgistrador de nombres de dominio tenga protección de Whois (WhoisGuard) para prevenir ataques de spam o de suplantación de indentidad a través de los datos personales que tienen que ser públicos al registrar un dominio en el ICANN.\nEn caso de usar un dominio de freenom, es necesario cambiar el DNS a un de Cloudflare siguiendo los pasos de este tutorial.\nInstalar NextcloudPi con Docker Para levantar el contenedor docker de nextcloudpi, simplemente se necesitan los siguientes pasos:\nAñadir la variable de entorno con el nombre del dominio: 1 $DOMINIO=dominioejemplo.org Levantar el contenedor desde el repositorio de Docker Hub: 1 docker run -d -p 4443:4443 -p 443:443 -p 80:80 -v ncdata:/data --restart unless-stopped --name nextcloudpi ownyourbits/nextcloudpi $DOMINIO Activación de nextcloudpi Escribir en el navegador la dirección http://\u0026lt;IP-Raspberry-Pi\u0026gt;. Aceptar el riesgo de seguridad. Aparecerá la ventana de activación de nextcloudpi. Es importante guardar las credenciales que se muestran, por ejemplo:\nNextcloudpi: 1 2 ncp cVYu90pMiZ8GyglILiLVUlD67ID69AOCarv68l4l/so Nextcloud user: 1 2 ncp 1CAhXuQgPEQ99/zfI5xeCNaE7cHeqZpjGhYnuBqVehI Pulsar activar e introducir las credenciales de nextcloudpi. En la primera ejecución, si se quiere acceder al servidor desde la fuera de la red local, se pedirá que se realice el Port forwarding para los puerto 80 (HTTP) y 443(HTTPS) para la IP asignada a la raspberrypi. Se necesita acceder al router desde un navegador a la IP 192.168.1.1 mediante la contraseña del router, suele estar en una etiqueta debajo del router o por defecto es admin o 1234. Si no se permite desde la configuración del proveedor, será necesario realizarlo desde los ajustes avanzados del router.\nUna vez realizado, o en caso de no que no quiera ser accesible desde fuera, se requiere ir al panel de configuración de nextcloudpi y en CONFIG-\u0026gt;nc-trusted-domains\nAceso a nextcloud Mediante el usuario ncp y la contraseña del Nextcloud user, ya se puede acceder al servidor de almacenamiento Nextcloud. Además tiene para calendario, notas, tareas y otras herramientas y aplicaciones que se pueden añadir como edición de textos de manera colaborativa, videollamadas, servidor de comunicación, mapas, reproductor de música y radio, gestor de contraseña, etc. Tiene una infinidad de opciones.\nHypriot GitHub. Issue: hostname can not be changed using normal CLI methods\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nHypriot Blog. Releasing HypriotOS 1.8.0: Raspberry Pi 3 B+, Stretch and more\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nSeguridad de SSH - Parte IV Securicemos nuestra servidora web | la_bekka\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-01-11T00:00:00Z","permalink":"/p/instalaci%C3%B3n-y-configuraci%C3%B3n-de-nextcloudpi/","title":"Instalación y configuración de NextcloudPi"},{"content":"En esta entrada se instalará y se configurará Nextcloud para una Raspberry Pi. Se utilizará la versión dockerizada nextcloudpi y se instalará sobre el sistema operativo HypriotOS.\n¿Qué es Nextcloud? Nextcloud es una serie de programas de código abierto, tanto el cliente como el servidor, con el objetivo de crear un servicio de alojamiento de archivos. Permite el alojamiento en un servidor propio, a modo de nube privada, para no tener la dependencia de nubes de terceros como Dropbox o Google Drive.\n¿Qué es Nextcloudpi? NextCloudPi es una instacia especial de Nextcloud que está adaptada y optimizada al hardware de las Raspberry Pi. De manera que garantiza la interacción más fluida posible de todos los componentes.\n¿Qué es HypriotOS? HypriotOS es un sistema operativo basado en Debian optimizado para ejecutar Docker en plataformas ARM como las Raspberry Pi.\nInstalación de HypriotOS En los siguientes pasos, se procede a quemar la imagen de HypriotOS en una tarjeta SD que esté conectada a un ordenador con sistema operativo GNU/Linux con distribuciones basadas en Debian o en Arch.\nFlasheo de la imagen Para quemar la imagen dentro de la tarjeta microSD, existen diversas maneras de hacerlo. Se recomienda utilizar la herramienta flash instalada de como se indica en su página de documentación:\nInstalación de la herramienta flash Distribuciones basadas en Debian: Se instala la herramienta con los siguientes comandos:\n1 2 3 curl -LO https://github.com/hypriot/flash/releases/download/2.7.0/flash chmod +x flash sudo mv flash /usr/local/bin/flash Se instalan las dependencias con:\n1 2 sudo apt-get install -y pv curl python-pip unzip hdparm sudo pip install awscli Distribuciones basadas en Arch: La instalación más cómoda es instalar el paquete desde los repositorios oficiales de Arch. Para encontrar el paquete en el programa de añadir software buscar flash hypriot.\nQuema de la imagen en la tarjeta SD Una vez instalada la herramienta para quemar la imagen, se copia el enlace de la imagen ISO comprimida desde la página oficial de HypriotOS o se descarga la imagen. Durante el flasheo de la imagen, se puede realizar la configuración inicial del usuario y de la conexión WiFi. En caso de descargar la imagen es necesario verificar que el checksum es el mismo con los siguientes comandos:\n1 2 sha256sum hypriotos-rpi-v1.12.3.img.zip cat hypriotos-rpi-v1.12.3.img.zip.sha256 Una vez verificado el checksum se puede flasear la imagen con el comando a continuación. Aunque se recomienda leer y seguir la opción de configurar el WiFi antes de quemar la imagen.\n1 sudo flash hypriotos-rpi-v1.10.0.img.zip Para quemar la imagen con el enlace directo, ejecutar:\n1 sudo flash https://github.com/hypriot/image-builder-rpi/releases/download/v1.12.3/hypriotos-rpi-v1.12.3.img.zip Solicitará la ubicación de la partición de la tarjeta SD y una confirmación. Una vez termine el proceso, se introducirá la SD en la Raspberry Pi y ya está lista para usar.\nConfiguración del usuario inicial y WiFi Primer creamos un archivo llamado wifi.yaml con la siguiente plantilla, donde es necesario modificar el SSID del WiFi y la clave precompartida en texto plano o cifrada con wpa_passphrase SSID passwordWiFi. En caso de añadir la clave en texto plano será necesario ponerla entre comillas psk=\u0026quot;ContraseñaWiFi\u0026quot;, mientras que si se añade cifrada no serán necesarias las comillas psk=jghXt58cfvfgbksFSJhoA. Para conseguir la contraseña cifrada es necesario ejecutar en un terminal wpa_passphrase \u0026quot;NOMBRE_WIFI\u0026quot; pedirá la contraseña en texto plano y devolverá la contraseña cifrada.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #cloud-config # vim: syntax=yaml # # Set your hostname here, the manage_etc_hosts will update the hosts file entries as well hostname: hypriot manage_etc_hosts: true # You could modify this for your own user information users: - name: pi gecos: \u0026#34;Hypriot Pirate\u0026#34; sudo: ALL=(ALL) NOPASSWD:ALL shell: /bin/bash groups: users,docker,video,input plain_text_passwd: hypriot lock_passwd: false ssh_pwauth: true chpasswd: { expire: false } # # Set the locale of the system locale: \u0026#34;es_ES.UTF-8\u0026#34; # # Set the timezone # # Value of \u0026#39;timezone\u0026#39; must exist in /usr/share/zoneinfo timezone: \u0026#34;Europe/Madrid\u0026#34; # # Update apt packages on first boot package_update: true package_upgrade: true package_reboot_if_required: true #package_upgrade: false # # Install any additional apt packages you need here packages: - software-properties-common # - python-software-properties # - xinput-calibrator # - console-data # - keyboard-configuration # - ntp # # WiFi connect to HotSpot # # - use `wpa_passphrase SSID PASSWORD` to encrypt the psk write_files: - content: | allow-hotplug wlan0 iface wlan0 inet dhcp wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf iface default inet dhcp path: /etc/network/interfaces.d/wlan0 - content: | country=es ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev update_config=1 network={ ssid=\u0026#34;NOMBRE_WIFI\u0026#34; psk=\u0026#34;ContraseñaWiFi\u0026#34; proto=RSN key_mgmt=WPA-PSK pairwise=CCMP auth_alg=OPEN } path: /etc/wpa_supplicant/wpa_supplicant.conf # These commands will be ran once on first boot only runcmd: # Pickup the hostname changes - \u0026#39;systemctl restart avahi-daemon\u0026#39; # # Activate WiFi interface - \u0026#39;ifup wlan0\u0026#39; Una vez se haya descargado la imagen de HypriotOS y se haya configurado la platilla de configuración inicial guardada como wifi.yaml. Desde el mismo directorio que almacena los dos archivos ejecutamos:\n1 sudo flash --hostname hypriot --userdata wifi.yaml hypriotos-rpi-v1.12.3.img.zip Donde el flag --hostname sirve para cambiar el nombre de la máquina y el flag --userdata sirve para cargar la configuración inicial.\nSolicitará la ubicación de la partición de la tarjeta SD y una confirmación. Una vez termine el proceso, se introducirá la SD en la Raspberry Pi y ya está lista para usar.\nEn caso de querer cambiar el hostname después de la instalación, usar el siguiente comando:\n1 sudo hostnamectl set-hostname --static nuevohostname Además, para que sea un cambio persistenten es necesario modificar el archivo sudo nano /etc/cloud/cloud.cfg con lo siguiente:\n1 preserve_hostname: true Después comprobar que se ha cambiado el hostname en /etc/hostname y en /etc/hosts, si no es así modificarlo manualmente. Por último, reiniciar el sistema. Todo lo anterior es necesario debido a un error a partir de la versión de Hypriot 1.11 1.\nPrimer arranque de Raspberry Pi con HypriotOS Una vez instalado HypriotOS en la tarjeta SD, se introduce en la tarjeta en la Raspberry Pi y se conecta a la corriente de alimentación. Si se siguieron correctamento los pasos para preconfigurar el WiFi, al arrancar (tardará varios minutos, aproximadamente entr 5-10mins) será posible conectarse mediante SSH a la Raspberry Pi sin necesidad de conectar un cable RJ-45 (Ethernet) al router ni un teclado y monitor directamente a la máquina. Aunque a pesar de haber seguido correctamente los pasos antiores, se recomienda utilizar un teclado, un monitor y una conexión a internet mediante un cable Ethernet al router en el primer arranque. En caso de no tener monitor ni teclado, saltar a los pasos del apartado Localización de de la IP local de la Rasberry Pi y Acceso mediante ssh, leyendo los pasos anteriores para conocer las credenciales por defecto.\nIniciar sesión En caso de no haber utilizado, durante la instalación de hypriot, el flag \u0026ndash;user-data con el fichero de configuración wifi.yaml, el usuario por defecto es pirate y la contraseña hypriot.\nEn caso de si haber utilizado el fichero de ejemplo, el usuario es pi y la contraseña hypriot.\nCambio de la contraseña por defecto Es obligatorio cambiar la contraseña del usuario por defecto (pirate) o del usuario creado con la configuración del archivo .yaml (pi) a partir de este punto.\nPara cambiar la contraseña se utiliza el comando:\n1 passwd Según el blog de HyriotOS 2, por motivos de seguridad no existe un usuario root construido por defecto.\nCambio de idioma de teclado Una vez conectado el monitor y el teclado USB, por defecto se ejecuta el teclado de US (Estados Unidos). Para cambiar al teclado ES (España), instalar el paquete console-data:\n1 sudo apt install console-data Se abrirá una pantalla gráfica con cuatro opciones, seleccionar la opción select keymap from full list. En la siguiente ventana seleccionar pc/qwerty/Spanish/Standard/CP850.\nAhora ya funcionarán todas las letras menos la ñ. Para poder usarla ejecutar:\n1 sudo loadkeys es Localización de la IP local de la Rasberry Pi Un método para conocer la IP de la Raspberry Pi, contectada a un monitor y un teclado, iniciar sesión con el usuario por defecto pirate(o el usuario de wifi.yaml, en el ejemplo es pi) y la contraseña por defecto hypriot. Una vez dentro, se ejecuta el comando:\n1 sudo ip addr show Primero ver a qué red local estamos conectados con el ordenador que queremos configurar la raspberry pi:\n1 sudo ip addr show ó\n1 sudo ifconfig Una vez que tengamos el rango de la subred (habitualmente siempre es por defecto la 192.168.1.0/24), realizamos un escaneo de red con nmap:\n1 sudo nmap -f 192.168.1.0/24 El flag -f es para realizar el escaneo rápido y poder averiguar la IP de la Raspberry mediante los dígitos fijos de la MAC del fabricante.\nUna vez terminado el escaneo, se mostrará una IP que la dirección MAC la identifique como un producto de la RaspberryPi Foundation.\nOtra opción para conocer la IP de la raspberry pi es a través de la interfaz web del router, accediendo mediante un navegador a http://192.168.1.1/. Solicitará la contraseña del router, por defecto siempre está escrita debajo del propio dispositivo o es admin o 1234). Dentro de la interfaz se debería de ver la IP asignada a la raspberry pi. Si se utiliza este método, se recomienda asignar una IP estática a la MAC de la raspberry pi para que siempre que se conecte al router se pueda acceder a través de la misma IP.\nAcceso mediante SSH Una vez se haya localizado la IP privada de la Raspberry y se conozca cuál es el usuario creado durante la instalación (usuario pirate y contraseña hypriot por defecto), ejecutamos lo siguiente:\n1 2 3 ssh \u0026lt;usuario\u0026gt;@\u0026lt;ip_privada_raspberry_pi\u0026gt; #Por ejemplo, en caso de haber usado el archivo wifi.yaml: ssh pi@192.168.1.50 Configuración de SSH a través de claves público-privada en vez de contraseña Desde el ordenador utilizado y desde la propia Raspberry Pi, al ejecutar el siguiente comando se generarán dos claves RSA, una pública y otra privada:\n1 ssh-keygen Pedirá una contraseña y una vez generadas las claves, copiar el contenido de la clave pública $HOME/.ssh/id_rsa.pub en el fichero /home/pi/.ssh/authorized_keys de cada nodo del clúster. Para ello, se recomienda utilizar el siguiente comando:\n1 ssh-copy-id -i $HOME/.ssh/id_rsa.pub pi@\u0026lt;ip de la raspberry\u0026gt; Solicitará la contraseña de la clave SSH y se conectará a la Raspberry Pi.\nA partir de ahora, cada vez que se acceda por SSH a algún nodo, por defecto se pedirá la contraseña de la clave privada SSH en vez de la contraseña de sesión del nodo.\nLo último, será restringir el acceso remoto con contraseñas. De manera que sólo se podrán conectar remotamente a las máquinas aquellas que hayan subido previamente su clave pública SSH a cada Rasberry Pi. Para realizarlo, es necesario editar el fichero de configuración sshd_config y modificar la línea PasswordAuthentication no.\n1 sudo nano /etc/ssh/sshd_config En la línea PasswordAuthentication se modifica a no:\n1 PasswordAuthentication no Se guardan los cambios y se reinicia el servicio con:\n1 sudo service ssh restart Cambio del puerto por defecto de las conexiones SSH Una práctica de seguridad habitual es cambiar el puerto por defecto de SSH (puerto 22). Esto es porque durante un ataque, probablemente se pruebe la conexión por ese puerto. De esta manera, al cambiar el puerto, se reducen el número de intentos de conexión por parte de posibles atacantes 3.\nSe puede escoger un puerto alto entre el 1024 hasta el 65535, para evitar los escaneos rápidos de red de los puertos más comunes. Antes de seleccionar un puerto, es necesario revisar que no haya otro servicio utilizando el mismo puerto. Para ello se ejecuta el comando:\n1 netstat -ltnp Donde los flags son:\nl muestra sólo los sockets a la escucha t muestra las conexiones tcp n muestra las direcciones de forma numérica p muestra los identificadores de procesos/programa Una vez comprobado que el puerto seleccionado no está en uso se modifica el archivo de configuración de SSH:\n1 sudo nano /etc/ssh/sshd_config Se cambia la línea #Port 22 por otro puerto, por ejemplo, Port 2251. Se guarda el fichero y se reinicia el servicio con:\n1 sudo service ssh restart En caso de haber un error en el proceso de cambio de puerto, se cerrará la sesión ssh de la máquina y se perderá el acceso. Por lo tanto, es recomendable estar físicamente cerca de la máquina.\nA partir de este momento, para acceder vía SSH a cada Raspberry Pi será necesario especificar el puerto modificado. El mandato a ejecutar será:\n1 ssh -p 2251 pi@\u0026lt;dirección ip\u0026gt; En caso de olvidar el puerto escogido, se puede hallar mediante un escaneo de puertos con el comando:\n1 sudo nmap -p 1-65535 -T4 -A -v \u0026lt;ip-servidora\u0026gt; Actualizar el sistema Utilizando la configuración del archivo wifi.yaml se actualizan todos los paquetes del sistema al iniciarlo, aunque para actualizar el sistema se utiliza en algún momento particular se utiliza:\n1 2 sudo apt update -y sudp apt upgrade -y Configurar cortafuegos ufw Para instalar el cortafuegos ufw ejecutar:\n1 sudo apt-get install ufw Permitimos las conexiones por el puerto 80 (HTTP), 443(HTTPS), 2251(SSH configurado) y 4443(puerto de configuración de nextcloud).\n1 2 3 4 sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 4443/tcp sudo ufw allow 2251/tcp Para activarlo:\n1 sudo ufw enable Para ver las reglas por defecto:\n1 sudo ufw show raw También se puede ver con un formato más legible:\n1 sudo ufw status verbose Apagar la Raspberry Pi de forma correcta Para apagar la Raspberry Pi evitando que se corrompa la tarjeta SD se ejecuta el siguiente comando:\n1 sudo shutdown -h now Esperar a que la luz verde deje de parpadear y ya desenchufar el cable de alimentación.\nObtener dominio Se requiere un dominio en caso de querer acceder desde el exterior de la red local, en otras palabras, desde Internet. Para ello existen varias páginas donde obtener dominios gratuitos o por menos de 1€ al año. Lo más importante es que el resgistrador de nombres de dominio tenga protección de Whois (WhoisGuard) para prevenir ataques de spam o de suplantación de indentidad a través de los datos personales que tienen que ser públicos al registrar un dominio en el ICANN.\nEn caso de usar un dominio de freenom, es necesario cambiar el DNS a un de Cloudflare siguiendo los pasos de este tutorial.\nInstalar NextcloudPi con Docker Para levantar el contenedor docker de nextcloudpi, simplemente se necesitan los siguientes pasos:\nAñadir la variable de entorno con el nombre del dominio: 1 $DOMINIO=dominioejemplo.org Levantar el contenedor desde el repositorio de Docker Hub: 1 docker run -d -p 4443:4443 -p 443:443 -p 80:80 -v ncdata:/data --restart unless-stopped --name nextcloudpi ownyourbits/nextcloudpi $DOMINIO Activación de nextcloudpi Escribir en el navegador la dirección http://\u0026lt;IP-Raspberry-Pi\u0026gt;. Aceptar el riesgo de seguridad. Aparecerá la ventana de activación de nextcloudpi. Es importante guardar las credenciales que se muestran, por ejemplo:\nNextcloudpi: 1 2 ncp cVYu90pMiZ8GyglILiLVUlD67ID69AOCarv68l4l/so Nextcloud user: 1 2 ncp 1CAhXuQgPEQ99/zfI5xeCNaE7cHeqZpjGhYnuBqVehI Pulsar activar e introducir las credenciales de nextcloudpi. En la primera ejecución, si se quiere acceder al servidor desde la fuera de la red local, se pedirá que se realice el Port forwarding para los puerto 80 (HTTP) y 443(HTTPS) para la IP asignada a la raspberrypi. Se necesita acceder al router desde un navegador a la IP 192.168.1.1 mediante la contraseña del router, suele estar en una etiqueta debajo del router o por defecto es admin o 1234. Si no se permite desde la configuración del proveedor, será necesario realizarlo desde los ajustes avanzados del router.\nUna vez realizado, o en caso de no que no quiera ser accesible desde fuera, se requiere ir al panel de configuración de nextcloudpi y en CONFIG-\u0026gt;nc-trusted-domains\nAceso a nextcloud Mediante el usuario ncp y la contraseña del Nextcloud user, ya se puede acceder al servidor de almacenamiento Nextcloud. Además tiene para calendario, notas, tareas y otras herramientas y aplicaciones que se pueden añadir como edición de textos de manera colaborativa, videollamadas, servidor de comunicación, mapas, reproductor de música y radio, gestor de contraseña, etc. Tiene una infinidad de opciones.\nHypriot GitHub. Issue: hostname can not be changed using normal CLI methods\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nHypriot Blog. Releasing HypriotOS 1.8.0: Raspberry Pi 3 B+, Stretch and more\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nSeguridad de SSH - Parte IV Securicemos nuestra servidora web | la_bekka\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2021-01-11T00:00:00Z","permalink":"/p/instalaci%C3%B3n-y-configuraci%C3%B3n-de-nextcloudpi/","title":"Instalación y configuración de NextcloudPi"},{"content":"En esta entrada se realizará una descripción de los objetos básicos de Kubernetes. Algunos de los ejemplos de los objetos de Kubernetes son los Pods, ReplicaSets, Deployments, Namespaces, etc.\nObjetos básicos Según la documentación de Kubernetes los objetos de Kubernetes son entidades persistentes. Kubernetes usa estas entidades para representar el estado del clúster. Cada objeto de Kubernetes está representado por un recurso RESTful y existe en una ruta HTTP única. Específicamente, los objetos pueden describir 1:\nQué aplicaciones en contenedores se están ejecutando (y en qué nodos). Los recursos disponibles para esas aplicaciones. Las políticas de comportamiento de esas aplicaciones, como políticas de reinicio, actualizaciones y tolerancia a fallas. Casi todos los objetos de Kubernetes incluyen dos campos del objeto que lo configuran: el spec o especificación del estado deseado objeto y el status o estado real o actual del objeto. En la sección spec se declara la intención o estado deseado del objeto. El plano de control es quién se encarga de intentar hacer coincidir el estado real del objeto con el estado deseado.\nPara crear un objeto es necesario que la API de Kubernetes reciba la información del mismo en formato JSON. Aunque la mayoría de las veces se envía la información mediante kubectl en un archivo .yaml que será convertido a formato JSON. Un ejemplo de archivo .yaml es el siguiente 1:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 2 # tells deployment to run 2 pods matching the template template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 Campos requeridos Se necesitan establecer los siguientes campos obligatorios para crear un objeto 1:\napiVersion: qué versión de la API de Kubernetes se está utilizando para crear el objeto. kind: qué tipo de objeto se quiere crear. metadata: datos que sirven para identificar de forma única el objeto, incluyendo un nombre, un UID y un namespace opcional. spec: el estado deseado para el objeto. Etiquetado (labels) Las etiquetas o labels son pares clave-valor adjuntos a los objetos de Kubernetes. Se utilizan para organizar y seleccionar subconjuntos de objetos, en función de unos requisitos preestablecidos. Muchos objetos pueden tener la misma etiqueta, por lo que no proporcionan unicidad a los objetos 2.\nPor ejemplo, para agregar la etiqueta color=verde a un Pod llamado planta, se puede ejecutar lo siguiente 3:\n1 kubectl label pods planta color=verde El comando anterior no sobreescribirá una etiqueta existente, por lo tanto, es necesario utilizar le flag --overwrite. O en caso de querer eliminar la etiqueta color, se hará con el comando a continuación:\n1 kubectl label pods bar color - Selectores de etiquetas (label selectors) Los controladores utilizan selectores de etiquetas para seleccionar un subconjunto de objetos. Kubernetes admite dos tipos de selectores 4:\nSelectores basados en la igualdad Permiten el filtrado de objetos en función de claves y valores de etiqueta. La coincidencia se consigue utilizando los operadores:\nSi es igual = o == (no existe diferencia entre los operadores) Si es distinto != Selectores basados en conjuntos Permiten el filtrado objetos en función de un conjunto de valores. Podemos usar operadores in, notin para valores de etiqueta, y el operador exists para claves de etiquetas.\nTipos de Objetos Pods Un pod es la unidad de programación más pequeña de Kubernetes. Es una colección lógica de uno o más contenedores que 2:\nEstán programados en el mismo host. Comparten el mismo network namespace, por lo tanto comparten una única dirección IP asignada al Pod. Tienen acceso para montar el mismo almacenamiento externo (volúmenes). Los pods tienen naturaleza efímera y no tienene la capacidad de autorreparación. Por eso se utilizan controladores para gestionar la replicación de Pods, tolerancia a fallos, autorreparación, etc. Algunos de estos controladores son Deployments, ReplicaSets, etc.\nReplicaSets Deployments Kubernetes Documentation, Understanding Kubernetes Objects\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nKubernetes Documentation, Labels and Selectors\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nO’Reilly, Kubernetes: Up and Running\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nKubernetes Documentation, Label selectors\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-12-22T00:00:00Z","permalink":"/p/objetos-b%C3%A1sicos-de-kubernetes/","title":"Objetos básicos de Kubernetes"},{"content":"En esta entrada se realizará un repaso de los comandos básicos del cli kubectl que se pueden aplicar a los objetos de Kubernetes. Algunos de los ejemplos de los objetos de Kubernetes son los Pods, ReplicaSets, Deployments, Namespaces, etc.\nNamespaces Se utilizan namespaces en Kubernetes para organizar los objetos del clúster. A fin de cuentas, un namespace representa una carpeta que contiene un conjunto de objetos. Por defecto, kubectl interactúa con el namespace default. Para usar otro tipo de de namespace es necesario utilizar el flag --namespace, por ejemplo --namespace=ejemplo. Si se quiere interacturar con todo el conjunto de namespaces, se utiliza el flag --all-namespace 1.\nContexts En caso de querer cambiar el namespace predreterminado de forma permanente, se puede utilizar un context. Al utilizarlo se registra en el archivo de configuración de kubectl, almacenado en HOME/.kube/config. Para crear un context con un nuevo nobre predeterminado de namespace, ejecutar 1:\n1 kubectl config set-context my-context --namespace=nuevonamespacepordefecto 1 kubectl config use-context my-context Objetos de la API de Kubernetes Cada objeto de Kubernetes está representado por un recurso RESTful y existe en una ruta HTTP única a la API de Kubernetes. Los recursos se representan como archivos JSON o YAML. A través del comando kubectl, se podrá acceder a dichos objetos. Por ejemplo, mediante el comando kubectl get se puede acceder a cualquier recurso del namespace por defecto 1:\n1 kubectl get \u0026lt;nombre-recurso\u0026gt; En caso de querer un recurso más específico:\n1 kubectl get \u0026lt;nombre-recurso\u0026gt; \u0026lt;nombre-obj\u0026gt; En caso de querer obtener más información del objeto en formato JSON o YAML, se pueden agregar los flags -o json o -o yaml respectivamente. Esta información no es tan legible para los humanos.\nOtra opción para obtener más detalles del objeto legible para humanos es usar el comando kubectl describe:\n1 kubectl describe \u0026lt;nombre-recurso\u0026gt; \u0026lt;nombre-obj\u0026gt; Creación, actualización o destrucción de objetos de Kubernetes Como se ha mencionado anteriormente, los objetos o recursos de Kubernetes se representan mediante archivos JSON o YAML. Para crear, actualizar o eliminar dichos objetos se utilizan ese tipo de archivos. Por ejemplo, en caso de querer crear o actualizar un objeto almacenado en ejemplo.yaml se ejecuta:\n1 kubectl apply -f ejemplo.yaml En caso de desear realizar ediciones intectivas en lugar del archivo local, se puede utilizar el comando kubectl edit para descargar la versión más reciente y lanza un editor. Después de guardar el archivo se subirá el archivo y se actualizará automáticamente.\n1 kubectl edit \u0026lt;nombre-recurso\u0026gt; \u0026lt;nombre-obj\u0026gt; El comando kubectl apply también guardará el historial de versiones de los archivos de configuración. Se pueden acceder a estos registros mediante las opciones edit-last-applied, set-last-applied, y view-last-applied.\n1 kubectl apply -f myobj.yaml view-last-applied Para eliminar un objeto, simplemente se necesita ejecutar:\n1 kubectl delete -f ejemplo.yaml Depuración kubectl también tiene una serie de comandos para depurar sus contenedores. Para ver los registros de un contenedor en ejecución, se ejecuta:\n1 kubectl logs \u0026lt;nombre-pod\u0026gt; Si existen varios contenedores en el pod, se puede elegir el contenedor que desea inspeccionar con el flag -c.\nDe forma predeterminada, kubectl logs enumera los registros y salidas actuales. Si, en cambio, se quiere transmitir continuamente los registros a la terminal, se puede agregar el flag -f (follow) en la línea de comandos.\nTambién se puede usar el comando exec para ejecutar un comando en un contenedor en ejecución:\n1 kubectl exec -it \u0026lt;pod-name\u0026gt; -- bash Esto proporcionará una consola interactiva dentro del contenedor en ejecución para realizar una depuración más detallada.\nO’Reilly, Kubernetes: Up and Running\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-12-21T00:00:00Z","permalink":"/p/comandos-b%C3%A1sicos-de-kubernetes/","title":"Comandos básicos de Kubernetes"},{"content":"En esta entrada se definirá el flujo de trabajo aplicado a un repositorio git conocido comunmente como Gitflow. Para entender dicho flujo de trabajo es necesario entender previamente qué es y para qué sirve git. Después de tener una base fijada, es habitual que vaya sobre ruedas.\n¿Qué es git? Git es un software de control de versiones diseñado por Linus Torvalds, pensando en la eficiencia y la confiabilidad del mantenimiento de versiones de aplicaciones cuando éstas tienen un gran número de archivos de código fuente. Su propósito es llevar registro de los cambios en los archivos y coordinar el trabajo que varias personas realizan sobre archivos compartido 1.\nSi quieres aprender más sobre los comandos más usados de git, visita esta entrada.\nIntroducción a Gitflow Gitflow es un flujo de trabajo para ayudar el desarrollo continuo de software y la implementación de prácticas DevOps. Fue publicado por primera vez por Vincent Driessen en nvie en el 2010.\n¿Cómo funciona? Permite la paralelización del desarrollo asignando roles específicos a las diferentes ramas para preparar, mantener y publicar versiones del proyecto y para la reparación de errores sin que cunda el pánico.\nProgramas GUI de git Buscando programas con una interfaz gráfica para gestionar git de manera sencilla y sean de código abierto o de software libre, se encuentran los siguientes:\ngitg GitAhead git-cola Git Extensions Wikipedia, Git\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-11-10T00:00:00Z","permalink":"/p/gitflow/","title":"Gitflow"},{"content":"En esta entrada se realizará un repaso de los comandos básicos del cli kubectl que se pueden aplicar a los objetos de Kubernetes. Algunos de los ejemplos de los objetos de Kubernetes son los Pods, ReplicaSets, Deployments, Namespaces, etc.\nNamespaces Se utilizan namespaces en Kubernetes para organizar los objetos del clúster. A fin de cuentas, un namespace representa una carpeta que contiene un conjunto de objetos. Por defecto, kubectl interactúa con el namespace default. Para usar otro tipo de de namespace es necesario utilizar el flag --namespace, por ejemplo --namespace=ejemplo. Si se quiere interacturar con todo el conjunto de namespaces, se utiliza el flag --all-namespace 1.\nContexts En caso de querer cambiar el namespace predreterminado de forma permanente, se puede utilizar un context. Al utilizarlo se registra en el archivo de configuración de kubectl, almacenado en HOME/.kube/config. Para crear un context con un nuevo nobre predeterminado de namespace, ejecutar 1:\n1 kubectl config set-context my-context --namespace=nuevonamespacepordefecto 1 kubectl config use-context my-context Objetos de la API de Kubernetes Cada objeto de Kubernetes está representado por un recurso RESTful y existe en una ruta HTTP única a la API de Kubernetes. Los recursos se representan como archivos JSON o YAML. A través del comando kubectl, se podrá acceder a dichos objetos. Por ejemplo, mediante el comando kubectl get se puede acceder a cualquier recurso del namespace por defecto 1:\n1 kubectl get \u0026lt;nombre-recurso\u0026gt; En caso de querer un recurso más específico:\n1 kubectl get \u0026lt;nombre-recurso\u0026gt; \u0026lt;nombre-obj\u0026gt; En caso de querer obtener más información del objeto en formato JSON o YAML, se pueden agregar los flags -o json o -o yaml respectivamente. Esta información no es tan legible para los humanos.\nOtra opción para obtener más detalles del objeto legible para humanos es usar el comando kubectl describe:\n1 kubectl describe \u0026lt;nombre-recurso\u0026gt; \u0026lt;nombre-obj\u0026gt; Creación, actualización o destrucción de objetos de Kubernetes Como se ha mencionado anteriormente, los objetos o recursos de Kubernetes se representan mediante archivos JSON o YAML. Para crear, actualizar o eliminar dichos objetos se utilizan ese tipo de archivos. Por ejemplo, en caso de querer crear o actualizar un objeto almacenado en ejemplo.yaml se ejecuta:\n1 kubectl apply -f ejemplo.yaml En caso de desear realizar ediciones intectivas en lugar del archivo local, se puede utilizar el comando kubectl edit para descargar la versión más reciente y lanza un editor. Después de guardar el archivo se subirá el archivo y se actualizará automáticamente.\n1 kubectl edit \u0026lt;nombre-recurso\u0026gt; \u0026lt;nombre-obj\u0026gt; El comando kubectl apply también guardará el historial de versiones de los archivos de configuración. Se pueden acceder a estos registros mediante las opciones edit-last-applied, set-last-applied, y view-last-applied.\n1 kubectl apply -f myobj.yaml view-last-applied Para eliminar un objeto, simplemente se necesita ejecutar:\n1 kubectl delete -f ejemplo.yaml Depuración kubectl también tiene una serie de comandos para depurar sus contenedores. Para ver los registros de un contenedor en ejecución, se ejecuta:\n1 kubectl logs \u0026lt;nombre-pod\u0026gt; Si existen varios contenedores en el pod, se puede elegir el contenedor que desea inspeccionar con el flag -c.\nDe forma predeterminada, kubectl logs enumera los registros y salidas actuales. Si, en cambio, se quiere transmitir continuamente los registros a la terminal, se puede agregar el flag -f (follow) en la línea de comandos.\nTambién se puede usar el comando exec para ejecutar un comando en un contenedor en ejecución:\n1 kubectl exec -it \u0026lt;pod-name\u0026gt; -- bash Esto proporcionará una consola interactiva dentro del contenedor en ejecución para realizar una depuración más detallada.\nO’Reilly, Kubernetes: Up and Running\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-29T00:00:00Z","permalink":"/p/comandos-b%C3%A1sicos-de-kubernetes/","title":"Comandos básicos de Kubernetes"},{"content":"En esta entrada se realizará una descripción de los objetos básicos de Kubernetes. Algunos de los ejemplos de los objetos de Kubernetes son los Pods, ReplicaSets, Deployments, Namespaces, etc.\nObjetos básicos Según la documentación de Kubernetes los objetos de Kubernetes son entidades persistentes. Kubernetes usa estas entidades para representar el estado del clúster. Cada objeto de Kubernetes está representado por un recurso RESTful y existe en una ruta HTTP única. Específicamente, los objetos pueden describir 1:\nQué aplicaciones en contenedores se están ejecutando (y en qué nodos). Los recursos disponibles para esas aplicaciones. Las políticas de comportamiento de esas aplicaciones, como políticas de reinicio, actualizaciones y tolerancia a fallas. Casi todos los objetos de Kubernetes incluyen dos campos del objeto que lo configuran: el spec o especificación del estado deseado objeto y el status o estado real o actual del objeto. En la sección spec se declara la intención o estado deseado del objeto. El plano de control es quién se encarga de intentar hacer coincidir el estado real del objeto con el estado deseado.\nPara crear un objeto es necesario que la API de Kubernetes reciba la información del mismo en formato JSON. Aunque la mayoría de las veces se envía la información mediante kubectl en un archivo .yaml que será convertido a formato JSON. Un ejemplo de archivo .yaml es el siguiente 1:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2 kind: Deployment metadata: name: nginx-deployment spec: selector: matchLabels: app: nginx replicas: 2 # tells deployment to run 2 pods matching the template template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80 Campos requeridos Se necesitan establecer los siguientes campos obligatorios para crear un objeto 1:\napiVersion: qué versión de la API de Kubernetes se está utilizando para crear el objeto. kind: qué tipo de objeto se quiere crear. metadata: datos que sirven para identificar de forma única el objeto, incluyendo un nombre, un UID y un namespace opcional. spec: el estado deseado para el objeto. Etiquetado (labels) Las etiquetas o labels son pares clave-valor adjuntos a los objetos de Kubernetes. Se utilizan para organizar y seleccionar subconjuntos de objetos, en función de unos requisitos preestablecidos. Muchos objetos pueden tener la misma etiqueta, por lo que no proporcionan unicidad a los objetos 2.\nPor ejemplo, para agregar la etiqueta color=verde a un Pod llamado planta, se puede ejecutar lo siguiente 3:\n1 kubectl label pods planta color=verde El comando anterior no sobreescribirá una etiqueta existente, por lo tanto, es necesario utilizar le flag --overwrite. O en caso de querer eliminar la etiqueta color, se hará con el comando a continuación:\n1 kubectl label pods bar color - Selectores de etiquetas (label selectors) Los controladores utilizan selectores de etiquetas para seleccionar un subconjunto de objetos. Kubernetes admite dos tipos de selectores 4:\nSelectores basados en la igualdad Permiten el filtrado de objetos en función de claves y valores de etiqueta. La coincidencia se consigue utilizando los operadores:\nSi es igual = o == (no existe diferencia entre los operadores) Si es distinto != Selectores basados en conjuntos Permiten el filtrado objetos en función de un conjunto de valores. Podemos usar operadores in, notin para valores de etiqueta, y el operador exists para claves de etiquetas.\nTipos de Objetos Pods Un pod es la unidad de programación más pequeña de Kubernetes. Es una colección lógica de uno o más contenedores que 2:\nEstán programados en el mismo host. Comparten el mismo network namespace, por lo tanto comparten una única dirección IP asignada al Pod. Tienen acceso para montar el mismo almacenamiento externo (volúmenes). Los pods tienen naturaleza efímera y no tienene la capacidad de autorreparación. Por eso se utilizan controladores para gestionar la replicación de Pods, tolerancia a fallos, autorreparación, etc. Algunos de estos controladores son Deployments, ReplicaSets, etc.\nReplicaSets Deployments Kubernetes Documentation, Understanding Kubernetes Objects\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nKubernetes Documentation, Labels and Selectors\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nO’Reilly, Kubernetes: Up and Running\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nKubernetes Documentation, Label selectors\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-29T00:00:00Z","permalink":"/p/objetos-b%C3%A1sicos-de-kubernetes/","title":"Objetos básicos de Kubernetes"},{"content":"Instalación en local de Kubernetes Existen varias herramientas que se pueden utilizar para desplegar Kubernetes en uno o muchos clusters. Algunos de ellos serían:\nMinikube Kind Docker Desktop MicroK8s K3S Minikube es el método más fácil y preferido para crear una configuración de Kubernetes de forma local. Se utiliza para administrar un clúster de un solo nodo aunque ya existe una funcionalidad experimental que es compatible con los clústeres de múltiples nodos.\nMinikube El proyecto minikube es una implementación local de clusters de Kubernetes para Linux, mac0S y Windows. Su objetivo es ser la mejor herramienta para desarrollar localmente aplicaciones de Kubernetes 1.\nLos primeros pasos con minikube se pueden seguir en la documentación oficial y son los siguientes 2:\nRequisitos 2 CPUs o más 2GB de memoria RAM 20GB de espacio en disco Conexión a internet Manejador de contenedores o máquinas virtuales, como: Docker, Hyperkit, Hyper-V, KVM, Parallels, Podman, VirtualBox, o VMWare. Instalación de minikube Para Linux hay tres opciones:\nPaquete binario: 1 2 curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube Paquete Debian: 1 2 curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb sudo dpkg -i minikube_latest_amd64.deb Paquete RPM: 1 2 curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-latest.x86_64.rpm sudo rpm -ivh minikube-latest.x86_64.rpm Para empezar con minikube ejecutar:\n1 minikube start Para parar de forma segura minikube ejecutar:\n1 minikube stop Instalación de kubernetes Kubernetes puede instalarse localmente en máquinas virtuales o directamente en el sistema operativo. Existen herramientas como Ansible o kubeadm para automatizar la instalación.\nCon la herramienta CLI kubectl se pueden administrar, desplegar y configurar los recursos y las aplicaciones del cluster de Minikube, por lo tanto se instala con los siguientes comandos:\n1 2 3 4 5 sudo apt-get update \u0026amp;\u0026amp; sudo apt-get install -y apt-transport-https gnupg2 curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - echo \u0026#34;deb https://apt.kubernetes.io/ kubernetes-xenial main\u0026#34; | sudo tee -a /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubectl Para los dellates de los comandos de kubectl se puede buscar en el libro de kubectl, en la documentación oficial de Kubernetes o en su repositorio github.\nUn paso muy habitual después de la instalación, es configurar y habilitar la autocompletado de comandos de kubectl:\n1 2 3 4 sudo apt install -y bash-completion source /usr/share/bash-completion/bash-completion source \u0026lt;(kubectl completion bash) echo \u0026#39;source \u0026lt;(kubectl completion bash)\u0026#39; \u0026gt;\u0026gt;~/.bashrc Otros paquetes relevantes a instalar son los siguientes:\nkubeadm: sirve para administrar o automatizar la instalación kubelet: es un agente que se ejecuta en cada nodo y se comunica con los componentes del plano de control kubernetes-cni: permite configurar los elementos de red 1 sudo apt-get install kubelet kubeadm kubernetes-cni GitHub, minikube\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nMinikube, Cómo empezar\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-29T00:00:00Z","permalink":"/p/primeros-pasos-con-minikube/","title":"Primeros pasos con Minikube"},{"content":"Instalación en local de Kubernetes Existen varias herramientas que se pueden utilizar para desplegar Kubernetes en uno o muchos clusters. Algunos de ellos serían:\nMinikube Kind Docker Desktop MicroK8s K3S Minikube es el método más fácil y preferido para crear una configuración de Kubernetes de forma local. Se utiliza para administrar un clúster de un solo nodo aunque ya existe una funcionalidad experimental que es compatible con los clústeres de múltiples nodos.\nMinikube El proyecto minikube es una implementación local de clusters de Kubernetes para Linux, mac0S y Windows. Su objetivo es ser la mejor herramienta para desarrollar localmente aplicaciones de Kubernetes 1.\nLos primeros pasos con minikube se pueden seguir en la documentación oficial y son los siguientes 2:\nRequisitos 2 CPUs o más 2GB de memoria RAM 20GB de espacio en disco Conexión a internet Manejador de contenedores o máquinas virtuales, como: Docker, Hyperkit, Hyper-V, KVM, Parallels, Podman, VirtualBox, o VMWare. Instalación de minikube Para Linux hay tres opciones:\nPaquete binario: 1 2 curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube Paquete Debian: 1 2 curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb sudo dpkg -i minikube_latest_amd64.deb Paquete RPM: 1 2 curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-latest.x86_64.rpm sudo rpm -ivh minikube-latest.x86_64.rpm Para empezar con minikube ejecutar:\n1 minikube start Para parar de forma segura minikube ejecutar:\n1 minikube stop Instalación de kubernetes Kubernetes puede instalarse localmente en máquinas virtuales o directamente en el sistema operativo. Existen herramientas como Ansible o kubeadm para automatizar la instalación.\nCon la herramienta CLI kubectl se pueden administrar, desplegar y configurar los recursos y las aplicaciones del cluster de Minikube, por lo tanto se instala con los siguientes comandos:\n1 2 3 4 5 sudo apt-get update \u0026amp;\u0026amp; sudo apt-get install -y apt-transport-https gnupg2 curl curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - echo \u0026#34;deb https://apt.kubernetes.io/ kubernetes-xenial main\u0026#34; | sudo tee -a /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubectl Para los dellates de los comandos de kubectl se puede buscar en el libro de kubectl, en la documentación oficial de Kubernetes o en su repositorio github.\nUn paso muy habitual después de la instalación, es configurar y habilitar la autocompletado de comandos de kubectl:\n1 2 3 4 sudo apt install -y bash-completion source /usr/share/bash-completion/bash-completion source \u0026lt;(kubectl completion bash) echo \u0026#39;source \u0026lt;(kubectl completion bash)\u0026#39; \u0026gt;\u0026gt;~/.bashrc Otros paquetes relevantes a instalar son los siguientes:\nkubeadm: sirve para administrar o automatizar la instalación kubelet: es un agente que se ejecuta en cada nodo y se comunica con los componentes del plano de control kubernetes-cni: permite configurar los elementos de red 1 sudo apt-get install kubelet kubeadm kubernetes-cni GitHub, minikube\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nMinikube, Cómo empezar\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-29T00:00:00Z","permalink":"/p/primeros-pasos-con-minikube/","title":"Primeros pasos con Minikube"},{"content":"En esta entrada se definirán los componentes de la arquitectura de Kubernetes. Las fuentes principales de la información a continuación son el curso de Introduction to Kubernetes de The Linux Foundation en edX, cuyos autores son Chris Pokorni y Neependra Khare, y la propia documentación de Kubernetes.\nComponentes de la arquitectura en Kubernetes Un clúster de Kubernetes consta de un conjunto de máquinas trabajadoras, llamadas nodos, que ejecutan aplicaciones en contenedores. Cada clúster tiene al menos un nodo trabajador. En un nivel muy alto de abstracción, Kubernetes tiene los siguientes componentes principales:\nUno o más nodos maestros (master nodes), en la parte del plano de control (control plane). Uno o más nodos trabajadores (worker nodes). Se puede ver en la siguiente figura que es la arquitectura de los componentes de un cluster de Kubernetes 1:\nEl nodo maestro proporciona un entorno de ejecución para el plano de control responsable de administrar el estado de un clúster de Kubernetes y es el cerebro detrás de todas las operaciones dentro del clúster. Los componentes del plano de control son agentes con roles muy distintos en la gestión del clúster. Para comunicarse con el clúster de Kubernetes, los usuarios envían solicitudes al plano de control a través de una herramienta de interfaz de línea de comandos (CLI), un panel de interfaz de usuario web o una interfaz de programación de aplicaciones (API) 2.\nEs importante mantener el plano de control funcionando a toda costa. La pérdida del plano de control puede generar tiempo de inactividad, provocando la interrupción del servicio a los clientes, con una posible pérdida de negocio. Para garantizar la tolerancia a fallos del plano de control, se pueden agregar réplicas del nodo maestro al clúster, configuradas en modo de alta disponibilidad. Si bien solo uno de los nodos maestros está dedicado a administrar activamente el clúster, los componentes del plano de control permanecen sincronizados en las réplicas del nodo maestro. Este tipo de configuración agrega resistencia al plano de control del clúster, en caso de que falle el nodo maestro que está activo 2.\nPara conservar el estado del clúster de Kubernetes, todos los datos de configuración del clúster se guardan en etcd. etcd es un almacén de valores clave distribuido que solo contiene datos relacionados con el estado del clúster, sin datos de carga de trabajo del cliente. etcd se puede configurar en el nodo maestro (topología apilada) o en su host dedicado (topología externa) para ayudar a reducir las posibilidades de pérdida del almacén de datos al desacoplarlo de los otros agentes del plano de control 2.\nCon la topología de etcd apilada, las réplicas del nodo maestro de alta disponibilidad también garantizan la resistencia del almacén de datos de etcd. Sin embargo, ese no es el caso de la topología externa etcd, donde los hosts etcd deben replicarse por separado para alta disponibilidad, una configuración que introduce la necesidad de hardware adicional.\nUn nodo maestro ejecuta los siguientes componentes del plano de control 1:\nkube-apiserver o servidor API kube-scheduler o planificador kube-controller-manager o manejador de controladores etcd o almacén de datos Mientras que un nodo trabajador tiene los siguientes componentes:\nContainer Runtime o entorno de ejecución del contenedor kubelet o agente de nodo kube-proxy o proxy Addons o complementos para DNS, interfaz de usuario, monitoreo y registro a nivel de clúster Nodo maestro kube-apiserver Todas las tareas administrativas están coordinadas por kube-apiserver, un componente central del plano de control que se ejecuta en el nodo maestro. El servidor API recibe las peticiones RESTful de usuarios, operadores y agentes externos, luego las valida y las procesa. Durante el procesamiento, el servidor API lee el estado actual del clúster de Kubernetes del almacén de datos etcd y, después de la ejecución de una llamada, el estado resultante del clúster de Kubernetes se guarda en el almacén de datos distribuido de clave-valor para debida su persistencia. El servidor API es el único componente del plano de control que se comunica con el almacén de datos etcd, tanto para leer como para guardar la información del estado del clúster de Kubernetes, actuando como una interfaz intermedia para cualquier otro agente del plano de control que pregunte sobre el estado del clúster.\nEl servidor API es altamente configurable y personalizable. Puede escalar horizontalmente, pero también admite la adición de servidores API secundarios personalizados, una configuración que transforma el servidor API principal en un proxy para todos los servidores API personalizados secundarios y enruta todas las llamadas RESTful entrantes a ellos en función de reglas definidas personalizadas 2.\nkube-scheduler La función del kube-scheduler o planificador es asignar nuevos objetos de carga de trabajo, como pods, a los nodos. Durante el proceso de planificación, las decisiones se toman según el estado actual del clúster de Kubernetes y los requisitos del nuevo objeto. El planificador obtiene del almacén de datos etcd, a través del servidor API, los datos de uso de recursos para cada nodo trabajador en el clúster. El planificador también recibe del servidor API los requisitos del nuevo objeto que forman parte de sus datos de configuración. Los requisitos pueden incluir restricciones que los usuarios y operadores establezcan, como programar el trabajo en un nodo etiquetado con disk == ssd como par clave/valor. El planificador también tiene en cuenta los requisitos de calidad de servicio (QoS), la localidad de los datos, la afinidad, la antiafinidad, localización de datos dependientes, la tolerancia, la topología del clúster, etc. Una vez que todos los datos del clúster están disponibles, el algoritmo de planificación filtra los nodos con predicados para aislar los posibles nodos candidatos que luego son puntuados con prioridades para seleccionar el nodo que satisface todos los requisitos para la nueva carga de trabajo. El resultado del proceso de decisión se comunica al servidor API, que luego delega la implementación de la carga de trabajo con otros agentes del plano de control.\nEl planificador es altamente configurable y personalizable mediante políticas de planificación, complementos y perfiles. También se admiten planificadores adicionales personalizados. Un planificador es extremadamente importante y complejo en un clúster de Kubernetes de varios nodos 2.\nkube-controller-manager Componente del plano de control que ejecuta los controladores para regular el estado del clúster de Kubernetes. Los controladores son bucles de vigilancia que se ejecutan continuamente y comparan el estado deseado del clúster (proporcionado por los datos de configuración de los objetos) con su estado actual (obtenido del almacén de datos etcd a través del servidor API). En caso de una discrepancia, se toman medidas correctivas en el clúster hasta que su estado actual coincida con el estado deseado. Ejecuta controladores responsables de actuar cuando los nodos dejan de estar disponibles, para garantizar que el número de pods sean los esperados, para crear endpoints, cuentas de servicio y tokens de acceso a la API 2. Lógicamente cada controlador es un proceso independiente, pero para reducir la complejidad, todos se compilan en un único binario y se ejecuta en un mismo proceso. Estos controladores incluyen 1:\nControlador de nodos: es el responsable de detectar y responder cuándo un nodo deja de funcionar Controlador de replicación: es el responsable de mantener el número correcto de pods para cada controlador de replicación del sistema Controlador de endpoints: construye el objeto Endpoints, es decir, hace una unión entre los Services y los Pods Controladores de tokens y cuentas de servicio: crean cuentas y tokens de acceso a la API por defecto para los nuevos Namespaces. etcd Almacén de datos persistente, consistente y distribuido de clave-valor utilizado para almacenar toda a la información del clúster de Kubernetes 1. Los nuevos datos se añaden al almacén de datos, nunca se reemplazan. Los datos obsoletos se comprimen periódicamente para minimizar el tamaño del almacén de datos.\nDe todos los componentes del plano de control, solo el servidor API puede comunicarse con el almacén de datos etcd.\nLa herramienta de administración CLI de etcd, etcdctl, proporciona la opción de realizar copias de seguridad, instantáneas y restauraciones. Son especialmente útiles para un clúster de Kubernetes de única instancia de etcd, común en entornos de desarrollo y aprendizaje. Sin embargo, en los entornos Stage y Production, es extremadamente importante replicar los almacenes de datos en modo alta disponibilidad.\nAlgunas herramientas de arranque del clúster de Kubernetes, como kubeadm, aprovisionan nodos maestros etcd apilados, donde el almacén de datos se ejecuta junto con los otros componentes del plano de control en el mismo nodo maestro y los comparte con ellos 2.\nPara el aislamiento del almacén de datos de los componentes del plano de control, el proceso de arranque se puede configurar para una topología etcd externa. El almacén de datos se despliega en un host dedicado separado del plano de control, reduciendo así las posibilidades de un fallo del etcd 2.\nLas topologías de etcd apilado y externa admiten configuraciones de alta disponibilidad. etcd se basa en protocolo de consenso Raft que permite que un conjunto de máquinas pueda sobrevivir al fallo de algunas de ellas, incluido a fallos de nodo maestro. En un momento dado, uno de los nodos del grupo será el maestro y el resto serán los seguidores 2.\netcd está escrito en el lenguaje de programación Go. En Kubernetes, además de almacenar el estado del clúster, etcd también se usa para almacenar detalles de configuración como subredes, ConfigMaps, Secrets, etc.\nNodo trabajador Un nodo trabajador proporciona un entorno de ejecución para las aplicaciones cliente. Aunque son microservicios en contenedores, estas aplicaciones están encapsuladas en pods, controlados por los agentes del plano de control del clúster que se ejecutan en el nodo maestro. Los pods se programan en los nodos trabajadores, donde encuentran los recursos informáticos, de memoria y de almacenamiento necesarios para ejecutarse, y las redes para comunicarse entre sí y con el mundo exterior. Un pod es la unidad de programación más pequeña de Kubernetes. Es una colección lógica de uno o más contenedores programados juntos, y la colección se puede iniciar, detener o reprogramar como una sola unidad de trabajo.\nAdemás, en un clúster de Kubernetes de varios trabajadores, el tráfico de red entre los usuarios del cliente y las aplicaciones en contenedores implementadas en Pods lo manejan directamente los nodos trabajadores y no se enruta a través del nodo maestro 2.\nContainer Runtime Aunque Kubernetes se describe como un \u0026ldquo;motor de orquestación de contenedores\u0026rdquo;, no tiene la capacidad de manejar contenedores directamente. Para administrar el ciclo de vida de un contenedor, Kubernetes requiere un entorno de ejecución del contendor en el nodo donde se programará un Pod y sus contenedores. Kubernetes admite muchos entornos de ejecución de contenedores 2:\nDocker: aunque es una plataforma de contenedores que usa containerd como entorno de ejecución de contenedor, es más popular usado con Kubernetes CRI-O: un entorno de ejecución de contenedor ligero para Kubernetes, también admite registros de imágenes de Docker containerd: un entorno de ejecución de contenedor simple y portátil que proporciona robustez frakti: un tiempo de ejecución de contenedor basado en hipervisor para Kubernetes kubelet El kubelet es un agente que se ejecuta en cada nodo y se comunica con los componentes del plano de control desde el nodo maestro. Recibe definiciones de pod, principalmente del servidor API, e interactúa con el entorno de ejecución del contenedor en el nodo para ejecutar contenedores asociados con el pod. También supervisa el estado y los recursos de los contenedores que ejecutan pods. El agente kubelet toma un conjunto de especificaciones de Pod, llamados PodSpecs, que han sido creados por Kubernetes y garantiza que los contenedores descritos en ellos estén funcionando y en buen estado.\nEl kubelet se conecta a los entornos de ejecución del contenedor a través de un complemento basado en el Container Runtime Interface (CRI). El CRI consta de protocolos de búferes, API de gRPC, bibliotecas y especificaciones y herramientas adicionales que se encuentran actualmente en desarrollo. Para conectarse a tiempos de ejecución de contenedores intercambiables, kubelet utiliza una aplicación de compensación que proporciona una capa de abstracción clara entre kubelet y el tiempo de ejecución del contenedor.\nObtenido de blog.kubernetes.io\nComo se muestra arriba, el kubelet que actúa como cliente grpc se conecta al shim CRI, que a su vez, actúa como servidor grpc para realizar operaciones en el contenedor y la imagen. El CRI implementa dos servicios: ImageService y RuntimeService. ImageService es responsable de todas las operaciones relacionadas con la imagen, mientras que RuntimeService es responsable de todas las operaciones relacionadas con el pod y el contenedor 2.\nkube-proxy El kube-proxy es el agente de red que se ejecuta en cada nodo responsable de las actualizaciones dinámicas y el mantenimiento de todas las reglas de red en el nodo. Extrae los detalles de la red de Pods y reenvía las solicitudes de conexión a los Pods.\nEl proxy kube es responsable del reenvío de transmisiones TCP, UDP y SCTP o el reenvío por turnos a través de un conjunto de backends de pod, e implementa reglas de reenvío definidas por los usuariosa través de objetos de API de servicio 2.\nAddons Los complementos son características y funcionalidades del clúster que aún no están disponibles en Kubernetes, por lo que se implementan a través de pods y servicios de terceros 2.\nDNS: el DNS del clúster es un servidor DNS necesario para asignar registros DNS a objetos y recursos de Kubernetes\nDashboard: una interfaz de usuario basada en web de propósito general para la administración de clústeres\nMonitorización: recopila métricas de contenedores a nivel de clúster y las guarda en un almacén de datos central\nRegistro: recopila registros de contenedores a nivel de clúster y los guarda en un almacén de registros central para su análisis.\nDesafíos de red Las aplicaciones basadas en microservicios desacoplados dependen en gran medida de las redes para imitar el acoplamiento estrecho que alguna vez estuvo disponible en la era monolítica. Las redes, en general, no son las más fáciles de entender e implementar. Kubernetes no es una excepción: como orquestador de microservicios en contenedores, debe abordar algunos desafíos de redes distintos 2:\nComunicación de contenedor a contenedor dentro de los pods Comunicación de pod a pod en el mismo nodo y en todos los nodos del clúster Comunicación Pod-to-Service dentro del mismo espacio de nombres y entre espacios de nombres de clústeres Comunicación externa al servicio para que los clientes accedan a aplicaciones en un clúster. De contenedor a contenedor dentro de los pods Al hacer uso de las funciones de virtualización del kernel del sistema operativo host subyacente, un entorno de ejecución de contenedor crea un espacio de red aislado para cada contenedor que inicia. En Linux, este espacio de red aislado que se denomina network namespace. Un network namespace se puede compartir entre contenedores o con el sistema operativo del host.\nCuando se inicia un pod, el Container Runtime inicializa un contenedor de pausa especial con el único propósito de crear un espacio de nombres de red para el pod. Todos los contenedores adicionales, creados a través de solicitudes de usuarios, que se ejecutan dentro del Pod compartirán el espacio de nombres de red del contenedor Pause para que todos puedan comunicarse entre sí a través de localhost.\nDe pod a pod a través de nodos En un clúster de Kubernetes, los pods se programan en los nodos de una manera casi impredecible. Independientemente de su nodo host, se espera que los pods puedan comunicarse con todos los demás pods del clúster, todo esto sin la implementación de la traducciones de direcciones de red (NAT). Este es un requisito fundamental de cualquier implementación de redes en Kubernetes.\nEl modelo de red de Kubernetes tiene como objetivo reducir la complejidad y trata a los Pods como VM en una red, donde cada VM está equipada con una interfaz de red, por lo que cada Pod recibe una dirección IP única. Este modelo se llama \u0026ldquo;IP por pod\u0026rdquo; y garantiza la comunicación de pod a pod, al igual que las máquinas virtuales pueden comunicarse entre sí en la misma red.\nSin embargo, no nos olvidemos de los contenedores. Comparten el espacio de nombres de la red del Pod y deben coordinar la asignación de puertos dentro del Pod tal como lo harían las aplicaciones en una VM, todo mientras pueden comunicarse entre sí en localhost, dentro del Pod. Sin embargo, los contenedores se integran con el modelo de red general de Kubernetes mediante el uso de Container Network Interface (CNI) compatible con los complementos CNI. CNI es un conjunto de una especificación y bibliotecas que permiten a los complementos configurar la red para contenedores. Si bien hay algunos complementos principales, la mayoría de los complementos CNI son soluciones de redes definidas por software (SDN) de terceros que implementan el modelo de redes de Kubernetes. Además de abordar el requisito fundamental del modelo de red, algunas soluciones de red ofrecen soporte para políticas de red. Flannel, Weave, Calico son solo algunas de las soluciones SDN disponibles para los clústeres de Kubernetes.\nDe Pod al mundo exterior Una aplicación implementada con éxito en contenedores que se ejecuta en pods dentro de un clúster de Kubernetes puede requerir accesibilidad desde el mundo exterior. Kubernetes permite la accesibilidad externa a través de Servicios, encapsulaciones complejas de definiciones de reglas de enrutamiento de red almacenadas en iptables en nodos de clúster e implementadas por agentes de kube-proxy. Al exponer los servicios al mundo externo con la ayuda de kube-proxy, las aplicaciones se vuelven accesibles desde fuera del clúster a través de una dirección IP virtual.\nDocumentation Kubernetes, Kubernetes Components\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nedX, Introduction to kubernetes - The Linux Foundation\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-28T00:00:00Z","permalink":"/p/componentes-de-la-arquitectura-de-kubernetes/","title":"Componentes de la arquitectura de Kubernetes"},{"content":"En esta entrada se definirán los componentes de la arquitectura de Kubernetes. Las fuentes principales de la información a continuación son el curso de Introduction to Kubernetes de The Linux Foundation en edX, cuyos autores son Chris Pokorni y Neependra Khare, y la propia documentación de Kubernetes.\nComponentes de la arquitectura en Kubernetes Un clúster de Kubernetes consta de un conjunto de máquinas trabajadoras, llamadas nodos, que ejecutan aplicaciones en contenedores. Cada clúster tiene al menos un nodo trabajador. En un nivel muy alto de abstracción, Kubernetes tiene los siguientes componentes principales:\nUno o más nodos maestros (master nodes), en la parte del plano de control (control plane). Uno o más nodos trabajadores (worker nodes). Se puede ver en la siguiente figura que es la arquitectura de los componentes de un cluster de Kubernetes 1:\nEl nodo maestro proporciona un entorno de ejecución para el plano de control responsable de administrar el estado de un clúster de Kubernetes y es el cerebro detrás de todas las operaciones dentro del clúster. Los componentes del plano de control son agentes con roles muy distintos en la gestión del clúster. Para comunicarse con el clúster de Kubernetes, los usuarios envían solicitudes al plano de control a través de una herramienta de interfaz de línea de comandos (CLI), un panel de interfaz de usuario web o una interfaz de programación de aplicaciones (API) 2.\nEs importante mantener el plano de control funcionando a toda costa. La pérdida del plano de control puede generar tiempo de inactividad, provocando la interrupción del servicio a los clientes, con una posible pérdida de negocio. Para garantizar la tolerancia a fallos del plano de control, se pueden agregar réplicas del nodo maestro al clúster, configuradas en modo de alta disponibilidad. Si bien solo uno de los nodos maestros está dedicado a administrar activamente el clúster, los componentes del plano de control permanecen sincronizados en las réplicas del nodo maestro. Este tipo de configuración agrega resistencia al plano de control del clúster, en caso de que falle el nodo maestro que está activo 2.\nPara conservar el estado del clúster de Kubernetes, todos los datos de configuración del clúster se guardan en etcd. etcd es un almacén de valores clave distribuido que solo contiene datos relacionados con el estado del clúster, sin datos de carga de trabajo del cliente. etcd se puede configurar en el nodo maestro (topología apilada) o en su host dedicado (topología externa) para ayudar a reducir las posibilidades de pérdida del almacén de datos al desacoplarlo de los otros agentes del plano de control 2.\nCon la topología de etcd apilada, las réplicas del nodo maestro de alta disponibilidad también garantizan la resistencia del almacén de datos de etcd. Sin embargo, ese no es el caso de la topología externa etcd, donde los hosts etcd deben replicarse por separado para alta disponibilidad, una configuración que introduce la necesidad de hardware adicional.\nUn nodo maestro ejecuta los siguientes componentes del plano de control 1:\nkube-apiserver o servidor API kube-scheduler o planificador kube-controller-manager o manejador de controladores etcd o almacén de datos Mientras que un nodo trabajador tiene los siguientes componentes:\nContainer Runtime o entorno de ejecución del contenedor kubelet o agente de nodo kube-proxy o proxy Addons o complementos para DNS, interfaz de usuario, monitoreo y registro a nivel de clúster Nodo maestro kube-apiserver Todas las tareas administrativas están coordinadas por kube-apiserver, un componente central del plano de control que se ejecuta en el nodo maestro. El servidor API recibe las peticiones RESTful de usuarios, operadores y agentes externos, luego las valida y las procesa. Durante el procesamiento, el servidor API lee el estado actual del clúster de Kubernetes del almacén de datos etcd y, después de la ejecución de una llamada, el estado resultante del clúster de Kubernetes se guarda en el almacén de datos distribuido de clave-valor para debida su persistencia. El servidor API es el único componente del plano de control que se comunica con el almacén de datos etcd, tanto para leer como para guardar la información del estado del clúster de Kubernetes, actuando como una interfaz intermedia para cualquier otro agente del plano de control que pregunte sobre el estado del clúster.\nEl servidor API es altamente configurable y personalizable. Puede escalar horizontalmente, pero también admite la adición de servidores API secundarios personalizados, una configuración que transforma el servidor API principal en un proxy para todos los servidores API personalizados secundarios y enruta todas las llamadas RESTful entrantes a ellos en función de reglas definidas personalizadas 2.\nkube-scheduler La función del kube-scheduler o planificador es asignar nuevos objetos de carga de trabajo, como pods, a los nodos. Durante el proceso de planificación, las decisiones se toman según el estado actual del clúster de Kubernetes y los requisitos del nuevo objeto. El planificador obtiene del almacén de datos etcd, a través del servidor API, los datos de uso de recursos para cada nodo trabajador en el clúster. El planificador también recibe del servidor API los requisitos del nuevo objeto que forman parte de sus datos de configuración. Los requisitos pueden incluir restricciones que los usuarios y operadores establezcan, como programar el trabajo en un nodo etiquetado con disk == ssd como par clave/valor. El planificador también tiene en cuenta los requisitos de calidad de servicio (QoS), la localidad de los datos, la afinidad, la antiafinidad, localización de datos dependientes, la tolerancia, la topología del clúster, etc. Una vez que todos los datos del clúster están disponibles, el algoritmo de planificación filtra los nodos con predicados para aislar los posibles nodos candidatos que luego son puntuados con prioridades para seleccionar el nodo que satisface todos los requisitos para la nueva carga de trabajo. El resultado del proceso de decisión se comunica al servidor API, que luego delega la implementación de la carga de trabajo con otros agentes del plano de control.\nEl planificador es altamente configurable y personalizable mediante políticas de planificación, complementos y perfiles. También se admiten planificadores adicionales personalizados. Un planificador es extremadamente importante y complejo en un clúster de Kubernetes de varios nodos 2.\nkube-controller-manager Componente del plano de control que ejecuta los controladores para regular el estado del clúster de Kubernetes. Los controladores son bucles de vigilancia que se ejecutan continuamente y comparan el estado deseado del clúster (proporcionado por los datos de configuración de los objetos) con su estado actual (obtenido del almacén de datos etcd a través del servidor API). En caso de una discrepancia, se toman medidas correctivas en el clúster hasta que su estado actual coincida con el estado deseado. Ejecuta controladores responsables de actuar cuando los nodos dejan de estar disponibles, para garantizar que el número de pods sean los esperados, para crear endpoints, cuentas de servicio y tokens de acceso a la API 2. Lógicamente cada controlador es un proceso independiente, pero para reducir la complejidad, todos se compilan en un único binario y se ejecuta en un mismo proceso. Estos controladores incluyen 1:\nControlador de nodos: es el responsable de detectar y responder cuándo un nodo deja de funcionar Controlador de replicación: es el responsable de mantener el número correcto de pods para cada controlador de replicación del sistema Controlador de endpoints: construye el objeto Endpoints, es decir, hace una unión entre los Services y los Pods Controladores de tokens y cuentas de servicio: crean cuentas y tokens de acceso a la API por defecto para los nuevos Namespaces. etcd Almacén de datos persistente, consistente y distribuido de clave-valor utilizado para almacenar toda a la información del clúster de Kubernetes 1. Los nuevos datos se añaden al almacén de datos, nunca se reemplazan. Los datos obsoletos se comprimen periódicamente para minimizar el tamaño del almacén de datos.\nDe todos los componentes del plano de control, solo el servidor API puede comunicarse con el almacén de datos etcd.\nLa herramienta de administración CLI de etcd, etcdctl, proporciona la opción de realizar copias de seguridad, instantáneas y restauraciones. Son especialmente útiles para un clúster de Kubernetes de única instancia de etcd, común en entornos de desarrollo y aprendizaje. Sin embargo, en los entornos Stage y Production, es extremadamente importante replicar los almacenes de datos en modo alta disponibilidad.\nAlgunas herramientas de arranque del clúster de Kubernetes, como kubeadm, aprovisionan nodos maestros etcd apilados, donde el almacén de datos se ejecuta junto con los otros componentes del plano de control en el mismo nodo maestro y los comparte con ellos 2.\nPara el aislamiento del almacén de datos de los componentes del plano de control, el proceso de arranque se puede configurar para una topología etcd externa. El almacén de datos se despliega en un host dedicado separado del plano de control, reduciendo así las posibilidades de un fallo del etcd 2.\nLas topologías de etcd apilado y externa admiten configuraciones de alta disponibilidad. etcd se basa en protocolo de consenso Raft que permite que un conjunto de máquinas pueda sobrevivir al fallo de algunas de ellas, incluido a fallos de nodo maestro. En un momento dado, uno de los nodos del grupo será el maestro y el resto serán los seguidores 2.\netcd está escrito en el lenguaje de programación Go. En Kubernetes, además de almacenar el estado del clúster, etcd también se usa para almacenar detalles de configuración como subredes, ConfigMaps, Secrets, etc.\nNodo trabajador Un nodo trabajador proporciona un entorno de ejecución para las aplicaciones cliente. Aunque son microservicios en contenedores, estas aplicaciones están encapsuladas en pods, controlados por los agentes del plano de control del clúster que se ejecutan en el nodo maestro. Los pods se programan en los nodos trabajadores, donde encuentran los recursos informáticos, de memoria y de almacenamiento necesarios para ejecutarse, y las redes para comunicarse entre sí y con el mundo exterior. Un pod es la unidad de programación más pequeña de Kubernetes. Es una colección lógica de uno o más contenedores programados juntos, y la colección se puede iniciar, detener o reprogramar como una sola unidad de trabajo.\nAdemás, en un clúster de Kubernetes de varios trabajadores, el tráfico de red entre los usuarios del cliente y las aplicaciones en contenedores implementadas en Pods lo manejan directamente los nodos trabajadores y no se enruta a través del nodo maestro 2.\nContainer Runtime Aunque Kubernetes se describe como un \u0026ldquo;motor de orquestación de contenedores\u0026rdquo;, no tiene la capacidad de manejar contenedores directamente. Para administrar el ciclo de vida de un contenedor, Kubernetes requiere un entorno de ejecución del contendor en el nodo donde se programará un Pod y sus contenedores. Kubernetes admite muchos entornos de ejecución de contenedores 2:\nDocker: aunque es una plataforma de contenedores que usa containerd como entorno de ejecución de contenedor, es más popular usado con Kubernetes CRI-O: un entorno de ejecución de contenedor ligero para Kubernetes, también admite registros de imágenes de Docker containerd: un entorno de ejecución de contenedor simple y portátil que proporciona robustez frakti: un tiempo de ejecución de contenedor basado en hipervisor para Kubernetes kubelet El kubelet es un agente que se ejecuta en cada nodo y se comunica con los componentes del plano de control desde el nodo maestro. Recibe definiciones de pod, principalmente del servidor API, e interactúa con el entorno de ejecución del contenedor en el nodo para ejecutar contenedores asociados con el pod. También supervisa el estado y los recursos de los contenedores que ejecutan pods. El agente kubelet toma un conjunto de especificaciones de Pod, llamados PodSpecs, que han sido creados por Kubernetes y garantiza que los contenedores descritos en ellos estén funcionando y en buen estado.\nEl kubelet se conecta a los entornos de ejecución del contenedor a través de un complemento basado en el Container Runtime Interface (CRI). El CRI consta de protocolos de búferes, API de gRPC, bibliotecas y especificaciones y herramientas adicionales que se encuentran actualmente en desarrollo. Para conectarse a tiempos de ejecución de contenedores intercambiables, kubelet utiliza una aplicación de compensación que proporciona una capa de abstracción clara entre kubelet y el tiempo de ejecución del contenedor.\nObtenido de blog.kubernetes.io\nComo se muestra arriba, el kubelet que actúa como cliente grpc se conecta al shim CRI, que a su vez, actúa como servidor grpc para realizar operaciones en el contenedor y la imagen. El CRI implementa dos servicios: ImageService y RuntimeService. ImageService es responsable de todas las operaciones relacionadas con la imagen, mientras que RuntimeService es responsable de todas las operaciones relacionadas con el pod y el contenedor 2.\nkube-proxy El kube-proxy es el agente de red que se ejecuta en cada nodo responsable de las actualizaciones dinámicas y el mantenimiento de todas las reglas de red en el nodo. Extrae los detalles de la red de Pods y reenvía las solicitudes de conexión a los Pods.\nEl proxy kube es responsable del reenvío de transmisiones TCP, UDP y SCTP o el reenvío por turnos a través de un conjunto de backends de pod, e implementa reglas de reenvío definidas por los usuariosa través de objetos de API de servicio 2.\nAddons Los complementos son características y funcionalidades del clúster que aún no están disponibles en Kubernetes, por lo que se implementan a través de pods y servicios de terceros 2.\nDNS: el DNS del clúster es un servidor DNS necesario para asignar registros DNS a objetos y recursos de Kubernetes\nDashboard: una interfaz de usuario basada en web de propósito general para la administración de clústeres\nMonitorización: recopila métricas de contenedores a nivel de clúster y las guarda en un almacén de datos central\nRegistro: recopila registros de contenedores a nivel de clúster y los guarda en un almacén de registros central para su análisis.\nDesafíos de red Las aplicaciones basadas en microservicios desacoplados dependen en gran medida de las redes para imitar el acoplamiento estrecho que alguna vez estuvo disponible en la era monolítica. Las redes, en general, no son las más fáciles de entender e implementar. Kubernetes no es una excepción: como orquestador de microservicios en contenedores, debe abordar algunos desafíos de redes distintos 2:\nComunicación de contenedor a contenedor dentro de los pods Comunicación de pod a pod en el mismo nodo y en todos los nodos del clúster Comunicación Pod-to-Service dentro del mismo espacio de nombres y entre espacios de nombres de clústeres Comunicación externa al servicio para que los clientes accedan a aplicaciones en un clúster. De contenedor a contenedor dentro de los pods Al hacer uso de las funciones de virtualización del kernel del sistema operativo host subyacente, un entorno de ejecución de contenedor crea un espacio de red aislado para cada contenedor que inicia. En Linux, este espacio de red aislado que se denomina network namespace. Un network namespace se puede compartir entre contenedores o con el sistema operativo del host.\nCuando se inicia un pod, el Container Runtime inicializa un contenedor de pausa especial con el único propósito de crear un espacio de nombres de red para el pod. Todos los contenedores adicionales, creados a través de solicitudes de usuarios, que se ejecutan dentro del Pod compartirán el espacio de nombres de red del contenedor Pause para que todos puedan comunicarse entre sí a través de localhost.\nDe pod a pod a través de nodos En un clúster de Kubernetes, los pods se programan en los nodos de una manera casi impredecible. Independientemente de su nodo host, se espera que los pods puedan comunicarse con todos los demás pods del clúster, todo esto sin la implementación de la traducciones de direcciones de red (NAT). Este es un requisito fundamental de cualquier implementación de redes en Kubernetes.\nEl modelo de red de Kubernetes tiene como objetivo reducir la complejidad y trata a los Pods como VM en una red, donde cada VM está equipada con una interfaz de red, por lo que cada Pod recibe una dirección IP única. Este modelo se llama \u0026ldquo;IP por pod\u0026rdquo; y garantiza la comunicación de pod a pod, al igual que las máquinas virtuales pueden comunicarse entre sí en la misma red.\nSin embargo, no nos olvidemos de los contenedores. Comparten el espacio de nombres de la red del Pod y deben coordinar la asignación de puertos dentro del Pod tal como lo harían las aplicaciones en una VM, todo mientras pueden comunicarse entre sí en localhost, dentro del Pod. Sin embargo, los contenedores se integran con el modelo de red general de Kubernetes mediante el uso de Container Network Interface (CNI) compatible con los complementos CNI. CNI es un conjunto de una especificación y bibliotecas que permiten a los complementos configurar la red para contenedores. Si bien hay algunos complementos principales, la mayoría de los complementos CNI son soluciones de redes definidas por software (SDN) de terceros que implementan el modelo de redes de Kubernetes. Además de abordar el requisito fundamental del modelo de red, algunas soluciones de red ofrecen soporte para políticas de red. Flannel, Weave, Calico son solo algunas de las soluciones SDN disponibles para los clústeres de Kubernetes.\nDe Pod al mundo exterior Una aplicación implementada con éxito en contenedores que se ejecuta en pods dentro de un clúster de Kubernetes puede requerir accesibilidad desde el mundo exterior. Kubernetes permite la accesibilidad externa a través de Servicios, encapsulaciones complejas de definiciones de reglas de enrutamiento de red almacenadas en iptables en nodos de clúster e implementadas por agentes de kube-proxy. Al exponer los servicios al mundo externo con la ayuda de kube-proxy, las aplicaciones se vuelven accesibles desde fuera del clúster a través de una dirección IP virtual.\nDocumentation Kubernetes, Kubernetes Components\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nedX, Introduction to kubernetes - The Linux Foundation\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-28T00:00:00Z","permalink":"/p/componentes-de-la-arquitectura-de-kubernetes/","title":"Componentes de la arquitectura de Kubernetes"},{"content":"En esta entrada se definirán los conceptos básicos e introductorios de Kubernetes. Las fuentes principales de la información a continuación son el curso de Introduction to Kubernetes de The Linux Foundation en edX, cuyos autores son Chris Pokorni y Neependra Khare, y la propia documentación de Kubernetes.\n¿Qué es Kubernetes y por qué se utiliza? Kubernetes o “K8s” es una plataforma portable y extensible de código libre, bajo la licencia Apache 2.0, para administrar cargas de trabajo y servicios. Sirve para la automatización del despliegue, ajuste de escala y manejo de aplicaciones en contenedores​ que fue originalmente diseñado por Google y donado a la Cloud Native Computing Foundation (parte de la Linux Foundation). Soporta diferentes entornos para la ejecución de contenedores, incluido Docker 1.\nActualmente, se tiende a una ejecución de procesos en lo que se conoce como \u0026ldquo;nube\u0026rdquo;. Aunque, por otra parte, se precede de un modelo conocido como monolítico donde se tienen principios de arquitectura software obsoletos, con grandes componentes programados en lenguajes de programación antiguos y todo el sistema desplegado requiriendo un hardware caro y costoso de manejar.\nPor lo tanto, la tendencia actual es separar y simplificar cada componente software para convertirlos en componentes distribuidos, descritos por sus respectivas características específicas. De manera que se crean microservicios que se acomplan unos con otros y fáciles de reemplazar o reubicar. La arquitectura de microservicios está alineada con los principios de la arquitectura dirigida por eventos (EDA) y de la arquitectura orientada a servicios (SOA).\nCada microservicio se desarrolla en un lenguaje de programación moderno, seleccionado para ser el más adecuado para el tipo de servicio y su función. Esto ofrece una gran flexibilidad al combinar microservicios con hardware específico cuando sea necesario, lo que permite implementaciones en hardware básico de bajo costo. Aunque la naturaleza distribuida de los microservicios agrega complejidad a la arquitectura, uno de los mayores beneficios de los microservicios es la escalabilidad. Con la aplicación general volviéndose modular, cada microservicio se puede escalar individualmente, ya sea de forma manual o automatizada a través del autoescalado basado en la demanda. Además, prácticamente no hay tiempo de inactividad ni interrupción del servicio para los clientes porque las actualizaciones se implementan sin problemas, un servicio a la vez, en lugar de tener que volver a compilar, reconstruir y reiniciar una aplicación monolítica completa 2.\nResumiendo, estos microservicios se despliegan en contenedores y kubernetes es un orquestador de contenedores. Por lo tanto, para comprender qué es kubernetes, es necesario revisar los conceptos básicos sobre contendores y orquestadores de contenedores.\n¿Qué son los contenedores? Los contenedores son espacios virtuales a nivel del sistema operativo que agrupan el código de una aplicación con las bibliotecas y los archivos de configuración asociados, junto con las dependencias necesarias para que la aplicación se ejecute. Ofrecen escalabilidad y alto rendimiento a las aplicaciones en cualquier infraestructura que se elija. Son los más adecuados para ofrecer microservicios al proporcionar entornos virtuales portátiles y aislados para que las aplicaciones se ejecuten sin interferencias de otras aplicaciones en ejecución.\nBeneficios de usar contenedores Los beneficios de usar contenedores incluyen 3:\nÁgil creación y despliegue de aplicaciones: Mayor facilidad y eficiencia al crear imágenes de contenedor en vez de máquinas virtuales. Desarrollo, integración y despliegue continuo: Permite que la imagen de contenedor se construya y despliegue de forma frecuente y confiable, facilitando los rollbacks debido a que la imagen es inmutable. Separación de tareas entre Dev y Ops: Puedes crear imágenes de contenedor al momento de compilar y no al desplegar, desacoplando la aplicación de la infraestructura. Observabilidad: No solamente se presenta la información y métricas del sistema operativo, sino la salud de la aplicación y otras señales. Consistencia entre los entornos de desarrollo, pruebas y producción: La aplicación funciona igual en un laptop y en la nube. Portabilidad entre nubes y distribuciones: Funciona en Ubuntu, RHEL, CoreOS, tu datacenter físico, Google Kubernetes Engine y todo lo demás. Administración centrada en la aplicación: Eleva el nivel de abstracción del sistema operativo y el hardware virtualizado a la aplicación que funciona en un sistema con recursos lógicos. Microservicios distribuidos, elásticos, liberados y débilmente acoplados: Las aplicaciones se separan en piezas pequeñas e independientes que pueden ser desplegadas y administradas de forma dinámica, y no como una aplicación monolítica que opera en una sola máquina de gran capacidad. Aislamiento de recursos: Hace el rendimiento de la aplicación más predecible. Utilización de recursos: Permite mayor eficiencia y densidad. ¿Qué son los orquestadores de contenedores? En entornos de desarrollo, la ejecución de contenedores en un solo host para el desarrollo y la prueba de aplicaciones puede ser una opción. Sin embargo, al migrar a entornos de control de calidad (QA) y producción (Prod), ya no es una opción viable porque las aplicaciones y los servicios deben cumplir con requisitos específicos 2:\nTolerancia a fallos. Escalabilidad bajo demanda. Uso óptimo de recursos. Descubrimiento automático para descubrir y comunicarse automáticamente entre componentes. Accesibilidad desde el mundo exterior. Actualizaciones o parches de seguridad sin interrupciones sin tiempo de inactividad. Los orquestadores de contenedores son herramientas que agrupan sistemas para formar clústeres en los que la implementación y la administración de contenedores se automatizan a escala y cumplen los requisitos mencionados anteriormente.\nExisten varias soluciones de orquestadores de contenedores y algunos de los disponibles son:\nAmazon Elastic Container Service (ECS). Azure Container Instances. Azure Service Fabric. Kubernetes. Marathon. Nomad. Docker Swarm. Aunque sea viable mantener algún contenedor manualmente, los orquestadores facilitan mucho la administración a los operadores, principalmente cuando se trata de cientos o miles de contenedores. La mayoría de los orquestadores de contenedores pueden realizar las siguientes acciones 2:\nAgrupar hosts mientras se crea un clúster. Programar contenedores para que se ejecuten en hosts del clúster según la disponibilidad de recursos. Permitir que los contenedores de un clúster se comuniquen entre sí independientemente del host en el que estén implementados en el clúster. Vincular contenedores y recursos de almacenamiento. Agrupar conjuntos de contenedores similares y vincularlos a construcciones de equilibrio de carga para simplificar el acceso a las aplicaciones en contenedores, creando un nivel de abstracción entre los contenedores y el usuario. Gestionar y optimizar el uso de recursos. Permitir la implementación de políticas para proteger el acceso a las aplicaciones que se ejecutan dentro de los contenedores. Con todas estas características, configurables pero flexibles, los orquestadores de contenedores son una buena opción cuando se trata de administrar aplicaciones en contenedores a gran escala.\nCaracterísticas de Kubernetes Kubernetes ofrece un conjunto muy amplio de funciones para la orquestación de contenedores. Sus principales características son 2:\nEmpaquetado automático de contenedores: Kubernetes programa automáticamente los contenedores en función de las necesidades y limitaciones de los recursos, para maximizar la utilización sin sacrificar la disponibilidad.\nAutocuración: Kubernetes reemplaza y reprograma automáticamente los contenedores de los nodos fallidos. Elimina y reinicia los contenedores que no responden a las comprobaciones de estado, según las reglas o políticas existentes. También evita que el tráfico se enrute a contenedores que no responden.\nEscalabilidad horizontal: Con Kubernetes, las aplicaciones se escalan de forma manual o automática según la CPU o el uso de métricas personalizadas.\nDescubrimiento de servicios y equilibrio de carga: Los contenedores reciben sus propias direcciones IP de Kubernetes, mientras que este asigna un único nombre de sistema de nombres de dominio (DNS) a un conjunto de contenedores para ayudar a equilibrar la carga de las solicitudes en todos los contenedores del conjunto.\nImplementaciones y restauraciones automatizadas: Kubernetes implementa y restaura las actualizaciones de la aplicación y los cambios de configuración sin problemas, monitoreando constantemente el estado de la aplicación para evitar cualquier tiempo de inactividad.\nGestión de secretos y configuraciones: Kubernetes administra los datos confidenciales y los detalles de la configuración de una aplicación por separado de la imagen del contenedor, para evitar una reconstrucción de la imagen respectiva. Los secretos consisten en la información sensible o confidencial que se pasa a la aplicación sin revelar el contenido sensible a la configuración del código.\nOrquestación de almacenamiento: Kubernetes monta automáticamente soluciones de almacenamiento definido por software (SDS) en contenedores de almacenamiento local, proveedores de nube externos, almacenamiento distribuido o sistemas de almacenamiento en red.\nEjecución por lotes: Kubernetes admite la ejecución por lotes, trabajos de larga ejecución y reemplaza los contenedores fallidos.\nLa arquitectura de Kubernetes es modular e interconectable. No solo organiza aplicaciones de tipo microservicios como módulos desacoplados, sino que también su arquitectura sigue patrones de microservicios desacoplados. Las funcionalidades de Kubernetes se puede ampliar escribiendo recursos personalizados, operadores, API personalizadas, reglas de programación o extensiones.\nWikipedia, Kubernetes\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nedX, Introduction to kubernetes - The Linux Foundation.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nDocumentación Kubernetes, ¿Qué es Kubernetes?\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-27T00:00:00Z","permalink":"/p/introducci%C3%B3n-a-kubernetes/","title":"Introducción a Kubernetes"},{"content":"En esta entrada se definirán los conceptos básicos e introductorios de Kubernetes. Las fuentes principales de la información a continuación son el curso de Introduction to Kubernetes de The Linux Foundation en edX, cuyos autores son Chris Pokorni y Neependra Khare, y la propia documentación de Kubernetes.\n¿Qué es Kubernetes y por qué se utiliza? Kubernetes o “K8s” es una plataforma portable y extensible de código libre, bajo la licencia Apache 2.0, para administrar cargas de trabajo y servicios. Sirve para la automatización del despliegue, ajuste de escala y manejo de aplicaciones en contenedores​ que fue originalmente diseñado por Google y donado a la Cloud Native Computing Foundation (parte de la Linux Foundation). Soporta diferentes entornos para la ejecución de contenedores, incluido Docker 1.\nActualmente, se tiende a una ejecución de procesos en lo que se conoce como \u0026ldquo;nube\u0026rdquo;. Aunque, por otra parte, se precede de un modelo conocido como monolítico donde se tienen principios de arquitectura software obsoletos, con grandes componentes programados en lenguajes de programación antiguos y todo el sistema desplegado requiriendo un hardware caro y costoso de manejar.\nPor lo tanto, la tendencia actual es separar y simplificar cada componente software para convertirlos en componentes distribuidos, descritos por sus respectivas características específicas. De manera que se crean microservicios que se acomplan unos con otros y fáciles de reemplazar o reubicar. La arquitectura de microservicios está alineada con los principios de la arquitectura dirigida por eventos (EDA) y de la arquitectura orientada a servicios (SOA).\nCada microservicio se desarrolla en un lenguaje de programación moderno, seleccionado para ser el más adecuado para el tipo de servicio y su función. Esto ofrece una gran flexibilidad al combinar microservicios con hardware específico cuando sea necesario, lo que permite implementaciones en hardware básico de bajo costo. Aunque la naturaleza distribuida de los microservicios agrega complejidad a la arquitectura, uno de los mayores beneficios de los microservicios es la escalabilidad. Con la aplicación general volviéndose modular, cada microservicio se puede escalar individualmente, ya sea de forma manual o automatizada a través del autoescalado basado en la demanda. Además, prácticamente no hay tiempo de inactividad ni interrupción del servicio para los clientes porque las actualizaciones se implementan sin problemas, un servicio a la vez, en lugar de tener que volver a compilar, reconstruir y reiniciar una aplicación monolítica completa 2.\nResumiendo, estos microservicios se despliegan en contenedores y kubernetes es un orquestador de contenedores. Por lo tanto, para comprender qué es kubernetes, es necesario revisar los conceptos básicos sobre contendores y orquestadores de contenedores.\n¿Qué son los contenedores? Los contenedores son espacios virtuales a nivel del sistema operativo que agrupan el código de una aplicación con las bibliotecas y los archivos de configuración asociados, junto con las dependencias necesarias para que la aplicación se ejecute. Ofrecen escalabilidad y alto rendimiento a las aplicaciones en cualquier infraestructura que se elija. Son los más adecuados para ofrecer microservicios al proporcionar entornos virtuales portátiles y aislados para que las aplicaciones se ejecuten sin interferencias de otras aplicaciones en ejecución.\nBeneficios de usar contenedores Los beneficios de usar contenedores incluyen 3:\nÁgil creación y despliegue de aplicaciones: Mayor facilidad y eficiencia al crear imágenes de contenedor en vez de máquinas virtuales. Desarrollo, integración y despliegue continuo: Permite que la imagen de contenedor se construya y despliegue de forma frecuente y confiable, facilitando los rollbacks debido a que la imagen es inmutable. Separación de tareas entre Dev y Ops: Puedes crear imágenes de contenedor al momento de compilar y no al desplegar, desacoplando la aplicación de la infraestructura. Observabilidad: No solamente se presenta la información y métricas del sistema operativo, sino la salud de la aplicación y otras señales. Consistencia entre los entornos de desarrollo, pruebas y producción: La aplicación funciona igual en un laptop y en la nube. Portabilidad entre nubes y distribuciones: Funciona en Ubuntu, RHEL, CoreOS, tu datacenter físico, Google Kubernetes Engine y todo lo demás. Administración centrada en la aplicación: Eleva el nivel de abstracción del sistema operativo y el hardware virtualizado a la aplicación que funciona en un sistema con recursos lógicos. Microservicios distribuidos, elásticos, liberados y débilmente acoplados: Las aplicaciones se separan en piezas pequeñas e independientes que pueden ser desplegadas y administradas de forma dinámica, y no como una aplicación monolítica que opera en una sola máquina de gran capacidad. Aislamiento de recursos: Hace el rendimiento de la aplicación más predecible. Utilización de recursos: Permite mayor eficiencia y densidad. ¿Qué son los orquestadores de contenedores? En entornos de desarrollo, la ejecución de contenedores en un solo host para el desarrollo y la prueba de aplicaciones puede ser una opción. Sin embargo, al migrar a entornos de control de calidad (QA) y producción (Prod), ya no es una opción viable porque las aplicaciones y los servicios deben cumplir con requisitos específicos 2:\nTolerancia a fallos. Escalabilidad bajo demanda. Uso óptimo de recursos. Descubrimiento automático para descubrir y comunicarse automáticamente entre componentes. Accesibilidad desde el mundo exterior. Actualizaciones o parches de seguridad sin interrupciones sin tiempo de inactividad. Los orquestadores de contenedores son herramientas que agrupan sistemas para formar clústeres en los que la implementación y la administración de contenedores se automatizan a escala y cumplen los requisitos mencionados anteriormente.\nExisten varias soluciones de orquestadores de contenedores y algunos de los disponibles son:\nAmazon Elastic Container Service (ECS). Azure Container Instances. Azure Service Fabric. Kubernetes. Marathon. Nomad. Docker Swarm. Aunque sea viable mantener algún contenedor manualmente, los orquestadores facilitan mucho la administración a los operadores, principalmente cuando se trata de cientos o miles de contenedores. La mayoría de los orquestadores de contenedores pueden realizar las siguientes acciones 2:\nAgrupar hosts mientras se crea un clúster. Programar contenedores para que se ejecuten en hosts del clúster según la disponibilidad de recursos. Permitir que los contenedores de un clúster se comuniquen entre sí independientemente del host en el que estén implementados en el clúster. Vincular contenedores y recursos de almacenamiento. Agrupar conjuntos de contenedores similares y vincularlos a construcciones de equilibrio de carga para simplificar el acceso a las aplicaciones en contenedores, creando un nivel de abstracción entre los contenedores y el usuario. Gestionar y optimizar el uso de recursos. Permitir la implementación de políticas para proteger el acceso a las aplicaciones que se ejecutan dentro de los contenedores. Con todas estas características, configurables pero flexibles, los orquestadores de contenedores son una buena opción cuando se trata de administrar aplicaciones en contenedores a gran escala.\nCaracterísticas de Kubernetes Kubernetes ofrece un conjunto muy amplio de funciones para la orquestación de contenedores. Sus principales características son 2:\nEmpaquetado automático de contenedores: Kubernetes programa automáticamente los contenedores en función de las necesidades y limitaciones de los recursos, para maximizar la utilización sin sacrificar la disponibilidad.\nAutocuración: Kubernetes reemplaza y reprograma automáticamente los contenedores de los nodos fallidos. Elimina y reinicia los contenedores que no responden a las comprobaciones de estado, según las reglas o políticas existentes. También evita que el tráfico se enrute a contenedores que no responden.\nEscalabilidad horizontal: Con Kubernetes, las aplicaciones se escalan de forma manual o automática según la CPU o el uso de métricas personalizadas.\nDescubrimiento de servicios y equilibrio de carga: Los contenedores reciben sus propias direcciones IP de Kubernetes, mientras que este asigna un único nombre de sistema de nombres de dominio (DNS) a un conjunto de contenedores para ayudar a equilibrar la carga de las solicitudes en todos los contenedores del conjunto.\nImplementaciones y restauraciones automatizadas: Kubernetes implementa y restaura las actualizaciones de la aplicación y los cambios de configuración sin problemas, monitoreando constantemente el estado de la aplicación para evitar cualquier tiempo de inactividad.\nGestión de secretos y configuraciones: Kubernetes administra los datos confidenciales y los detalles de la configuración de una aplicación por separado de la imagen del contenedor, para evitar una reconstrucción de la imagen respectiva. Los secretos consisten en la información sensible o confidencial que se pasa a la aplicación sin revelar el contenido sensible a la configuración del código.\nOrquestación de almacenamiento: Kubernetes monta automáticamente soluciones de almacenamiento definido por software (SDS) en contenedores de almacenamiento local, proveedores de nube externos, almacenamiento distribuido o sistemas de almacenamiento en red.\nEjecución por lotes: Kubernetes admite la ejecución por lotes, trabajos de larga ejecución y reemplaza los contenedores fallidos.\nLa arquitectura de Kubernetes es modular e interconectable. No solo organiza aplicaciones de tipo microservicios como módulos desacoplados, sino que también su arquitectura sigue patrones de microservicios desacoplados. Las funcionalidades de Kubernetes se puede ampliar escribiendo recursos personalizados, operadores, API personalizadas, reglas de programación o extensiones.\nWikipedia, Kubernetes\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nedX, Introduction to kubernetes - The Linux Foundation.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nDocumentación Kubernetes, ¿Qué es Kubernetes?\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-27T00:00:00Z","permalink":"/p/introducci%C3%B3n-a-kubernetes/","title":"Introducción a Kubernetes"},{"content":"En esta entrada se explicarán los pasos a seguir para añadir la funcionalidad de multilenguaje con i18n en un proyector de Angular 10/9/8. Para este tutorial es necesario tener un proyecto que esté creado previamente.\nAñadir ngx-translate en Angular 10/9/8 Se instalan los paquetes de ngx-translate con:\n1 npm i @ngx-translate/core @ngx-translate/http-loader --save @ngx-translate/core incluye los servicios esenciales, la canalización y las directivas para convertir el contenido en varios idiomas.\n@ngx-translate/http-loader ayuda a obtener los archivos de traducción de un servidor web.\nSe añaden los módulos en el archivo app.module.ts:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import { TranslateLoader, TranslateModule } from \u0026#39;@ngx-translate/core\u0026#39;; import { TranslateHttpLoader } from \u0026#39;@ngx-translate/http-loader\u0026#39;; ... @NgModule({ ... imports: [ ... TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: httpTranslateLoader, deps: [HttpClient] } }) ], ... }) export function httpTranslateLoader(http: HttpClient) { return new TranslateHttpLoader(http); } Configuración de los archivos traducidos Se abre la carpeta assets y se crea el directorio i18n. Dentro de ella se añadirán tantos ficheros \u0026lt;codigo_idioma_país\u0026gt;.json como idiomas distintos se quieran traducir. Por ejemplo el fichero src/assets/es.json contendrá lo siguiente:\n1 2 3 4 5 6 { \u0026#34;HOME\u0026#34;:\u0026#34;Inicio\u0026#34;, \u0026#34;ABOUT\u0026#34;: \u0026#34;Acerca de\u0026#34;, \u0026#34;SING_IN\u0026#34;:\u0026#34;Iniciar sesión\u0026#34;, \u0026#34;LOG_OUT\u0026#34;: \u0026#34;Cerrar sesión\u0026#34; } Otro ejemplo puede ser el fichero en inglés src/assets/en.json:\n1 2 3 4 5 6 { \u0026#34;HOME\u0026#34;:\u0026#34;Home\u0026#34;, \u0026#34;ABOUT\u0026#34;: \u0026#34;About\u0026#34;, \u0026#34;SING_IN\u0026#34;:\u0026#34;Sing in\u0026#34;, \u0026#34;LOG_OUT\u0026#34;: \u0026#34;Log out\u0026#34; } Implementar las traducciones con TranslateService Importamos el servicio TranslateService en app.component.ts:\n1 import { TranslateService } from \u0026#39;@ngx-translate/core\u0026#39;; Inyectamos el servicio TranslateService en el constructor para tener acceso al servicio:\n1 2 3 4 5 6 7 8 export class AppComponent { constructor( public translate: TranslateService ) { translate.addLangs([\u0026#39;en\u0026#39;, \u0026#39;en\u0026#39;]); translate.setDefaultLang(\u0026#39;es\u0026#39;); } } Función elegir el idioma Mediante la función switchLang se elegirá el idioma que queramos. Para ello es necesario añadirla en el archivo TypeScript del componente donde queramos que aparezca:\n1 2 3 switchLang(lang: string) { this.translate.use(lang); } Añadimos un desplegable para que se pueda elegir el idioma:\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026lt;span class=\u0026#34;form-inline\u0026#34;\u0026gt; \u0026lt;select class=\u0026#34;form-control\u0026#34; #selectedLang (change)=\u0026#34;switchLang(selectedLang.value)\u0026#34;\u0026gt; \u0026lt;option *ngFor=\u0026#34;let language of translate.getLangs()\u0026#34; [value]=\u0026#34;language\u0026#34; [selected]=\u0026#34;language === translate.currentLang\u0026#34;\u0026gt; {{ language }} \u0026lt;/option\u0026gt; \u0026lt;/select\u0026gt; \u0026lt;/span\u0026gt; Configuración de las traducciones con TranslatePipe Por último, una vez definida la constante en los archivos de idiomas (src/ssets/\u0026lt;codigo_idioma_país\u0026gt;.json), mediante la función pipe {{'HOME' | translate }} se traducirá la constante HOME al idioma elegido. Por ejemplo:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026lt;nav class=\u0026#34;navbar navbar-dark bg-primary\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;container\u0026#34;\u0026gt; \u0026lt;a class=\u0026#34;navbar-item\u0026#34;\u0026gt; {{\u0026#39;HOME\u0026#39; | translate }} \u0026lt;/a\u0026gt; \u0026lt;a class=\u0026#34;navbar-item\u0026#34;\u0026gt; {{\u0026#39;ABOUT\u0026#39; | translate }} \u0026lt;/a\u0026gt; \u0026lt;span class=\u0026#34;form-inline\u0026#34;\u0026gt; \u0026lt;select class=\u0026#34;form-control\u0026#34; #selectedLang (change)=\u0026#34;switchLang(selectedLang.value)\u0026#34;\u0026gt; \u0026lt;option *ngFor=\u0026#34;let language of translate.getLangs()\u0026#34; [value]=\u0026#34;language\u0026#34; [selected]=\u0026#34;language === translate.currentLang\u0026#34;\u0026gt; {{ language }} \u0026lt;/option\u0026gt; \u0026lt;/select\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/nav\u0026gt; Conclusión Finalmente, se ha implementado el multilenguage de la apliación Angular usando ngx-translate. Se ha analizado cómo configurar un entorno para traducir una aplicación Angular, cómo acceder a los métodos del servicio de traducción y cómo usar TranslatePipe.\nEnlaces consultados PositronX.io - Create Angular 10/9/8 MultiLingual Site with ngx-translate i18n Library\n","date":"2020-10-20T00:00:00Z","permalink":"/p/multilenguaje-en-angular-10/9/8-con-la-librer%C3%ADa-ngx-translate-i18n/","title":"Multilenguaje en Angular 10/9/8 con la librería ngx-translate (i18n)"},{"content":"En esta entrada se explicarán los pasos a seguir para añadir la funcionalidad de multilenguaje con i18n en un proyector de Angular 10/9/8. Para este tutorial es necesario tener un proyecto que esté creado previamente.\nAñadir ngx-translate en Angular 10/9/8 Se instalan los paquetes de ngx-translate con:\n1 npm i @ngx-translate/core @ngx-translate/http-loader --save @ngx-translate/core incluye los servicios esenciales, la canalización y las directivas para convertir el contenido en varios idiomas.\n@ngx-translate/http-loader ayuda a obtener los archivos de traducción de un servidor web.\nSe añaden los módulos en el archivo app.module.ts:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import { TranslateLoader, TranslateModule } from \u0026#39;@ngx-translate/core\u0026#39;; import { TranslateHttpLoader } from \u0026#39;@ngx-translate/http-loader\u0026#39;; ... @NgModule({ ... imports: [ ... TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: httpTranslateLoader, deps: [HttpClient] } }) ], ... }) export function httpTranslateLoader(http: HttpClient) { return new TranslateHttpLoader(http); } Configuración de los archivos traducidos Se abre la carpeta assets y se crea el directorio i18n. Dentro de ella se añadirán tantos ficheros \u0026lt;codigo_idioma_país\u0026gt;.json como idiomas distintos se quieran traducir. Por ejemplo el fichero src/assets/es.json contendrá lo siguiente:\n1 2 3 4 5 6 { \u0026#34;HOME\u0026#34;:\u0026#34;Inicio\u0026#34;, \u0026#34;ABOUT\u0026#34;: \u0026#34;Acerca de\u0026#34;, \u0026#34;SING_IN\u0026#34;:\u0026#34;Iniciar sesión\u0026#34;, \u0026#34;LOG_OUT\u0026#34;: \u0026#34;Cerrar sesión\u0026#34; } Otro ejemplo puede ser el fichero en inglés src/assets/en.json:\n1 2 3 4 5 6 { \u0026#34;HOME\u0026#34;:\u0026#34;Home\u0026#34;, \u0026#34;ABOUT\u0026#34;: \u0026#34;About\u0026#34;, \u0026#34;SING_IN\u0026#34;:\u0026#34;Sing in\u0026#34;, \u0026#34;LOG_OUT\u0026#34;: \u0026#34;Log out\u0026#34; } Implementar las traducciones con TranslateService Importamos el servicio TranslateService en app.component.ts:\n1 import { TranslateService } from \u0026#39;@ngx-translate/core\u0026#39;; Inyectamos el servicio TranslateService en el constructor para tener acceso al servicio:\n1 2 3 4 5 6 7 8 export class AppComponent { constructor( public translate: TranslateService ) { translate.addLangs([\u0026#39;en\u0026#39;, \u0026#39;en\u0026#39;]); translate.setDefaultLang(\u0026#39;es\u0026#39;); } } Función elegir el idioma Mediante la función switchLang se elegirá el idioma que queramos. Para ello es necesario añadirla en el archivo TypeScript del componente donde queramos que aparezca:\n1 2 3 switchLang(lang: string) { this.translate.use(lang); } Añadimos un desplegable para que se pueda elegir el idioma:\n1 2 3 4 5 6 7 8 9 10 11 12 \u0026lt;span class=\u0026#34;form-inline\u0026#34;\u0026gt; \u0026lt;select class=\u0026#34;form-control\u0026#34; #selectedLang (change)=\u0026#34;switchLang(selectedLang.value)\u0026#34;\u0026gt; \u0026lt;option *ngFor=\u0026#34;let language of translate.getLangs()\u0026#34; [value]=\u0026#34;language\u0026#34; [selected]=\u0026#34;language === translate.currentLang\u0026#34;\u0026gt; {{ language }} \u0026lt;/option\u0026gt; \u0026lt;/select\u0026gt; \u0026lt;/span\u0026gt; Configuración de las traducciones con TranslatePipe Por último, una vez definida la constante en los archivos de idiomas (src/ssets/\u0026lt;codigo_idioma_país\u0026gt;.json), mediante la función pipe {{'HOME' | translate }} se traducirá la constante HOME al idioma elegido. Por ejemplo:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 \u0026lt;nav class=\u0026#34;navbar navbar-dark bg-primary\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;container\u0026#34;\u0026gt; \u0026lt;a class=\u0026#34;navbar-item\u0026#34;\u0026gt; {{\u0026#39;HOME\u0026#39; | translate }} \u0026lt;/a\u0026gt; \u0026lt;a class=\u0026#34;navbar-item\u0026#34;\u0026gt; {{\u0026#39;ABOUT\u0026#39; | translate }} \u0026lt;/a\u0026gt; \u0026lt;span class=\u0026#34;form-inline\u0026#34;\u0026gt; \u0026lt;select class=\u0026#34;form-control\u0026#34; #selectedLang (change)=\u0026#34;switchLang(selectedLang.value)\u0026#34;\u0026gt; \u0026lt;option *ngFor=\u0026#34;let language of translate.getLangs()\u0026#34; [value]=\u0026#34;language\u0026#34; [selected]=\u0026#34;language === translate.currentLang\u0026#34;\u0026gt; {{ language }} \u0026lt;/option\u0026gt; \u0026lt;/select\u0026gt; \u0026lt;/span\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/nav\u0026gt; Conclusión Finalmente, se ha implementado el multilenguage de la apliación Angular usando ngx-translate. Se ha analizado cómo configurar un entorno para traducir una aplicación Angular, cómo acceder a los métodos del servicio de traducción y cómo usar TranslatePipe.\nEnlaces consultados PositronX.io - Create Angular 10/9/8 MultiLingual Site with ngx-translate i18n Library\n","date":"2020-10-20T00:00:00Z","permalink":"/p/multilenguaje-en-angular-10/9/8-con-la-librer%C3%ADa-ngx-translate-i18n/","title":"Multilenguaje en Angular 10/9/8 con la librería ngx-translate (i18n)"},{"content":"Git es un software de control de versiones diseñado por Linus Torvalds, pensando en la eficiencia y la confiabilidad del mantenimiento de versiones de aplicaciones cuando éstas tienen un gran número de archivos de código fuente. Su propósito es llevar registro de los cambios en los archivos y coordinar el trabajo que varias personas realizan sobre archivos compartido 1.\nPara empezar con Git es necesario tener claro que un proyecto se suele guardar en dos lugares: en un repositorio local y uno remoto. El local es la versión que se encuentra en el ordenador donde se realizan los cambios propios y en el remoto es la versión que se guarda en el servicio web de control de versiones que elijas. Lo habitual que se recomienda son los servicios web como GitLab o Gitea(en caso de querer autoalojarlo), mientras que el antiguo GitHub ha quedado renegado desde su compra por parte de Microsoft.\nConfigurar git Configuración global de git con un nombre de usuario o un correo electrónico:\n1 2 git config --global user.name \u0026#34;Nombre de Ejemplo\u0026#34; git config --global user.email nombre@ejemplo.com Clonar un repositorio Si es un repositorio local:\n1 git clone /ruta/del/repositorio En caso de querer utilizar un proyecto en un repositorio remoto:\n1 git clone https://\u0026lt;URL_repositorio_remoto\u0026gt; Iniciar un repositorio Estando en el directorio en el que queremos iniciar el repositorio introducimos en el siguiente comando:\n1 git init Crear un commit Primero se agregan los archivos modificados al index y se confirma el commit con un mensaje explicativo:\n1 2 git add . git commit -m \u0026#34;Mensaje explicativo de que se ha hecho\u0026#34; Ver la lista de archivos que han cambiado o están en el index 1 git status Crear una rama o cambiar a otra ya creada Si quieres crear una rama:\n1 git checkout -b \u0026lt;nombre_rama\u0026gt; Para cambiar a una rama ya creada:\n1 git checkout \u0026lt;nombre_rama\u0026gt; Conectar un repositorio remoto Primero, si quieres ver los repositorios ya conectados:\n1 git remote -v Para añadir un nuevo repositorio remoto ya existente:\n1 git remote add origin https://\u0026lt;URL_repositorio_remoto\u0026gt; Enviar los cambios desde una rama local al repositorio remoto 1 git push origin \u0026lt;nombre_rama\u0026gt; Buscar los cambios realizados desde el repositorio remoto que no están en el repositorio local 1 git fetch \u0026lt;origin\u0026gt; Fusionar o unir los cambios realizados en la rama “nombre_rama” con la rama actual 1 git merge \u0026lt;nombre_rama\u0026gt; Fusionar los cambios realizados en el repositorio local con e remoto (unifica los comandos fetch y merge en un único comando) 1 git pull Visualizar los conflictos presentes Si se quieren todos los conflictos:\n1 git diff Si se quiere entre dos ramas:\n1 git diff \u0026lt;rama_origen\u0026gt; \u0026lt;rama_objetivo\u0026gt; Visualizar todas las ramas del repositorio local y remoto 1 git branch -a -v Borrar una rama 1 git branch -d \u0026lt;nombre_rama\u0026gt; Borrar archivos del index y del directorio que está trabajando 1 git rm \u0026lt;nombre_archivo\u0026gt; Visualizar la historia de commits de la rama donde te encuentre 1 git log --graph Visualizar la historia de commits de todo (repositorio local y remoto) 1 git log --graph --all Inspeccionar un repositorio Si se quiere inspccionar un repositorio local:\n1 git show Si se trata de un repositorio remoto:\n1 git remote show origin Wikipedia, Git\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-12T00:00:00Z","permalink":"/p/comandos-b%C3%A1sicos-de-git/","title":"Comandos básicos de Git"},{"content":"Git es un software de control de versiones diseñado por Linus Torvalds, pensando en la eficiencia y la confiabilidad del mantenimiento de versiones de aplicaciones cuando éstas tienen un gran número de archivos de código fuente. Su propósito es llevar registro de los cambios en los archivos y coordinar el trabajo que varias personas realizan sobre archivos compartido 1.\nPara empezar con Git es necesario tener claro que un proyecto se suele guardar en dos lugares: en un repositorio local y uno remoto. El local es la versión que se encuentra en el ordenador donde se realizan los cambios propios y en el remoto es la versión que se guarda en el servicio web de control de versiones que elijas. Lo habitual que se recomienda son los servicios web como GitLab o Gitea(en caso de querer autoalojarlo), mientras que el antiguo GitHub ha quedado renegado desde su compra por parte de Microsoft.\nConfigurar git Configuración global de git con un nombre de usuario o un correo electrónico:\n1 2 git config --global user.name \u0026#34;Nombre de Ejemplo\u0026#34; git config --global user.email nombre@ejemplo.com Clonar un repositorio Si es un repositorio local:\n1 git clone /ruta/del/repositorio En caso de querer utilizar un proyecto en un repositorio remoto:\n1 git clone https://\u0026lt;URL_repositorio_remoto\u0026gt; Iniciar un repositorio Estando en el directorio en el que queremos iniciar el repositorio introducimos en el siguiente comando:\n1 git init Crear un commit Primero se agregan los archivos modificados al index y se confirma el commit con un mensaje explicativo:\n1 2 git add . git commit -m \u0026#34;Mensaje explicativo de que se ha hecho\u0026#34; Ver la lista de archivos que han cambiado o están en el index 1 git status Crear una rama o cambiar a otra ya creada Si quieres crear una rama:\n1 git checkout -b \u0026lt;nombre_rama\u0026gt; Para cambiar a una rama ya creada:\n1 git checkout \u0026lt;nombre_rama\u0026gt; Conectar un repositorio remoto Primero, si quieres ver los repositorios ya conectados:\n1 git remote -v Para añadir un nuevo repositorio remoto ya existente:\n1 git remote add origin https://\u0026lt;URL_repositorio_remoto\u0026gt; Enviar los cambios desde una rama local al repositorio remoto 1 git push origin \u0026lt;nombre_rama\u0026gt; Buscar los cambios realizados desde el repositorio remoto que no están en el repositorio local 1 git fetch \u0026lt;origin\u0026gt; Fusionar o unir los cambios realizados en la rama “nombre_rama” con la rama actual 1 git merge \u0026lt;nombre_rama\u0026gt; Fusionar los cambios realizados en el repositorio local con e remoto (unifica los comandos fetch y merge en un único comando) 1 git pull Visualizar los conflictos presentes Si se quieren todos los conflictos:\n1 git diff Si se quiere entre dos ramas:\n1 git diff \u0026lt;rama_origen\u0026gt; \u0026lt;rama_objetivo\u0026gt; Visualizar todas las ramas del repositorio local y remoto 1 git branch -a -v Borrar una rama 1 git branch -d \u0026lt;nombre_rama\u0026gt; Borrar archivos del index y del directorio que está trabajando 1 git rm \u0026lt;nombre_archivo\u0026gt; Visualizar la historia de commits de la rama donde te encuentre 1 git log --graph Visualizar la historia de commits de todo (repositorio local y remoto) 1 git log --graph --all Inspeccionar un repositorio Si se quiere inspccionar un repositorio local:\n1 git show Si se trata de un repositorio remoto:\n1 git remote show origin Wikipedia, Git\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-12T00:00:00Z","permalink":"/p/git/","title":"Git"},{"content":"En esta entrada se definirá el flujo de trabajo aplicado a un repositorio git conocido comunmente como Gitflow. Para entender dicho flujo de trabajo es necesario entender previamente qué es y para qué sirve git. Después de tener una base fijada, es habitual que vaya sobre ruedas.\n¿Qué es git? Git es un software de control de versiones diseñado por Linus Torvalds, pensando en la eficiencia y la confiabilidad del mantenimiento de versiones de aplicaciones cuando éstas tienen un gran número de archivos de código fuente. Su propósito es llevar registro de los cambios en los archivos y coordinar el trabajo que varias personas realizan sobre archivos compartido 1.\nSi quieres aprender más sobre los comandos más usados de git, visita esta entrada.\nIntroducción a Gitflow Gitflow es un flujo de trabajo para ayudar el desarrollo continuo de software y la implementación de prácticas DevOps. Fue publicado por primera vez por Vincent Driessen en nvie en el 2010.\n¿Cómo funciona? Permite la paralelización del desarrollo asignando roles específicos a las diferentes ramas para preparar, mantener y publicar versiones del proyecto y para la reparación de errores sin que cunda el pánico.\nProgramas GUI de git Buscando programas con una interfaz gráfica para gestionar git de manera sencilla y sean de código abierto o de software libre, se encuentran los siguientes:\ngitg GitAhead git-cola Git Extensions Wikipedia, Git\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-12T00:00:00Z","permalink":"/p/gitflow/","title":"Gitflow"},{"content":"En esta publicación se detallará una comparación con las ventajas y desventajas de SQL y NoSQL. Para la elección de una base de datos que se ajuste a las necesidades de cada proyecto, es necesario conocer las diferencias entre los distintos modelos.\nSQL SQL (Structured Query Language) o lenguaje de consulta estructurada se utiliza en programación para administrar y recuperar información de sistemas de gestión de bases de datos relacionales. Se caracteriza por su manejo del álgebra y el cálculo relacional para efectuar consultas con el fin de operar con la información de bases de datos. 1\nSe pueden garantizar las características ACID (Atomicidad, Consistencia, Aislamiento y Durabilidad): 2\nAtomicidad: Si cuando una operación consiste en una serie de pasos, de los que o bien se ejecutan todos o ninguno, es decir, las transacciones son completas. Consistencia: (Integridad). Es la propiedad que asegura que sólo se empieza aquello que se puede acabar. Por lo tanto se ejecutan aquellas operaciones que no van a romper las reglas y directrices de Integridad de la base de datos. La propiedad de consistencia sostiene que cualquier transacción llevará a la base de datos desde un estado válido a otro también válido. \u0026ldquo;La Integridad de la Base de Datos nos permite asegurar que los datos son exactos y consistentes, es decir que estén siempre intactos, sean siempre los esperados y que de ninguna manera cambian ni se deformen. De esta manera podemos garantizar que la información que se presenta al usuario será siempre la misma.\u0026rdquo; Aislamiento: Esta propiedad asegura que una operación no puede afectar a otras. Esto asegura que la realización de dos transacciones sobre la misma información sean independientes y no generen ningún tipo de error. Esta propiedad define cómo y cuándo los cambios producidos por una operación se hacen visibles para las demás operaciones concurrentes. El aislamiento puede alcanzarse en distintos niveles, siendo el parámetro esencial a la hora de seleccionar SGBDs. Durabilidad: (Persistencia). Esta propiedad asegura que una vez realizada la operación, esta persistirá y no se podrá deshacer aunque falle el sistema y que de esta forma los datos sobrevivan de alguna manera. Por lo tanto, un resumen sobre las ventajas y desventajas podría ser el siguiente:\nVentajas Mayor eficiencia para extraer información relacionada. Estructuración y jerarquía de datos. Respeto de la integridad de los datos. Operaciones atómicas con cambios que afecta a múltiples entidades de la base de datos al mismo tiempo. Desventajas Escalabilidad vertical, se incrementa en hardware potente y caro. Necesidad de mayor procesamiento. No es flexible, añadir nuevos datos puede resultar la modificación de esquema o relleno de datos. Herramientas más asentadas y mayor documentación. NoSQL Los sistemas NoSQL se denominan a veces \u0026ldquo;no solo SQL\u0026rdquo; para subrayar el hecho de que también pueden soportar lenguajes de consulta de tipo SQL. Los datos almacenados no requieren estructuras fijas como tablas, normalmente no soportan operaciones JOIN, ni garantizan completamente ACID (atomicidad, consistencia, aislamiento y durabilidad) y habitualmente escalan bien horizontalmente. Las bases de datos NoSQL están altamente optimizadas para las operaciones recuperar y agregar, y normalmente no ofrecen mucho más que la funcionalidad de almacenar los registros (p.ej. almacenamiento clave-valor). La pérdida de flexibilidad en tiempo de ejecución, comparado con los sistemas SQL clásicos, se ve compensada por ganancias significativas en escalabilidad y rendimiento cuando se trata con ciertos modelos de datos. 3\nPor último, un resumen con las ventajas y desventajas podría ser el siguiente:\nVentajas Flexibilidad al añadir nuevos datos. Carácter descentralizado, soporta estructuras distribuidas. Escalabilidad horizontal, se crece en número de máquinas en vez de hardware más potente. Ejecución en máquinas con pocos recursos. Desventajas No se permiten consultas complejas. Posibilidad de inconsistencia en los datos. Conclusiones Las bases de datos SQL y NoSQL tienen características distintas y conviene estudiar cual se adapta mejor a las necesidades de cada proyecto. Se recomienda evaluar las diferentes ventajas y desventajas de cada sistema de gestión de base de datos.\nWikipedia, SQL\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, ACID\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nWikipedia, NoSQL\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-10-08T00:00:00Z","permalink":"/p/base-de-datos-sql-o-nosql/","title":"Base de datos SQL o NoSQL"},{"content":"Se llevará a cabo en un servidor LAMP (Linux, Apache, MySQL/MariaDB, PHP). La distribución GNU/Linux puede ser cualquiera Ubuntu, Trisquel, Manjaro, etc. Se ha realizado la configuración con Nextcloud 19.0.0\nConfiguración del cortafuegos Utilizando el cortafuegos sencillo ufw, permitiremos el tráfico SSH (puerto 22) y web (puerto 80):\n1 2 3 sudo apt install ufw sudo ufw allow 22 sudo ufw allow 80 Instalación de de Apache Instalación del servidor Apache:\n1 sudo apt install apache2 Instalación de php Instalación de php para poder servir el contenido dinámico:\nSi se está utilizando una distribución basada en debian, es necesario añadir un repositorio para acceder a la versión 7.3. Por defecto, se encuentra disponible la versión 7. 1 2 sudo add-apt-repository ppa:ondrej/php sudo apt update Instalación de la versión 7.3 y de los módulos requeridos: 1 2 sudo apt install php7.3 sudo apt install php7.3-ctype php7.3-curl php7.3-dom php7.3-gd php7.3-iconv php7.3-mbstring php7.3-posix php7.3-xmlreader php7.3-zip php7.3-bz2 php7.3-exif php7.3-intl Instalación del módulo para poder conectarse a la base de datos: 1 sudo apt install php7.3-mysql Instalación de la base de datos 1 sudo apt install mariadb-server Ejecución de un archivo de seguridad de MySql Este script se utiliza para utilizar el servidor MariaDB en producción:\n1 sudo mysql_secure_installation Como es la primera vez que se ejecuta, introducir un intro y configurar una nueva contraseña de root. Además, confirmar con Y las siguientes opciones:\nEliminar usuario anónimo Deshabilitar conectarse como root remotamente Eliminar base de datos de prueba Recargar tabla de priviligios Configuración de base de datos Entrar en el monitor de MariaDB:\n1 sudo mysql Creación de una nueva base de datos llamada nextcloud_db (aunque se puede nombrar de otra manera). Creación de un usuario llamado nc_admin@localhost con una contraseña segura (cambiar password por una de verdad). Para evitar errores se utiliza la regla GRANT ALL ON, se actualizan los privilegios, y se sale de la base de datos:\n1 2 3 4 5 CREATE DATABASE nextcloud_db; CREATE USER \u0026#39;nc_admin\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;password\u0026#39; GRANT ALL ON nextcloud_db.* TO \u0026#39;nc_admin\u0026#39;@\u0026#39;localhost\u0026#39;; flush privileges; exit; Descarga de Nextcloud Se descarga el archivo y se descomprime en la carpeta /var/www/:\n1 2 wget https://download.nextcloud.com/server/releases/nextcloud-19.0.0.zip unzip /home/ubuntu/nextcloud-19.0.0.zip -d /var/www/ Configuración de apache Se crea un archivo de configuración:\n1 sudo nano /etc/apache2/sites-available/nextcloud.conf Se copia y se pega en su interior la configuración de apache (sacada de la documentación oficial):\n1 2 3 4 5 6 7 8 9 10 11 12 Alias /nextcloud \u0026#34;/var/www/nextcloud/\u0026#34; \u0026lt;Directory /var/www/nextcloud/\u0026gt; Require all granted AllowOverride All Options FollowSymLinks MultiViews \u0026lt;IfModule mod_dav.c\u0026gt; Dav off \u0026lt;/IfModule\u0026gt; \u0026lt;/Directory\u0026gt; Se activa la nueva configuración:\n1 2 sudo a2ensite nextcloud.conf systemctl reload apache2 Accediendo a http://IP_MÁQUINA/nextcloud se podrá visibilizar un error interno del servidor, esto se debe a la falta de permisos del usuario web en la carpeta nextcloud.\nSe añaden los siguientes permisos:\nEl usuario por defecto www-data es cualquier usuario que se conecte a través de la web. 1 2 sudo chown -R www-data:www-data /var/www/nextcloud/ sudo chmod -R 755 /var/www/nextcloud/ Volvemos a acceder a http://IP_MÁQUINA/nextcloud y rellenamos lo siguiente:\nUnas credenciales para el usuario administrador Añadir el nombre del usuario de la base de datos: nc_admin Su respectiva contraseña definida anteriormente Nombre de la base de datos: nextcloud_db Terminamos la instalación.\nConfiguración adicional recomendable Cambiar el límite de memoria (memory_limit) php a 512M en el archivo siguiente: 1 2 sudo nano /etc/php/7.3/apache2/php.ini systemctl reload apache2 Descargar módulos php recomendados: 1 sudo apt install php7.3-imagick php7.3-bcmath php7.3-gmp Recargar el servicio apache2 para hacer efectivos los cambios:\n1 systemctl reload apache2 Enlaces útiles Taller básico de NextCloud con Apache - Rafael Mateus (LibreLabUCM)\nComandos utilizados\nDocumentación oficial de Nextcloud\n","date":"2020-10-03T00:00:00Z","permalink":"/p/configuraci%C3%B3n-de-tu-propio-servidor-nextcloud/","title":"Configuración de tu propio servidor Nextcloud"},{"content":"Se llevará a cabo en un servidor LAMP (Linux, Apache, MySQL/MariaDB, PHP). La distribución GNU/Linux puede ser cualquiera Ubuntu, Trisquel, Manjaro, etc. Se ha realizado la configuración con Nextcloud 19.0.0\nConfiguración del cortafuegos Utilizando el cortafuegos sencillo ufw, permitiremos el tráfico SSH (puerto 22) y web (puerto 80):\n1 2 3 sudo apt install ufw sudo ufw allow 22 sudo ufw allow 80 Instalación de de Apache Instalación del servidor Apache:\n1 sudo apt install apache2 Instalación de php Instalación de php para poder servir el contenido dinámico:\nSi se está utilizando una distribución basada en debian, es necesario añadir un repositorio para acceder a la versión 7.3. Por defecto, se encuentra disponible la versión 7. 1 2 sudo add-apt-repository ppa:ondrej/php sudo apt update Instalación de la versión 7.3 y de los módulos requeridos: 1 2 sudo apt install php7.3 sudo apt install php7.3-ctype php7.3-curl php7.3-dom php7.3-gd php7.3-iconv php7.3-mbstring php7.3-posix php7.3-xmlreader php7.3-zip php7.3-bz2 php7.3-exif php7.3-intl Instalación del módulo para poder conectarse a la base de datos: 1 sudo apt install php7.3-mysql Instalación de la base de datos 1 sudo apt install mariadb-server Ejecución de un archivo de seguridad de MySql Este script se utiliza para utilizar el servidor MariaDB en producción:\n1 sudo mysql_secure_installation Como es la primera vez que se ejecuta, introducir un intro y configurar una nueva contraseña de root. Además, confirmar con Y las siguientes opciones:\nEliminar usuario anónimo Deshabilitar conectarse como root remotamente Eliminar base de datos de prueba Recargar tabla de priviligios Configuración de base de datos Entrar en el monitor de MariaDB:\n1 sudo mysql Creación de una nueva base de datos llamada nextcloud_db (aunque se puede nombrar de otra manera). Creación de un usuario llamado nc_admin@localhost con una contraseña segura (cambiar password por una de verdad). Para evitar errores se utiliza la regla GRANT ALL ON, se actualizan los privilegios, y se sale de la base de datos:\n1 2 3 4 5 CREATE DATABASE nextcloud_db; CREATE USER \u0026#39;nc_admin\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;password\u0026#39; GRANT ALL ON nextcloud_db.* TO \u0026#39;nc_admin\u0026#39;@\u0026#39;localhost\u0026#39;; flush privileges; exit; Descarga de Nextcloud Se descarga el archivo y se descomprime en la carpeta /var/www/:\n1 2 wget https://download.nextcloud.com/server/releases/nextcloud-19.0.0.zip unzip /home/ubuntu/nextcloud-19.0.0.zip -d /var/www/ Configuración de apache Se crea un archivo de configuración:\n1 sudo nano /etc/apache2/sites-available/nextcloud.conf Se copia y se pega en su interior la configuración de apache (sacada de la documentación oficial):\n1 2 3 4 5 6 7 8 9 10 11 12 Alias /nextcloud \u0026#34;/var/www/nextcloud/\u0026#34; \u0026lt;Directory /var/www/nextcloud/\u0026gt; Require all granted AllowOverride All Options FollowSymLinks MultiViews \u0026lt;IfModule mod_dav.c\u0026gt; Dav off \u0026lt;/IfModule\u0026gt; \u0026lt;/Directory\u0026gt; Se activa la nueva configuración:\n1 2 sudo a2ensite nextcloud.conf systemctl reload apache2 Accediendo a http://IP_MÁQUINA/nextcloud se podrá visibilizar un error interno del servidor, esto se debe a la falta de permisos del usuario web en la carpeta nextcloud.\nSe añaden los siguientes permisos:\nEl usuario por defecto www-data es cualquier usuario que se conecte a través de la web. 1 2 sudo chown -R www-data:www-data /var/www/nextcloud/ sudo chmod -R 755 /var/www/nextcloud/ Volvemos a acceder a http://IP_MÁQUINA/nextcloud y rellenamos lo siguiente:\nUnas credenciales para el usuario administrador Añadir el nombre del usuario de la base de datos: nc_admin Su respectiva contraseña definida anteriormente Nombre de la base de datos: nextcloud_db Terminamos la instalación.\nConfiguración adicional recomendable Cambiar el límite de memoria (memory_limit) php a 512M en el archivo siguiente: 1 2 sudo nano /etc/php/7.3/apache2/php.ini systemctl reload apache2 Descargar módulos php recomendados: 1 sudo apt install php7.3-imagick php7.3-bcmath php7.3-gmp Recargar el servicio apache2 para hacer efectivos los cambios:\n1 systemctl reload apache2 Enlaces útiles Taller básico de NextCloud con Apache - Rafael Mateus (LibreLabUCM)\nComandos utilizados\nDocumentación oficial de Nextcloud\n","date":"2020-10-03T00:00:00Z","permalink":"/p/configuraci%C3%B3n-de-tu-propio-servidor-nextcloud/","title":"Configuración de tu propio servidor Nextcloud"},{"content":"En esta página están almacenadas herramientas de privacidad, hacking, administración de sistemas, análisis de red y programación segura. La intención es ir actualizando las herramientas y especificar un breve resumen de qué se encuentra en cada enlace.\nPrivacidad o software libre Prism break Switching.software Desgooglicemos internet Extensiones para el navegador uBlock Privacy redirect Anonimato Guía de anonimato en internet Correos temporales: Tempail Recibidores de SMS: sms24, oksms ó fake-sms Hacking Awesome hacking Awesome Hacking Resources Administración de sistemas Snowflake SSH Client es una navaja suiza para los administradores de sistemas Análisis de red Subdominios Comparativa de herramientas de enumeración de subdominios:\nAmass: más lenta pero encuentra más subdominios válidos Findomain: más rápida con buen número de subdominios encontrados Subfinder Sublist3r DNSRecon dnssearch Knock SubBrute Programación segura Revisión de código De pago: Check Marx VeraCode Fortify AppScan-IBM Kiuwan Revisión de dependencias: Dependency check Kiuwan Sonatype SourceClear BlackDuck Snyk Secretos hardcodeados (contraseñas en el código) Gitleaks Soberanía tecnológica Colección de herramientas para autoalojar CapRover Cloudron.io Sandstorm.io ","date":"2020-09-30T00:00:00Z","permalink":"/p/colecci%C3%B3n-de-herramientas/","title":"Colección de herramientas"},{"content":"En esta entrada se definen los primeros pasos a seguir con una Raspberry Pi sin necesidad de una pantalla o un cable HDMI. Es una configuración rápida y básica para poder empezar a cacharrear con el terminal.\n1. Instalación del SO Usando el programa Raspberry Pi Imager se puede quemar la imagen de Ubuntu, RaspberryPiOS, LibreElec o que prefieras, en cualquier tarjeta micro SD. 1\n2. Conexión WiFi Si prefieres no utilizar el cable HDMI para la configuración de la red, únicamente con modificar el archivo network-config con la siguiente configuración:\n1 2 3 4 5 6 7 wifis: wlan0: dhcp4: true optional: true access-points: \u0026#34;SSID\u0026#34;: password: \u0026#34;contraseña\u0026#34; El SSID es el nombre de la red WiFi y no hace falta comillas, mientras que para la contraseña si que se necesitan comillas.\n3. Primera conexión Lo más sencillo es conectarse a través de SSH. Para ello es necesario saber cuál es la dirección IP que se asigna automáticamente mediante DHCP a la Raspberry. Se puede conocer a través de la interfaz web del router o realizando un escaneo de red con nmap.\nLa conexión se realiza mediante el siguiente comando:\n1 ssh ubuntu@IP_máquina El usuario y contraseña por defecto son ubuntu\n4. Seguridad SSH 1. Configuración de SSH mediante llaves La diferencia de conectarse por SSH a un dispositivo mediante una contraseña o un par de llaves RSA es que la contraseña la puede conocer cualquiera y las llaves son personales e intransferibles 2. Por eso para generar un par de claves público-privada será a través del siguiente comando:\n1 ssh-keygen -t rsa Nos pedirá una contraseña para usar la clave SSH y se crearán dos claves en el diretorio .ssh en el home del usuario. La clave privada será id_rsa, la cuál no habrá que compartirla nunca, y la pública id_rsa.pub.\nEn el siguiente paso es necesario copiar la clave pública al archivo ~/.ssh/authorized_keys de la RaspberryPi. Para ello se utilizará el siguiente comando:\n1 ssh-copy-id -i ubuntu@\u0026lt;ip de la raspberry\u0026gt; Ahora nos pedirá la contraseña de nuestra clave SSH y se conectará a la RaspberryPi.\nLo último que haremos en este apartado será restringir el acceso remoto con contraseñas. De esa manera sólo podrán conectarse remotamente aquellas personas que hayan subido previamente su llave SSH pública a la Raspberry Pi. Lo que tendremos que hacer es editar el archivo de configuración sshd_config`. Ejecutamos el siguiente comando en nuestra Raspberry Pi:\n1 sudo nano /etc/ssh/sshd_config Y en la línea PasswordAuthentication poner no:\n1 PasswordAuthentication no Guardamos los cambios y reiniciamos el servicio con:\n1 sudo service ssh restart 2. Cambio del puerto de las conexiones SSH Una buena práctica de seguridad es cambiar el puerto por defecto para las conexiones SSH (el puerto 22), ya que si intentan atacarnos probablemente prueben a conectarse por ese puerto. De esta manera, cambiando el puerto se reducirá considerablemente el numero de intentos de conexión por parte de posibles atacantes. Pueden elegir un número desde el 1024 hasta el 65535 si quieren. Pero primero debemos revisar que no haya otro servicio utilizando ese mismo puerto. Escribimos en la terminal:\n1 netstat -punta | grep LISTEN Una vez comprobado que el puerto que elegimos está libre deben modificar el archivo de configuración de SSH:\n1 sudo nano /etc/ssh/sshd_config Cambien la línea #Port 22 por, por ejemplo, Port 2251 u otro puerto que prefieran y que no esté ocupado. Es importante que borren la almohadilla/gato/numeral porque si no el sistema lo interpreta como un comentario.\nGuarden, salgan y reinicien el servicio para que se haga efectivo el cambio en la configuración:\n1 sudo service ssh restart Cuidado, si hay un error en el cambio de puerto puede que se queden fuera de la servidora y pierdan la conexión por SSH que tenían. Es mejor si están físicamente cerca de la servidora en este paso.\nA partir de ahora para conectarse a la Raspberry Pi via SSH deberán especificar el puerto, porque ya no será el puerto por defecto. Así que el comando que deberán escribir de ahora en más será:\n1 ssh -p 2251 ubuntu@\u0026lt;dirección ip\u0026gt; Si se se les olvida el puerto que pusieron o no saben si está abierto, pueden hacer un escaneo de puertos desde otra computadora con nmap así:\n1 sudo nmap -p 1-65535 -T4 -A -v \u0026lt;ip-servidora\u0026gt; Nota: apartado copiado y reproducido de La_bekka, Seguridad de SSH - Parte IV: Securicemos nuestra servidora web 2.\nInstalación de Ubuntu en la Raspberry - Atareao\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nLa_bekka, Accedamos remotamente a la Raspberry Pi usando SSH - Parte II: ¡Hola maquinita!\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-09-28T00:00:00Z","permalink":"/p/primeros-pasos-con-una-raspberry-pi/","title":"Primeros pasos con una Raspberry Pi"},{"content":"En esta entrada se definen los primeros pasos a seguir con una Raspberry Pi sin necesidad de una pantalla o un cable HDMI. Es una configuración rápida y básica para poder empezar a cacharrear con el terminal.\n1. Instalación del SO Usando el programa Raspberry Pi Imager se puede quemar la imagen de Ubuntu, RaspberryPiOS, LibreElec o que prefieras, en cualquier tarjeta micro SD. 1\n2. Conexión WiFi Si prefieres no utilizar el cable HDMI para la configuración de la red, únicamente con modificar el archivo network-config con la siguiente configuración:\n1 2 3 4 5 6 7 wifis: wlan0: dhcp4: true optional: true access-points: \u0026#34;SSID\u0026#34;: password: \u0026#34;contraseña\u0026#34; El SSID es el nombre de la red WiFi y no hace falta comillas, mientras que para la contraseña si que se necesitan comillas.\n3. Primera conexión Lo más sencillo es conectarse a través de SSH. Para ello es necesario saber cuál es la dirección IP que se asigna automáticamente mediante DHCP a la Raspberry. Se puede conocer a través de la interfaz web del router o realizando un escaneo de red con nmap.\nLa conexión se realiza mediante el siguiente comando:\n1 ssh ubuntu@IP_máquina El usuario y contraseña por defecto son ubuntu\n4. Seguridad SSH 4.1. Configuración de SSH mediante llaves La diferencia de conectarse por SSH a un dispositivo mediante una contraseña o un par de llaves RSA es que la contraseña la puede conocer cualquiera y las llaves son personales e intransferibles 2. Por eso para generar un par de claves público-privada será a través del siguiente comando:\n1 ssh-keygen -t rsa Nos pedirá una contraseña para usar la clave SSH y se crearán dos claves en el diretorio .ssh en el home del usuario. La clave privada será id_rsa, la cuál no habrá que compartirla nunca, y la pública id_rsa.pub.\nEn el siguiente paso es necesario copiar la clave pública al archivo ~/.ssh/authorized_keys de la RaspberryPi. Para ello se utilizará el siguiente comando:\n1 ssh-copy-id -i ubuntu@\u0026lt;ip de la raspberry\u0026gt; Ahora nos pedirá la contraseña de nuestra clave SSH y se conectará a la RaspberryPi.\nLo último que haremos en este apartado será restringir el acceso remoto con contraseñas. De esa manera sólo podrán conectarse remotamente aquellas personas que hayan subido previamente su llave SSH pública a la Raspberry Pi. Lo que tendremos que hacer es editar el archivo de configuración sshd_config`. Ejecutamos el siguiente comando en nuestra Raspberry Pi:\n1 sudo nano /etc/ssh/sshd_config Y en la línea PasswordAuthentication poner no:\n1 PasswordAuthentication no Guardamos los cambios y reiniciamos el servicio con:\n1 sudo service ssh restart 4.2. Cambio del puerto de las conexiones SSH Una buena práctica de seguridad es cambiar el puerto por defecto para las conexiones SSH (el puerto 22), ya que si intentan atacarnos probablemente prueben a conectarse por ese puerto. De esta manera, cambiando el puerto se reducirá considerablemente el numero de intentos de conexión por parte de posibles atacantes. Pueden elegir un número desde el 1024 hasta el 65535 si quieren. Pero primero debemos revisar que no haya otro servicio utilizando ese mismo puerto. Escribimos en la terminal:\n1 netstat -punta | grep LISTEN Una vez comprobado que el puerto que elegimos está libre deben modificar el archivo de configuración de SSH:\n1 sudo nano /etc/ssh/sshd_config Cambien la línea #Port 22 por, por ejemplo, Port 2251 u otro puerto que prefieran y que no esté ocupado. Es importante que borren la almohadilla/gato/numeral porque si no el sistema lo interpreta como un comentario.\nGuarden, salgan y reinicien el servicio para que se haga efectivo el cambio en la configuración:\n1 sudo service ssh restart Cuidado, si hay un error en el cambio de puerto puede que se queden fuera de la servidora y pierdan la conexión por SSH que tenían. Es mejor si están físicamente cerca de la servidora en este paso.\nA partir de ahora para conectarse a la Raspberry Pi via SSH deberán especificar el puerto, porque ya no será el puerto por defecto. Así que el comando que deberán escribir de ahora en más será:\n1 ssh -p 2251 ubuntu@\u0026lt;dirección ip\u0026gt; Si se se les olvida el puerto que pusieron o no saben si está abierto, pueden hacer un escaneo de puertos desde otra computadora con nmap así:\n1 sudo nmap -p 1-65535 -T4 -A -v \u0026lt;ip-servidora\u0026gt; Nota: apartado copiado y reproducido de La_bekka, Seguridad de SSH - Parte IV: Securicemos nuestra servidora web 2.\nInstalación de Ubuntu en la Raspberry - Atareao\u0026#160;\u0026#x21a9;\u0026#xfe0e;\nLa_bekka, Accedamos remotamente a la Raspberry Pi usando SSH - Parte II: ¡Hola maquinita!\u0026#160;\u0026#x21a9;\u0026#xfe0e;\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-09-28T00:00:00Z","permalink":"/p/primeros-pasos-con-una-raspberry-pi-y-ubuntu-server/","title":"Primeros pasos con una Raspberry Pi y Ubuntu server"},{"content":"Este artículo ofrece una muestra de la sintaxis básica de Markdown que se puede utilizar en los archivos de contenido de Hugo, y también muestra si los elementos HTML básicos están decorados con CSS en un tema de Hugo.\nCabeceras Los siguientes elementos HTML \u0026lt;h1\u0026gt; — \u0026lt;h6\u0026gt; representan seis niveles de encabezados de sección. \u0026lt;h1\u0026gt; es el nivel de sección más alto mientras que \u0026lt;h6\u0026gt; es el más bajo.\nH1 H2 H3 H4 H5 H6 Párrafo Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.\nItatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.\nBloque El elemento bloque representa contenido que se cita de otra fuente, opcionalmente con una cita que debe estar dentro de un elemento footer o cite, y opcionalmente con cambios en línea como anotaciones y abreviaturas.\nBloque sin atribución Tiam, ad mint andaepu dandae nostion secatur sequo quae. Nota: puede usar el Markdown sintaxis dentro de una blockquote.\nBloque con atribución Don\u0026rsquo;t communicate by sharing memory, share memory by communicating.\n— Rob Pike1\nTablas Las tablas no forman parte de la especificación principal de Markdown, pero Hugo las admite de forma inmediata.\nName Age Bob 27 Alice 23 Markdown dentro de las tablas Italics Bold Code italics bold code Bloque de código Bloque de código con comilla invertida 1 2 3 4 5 6 7 8 9 10 11 \u0026lt;!doctype html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; \u0026lt;title\u0026gt;Ejemplo de documento HTML5\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;!-- this line is extraneous 2Error from server (Forbidden): deployments.apps is forbidden: User \u0026#34;chiptest\u0026#34; cannot create resource \u0026#34;deployments\u0026#34; in API group \u0026#34;apps\u0026#34; in the namespace \u0026#34;default\u0026#34; --\u0026gt; \u0026lt;/html\u0026gt; Codigo en bloque con sangrado de cuatro espacios \u0026lt;!doctype html\u0026gt; \u0026lt;html lang=\u0026quot;en\u0026quot;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026quot;utf-8\u0026quot;\u0026gt; \u0026lt;title\u0026gt;Ejemplo de documento HTML5\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Bloque de código con resaltado interno de Hugo 1 2 3 4 5 6 7 8 9 10 \u0026lt;!doctype html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;utf-8\u0026#34;\u0026gt; \u0026lt;title\u0026gt;Ejemplo de documento HTML5\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;p\u0026gt;Test\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; Tipo de lista Lista ordenada Primer item Segundo item Tercer item Lista no ordenada Un item Otro item Y otro item List anidada Fruta Manzana Naranja Plátano Lácteos Leche Queso Otros elementos — abbr, sub, sup, kbd, mark GIF es un formato de imagen de mapa de bits.\nH2O\nXn + Yn = Zn\nPresiona CTRL+ALT+Delete y termina la sesión.\nLa mayoría de las salamandras son nocturnos y cazan insectos, gusanos y otras criaturas pequeñas.\nThe above quote is excerpted from Rob Pike\u0026rsquo;s talk during Gopherfest, November 18, 2015.\u0026#160;\u0026#x21a9;\u0026#xfe0e;\n","date":"2020-09-26T00:00:00Z","permalink":"/p/ejemplo-de-sintaxis-de-markdown/","title":"Ejemplo de sintaxis de Markdown"}]