Saltar a contenido

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 Admission restricted.
  • Una ServiceAccount sin token montado: kubelatch no habla con el API server del cluster de gestión con ella.
  • Un Deployment de una réplica: maxSurge: 1, maxUnavailable: 0, terminationGracePeriodSeconds: 60, usuario no root, sistema de ficheros de solo lectura y sin capabilities.
  • Un Service LoadBalancer con externalTrafficPolicy: Local y anotaciones por nube comentadas.
  • El ConfigMap kubelatch-config, generado desde config.env con 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

  1. Edita deploy/k8s/base/config.env. Como mínimo KUBELATCH_BASE_URL: la URL pública exacta, sin barra final. El resto de variables está en Configuración. No añadas todavía las variables GITHUB_*: el login con GitHub se activa después, siguiendo Login con GitHub.

  2. 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_KEY en 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.

  3. Pon el certificado y aplica los manifiestos. ¿Tienes que pasar por un Ingress? Lee antes Exponer kubelatch y aplica overlays/ingress. Con cert-manager, edita deploy/k8s/overlays/cert-manager/certificate.yaml (nombre DNS e issuerRef) y aplica el overlay:

    kubectl --kubeconfig "$MGMT_KUBECONFIG" apply -k deploy/k8s/overlays/cert-manager
    

    Sin 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
    
  4. 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/readyz
    

    El log muestra listening con version, tls=true y audit_retention. /readyz responde ok.

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

  1. Abre https://kubelatch.example.com y entra como admin.
  2. Registra un cluster en «Clusters»: Registrar un cluster.
  3. Invita a las personas en «Usuarios» (Usuarios y bots) y concédeles niveles en «Permisos» (Conceder permisos).
  4. 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:

  1. proxy-read-timeout y proxy-send-timeout a 3600. Los 60 s por defecto cortan watch, logs -f y un exec inactivo.
  2. proxy-body-size: "0". Con 1 MiB por defecto, un kubectl apply grande recibe 413 antes de llegar a kubelatch.
  3. 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.env sustituye entero al de la base: pon ahí KUBELATCH_BASE_URL y el resto de variables que uses.
  • KUBELATCH_TRUSTED_PROXIES en overlays/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 con hostNetwork). 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 :8080 desde el namespace ingress-nginx. Cambia kubernetes.io/metadata.name si 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 /8 en IPv4 o /16 en 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