Gestión de secretos en Kubernetes: el problema del Base64

Kubernetes facilita desplegar aplicaciones, pero también facilita cometer un error recurrente: asumir que un Secret nativo es “seguro” porque su valor aparece como Base64. Base64 no es cifrado; es una representación. Y esa diferencia, en empresas, termina materializándose en credenciales expuestas en repos, en CI/CD, en tickets, o en incidentes por permisos mal acotados.

Este artículo se centra en el impacto práctico de ese detalle (Base64) y en un patrón operativo para salir del problema usando External Secrets Operator integrado con Azure Key Vault o AWS Secrets Manager, sin depender de “buenas intenciones” ni de procesos manuales.

Qué significa realmente que un Secret sea Base64 (y por qué importa en auditoría)

Un Secret de Kubernetes en formato YAML guarda sus valores en Base64 dentro del campo data. Eso evita caracteres problemáticos en YAML/JSON, pero no añade confidencialidad. Cualquier persona o proceso con acceso de lectura al objeto puede decodificarlo en segundos. En auditorías es habitual ver esta confusión: se evalúa “si hay Secrets” en el clúster, pero no quién puede leerlos, cómo se registran, y si están protegidos en reposo.

En entornos corporativos, el riesgo rara vez es “alguien entra al clúster y ve un Secret”. Lo típico es una cadena de exposiciones pequeñas: un rol con permisos de lectura excesivos, una consola de observabilidad que captura manifiestos, un operador que hace kubectl get secret -o yaml durante un troubleshooting y lo pega en un chat interno, o un pipeline que imprime variables de entorno en logs. Base64 convierte esos fallos de higiene en una filtración real, porque no hay una barrera criptográfica.

Un ejemplo muy común: se usa stringData para comodidad (texto plano en YAML) y se comitea el manifiesto por error. Aunque data se vea “ofuscado”, el repositorio termina conteniendo el secreto equivalente. Desde el punto de vista de cumplimiento (ISO 27001, SOC 2, PCI según contexto), esto suele ser indistinguible de tener credenciales en texto plano, porque el esfuerzo para recuperarlas es trivial.

Cómo se filtran Secrets en la vida real: RBAC, etcd, logs y backups

El primer vector práctico es RBAC. Muchas organizaciones dan permisos de lectura amplios para acelerar operaciones (“que el equipo de soporte pueda ver todo”). El resultado: roles con get/list/watch sobre secrets en namespaces de aplicaciones. Con Base64, ese permiso es equivalente a entregar credenciales en claro. En incidentes internos, he visto más fugas por exceso de permisos que por ataques sofisticados.

El segundo vector es la persistencia. Los Secrets viven en etcd; si no está configurado el cifrado en reposo (encryption at rest) y la gestión de claves, cualquier acceso a backups o snapshots de etcd se convierte en acceso a secretos. Esto aparece especialmente cuando se externalizan backups a almacenamiento centralizado y el control de acceso no está alineado con el modelo de mínimos privilegios del clúster.

  • Logs y herramientas de troubleshooting: si un equipo vuelca objetos Kubernetes completos a logs (por ejemplo, ante un error de reconciliación de un operador), puede terminar registrando el campo data y, por tanto, el secreto en Base64.
  • Backups y DR: un plan de recuperación que replica etcd o manifiestos a otro entorno sin cifrado/segregación puede propagar credenciales a entornos menos controlados.
  • CI/CD: pipelines que renderizan Helm/Kustomize y almacenan artefactos (manifiestos) como evidencia de despliegue pueden conservar los Secrets “ofuscados” pero recuperables.

En todos los casos, el patrón es el mismo: Base64 no frena nada. Si tu control compensatorio es “solo lo verá gente de confianza”, ya has trasladado el riesgo a permisos, procesos y herramientas que no siempre están diseñadas para custodia de secretos.

Decisión operativa: qué cambia al mover los secretos a un gestor externo

La salida práctica en empresas no suele ser “cifremos mejor el YAML”, sino cambiar el punto de control: que Kubernetes no sea el sistema de registro del secreto, sino un consumidor temporal. Ahí entran Azure Key Vault o AWS Secrets Manager como origen, y External Secrets Operator (ESO) como mecanismo para materializar el secreto donde el workload lo necesita.

Esto no elimina los Secret dentro del clúster (muchas apps los siguen requiriendo), pero sí cambia la gobernanza: rotación, auditoría de accesos, versionado, y políticas de quién puede leer el secreto se gestionan en el vault, no en etcd. En la práctica, el equipo de seguridad puede imponer controles (por ejemplo, MFA, condiciones, logging centralizado) en el plano cloud en lugar de perseguir manifiestos YAML dispersos.

  • Trade-off de disponibilidad: introduces dependencia del servicio de secretos (Key Vault/Secrets Manager). Esto obliga a diseñar caché, refresco y tolerancia a fallos del operador.
  • Trade-off de permisos: pasas de RBAC puro a una combinación de RBAC + identidad cloud (workload identity/IRSA). Si esto se hace mal, puedes empeorar el radio de impacto.

En entornos con múltiples clusters y equipos, el mayor beneficio suele ser organizativo: reduces el “sprawl” de secretos y centralizas la responsabilidad. El mayor riesgo suele ser operacional: una mala configuración de identidad (por ejemplo, una federación demasiado abierta) que permita a pods no autorizados pedir secretos al vault.

Cómo hacerlo en la práctica con External Secrets Operator + Azure Key Vault / AWS Secrets Manager

El objetivo operativo es que el pod tenga una identidad verificable (sin secretos estáticos), que ESO use esa identidad para leer del vault, y que se cree/actualice un Secret en el namespace objetivo. La clave: eliminar credenciales “bootstrap” en YAML y reducir al mínimo el acceso tanto en Kubernetes como en el gestor externo.

Pasos concretos (comunes): instalar ESO, definir un SecretStore/ClusterSecretStore apuntando al proveedor, y crear un ExternalSecret que mapea claves remotas a un Secret local. A partir de ahí, validar que: (a) la identidad utilizada es la esperada, (b) el operador no puede leer más de lo necesario, y (c) el secreto se refresca según la política (rotación/TTL).

AWS (IRSA + Secrets Manager): el patrón recomendado es asociar el ServiceAccount de ESO (o del namespace que corresponda, según tu modelo) a un rol IAM vía OIDC. La política debe limitar el acceso a ARNs concretos.

  • Policy IAM mínima (ejemplo):

    Limita el acceso a lectura de un secreto específico. Evita comodines amplios, porque convierten un error en un incidente lateral.

    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": [
    "secretsmanager:GetSecretValue",
    "secretsmanager:DescribeSecret"
    ],
    "Resource": "arn:aws:secretsmanager:REGION:ACCOUNT_ID:secret:app/prod/db-??????"
    }
    ]
    }

  • Trust policy del rol (OIDC) acotada:

    Restringe por sub al ServiceAccount exacto. En corporativo, este es el punto donde más se “abre de más” por prisa.

    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Principal": {
    "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/OIDC_PROVIDER"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
    "StringEquals": {
    "OIDC_PROVIDER:sub": "system:serviceaccount:NAMESPACE:external-secrets"
    }
    }
    }
    ]
    }

Validación en AWS: verifica en CloudTrail eventos de GetSecretValue con el rol esperado; revisa que el rol no pueda listar secretos; y comprueba que el OIDC sub no permite otros ServiceAccounts. En el clúster, valida con kubectl describe externalsecret y eventos que el refresh funciona sin errores de autorización.

Azure (Workload Identity + Key Vault): el patrón equivalente es federar el ServiceAccount con una Managed Identity / App Registration y conceder permisos mínimos en Key Vault (por ejemplo, acceso solo a get de secretos concretos). La validación práctica suele apoyarse en los logs de Key Vault (diagnostic settings) para confirmar qué identidad accedió a qué secreto y desde qué contexto, además de los eventos del operador en Kubernetes.

Recomendaciones para entornos corporativos

El problema del Base64 en Kubernetes no es teórico: convierte cualquier exceso de permisos o mala práctica operativa (logs, backups, artefactos de CI/CD) en una exposición directa. Tratar los Secret nativos como “cifrado” es una de las causas más frecuentes de hallazgos repetidos en auditorías y revisiones internas.

External Secrets Operator con Azure Key Vault o AWS Secrets Manager suele ser la forma más realista de recuperar control: el secreto vive y se audita en el vault; Kubernetes lo consume. Para que funcione en empresa, la pieza crítica es la identidad (Workload Identity/IRSA) con permisos mínimos y trust acotado, más una validación continua (CloudTrail/Key Vault logs + eventos del operador) que demuestre que solo lo esperado puede leer lo necesario.

Si tienes que priorizar: corta primero el acceso RBAC a secrets, evita que manifiestos con secretos circulen por CI/CD y repositorios, y mueve la fuente de verdad a un gestor externo con auditoría. Base64 no es el enemigo; la falsa sensación de seguridad sí.


¿Te interesa la seguridad en Cloud?

Comparto análisis técnicos, laboratorios prácticos y experiencias reales sobre Cloud Security.

Política de privacidad