Devops
Secretos en k8s I – De secretos en plano a SealedSecrets
Contexto
La situación que se describe en este post tiene su origen en un proyecto en un cliente de la industria farmacéutica: muchos equipos de trabajo (varios miles), que operan en remoto desde distintas partes del planeta y que en muchos casos no disponen de personal técnico, sino que sus componentes son investigadores de diversas materias relacionadas que se han tenido que adaptar a trabajar con herramientas de software avanzadas, tales como máquinas virtuales, bases de datos para gestión de grandes cantidades de información, repositorios de código, contenedores o clusters de kubernetes.
Estos equipos se dedican en la mayor parte de los casos a investigación de productos propios de la empresa, o a crear herramientas que dan apoyo a los primeros. Esto hace que en muchos casos, la información que se maneja sea extremadamente sensible, ya que se trata de datos privilegiados, cuyo mal uso puede derivar en errores de cálculo, resultados inexactos, pérdida de información altamente privada, espionaje, etc.
1. El problema: Secretos en plano
El problema que aquí se describe es muy común en empresas que han trabajado desde hace largo tiempo con repositorios de código para el tracking de su código: llega un momento en el que hay que manejar datos sensibles, como contraseñas, tokens de acceso, claves privadas, etc. El problema real es dónde almacenar esta información, más alla del posit pegado a la pantalla del ordenador.
En nuestro caso, nos encontramos que las primeras iteraciones del proyecto se habían producido en un momento en el que no existían requerimientos corporativos sobre cómo manejar este tipo de datos, unido a que se utilizaba una versión de Github Enterprise Server, alojado en servidores propios. Esto había derivado en que cada equipo había empezado a almacenar estos secretos directamente en sus repos de Github, pudiendo ser legibles por cualquier persona que tuviera acceso de lectura al repo.
A medida que el número de repos creció y también el número de personas que tenían acceso a los mismos, se convirtió en un verdadero problema de seguridad al no poder controlar quién podía conocer información tan sensible. Y recordemos que encima, se trata de un área destinada a la investigación, con lo que la información expuesta era un peligro desde el punto de vista corporativo.
Unido a esto, podemos añadir el “inconveniente” de que la filosofía que se adoptó desde el equipo de Ingenieros DevOps fue la de adoptar la filosofía GITOPS, que convierte la información en repositorios y herramientas externas en la única fuente de verdad sobre las aplicaciones desplegadas. Como nuestra plataforma de despliegue de aplicaciones son clusters AKS de Azure, esto hacía que crear directamente secretos en los clusters no fuera una medida idónea siempre que existiese alguna alternativa, porque podía hacer que la información se perdiera si herramientas como ArgoCD interpretaban que los componentes creados manualmente no estaban sincronizados con la fuente de verdad.
Nos encontrabamos con dos problemas a resolver:
- Queríamos que nuestros secretos se encontrasen almacenados en algún lugar externo a los clusters, y que su valor fuera sincronizado de alguna manera en el entorno productivo.
- Los valores secretos no podían ser accesibles por el público general que sí tenía acceso de lectura a los repositorios de código, quedando su consulta y modificación restringidos a una serie de personas con un nivel de permisos superior.
2. Primera solución: Sealed Secrets
La opción elegida fue utilizar SealedSecrets Operator. SealedSecrets es una herramienta diseñada para ofuscar secretos de tal forma que solo puedan descifrarse en el destino en el que se sellaron. A modo de ejemplo, la herramienta se instala en un clúster de Kubernetes. Mediante un cliente (kubeseal), podemos generar el valor ofuscado de un secreto determinado específicamente para ese clúster, e incluso para un espacio de nombres concreto.
A partir de ese momento, este valor sellado puede almacenarse tal cual en cualquier repositorio, ya que el valor en sí mismo no proporciona ninguna información significativa a terceros. Solo cuando ese SealedSecret se implemente en el clúster de Kubernetes de destino, la herramienta lo descifrará de nuevo y creará un secreto normal que pueda ser utilizado por una aplicación que se ejecute en un pod.
3. ¿Cómo se sincronizan los secretos ahora?
De esta manera, el método para crear un secreto en el cluster ahora queda así:
- Un usuario con privilegios de acceso al cluster utiliza kubeseal desde algun dispositivo donde este cliente pueda ejecutarse para encriptar un valor secreto. Este secreto encriptado será únicamente desencriptable mediante la herramienta instalada en el cluster AKS.
- El valor encriptado se guarda en un fichero dentro del repositorio de Github. Este valor, bien directamente en un manifiesto, o bien utilizando alguna herramienta de despliegue como Helm, se utiliza para crear un objeto SealedSecret en el cluster AKS
- El controller de la herramienta detecta el SealedSecret en el cluster, y mediante los certificados propios que tiene instalados, lo desencripta para crear un objeto Secret de kubernetes.
- El valor está ya disponible para ser consumido por los “pods” de aplicación, que lo utilizarán a conveniencia para las configuraciones que lo necesiten

Now we have fixed the two problems that we had before:
- We can keep our configuration in Git without exposing the actual secret values, and information is synchronized to the cluster with an automatic process
- Only people with privileges can use kubeseal connected to the AKS cluster to seal values that will be decrypted once deployed.
4. Y Ahora Tenemos Otros Problemas
Lo que al principio supuso una gran ayuda acabó provocando otros problemas más adelante, todos ellos relacionados principalmente con la renovación y la rotación de secretos:
- El cliente Kubeseal no funciona bien en Windows y entraba en grave conflicto con nuestros controles de seguridad. Esto, unido a la necesidad de tener acceso directo al clúster, creó un claro cuello de botella a la hora de rotar o renovar secretos, ya que solo el personal con privilegios elevados podía realizar los cambios.
- Cuando el acceso a los clústeres se restringió aún más para que solo fuera posible desde la red interna de la empresa, el número de personas que podían actualizar los secretos se redujo aún más. En algunos casos, incluso se crearon herramientas ad hoc para generar los valores sellados a partir de pods montados dentro del propio clúster, pero el acceso seguía siendo costoso y muy restringido.
- Los bots de revisión de código señalaban con frecuencia los SealedSecrets como secretos expuestos en los repositorios de GitHub, lo que entraba en conflicto con las políticas de seguridad existentes.
- En muchos casos, el mismo secreto está distribuido por multitud de namespaces, ya que lo usan las distintas aplicaciones (por ejemplo, unas credenciales para el registry de docker). Cuando hay que rotar un secreto, implica tener que revisar una gran cantidad de recursos y repositorios por los que está distribuido el valor.
5. Siguientes Pasos
Una vez que hemos solucionado el problema real, que era la falla de seguridad que suponía tener expuestos los secretos en claro directamente en el repositorio, necesitamos replantear la forma en la que estamos sincronizando nuestros secretos. Los problemas derivados del nuevo enfoque, si bien no afectan a la seguridad, si que añaden una complejidad bastante importante de cara al mantenimiento y rotación de secretos.
Por ello, ahora ya sin urgencia, nos replanteamos el enfoque y necesitamos encontrar una solución que:
- Permita una gestión lo más centralizada posible de los secretos, con herramientas que no requieran un sistema operativo concreto.
- La gestión de los secretos debe ser realizada sólo por personal con un nivel de privilegios superior.
- Facilite una automatización lo más amplia posible de los procesos de creación y rotación de los secretos en el entorno productivo.
- No exponga los secretos ni siquiera cifrados en los repositorios para facilitar la validación del código publicado.
Continuará…