Migrando secrets a Vault y optimizando WordPress en mi clúster K3s


Hoy ha sido un día intenso de infraestructura. Os cuento todo lo que hemos hecho en el clúster K3s de casa.
1. Gestión de secrets con HashiCorp Vault + External Secrets Operator
Hasta ahora teníamos secrets en texto plano en los ficheros YAML del repo. No es lo ideal para un GitOps con ArgoCD. Así que instalamos HashiCorp Vault (standalone con file storage sobre MooseFS) y External Secrets Operator para sincronizar los secrets automáticamente.
- Vault desplegado vía Helm chart en el namespace
vault, con PVC en moosefs-storage - ESO en el namespace
external-secrets, con ClusterSecretStore apuntando a Vault - Autenticación Kubernetes: el service account de ESO se autentica directamente en Vault
- Migrados todos los secrets de Authelia: LDAP, sesión, encryption, JWT, SMTP, OIDC clients, y clave privada RSA
- La clave privada OIDC era multi-línea — hubo que usar un init container con heredoc para insertarla correctamente en el YAML
2. Authelia ahora usa ConfigMap + init container
Authelia no soporta interpolación de variables de entorno en su config YAML. La solución: un ConfigMap con placeholders ${VAR}, y un init container que los substituye con los valores reales del K8s Secret (sincronizado desde Vault via ESO).
- Adiós al PVC para el config de Authelia
- El config se genera en un emptyDir desde el init container
- La clave privada OIDC se inyecta con un heredoc en el propio init container
- Authelia arranca limpio: Startup complete ✅
3. WordPress: re-activado y optimizado para velocidad
El WordPress estaba desactivado (en applications_old/). Lo hemos reactivado y aprovechado para hacer una optimización en profundidad.
Arquitectura: Nginx + PHP-FPM (adiós Apache)
Cambiamos la imagen wordpress:latest (Apache + mod_php) por wordpress:php8.3-fpm-alpine con un sidecar de nginx:1.27-alpine. Esto nos da:
- FastCGI cache en Nginx: respuestas cacheadas 10 minutos, TTFB mínimo
- Gzip + cabeceras de caché: assets estáticos con 365 días de caché (immutable)
- PHP-FPM tuning: OPcache con JIT, realpath cache, zlib compression
- Redis para sesiones y caché de objetos, con append-only y maxmemory 256MB
- Seguridad: headers (X-Frame-Options, XSS Protection, etc.), XML-RPC bloqueado, PHP denegado en uploads
- MySQL tuneado: InnoDB buffer pool 256MB, O_DIRECT, connection pool ajustado
- Storage class: todos los PVCs con moosefs-storage
4. Housekeeping en el repo
Además de todo lo anterior, se movió la web estática (Caddy) a applications_old/ para que WordPress coja el dominio innercys.eu, y se hicieron varias mejoras en el repo (labels estandarizados, resources, kustomization.yaml).
Lecciones aprendidas
- K3s tiene un límite de 262KB en anotaciones de CRDs → usar
--server-side=truepara CRDs grandes - Authelia no interpreta
${VAR}en el YAML de configuración → init container necesario - MySQL 8.0 eliminó
query_cache_type→ no ponerlo en el my.cnf - La imagen nginx:alpine no incluye el módulo brotli → usar solo gzip
- Para secrets multi-línea en Vault, usar heredoc en el init container en vez de sed
Y hasta aquí el día de hoy. El clúster cada vez más equipado 💪