Saltar al contenido principal

APIs, TLS y seguridad avanzada en Kubernetes

Todo en Kubernetes pasa por el API server: kubectl, los kubelets, los controladores y cualquier aplicación que hable con el cluster. Eso lo convierte en la pieza más crítica a proteger y en un tema recurrente de los exámenes CKA y CKS. En este capítulo veremos cómo se estructura la API, cómo se protege con TLS y qué configuraciones debes conocer (y auditar).

Anatomía de la API de Kubernetes

La API es una API REST: cada recurso tiene su ruta. Cuando ejecutas kubectl get pods, en realidad se hace una petición GET https://<api-server>:6443/api/v1/namespaces/default/pods.

Los recursos se organizan en grupos de API (los apiGroups que ya vimos en RBAC):

  • /api/v1: el grupo core (pods, services, configmaps, secrets...).
  • /apis/<grupo>/<versión>: el resto, por ejemplo /apis/apps/v1 (deployments) o /apis/batch/v1 (jobs).

Puedes explorar la API directamente:

# Listar todos los recursos, sus grupos y abreviaturas
kubectl api-resources

# Listar las versiones de API disponibles
kubectl api-versions

# Ver la estructura de cualquier recurso (tu mejor amigo en el examen)
kubectl explain pod.spec.containers

Versionado y deprecaciones

Las versiones de API siguen una progresión: v1alpha1v1beta1v1 (estable). Las versiones alpha están desactivadas por defecto y las beta pueden cambiar; cuando un recurso se gradúa, las versiones antiguas se marcan como deprecated y acaban eliminándose.

Esto importa porque las actualizaciones de cluster rompen manifiestos antiguos: si tus YAML usan una API eliminada (como extensions/v1beta1 para deployments, o las PodSecurityPolicies que vimos en seguridad), dejarán de aplicar. Antes de actualizar, revisa la guía de APIs deprecadas y comprueba qué usa tu cluster:

# ¿Qué versión estoy usando para cada recurso?
kubectl get deployments.v1.apps -o yaml | head

# Herramientas como kubent o pluto detectan APIs deprecadas en uso

Acceder a la API directamente

Para entender la seguridad de la API, nada como llamarla sin kubectl.

La forma fácil es kubectl proxy, que abre un túnel local ya autenticado con tu kubeconfig:

kubectl proxy --port=8001 &
curl http://localhost:8001/api/v1/namespaces/default/pods

La forma manual, con certificados, te enseña qué hay realmente en tu kubeconfig:

# Extraer las credenciales del kubeconfig
kubectl config view --raw -o jsonpath='{.users[0].user.client-certificate-data}' | base64 -d > client.crt
kubectl config view --raw -o jsonpath='{.users[0].user.client-key-data}' | base64 -d > client.key
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt

curl https://<ip-api-server>:6443/api/v1/pods \
--cert client.crt --key client.key --cacert ca.crt

Desde dentro de un pod, las aplicaciones usan el token de su service account:

TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl https://kubernetes.default.svc/api/v1/namespaces/default/pods \
--header "Authorization: Bearer $TOKEN" \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt

TLS en el cluster

Toda la comunicación interna de Kubernetes va cifrada con TLS: kubectl ↔ API server, API server ↔ kubelets, API server ↔ etcd... Cada componente tiene su par de certificado y clave, firmados por la CA del cluster que vive en /etc/kubernetes/pki/.

ls /etc/kubernetes/pki/
# apiserver.crt, apiserver.key -> el certificado del API server
# apiserver-kubelet-client.crt/key -> para hablar con los kubelets
# ca.crt, ca.key -> la CA del cluster
# etcd/ -> PKI propia de etcd
# front-proxy-* -> para el agregador de APIs
# sa.key, sa.pub -> firma de tokens de service accounts

En el próximo capítulo gestionaremos estos certificados en detalle (caducidades, renovaciones, kubeadm certs). De momento, quédate con la foto: una CA raíz firma la identidad de cada componente, y cualquier petición se valida contra ella.

Flags de seguridad del API server

La configuración del API server vive en /etc/kubernetes/manifests/kube-apiserver.yaml (es un static pod, como vimos en troubleshooting). Estos son los flags que debes conocer y auditar:

spec:
containers:
- command:
- kube-apiserver
- --anonymous-auth=false # Rechazar peticiones anónimas (cuidado: los health checks las usan)
- --authorization-mode=Node,RBAC # Nunca AlwaysAllow
- --enable-admission-plugins=NodeRestriction
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
- --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
- --kubelet-client-certificate=... # Autenticación mutua con los kubelets
- --audit-log-path=/var/log/kubernetes/audit.log # Auditoría (si está configurada)

Puntos calientes que pregunta el examen (y que explotan los atacantes):

  • --anonymous-auth: si está en true (valor por defecto) las peticiones sin credenciales se tratan como el usuario system:anonymous. Combinado con un RBAC permisivo, es una puerta abierta.
  • --authorization-mode=AlwaysAllow: desactiva la autorización por completo. Nunca en producción.
  • --insecure-port: el antiguo puerto 8080 sin TLS ni autenticación. Eliminado en versiones modernas, pero pregunta clásica de hardening.
  • NodeRestriction: admission plugin que limita lo que cada kubelet puede modificar (solo su propio nodo y sus pods). Esencial para que un nodo comprometido no afecte al resto.

Tras cualquier cambio en este fichero, recuerda que el kubelet recrea el pod automáticamente; vigílalo con crictl ps si el API deja de responder.

Puertos del cluster

Conocer los puertos es necesario tanto para configurar firewalls como para el examen:

PuertoComponenteUso
6443kube-apiserverAPI del cluster (TLS)
2379-2380etcdCliente y comunicación entre pares
10250kubeletAPI del kubelet (¡protégela! permite ejecutar comandos en pods)
10257kube-controller-managerMétricas/health (localhost)
10259kube-schedulerMétricas/health (localhost)
30000-32767nodosRango NodePort

El puerto 10250 del kubelet merece mención especial: es un objetivo clásico de ataques, porque si queda accesible sin autenticación permite listar pods y ejecutar comandos en ellos. Verifica que el kubelet tenga authentication.anonymous.enabled: false y authorization.mode: Webhook en /var/lib/kubelet/config.yaml.

Resumen

  • La API es REST y se organiza en grupos versionados; kubectl explain y kubectl api-resources son tus herramientas de exploración.
  • Las APIs se deprecan y eliminan: revisa tus manifiestos antes de cada actualización de cluster.
  • Todo el tráfico interno va con TLS firmado por la CA de /etc/kubernetes/pki/.
  • Audita los flags del API server (anonymous-auth, authorization-mode, admission plugins) y protege el puerto 10250 del kubelet.

Volver al índice