saltar al contenido
volver al mapa
práctica
etapa: proteger
4 min de lectura

Kubernetes - runtime seguro

El clúster Kubernetes es un sistema operativo distribuido: RBAC, admission controllers y policies rigen lo que cada pod puede hacer, montar y exponer.

KubernetesOPA GatekeeperKyvernoKube-bench

Qué es

Kubernetes no es solo un orquestador de contenedores, es un sistema operativo distribuido con propia: API, etcd, red de pods, secrets y volúmenes. Cada capa trae controles: RBAC dice quién puede pedir qué a la API, los admission controllers dicen qué puede entrar al clúster, las NetworkPolicies dicen con qué otros pods puede hablar cada pod, y el kubelet dice qué puede hacer cada contenedor en el nodo.

Tratar a Kubernetes como 'solo un deploy runner' es el error que filtra tokens en logs, abre puertos a internet y corre contenedores como root con sistemas de archivos escribibles. Defender el clúster exige los cuatro controles combinados, no solo uno.

RBAC: la primera cerca

RBAC (Role-Based Access Control) vincula un sujeto (ServiceAccount, User, Group) a un rol, y el rol a un conjunto de verbos sobre recursos. Funciona en dos niveles: Role + RoleBinding (alcance de namespace) y ClusterRole + ClusterRoleBinding (alcance de todo el clúster).

El error clásico es dar cluster-admin al pipeline de CI o a un service account de aplicación. Funciona, el deploy pasa, y cualquier RCE en un pod se vuelve control total del clúster, incluyendo la lectura de todos los secrets en todos los namespaces.

rbac-inseguro.yamlyaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: ci-deployer-all
subjects:
  - kind: ServiceAccount
    name: ci-runner
    namespace: ci
roleRef:
  kind: ClusterRole
  name: cluster-admin          # poder total, en todo el clúster
  apiGroup: rbac.authorization.k8s.io
rbac-corregido.yamlyaml
apiVersion: v1
kind: Namespace
metadata:
  name: payments
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployer
  namespace: payments
rules:
  - apiGroups: ["apps"]
    resources: ["deployments", "replicasets"]
    verbs: ["get", "list", "watch", "update", "patch"]
  - apiGroups: [""]
    resources: ["pods", "pods/log"]
    verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-deployer
  namespace: payments
subjects:
  - kind: ServiceAccount
    name: ci-runner
    namespace: ci
roleRef:
  kind: Role
    name: deployer
  apiGroup: rbac.authorization.k8s.io

NetworkPolicies: el firewall de los pods

Por defecto, todo pod habla con todo pod en todo namespace. Las NetworkPolicies corrigen esto: son selectores de pod que dicen quién puede entrar y salir, con semántica de allowlist (lo que no está permitido está bloqueado).

La primera política siempre es la de deny-by-default en el namespace. Sin ella, abrir un puerto nuevo en un pod es abrir un puerto nuevo en todo el clúster. La segunda viene con allow explícito para el tráfico legítimo (ingress desde el ingress controller, salida hacia APIs externas, pod-to-pod dentro de la misma app).

netpol-default-deny.yamlyaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: payments
spec:
  podSelector: {}              # vale para todos los pods del namespace
  policyTypes:
    - Ingress
    - Egress
  ingress: []                  # nada entra
  egress:
    - to:
        - namespaceSelector:
            matchLabels:
              kubernetes.io/metadata.name: kube-system
      ports:
        - protocol: UDP
          port: 53             # DNS para resolver servicios externos

Admission control: política antes de que el pod suba

Los admission controllers están entre la aceptación del request y la persistencia en etcd. Pueden validar (rechazar) o mutar (reescribir) el manifiesto. Kubernetes trae Pod Security Admission (PSA) integrado desde la 1.23, con profiles privileged, baseline y restricted. Para lógica más fina entran los policy engines:

  • Gatekeeper: usa Rego, sintaxis de , ideal para equipos con cultura de ingeniería de políticas
  • Kyverno: YAML puro, se lee como un manifiesto normal de Kubernetes, ideal para equipos que quieren escribir policies sin aprender otro lenguaje
  • Pod Security Admission: nativo, sin dependencias extra, los profiles baseline y restricted cubren el 80% de los casos
  • ValidatingAdmissionPolicy (KEP-3485): admission declarativo en CEL, estabilizándose en versiones recientes

Secretos en etcd: cifrado en reposo

Por defecto, los secrets en etcd se guardan en texto plano (solo base64 en el YAML). Quien tenga acceso de lectura a etcd, o a un backup de este, lee todos los tokens, contraseñas y claves. El encryption at rest resuelve esto: cada clave de etcd se cifra con una clave envuelta por un .

El precio es gestionar una clave (rotación, revocación), y lo que se gana es : incluso un dump de etcd se vuelve dato inerte sin el KMS.

kube-apiserver --encryption-configyaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - kms:
          name: aws-kms
          endpoint: unix:///var/run/kms-provider/socket
          cachesize: 100
          keyid: arn:aws:kms:us-east-1:111122223333:key/abcd-...
      - identity: {}                  # fallback para leer datos antiguos

Dónde aparece

Kubernetes es la frontera entre lo que produjo el pipeline y lo que va a correr en producción. Toda defensa que falló antes (imagen sin escanear, manifiesto sin policy) cae aquí: el admission control rechaza, la NetworkPolicy aísla, el RBAC limita el daño. Por otro lado, es la última oportunidad de corregir lo que pasó: PSP/PSA atrapa un manifiesto laxo, OPA atrapa labels incorrectos, los secrets en KMS neutralizan un dump de etcd.

Puntos fuertes

  • los controles nativos de Kubernetes ya cubren RBAC, NetworkPolicy, PSA, encryption at rest: no hay que comprar nada
  • policy as code (Kyverno, Gatekeeper) pasa a ser cosa de PR, con review y pruebas, no de ticket urgente
  • los namespaces se vuelven unidades de aislamiento baratas, dando un límite de sin necesitar clústeres separados

Limitaciones

  • RBAC, NetworkPolicy y admission son controles default-deny: deben configurarse antes de que corra cualquier cosa, y el camino de migración para un clúster existente es manual
  • todo el clúster es tan seguro como el nodo: un kubelet expuesto o un contenedor con privilegios rompe las garantías de las capas de arriba
  • operar policies a escala (X clústeres, Y namespaces) se vuelve trabajo de plataforma, no de app, y sin un responsable se vuelve un desorden
Superficie de ataqueTodo lo que está expuesto a entrada no confiable: endpoints, formularios, dependencias, puertos, pipelines. Una superficie mínima es una estrategia de defensa.ver en el glosario →RegoOPALenguaje declarativo de Open Policy Agent para escribir políticas que se evalúan sobre una entrada (un plan de Terraform, un manifiesto de Kubernetes, una solicitud de API).ver en el glosario →Policy as codeOPA / RegoLa política de seguridad escrita como un archivo versionado que el pipeline consulta (denegar imagen con vulnerabilidad crítica, exigir firma). Cambia el criterio = cambia el archivo, con revisión.ver en el glosario →KMSkey management serviceServicio administrado que crea, almacena y controla el uso de claves criptográficas. La aplicación rara vez toca la clave maestra: le pide al KMS que cifre o descifre, y el proveedor registra cada uso en un log auditable. Sin KMS, la clave termina en disco y se vuelve un objetivo.ver en el glosario →Defensa en profundidadCapas independientes de protección, bajo la premisa de que cualquiera puede fallar: validación + parametrización + WAF + monitoreo.ver en el glosario →Radio de impactoblast radiusEl tamaño del daño cuando algo se rompe: una cuenta, una región completa, un tenant. Un buen diseño de nube limita el radio mediante aislamiento (cuentas separadas, VPCs separadas, roles estrechos) para que una falla o un ataque no se convierta en un desastre total.ver en el glosario →

conexiones en el mapa

actualizado el 14/10/2026 · fuentes para profundizar · reportar un error

Estudia antes

pon a prueba lo que entendiste

Cargando preguntas…