Secretos externos de Kubernetes

En este post hablaremos de los Kubernetes external secrets. Es un proyecto desarrollado por el equipo de ingenieros de GoDaddy que permite utilizar un sistema de gestión de secrets externo para agregar o añadir de forma completamente segura a tu clúster de Kubernetes nuevos secrets. A día de hoy, existe soporte para los siguientes backends:

  • AWS Secrets Manager
  • AWS System Manager
  • GCP Secret Manager
  • Azure Key Vault
  • Hashicorp Vault

Con los external secrets, podrás utilizar los secrets creados y almacenados en tu backends externos dentro de tu clúster de Kubernetes, de tal forma que podrás gestionar de forma centralizada los secrets que necesitan tus aplicaciones, CICD, etc. Con este enfoque, evitarás almacenar secrets en diferentes lugares y guardar datos confidenciales en tus repositorios de código.

architecture aws
Figure 1. External secrets architecture

Descripción figura 1. :

  1. El ExternalSecrets controller se agrega al k8s clúster
  2. El Controller busca ExternalSecrets usando la API de Kubernetes
  3. El Controller usa los ExternalSecrets para obtener datos secretos de proveedores externos (por ejemplo, AWS Secrets Manager)
  4. El Controller inserta y/o actualiza los Secrets, los pods pueden acceder a los namespaces con normalidad.

Utilizamos este software en diferentes clientes y funciona a la perfección.

Ahora, te mostraremos un ejemplo usando la infraestructura cloud de AWS (EKS) y verás cuán fácil es implementar este servicio.

Secret creation

En primer lugar, crearemos el secreto mismo. Para este ejemplo, usaremos AWS Secrets Manager y crearemos el secreto usando Cloudformation:

AWSTemplateFormatVersion: '2010-09-09'
Description: Secrets definitions

Parameters:
  EnvName:
    Description: 'Environment name'
    Type: String

Resources:
  DBCredentials:
    Type: 'AWS::SecretsManager::Secret'
    Properties:
      Name: !Sub DB-${EnvName}
      Description:
        Fn::Join:
        - ' - '
        - - 'DB credentials'
          - !Ref EnvName
      SecretString: '
        {
          "user": "myappuser",
          "password": "changeme"
        } '

En este ejemplo, hemos creado el secret con el valor de contraseña ‘changeme’ y deberás cambiarlo después de la creación del secret. ¡Recuerda que este archivo yaml se almacenará en tu proveedor Git preferido y no es recomendable almacenar contraseñas en repositorios de código! 😉

TIP: puede cambiar la contraseña manualmente a través de la consola de AWS por primera vez y después de eso, por ejemplo, puedes implementar una rotación automática de contraseña. En este caso, asegúrate de que la contraseña configurada en el servicio también cambie. Para la rotación de contraseña de AWS RDS (que usamos en este ejemplo), lee esto.

Deployment

Una vez que hayamos creado el secret con el valor de contraseña correcto, instalaremos external secrets en nuestro clúster EKS. Lo instalaremos a través del paquete helm de la siguiente manera:

# En primer lugar, agregamos el repo external-secrets de helm: 
helm repo add external-secrets https://godaddy.github.io/kubernetes-external-secrets/

# E instalamos el paquete de helm. En este caso lo instalamos en el namespace kube-system, pero puedes instalarlo donde quieras.
helm upgrade --install 
    --namespace kube-system 
    external-secrets external-secrets/kubernetes-external-secrets

Probablemente, necesitarás configurar el helm chart con los valores apropiados en el fichero values. Puedes revisarlos en helm chart docs.

Podemos verificar que el pod está en ejecución:

$ kubectl get pod external-secrets-598f9cb66f-m5xn5 -n kube-system
NAME                               READY  STATUS   RESTARTS  AGE
external-secrets-598f9cb66f-m5xn5  1/1    Running  0         97d

External secrets object creation

Ha llegado el momento de crear el objeto ExternalSecret:

apiVersion: 'kubernetes-client.io/v1'
kind: ExternalSecret
metadata:
  name: db-app-credentials
  namespace: your_namespace
spec:
  backendType: secretsManager
  # optional: specify role to assume when retrieving the data
  roleArn: arn:aws:iam::123456789012:role/secrets-readonly-example
  data:
    - key: DB-
      name: user
    - key: DB-
      name: password

Debido a que estamos ejecutando el k8s en EKS hay que tener en cuenta que usamos un roleArn que permite el acceso a AWS Secrets Manager. Tambien puedes otorgar acceso a los workers de EKS definiendo y configurando un node instance role.

En caso de que tu clúster se ejecute fuera de AWS, GCP o Azure, puedes pasar las credenciales como variables de entorno cuando despliegas el chart de helm (echa un vistazo a las opciones del values.yaml)

Unos segundos después de haber creado el objeto ExternalSecret, un nuevo secret de k8s se creará en el namespace indicado.

$ kubectl get secret db-app-credentials -n your_namespace 
NAME                            TYPE    DATA     AGE
db-app-credentials              Opaque  2        23m

El contenido del secret será algo parecido a esto: 

$ kubectl get secret db-app-credentials-n your_namespace -o yaml
apiVersion: v1
data:
  password: sgdhfh7w98JHGFsq1shdgA==
  user: bXlhcHB1c2VyCg==
kind: Secret
metadata:
  creationTimestamp: "2020-03-30T10:26:34Z"
  name: db-app-credentials
  namespace: your_namespace
  ownerReferences:
  - apiVersion: kubernetes-client.io/v1
    controller: true
    kind: ExternalSecret
    name: db-app-credentials
    uid: 8a69iac3-2007-11ea-ae84-0awqa0e278d8
  resourceVersion: "14684195"
  selfLink: /api/v1/namespaces/your_namespace/secrets/db-app-credentials
  uid: aeha168b-2007-11ea-ae84-0a0ath7278d8
type: Opaque

A partir de ahora, cada vez que actualices el secret en el backend, el secret se actualizará también en el clúster de k8s.

Apuntes finales:

Puedes configurar el intervalo de sondeo o poll interval (la fecuencia en la que External Secrets se sincronizara con el backend para actualizar nuevos cambios o nuevos secrets). Por favor, ten en cuenta que muchos proveedores cloud cobran por cada secret access o llamadas a las API.

Es importante saber que los external secrets de Kubernetes solo realizan upserts (inserts o updates). En ningún caso se eliminarán secrets del clúster k8s en caso de falla o problemas de acceso/sincronización con el backend.

¡¡Eso es todo!! 🙂 Para obtener más información, puedes visitar el repositorio de secretos externos de Github.


Espero que hayas disfrutado de este post y te animo a que revises nuestro blog para leer otrosposts que puedan ser de tu interés. No dudes en contactarnos si deseas que te ayudemos en tus proyectos.

¡Nos vemos en la próxima entrada!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *