Instalar¶
Esta guía deja kubelatch funcionando en un cluster de gestión, con Postgres, TLS y el primer administrador.
Hay un test, make e2e-install (e2e/install.sh), que repite estos pasos en un cluster kind desechable: úsalo como ejemplo que funciona.
Antes de empezar¶
| Pieza | Detalle |
|---|---|
| Cluster de gestión | Kubernetes 1.28 o superior, con kubectl de administrador. Puede ser uno de los clusters que kubelatch va a gestionar. |
| Postgres | 14 o superior, externo o gestionado (RDS, Cloud SQL, Azure Database…). Un rol que pueda crear tablas en la base de datos: kubelatch crea el esquema al arrancar. |
| Nombre DNS y certificado | Un nombre público o interno (kubelatch.example.com) y un certificado para él: cert-manager (recomendado) o uno propio. |
| Red | Los pods de kubelatch deben llegar por https al API server de cada cluster gestionado. Las personas y los runners de CI deben llegar a kubelatch por https. |
| Imagen | make image construye kubelatch:dev (IMAGE= y VERSION= la cambian): la SPA y un binario estático sobre distroless/static-debian12:nonroot, sin shell. Publícala en tu registro y apunta a ella en images: de deploy/k8s/base/kustomization.yaml. |
Todos los comandos de esta guía apuntan al cluster de gestión con esta variable. Defínela antes de empezar:
export MGMT_KUBECONFIG=<ruta-al-kubeconfig-del-cluster-de-gestión>
Usa siempre un kubeconfig explícito
En una máquina con varios clusters, un kubectl sin --kubeconfig puede aplicar cambios en el cluster equivocado. Por eso todos los comandos de esta guía llevan --kubeconfig "$MGMT_KUBECONFIG".
Qué trae deploy/k8s¶
Los manifiestos son kustomize. La base (deploy/k8s/base) crea:
- El
Namespace kubelatch, con Pod Security Admissionrestricted. - Una
ServiceAccountsin token montado: kubelatch no habla con el API server del cluster de gestión con ella. - Un
Deploymentde una réplica:maxSurge: 1,maxUnavailable: 0,terminationGracePeriodSeconds: 60, usuario no root, sistema de ficheros de solo lectura y sin capabilities. - Un
ServiceLoadBalancerconexternalTrafficPolicy: Localy anotaciones por nube comentadas. - El
ConfigMap kubelatch-config, generado desdeconfig.envcon un hash en el nombre: cambiarlo redespliega.
Los secretos y el certificado los creas tú. Encima de la base hay tres overlays:
| Overlay | Qué añade |
|---|---|
overlays/cert-manager |
Un Certificate que rellena el Secret kubelatch-tls. |
overlays/ha |
Dos réplicas y un PodDisruptionBudget con minAvailable: 1. Ver Actualizar. |
overlays/ingress |
Ingress (ingress-nginx) en vez de LoadBalancer, con HTTP plano dentro del cluster y una NetworkPolicy. Ver Ingress. |
Instalar paso a paso¶
-
Edita
deploy/k8s/base/config.env. Como mínimoKUBELATCH_BASE_URL: la URL pública exacta, sin barra final. El resto de variables está en Configuración. No añadas todavía las variablesGITHUB_*: el login con GitHub se activa después, siguiendo Login con GitHub. -
Crea el namespace y los secretos.
kubectl --kubeconfig "$MGMT_KUBECONFIG" apply -f deploy/k8s/base/namespace.yaml kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch create secret generic kubelatch-secrets \ --from-literal=DATABASE_URL='postgres://kubelatch:<contraseña>@<host>:5432/kubelatch?sslmode=require' \ --from-literal=KUBELATCH_ENCRYPTION_KEY="$(head -c32 /dev/urandom | base64)"Guarda
KUBELATCH_ENCRYPTION_KEYen tu gestor de secretos, aparte de las copias de Postgres. Cifra los tokens de las ServiceAccounts de cada cluster y firma las sesiones. Si la pierdes, ver Actualizar y copias de seguridad. -
Pon el certificado y aplica los manifiestos. ¿Tienes que pasar por un Ingress? Lee antes Exponer kubelatch y aplica
overlays/ingress. Con cert-manager, editadeploy/k8s/overlays/cert-manager/certificate.yaml(nombre DNS eissuerRef) y aplica el overlay:kubectl --kubeconfig "$MGMT_KUBECONFIG" apply -k deploy/k8s/overlays/cert-managerSin cert-manager, crea el Secret a mano y aplica la base:
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch create secret tls kubelatch-tls --cert=tls.crt --key=tls.key kubectl --kubeconfig "$MGMT_KUBECONFIG" apply -k deploy/k8s/base -
Comprueba el arranque.
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch rollout status deploy/kubelatch kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch logs deploy/kubelatch | head curl https://kubelatch.example.com/readyzEl log muestra
listeningconversion,tls=trueyaudit_retention./readyzrespondeok.
Las sondas funcionan así: el startupProbe da hasta dos minutos a las migraciones. /readyz hace ping a Postgres. /healthz solo comprueba el proceso: una caída de Postgres no reinicia el pod ni corta las sesiones abiertas, y el proxy responde 503 mientras tanto.
Crear el primer administrador¶
La imagen no tiene shell: kubectl exec ejecuta el binario directamente, con las mismas variables que el servidor.
kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch exec -it deploy/kubelatch -- /kubelatch user create admin --admin --display-name "Admin"
Pide la contraseña dos veces, sin eco (mínimo 12 caracteres). Sin terminal, pásala por la entrada estándar:
printf '%s' '<contraseña larga>' | kubectl --kubeconfig "$MGMT_KUBECONFIG" -n kubelatch exec -i deploy/kubelatch -- /kubelatch user create admin --admin --password-stdin
Si vas a activar el login con GitHub, marca ya esta cuenta como cuenta de emergencia (--break-glass). Lo explica Cuentas y recuperación.
Comprueba que funciona¶
- Abre
https://kubelatch.example.comy entra comoadmin. - Registra un cluster en «Clusters»: Registrar un cluster.
- Invita a las personas en «Usuarios» (Usuarios y bots) y concédeles niveles en «Permisos» (Conceder permisos).
- Cada persona entra en «Inicio» y emite su credencial: Obtener una credencial.
Exponer kubelatch: LoadBalancer L4 o Ingress¶
kubelatch lleva conexiones largas e inusuales: watch y logs -f de horas casi sin tráfico, exec/attach/port-forward como upgrades SPDY o WebSocket sobre HTTP/1.1, y apply de varios megabytes. Cualquier intermediario con timeouts o buffers de aplicación las rompe. Por eso la opción por defecto es L4.
LoadBalancer L4 (por defecto)¶
El balanceador pasa los bytes TLS tal cual y kubelatch termina el TLS. La IP de origen llega intacta (auditoría y límites por IP sin X-Forwarded-For), sin timeouts de aplicación ni límites de tamaño. Solo puede cortar una conexión el idle timeout TCP del balanceador. Go envía keepalives TCP cada 15 s, que las tres nubes cuentan como actividad.
| Nube | Idle timeout | Qué hacer |
|---|---|---|
| AWS NLB | 350 s, fijo | Nada: los keepalives lo reinician. Anotaciones de ejemplo en service.yaml. |
| Azure Load Balancer | 4 min por defecto | service.beta.kubernetes.io/azure-load-balancer-tcp-idle-timeout: "30" (el máximo, en minutos). |
| GCP (Network LB passthrough) | Sin timeout | Nada. |
| On-prem (MetalLB, kube-vip) | Sin timeout | Nada. |
Con externalTrafficPolicy: Local solo pasan el health check los nodos con un pod de kubelatch. Es lo deseado. Deja KUBELATCH_TRUSTED_PROXIES vacío.
Ingress (alternativa)¶
Si tu organización obliga a pasar por un Ingress, usa deploy/k8s/overlays/ingress. Está pensado para ingress-nginx y el test de instalación no lo cubre: valídalo en tu cluster. El TLS termina en el controlador (Secret kubelatch-tls en el namespace kubelatch) y kubelatch escucha HTTP en :8080.
ingress.yaml trae los tres ajustes obligatorios:
proxy-read-timeoutyproxy-send-timeouta3600. Los 60 s por defecto cortanwatch,logs -fy unexecinactivo.proxy-body-size: "0". Con 1 MiB por defecto, unkubectl applygrande recibe413antes de llegar a kubelatch.- Backend por HTTP/1.1 (
backend-protocol: HTTP). Nunca HTTP/2 ni gRPC hacia el backend: los upgrades SPDY/WebSocket viajan por HTTP/1.1.
Además tienes que ajustar tres cosas del overlay:
- Su propio
config.env.overlays/ingress/config.envsustituye entero al de la base: pon ahíKUBELATCH_BASE_URLy el resto de variables que uses. KUBELATCH_TRUSTED_PROXIESenoverlays/ingress/config.env: las IP de los pods del controlador y nada más (el rango más estrecho que las cubra, o el CIDR de los nodos si corre conhostNetwork). El valor de ejemplo,10.244.0.0/16, es el CIDR de pods de todo un cluster kind: no sirve para producción. Detalle en Proxies de confianza.- La
NetworkPolicy(networkpolicy.yaml) solo deja llegar al:8080desde el namespaceingress-nginx. Cambiakubernetes.io/metadata.namesi tu controlador vive en otro. La salida no se restringe: kubelatch necesita Postgres, los clusters y GitHub.
La NetworkPolicy necesita un CNI que la aplique
Sin un CNI que aplique NetworkPolicy (Calico, Cilium…), se ignora en silencio. kubelatch queda entonces expuesto en HTTP plano a cualquier pod, y cualquiera dentro del rango de confianza puede falsificar la IP de la auditoría.
Otros controladores (Traefik, HAProxy, ALB de AWS) tienen ajustes equivalentes. Con cualquiera, ingress-nginx incluido, haz tres pruebas antes de darlo por bueno: kubectl get pods -w durante más de 2 minutos, un kubectl exec inactivo 5 minutos y un kubectl create -f de 2 MB.
Proxies de confianza y la IP de origen¶
La auditoría, el registro del plano de control y los tres limitadores por IP (login, intercambio de CI y fallos de autenticación del proxy) usan la IP de la conexión TCP. Detrás de un proxy L7 esa IP es la del proxy. KUBELATCH_TRUSTED_PROXIES dice de qué redes se cree X-Forwarded-For:
- Se lee de derecha a izquierda. El primer salto que no es de confianza es el cliente; lo que un cliente falsifique queda a la izquierda y se ignora.
- Solo admite CIDR (
10.244.0.0/16,10.0.0.1/32). Una IP suelta impide el arranque. - Un prefijo más amplio que
/8en IPv4 o/16en IPv6 también impide el arranque. - Las direcciones IPv4 mapeadas en IPv6 (
::ffff:10.0.0.1) se comparan sin mapear.
Nunca pongas un rango que alcance un cliente (por ejemplo 0.0.0.0/0): podría elegir su IP en la auditoría y esquivar los límites. Si falta detrás de un Ingress, todo aparece como venido del controlador y el límite de login se aplica a todos a la vez.
Certificados y CA privada¶
kubelatch lee el certificado de /etc/kubelatch/tls y recarga la pareja cuando cambia en disco: comprueba las fechas como mucho cada 10 s. Una renovación de cert-manager no necesita reiniciar. Si la pareja nueva no es válida (clave de otro certificado, fichero a medias), sigue sirviendo la anterior y lo registra (tls: reload failed). Cada hora avisa si quedan menos de 30 días.
Con una CA pública (Let's Encrypt), los kubeconfigs no llevan CA: kubectl confía por el almacén del sistema. Con una CA privada, apunta KUBELATCH_KUBECONFIG_CA al bundle PEM y cada kubeconfig emitido llevará certificate-authority-data. Con un issuer privado de cert-manager, el Secret ya trae ca.crt: usa /etc/kubelatch/tls/ca.crt.
El fichero debe ser regular, de 1 MiB como mucho, y contener solo bloques CERTIFICATE. Una clave pegada por error u otro bloque PEM impide el arranque.
kubelatch nunca mete la CA de los clusters gestionados en los kubeconfigs. kubectl verifica a kubelatch, y kubelatch verifica cada API server con la CA que se pegó al registrarlo.
Siguientes pasos¶
- Login con GitHub, si tu organización usa GitHub.
- Registrar un cluster y, opcionalmente, endurecerlo.
- Actualizar y copias de seguridad, antes de ir a producción.