Drivers de Helm explicados: Secrets, ConfigMaps y almacenamiento de estado

Drivers de Helm explicados: Secrets, ConfigMaps y almacenamiento de estado

Cuando trabajas en serio con Helm en entornos de producción, uno de los temas menos discutidos —pero con mayor impacto operativo— es cómo Helm almacena y gestiona el estado de los releases. Aquí es donde entran en juego los drivers de Helm. Entender este mecanismo no es un ejercicio académico: afecta directamente a la seguridad, la escalabilidad, la resolución de problemas y las estrategias de recuperación ante desastres.

Los drivers de Helm son una pieza fundamental que todo equipo que gestione Kubernetes en producción debería conocer en profundidad. En este artículo desgranaremos qué son, cómo han evolucionado, cuándo usar cada uno y qué consecuencias prácticas tiene elegir mal el backend de almacenamiento.


Qué es un driver de Helm y cómo se configura

Un driver de Helm define el mecanismo de almacenamiento backend que Helm utiliza para persistir la información de cada release: manifiestos generados, valores aplicados e historial de revisiones. Todo release de Helm tiene estado, y ese estado tiene que residir en algún lugar. El driver determina dónde y cómo se guarda esa información.

Los drivers de Helm se configuran mediante la variable de entorno HELM_DRIVER. Si no se establece explícitamente, Helm utiliza por defecto Kubernetes Secrets:

export HELM_DRIVER=secrets

Esta elección, aparentemente trivial, puede tener consecuencias operativas profundas, especialmente en entornos regulados o en clusters de gran escala donde la seguridad, la auditabilidad y el rendimiento son requisitos no negociables.

A diferencia de otras configuraciones de Helm que se establecen en ficheros de valores o en el propio chart, el driver opera a nivel de proceso del cliente Helm. Esto significa que distintos operadores o pipelines de CI/CD podrían, en teoría, utilizar drivers distintos sobre el mismo cluster si no se establece una política coherente. Esa inconsistencia puede llevar a situaciones confusas en las que Helm no encuentra el estado de un release simplemente porque el driver activo no coincide con el que se usó al instalar.


Los drivers de Helm disponibles

Helm ofrece actualmente tres drivers estables: secrets, configmaps y memory. Cada uno tiene un perfil de uso distinto y unas implicaciones de seguridad específicas que conviene conocer.

Driver Secrets (predeterminado)

El driver secrets almacena la información de los releases de Helm como Kubernetes Secrets en el namespace de destino. Es el driver por defecto desde la introducción de Helm 3 y la opción recomendada para la mayoría de entornos de producción.

Los Secrets en Kubernetes están codificados en base64. Si bien base64 no es cifrado en sí mismo, los clusters que tienen activado el cifrado en reposo (encryption at rest) de la API de Kubernetes cifrarán estos objetos antes de escribirlos en etcd. Esto convierte al driver secrets en la opción alineada con los modelos de seguridad nativos de Kubernetes.

Además, los Secrets se integran de forma natural con RBAC (Role-Based Access Control). Se puede restringir quién tiene acceso de lectura o escritura a los Secrets del namespace donde se gestiona el release, lo que permite aplicar el principio de mínimo privilegio sobre la información de estado de Helm.

Cada release almacenado por este driver genera un Secret con un nombre de la forma sh.helm.release.v1.<release-name>.v<revision>. Helm mantiene un historial de revisiones, y cada revisión tiene su propio Secret. El flag --history-max de Helm permite limitar cuántas revisiones se retienen:

helm upgrade my-release ./chart --history-max 5

Sin ese límite, en releases con muchos upgrades, el número de Secrets puede crecer indefinidamente y saturar el namespace o generar presión innecesaria sobre etcd.

Cuándo usarlo: prácticamente siempre en producción. Es el estándar de facto y el que mejor encaja con las políticas de seguridad empresariales.


Driver ConfigMaps

El driver configmaps almacena el estado de los releases de Helm como Kubernetes ConfigMaps. Funcionalmente, el comportamiento es muy similar al driver secrets: se crean objetos por release y revisión, se integra con RBAC y permite gestionar el historial de upgrades.

La diferencia fundamental está en la confidencialidad. Los ConfigMaps no tienen ningún tratamiento especial de privacidad en Kubernetes. Su contenido es texto plano legible para cualquier actor con permisos de lectura sobre el namespace. Esto incluye operadores, scripts de auditoría, herramientas de backup o cualquier proceso que liste recursos del cluster.

export HELM_DRIVER=configmaps

Para activar el driver de forma puntual en un comando:

HELM_DRIVER=configmaps helm list -n production

La legibilidad humana de los ConfigMaps —a diferencia de los Secrets, que requieren decodificar el base64— puede ser ventajosa en escenarios de depuración. Si un upgrade ha fallado y necesitas inspeccionar el manifiesto que Helm intentó aplicar, hacerlo desde un ConfigMap es más directo:

HELM_DRIVER=configmaps helm get manifest my-release -n staging

Sin embargo, esa misma legibilidad es un riesgo en entornos donde los valores del release contienen información sensible: credenciales de base de datos, tokens de acceso, configuración de conexiones a servicios externos. En esos casos, exponer esos valores en ConfigMaps es inadmisible desde el punto de vista de seguridad.

Cuándo usarlo: en entornos de desarrollo, staging sin datos sensibles, o cuando necesitas hacer troubleshooting específico del estado de un release. Nunca en producción si los valores contienen secretos.


Driver Memory

El driver memory almacena el estado de los releases únicamente en memoria RAM del proceso Helm. En el momento en que el proceso Helm termina —ya sea porque el comando completó o porque falló—, todo el estado se pierde irrecuperablemente.

export HELM_DRIVER=memory

A primera vista, un driver que no persiste nada puede parecer inútil. Sin embargo, tiene un nicho de uso muy concreto y valioso: pipelines de CI/CD donde no se quiere contaminar el cluster con estado de prueba.

Considera un pipeline de integración continua que valida un chart antes de desplegarlo:

HELM_DRIVER=memory helm upgrade --install test ./chart --dry-run

Con el driver memory, el proceso de Helm puede simular un upgrade, renderizar los manifiestos, validar los templates y ejecutar los hooks de pre-upgrade sin escribir nada en el cluster. Una vez que el proceso termina, no queda ningún rastro en etcd, ningún Secret ni ConfigMap que limpiar, ninguna revisión que gestionar.

Esto es especialmente útil en entornos de CI con permisos limitados sobre el cluster, o donde múltiples pipelines paralelas ejecutan validaciones simultáneamente sobre el mismo namespace y podrían colisionar si cada una intentara escribir su estado en Kubernetes.

El driver memory también es relevante en escenarios de testing local donde simplemente se quiere probar el renderizado de un chart sin necesidad de un cluster en absoluto —aunque en ese caso, helm template suele ser suficiente.

Cuándo usarlo: exclusivamente en CI/CD para validaciones, dry-runs, o testing de charts sin necesidad de persistencia. Nunca en despliegues reales.


Almacenamiento de estado en Helm: qué se guarda y por qué importa

Para entender por qué la elección del driver tiene consecuencias reales, es útil saber exactamente qué información persiste Helm en cada release.

Cada objeto de estado generado por Helm (sea un Secret o un ConfigMap) contiene:

  • El manifiesto renderizado: los manifiestos YAML de todos los recursos Kubernetes que componen el release en esa revisión.
  • Los valores aplicados: el resultado de la fusión de los valores por defecto del chart con los values sobrescritos por el operador. Esto incluye cualquier valor pasado con --set, --set-string o -f values.yaml.
  • Metadatos del release: nombre del release, namespace, versión del chart, timestamps, estado (deployed, failed, superseded…) y número de revisión.
  • Los hooks: definición de los hooks del chart para esa revisión.

La presencia de los valores aplicados en el estado es lo que hace que la elección del driver sea una decisión de seguridad. Si esos valores incluyen una contraseña de base de datos o un token de API, ese secreto queda persistido en el objeto de estado de Helm. Con el driver secrets y cifrado en reposo activo, esto es aceptable. Con el driver configmaps en texto plano, es un problema de seguridad.

Esto también explica por qué comandos como helm get values my-release pueden recuperar los valores que se usaron en el último upgrade: Helm los lee directamente del objeto de estado almacenado por el driver activo.


Evolución histórica de los drivers de Helm

Para entender el diseño actual de los drivers, hay que conocer la historia de Helm 2 y la decisión arquitectónica central que motivó Helm 3.

Helm 2 y Tiller: el origen del problema

Helm 2 utilizaba un componente servidor llamado Tiller, que se desplegaba como un Pod en el cluster Kubernetes, normalmente en el namespace kube-system. Tiller era el responsable de gestionar el estado de los releases y de aplicar los cambios al cluster.

En Helm 2, el driver por defecto era ConfigMaps, y Tiller era el único que tenía acceso a ellos. Esto simplificaba el modelo de seguridad —solo Tiller necesitaba permisos sobre esos objetos— pero a costa de convertir a Tiller en un punto único de fallo y, más problemáticamente, en un vector de escalada de privilegios.

Tiller solía desplegarse con permisos de cluster-admin para poder gestionar recursos en cualquier namespace. Esto era conveniente pero representaba un riesgo de seguridad inaceptable en entornos empresariales: comprometer el Pod de Tiller equivalía a comprometer todo el cluster.

Helm 3: eliminación de Tiller y Secrets como default

La llegada de Helm 3 en noviembre de 2019 supuso una reescritura significativa de la arquitectura. Las decisiones clave:

  1. Eliminación de Tiller: Helm 3 opera únicamente como cliente. No existe componente servidor. Helm habla directamente con la API de Kubernetes usando las credenciales del cliente (kubeconfig).

  2. Cambio del driver por defecto: de ConfigMaps a Secrets. Dado que ahora era el cliente Helm —con sus propias credenciales de usuario o service account— quien escribía el estado directamente en el cluster, tenía sentido usar Secrets para que esa información tuviera al menos el nivel de protección que Kubernetes ofrece para ese tipo de objeto.

  3. Arquitectura de drivers pluggable: la capa de almacenamiento se abstrajo mediante una interfaz interna limpia, lo que teóricamente permite implementar drivers alternativos (SQL, almacenamiento externo) sin modificar el núcleo de Helm.

Desde Helm 3, las mejoras en los drivers han sido incrementales: mejor manejo de errores, optimizaciones de rendimiento en clusters con muchos releases, y ajustes en la lógica de limpieza del historial. La abstracción central no ha cambiado de forma sustancial, lo que es una señal de madurez del diseño.


Implicaciones de seguridad: Helm Secrets vs ConfigMaps

La distinción entre el driver secrets y el driver configmaps va más allá de la nomenclatura. Tiene consecuencias prácticas en varios vectores de seguridad:

Control de acceso (RBAC)

Tanto los Secrets como los ConfigMaps son objetos de la API de Kubernetes y están sujetos a RBAC. La diferencia es que en muchas organizaciones los Secrets tienen políticas de acceso más restrictivas que los ConfigMaps por convención.

Si tu organización aplica políticas que limitan quién puede leer Secrets en namespaces de producción, usar el driver secrets se beneficia automáticamente de esas restricciones. Con ConfigMaps, cualquier rol con get/list sobre ConfigMaps en el namespace tendría acceso al estado de Helm, incluyendo valores sensibles.

Cifrado en reposo

Los Kubernetes Secrets son elegibles para cifrado en reposo mediante la configuración EncryptionConfiguration en el API server. Esta funcionalidad no aplica a los ConfigMaps: no existe un mecanismo nativo de Kubernetes para cifrar ConfigMaps en reposo.

# Ejemplo de configuración de cifrado en reposo para Secrets
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
      - secrets
    providers:
      - aescbc:
          keys:
            - name: key1
              secret: <base64-encoded-key>
      - identity: {}

Con esta configuración activa, los objetos de estado de Helm almacenados con el driver secrets se cifran antes de escribirse en etcd. Los valores sensibles en el estado de Helm quedan protegidos incluso si alguien obtiene acceso directo a la base de datos de etcd.

Auditoría y trazabilidad

En entornos regulados (PCI-DSS, ENS, ISO 27001), los accesos a Secrets suelen registrarse en los audit logs de Kubernetes con mayor granularidad. Esto permite auditar quién accedió al estado de un release de Helm y cuándo, lo cual es un requisito común en auditorías de seguridad.


Casos prácticos y cuándo usar cada driver

Producción: siempre Secrets

En clusters de producción, el driver secrets debe ser el estándar sin excepciones. Las razones son claras:

  • Se integra con las políticas RBAC existentes.
  • Soporta cifrado en reposo.
  • Es el default de Helm, por lo que herramientas del ecosistema (Helm Operator, ArgoCD con Helm, Flux CD) lo esperan.
  • Minimiza la superficie de exposición de valores sensibles.

Si tu pipeline de despliegue en producción usa un service account de Kubernetes, asegúrate de que ese service account tenga permisos para crear, leer, actualizar y borrar Secrets en el namespace de destino:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: helm-release-manager
  namespace: production
rules:
  - apiGroups: [""]
    resources: ["secrets"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

Desarrollo y troubleshooting: ConfigMaps con precaución

En entornos locales o de desarrollo donde no se manejan valores sensibles, el driver configmaps puede simplificar la inspección del estado. Ver el contenido de un ConfigMap con kubectl get configmap es más directo que decodificar un Secret.

Para inspeccionar el manifiesto de un release en un entorno de desarrollo:

HELM_DRIVER=configmaps helm get manifest my-app -n development

O para listar todos los releases almacenados como ConfigMaps:

HELM_DRIVER=configmaps helm list -n development

La clave es no usar este driver en entornos con valores sensibles y asegurarse de que el equipo es consciente del driver activo para evitar situaciones en las que Helm «no encuentra» un release porque el driver configurado no coincide con el que se usó al instalarlo.

CI/CD: Memory para validaciones sin efectos secundarios

En pipelines de integración continua, el driver memory permite ejecutar validaciones de charts sin escribir nada en el cluster:

# Validación de templates en CI
HELM_DRIVER=memory helm upgrade --install \
  --dry-run \
  --namespace ci-validation \
  my-chart ./charts/my-chart \
  -f values-ci.yaml

Este patrón es especialmente útil cuando el pipeline de CI tiene acceso al cluster (para poder hacer el dry-run contra la API real y validar los manifiestos), pero no se quiere dejar rastro de las ejecuciones de CI en etcd.

Otra aplicación: validar que un chart funciona con múltiples combinaciones de valores sin acumular historial de revisiones:

for env in dev staging prod; do
  HELM_DRIVER=memory helm upgrade --install test ./chart \
    -f values-${env}.yaml \
    --dry-run \
    --namespace validation 2>&1 | grep -E "(HOOK|MANIFEST|ERROR)"
done

Gestión del historial de revisiones y su impacto en almacenamiento

Un aspecto que muchos equipos descubren tarde es el crecimiento del número de objetos de estado en clusters con releases activos durante meses. Cada upgrade, rollback o instalación genera un nuevo objeto Secret (o ConfigMap) en el namespace.

Por defecto, Helm mantiene las últimas 10 revisiones. Esto se puede configurar al instalar o al actualizar:

helm install my-app ./chart --history-max 3
helm upgrade my-app ./chart --history-max 3

O de forma global mediante la variable de entorno:

export HELM_MAX_HISTORY=3

Para verificar cuántos objetos de estado ha generado Helm en un namespace:

kubectl get secrets -n production -l owner=helm | wc -l

En clusters con decenas de releases y años de historial sin limpiar, es habitual encontrar cientos o incluso miles de Secrets relacionados con Helm. Esto no es un problema crítico de rendimiento en Kubernetes, pero sí genera ruido en las herramientas de monitorización y puede complicar las auditorías de seguridad si nadie ha revisado ese estado en meses.


Migración entre drivers: consideraciones importantes

Una pregunta frecuente en equipos que adoptan estas buenas prácticas tardíamente es: ¿cómo migro los releases existentes de ConfigMaps a Secrets?

La respuesta corta es que Helm no proporciona un comando de migración nativo entre drivers. El cambio de driver no hace que Helm «adopte» automáticamente el estado existente en el formato anterior.

La aproximación práctica para migrar es:

  1. Exportar el estado actual de los releases relevantes:
    bash
    HELM_DRIVER=configmaps helm get values my-release -n production > values-backup.yaml

  2. Documentar la revisión actual:
    bash
    HELM_DRIVER=configmaps helm history my-release -n production

  3. Cambiar el driver a secrets en todos los entornos del equipo y en el pipeline de CI/CD.

  4. Hacer un upgrade del release (que puede ser idempotente, con los mismos valores) para que Helm cree el primer objeto de estado con el nuevo driver:
    bash
    HELM_DRIVER=secrets helm upgrade my-release ./chart -f values-backup.yaml -n production

  5. Limpiar manualmente los ConfigMaps de estado anteriores:
    bash
    kubectl get configmaps -n production -l owner=helm
    kubectl delete configmap sh.helm.release.v1.my-release.v1 -n production
    # Repetir para cada revisión

Este proceso requiere coordinación en equipos donde múltiples personas ejecutan comandos Helm sobre el mismo cluster, precisamente para evitar que alguien con el driver antiguo configurado ejecute un comando que no encuentre el estado o genere entradas duplicadas en el formato incorrecto.


Herramientas del ecosistema y drivers de Helm

Las herramientas GitOps más populares que usan Helm internamente —ArgoCD, Flux CD, Helmfile— tienen su propia gestión del driver:

  • ArgoCD usa el driver secrets por defecto cuando gestiona releases de Helm. No expone directamente la configuración del driver al usuario, lo que en la práctica significa que siempre usarás secrets si gestionas releases a través de ArgoCD.

  • Flux CD con HelmRelease también usa secrets por defecto a través del Helm Controller.

  • Helmfile respeta la variable de entorno HELM_DRIVER del shell donde se ejecuta.

Esto tiene una implicación importante: si gestionas un cluster con una mezcla de releases instalados directamente con Helm CLI y releases gestionados por ArgoCD, ambos usarán el driver secrets siempre que no hayas cambiado la configuración por defecto. La consistencia aquí es positiva.


Reflexión final: el driver como decisión arquitectónica

Los drivers de Helm raramente aparecen en las revisiones de arquitectura ni en los runbooks de los equipos de plataforma. Y sin embargo, influyen en la fiabilidad, la seguridad y la observabilidad de todos los flujos de trabajo que dependen de Helm.

Tratar la elección del driver como una decisión arquitectónica deliberada —y no como una configuración por defecto que nadie ha cuestionado— es uno de esos detalles pequeños que diferencian una plataforma Kubernetes madura de una automatización improvisada.

Las recomendaciones prácticas para cualquier equipo:

  • Estandariza el driver secrets en producción y documéntalo en el runbook del equipo.
  • Establece un límite de historial razonable (--history-max 5 o 10) para evitar la acumulación de objetos de estado.
  • Activa el cifrado en reposo de Secrets en el API server si manejas valores sensibles en tus releases de Helm.
  • Usa el driver memory en CI para validaciones y dry-runs que no deben persistir estado.
  • Audita periódicamente los objetos de estado de Helm en tus namespaces con kubectl get secrets -l owner=helm.

Estos pasos no requieren herramientas adicionales ni cambios en los charts. Son configuraciones operativas que cualquier equipo puede aplicar hoy y que reducen la superficie de riesgo y el ruido operativo de forma inmediata.


Este artículo forma parte de la guía completa de gestión de paquetes con Helm en alexandre-vazquez.com.