El acceso a los secretos siempre es uno de los puntos clave en los entornos Kubernetes y tenemos varias herramientas para poder almacenarlos haciendo uso de servicios externos. En este artículo veremos cómo usar Azure Key Vault como almacén de secretos y certificados.

Haciendo uso de un Secret Store Provider vamos a montar los secretos directamente desde el Azure Key Vault sin tener que preocuparnos de que nuestras aplicaciones tengan que tener la lógica necesaria para acceder a los mismos.

Dentro del pod se leerán como variables de entorno o se montarán como rutas de manera que podemos cambiar el provider de secretos sin tener que tocar las aplicaciones desplegadas.

La ventaja que sacamos de esto es romper dependencias de nuestro código a servicios concretos y evitar así tener que pasar credenciales o permisos de lectura a los desarrolladores para cualquier entorno.

Creación del cluster AKS

Vamos a desplegar un nuevo cluster donde habilitaremos las managed identity y usaremos el plugin Azure para la red.

El network plugin azure es necesario para poder asignar una managed identity a los pods que desplegaremos.

Esa identidad es la que usará para conectar con el Azure Key Vault.

az group create –name gperez-demo-rg –location northeurope
 
az aks create -g gperez-demo-rg -n gperez-aks-demo –enable-managed-identity
–generate-ssh-keys –kubernetes-version 1.20.7 –network-plugin azure –node-count 1

Obtenemos las credenciales asignadas al cluster. Con esto podemos empezar a usar kubectl desde nuestra terminal.

az aks get-credentials –resource-group gperez-demo-rg –name gperez-aks-demo
 

Instalación Helm

Para dejarlo ya preparado añadiremos los repositorios de los paquetes Helm que vamos a utilizar.

CSI Secrets Store Provider Azure

Nos permite crear secrets store providers con Azure Key Vault.

helm repo add csi-secrets-store-provider-azure
https://raw.githubusercontent.com/Azure/secrets-store-csi-driver-provider-azure/master/charts
 

AAD Pod Identity

Lo utilizaremos para asociar la manage identity a los pods para permitir el acceso al Key Vault.

helm repo add aad-pod-identity https://raw.githubusercontent.com/Azure/aad-pod-identity/master/charts
 

Permisos de Managed Identity Operator

Un punto importante que tenemos que configurar es permitir a la identidad del Kubelet del cluster tenga los roles de Managed Identity Operator y Virtual Machine Contributor en los grupos de recursos del cluster, y así poder asignar en los nodos las identidades que seleccionemos más adelante para que usen los pods.

Si el cluster donde estamos haciendo esto, ya tiene habilitada la opción de managed identity es posible que ya esté configurado y no tengamos que hacerlo.

kubeletClientId=$(az aks show -g gperez-demo-rg -n gperez-aks-demo –query “identityProfile.kubeletidentity” | jq -r ‘.clientId’ )
resourceGroupId=$(az group list –query “[?name==’gperez-demo-rg’]” | jq -r ‘.[].id’)
nodesResourceGroupId=$(az group list –query “[?contains(name,’MC_gperez-demo-rg’)]” | jq -r ‘.[].id’)
 
az role assignment create –role “Managed Identity Operator” –assignee $kubeletClientId –scope $resourceGroupId
az role assignment create –role “Managed Identity Operator” –assignee $kubeletClientId –scope $nodesResourceGroupId
az role assignment create –role “Virtual Machine Contributor” –assignee $kubeletClientId –scope $nodesResourceGroupId

Creación de Pod Identity

A continuación, creamos la identidad que asignaremos a los pods y desplegamos el helm de aad-pod-identity

az identity create -g gperez-demo-rg -n demo-pod-identity
 
helm install pod-identity-deploy aad-pod-identity/aad-pod-identity
 

Si inspeccionamos los pods desplegados debe tener este aspecto:

pod identity demo 1

Si no hemos desplegado el cluster con el Network plugin de Azure al hacer la instalación el estado de los pods uno de ellos quedará crasheado.

AKS y Azure Key Vault – Parte 1: Secrets, Identities y variables de entorno

Y viendo el log del pod crasheado, vemos que nos indica claramente que no está soportado para Kubenet

AKS y Azure Key Vault – Parte 1: Secrets, Identities y variables de entorno

Asignación de permisos al pod identity

Seguidamente lo que debemos hacer es darle permisos de lectura a la identidad que hemos creado para los pods en el Azure Key Vault.

En este caso el Key Vault ya existe y ya tiene cargados los certificados y los secretos que vamos a utilizar en esta demo.

Obtenemos el clientId de la identidad que hemos creado para los pods y el id del Key Vault

kvIdentityClientId=$(az identity list –resource-group gperez-demo-rg –query “[?name==’demo-pod-identity’].clientId” | jq -r ‘.[]’)
kvScope=$(az keyvault list –query ‘[].id’ | jq -r ‘.[]’)
 

A continuación, proporcionamos el acceso al recurso del Key Vault

az role assignment create \
–role “Reader” \
–assignee $kvIdentityClientId \
–scope $kvScope
 

Y damos acceso a la identidad manejada a la obtención de los valores de los secretos, claves y certificados del Key Vault

az keyvault set-policy -n gperez-kv –secret-permissions get –spn $kvIdentityClientId
az keyvault set-policy -n gperez-kv –key-permissions get –spn $kvIdentityClientId
az keyvault set-policy -n gperez-kv –certificate-permissions get –spn $kvIdentityClientId
 

Creación de la identidad dentro del cluster

Una vez hecho esto, ya tenemos nuestros recursos en Azure para poder consumir dentro del cluster.

  • Managed Identity para los pods
  • Key Vault
  • Permisos del Managed Identity en el KV

Ahora debemos de crear recursos dentro de nuestro cluster y el primero de ellos es un AzureIdentity y un AzureIdentityBinding

AzureIdentity: Recurso que establece la managed identity a utilizar

AzureIdentityBinding: Generamos el selector que tendremos que poder en los recursos desplegados para usar la AzureIdentity

Para hacer esto necesitaremos obtener el id de la identidad que hemos creado y usarlo dentro del taml del AzureIdentity

kvIdentityId=$(az identity list –resource-group gperez-demo-rg –query “[?name==’demo-pod-identity’].id” | jq -r ‘.[]’)
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentity
metadata:
name: “gperez-demo-kv-identity”
spec:
type: 0
resourceID: /subscriptions/XXXXXXXXX/resourcegroups/gperez-demo-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/demo-pod-identity #kvIdentityId
clientID: “XXXXX-23c6-4b12-89b5-XXXXXXXXXX” # $kvIdentityClientId
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentityBinding
metadata:
name: gperez-demo-kv-identity-binding
spec:
azureIdentity: “gperez-demo-kv-identity” #El nombre de la identidad creada anteriormente
selector: gperez-demo-kv-identity-binding-selector #El selector que usaremos para asignarla a los despliegues

Storage Provider

Bien, ya somos capaces de asignar la identidad que tiene acceso al Key Vault a los elementos desplegados del cluster.

Pero ahora, ¿cómo accedemos al Key Vault?

Para poder montar los secretos, debemos dar de alta un Storage Provider usando el helm que hemos instalado al principio:

helm install azure-secrets-store-provider csi-secrets-store-provider-azure/csi-secrets-store-provider-azure –namespace –set secrets-store-csi-driver.syncSecret.enabled=true
 

Cuando lo hayamos instalado, el siguiente paso es definir un Storage Provider usando el nuevo driver dentro de nuestro cluster. En este Storage Provider definiremos a que secretos concede acceso el provider y de que Key Vault.

apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
name: gperez-kv-secret-provider
spec:
provider: azure
secretObjects:
– secretName: kv-secret
type: Opaque
data:
– objectName: MyKeyVaultSecretParameter
key: MySecretParameter
parameters:
usePodIdentity: “true”
keyvaultName: gperez-kv
objects: |
array:
|
objectName: MyKeyVaultSecretParameter
objectType: secret
objectVersion: “”
resourceGroup: “gperezivo.dev-rg” #En mi caso el Key Vault lo tengo en otro grupo de recursos
subscriptionId: “XXXXXXXXXXXXX”
tenantId: “XXXXXXXXXXX”
 

El Secret Provider tiene dos partes a configurar:

  • secretObjects: Son los secretos a los que se podrá acceder haciendo uso del secret provider dentro de los elementos desplegados en el cluster.
  • objects: Define los elementos del Key Vault a los que queremos dar acceso.

Tal y como tenemos definido el Secret Provider Class, nuestro secret MyKeyVaultSecretParameter vamos a darle visibilidad dentro del cluster con el nombre MySecretParameter, lo que nos permite proporcionar el acceso a secretos sin que ni siquiera los equipos de desarrollo conozcan su nombre original.

Para comprobar que podemos utilizar el contenido del Key Vault como inline secret store y como variables de entorno vamos a desplegar el siguiente pod:

apiVersion: v1
kind: Pod
metadata:
name: gperez-demo-kv-test-pod
labels:
name: gperez-demo-kv-test-pod
aadpodidbinding: gperez-demo-kv-identity-binding-selector
spec:
containers:
– name: gperez-demo-kv-test-pod
image: enriquecatala/fastapi-helloworld
resources:
limits:
memory: “128Mi”
cpu: “500m”
env:
– name: HELLOWORLD_ENV
valueFrom:
secretKeyRef:
name: kv-secret
key: MySecretParameter
 
volumeMounts:
– name: secrets-store-inline
mountPath: “/mnt/secrets-store”
readOnly: true
ports:
– containerPort: 5000
volumes:
– name: secrets-store-inline
csi:
driver: secrets-store.csi.k8s.io
readOnly: true
volumeAttributes:
secretProviderClass: “gperez-kv-secret-provider”
 

La imagen que vamos a utilizar es enriquecatala/fastapi-helloworld que pertenece a mi compañero Enrique Catalá y viene muy bien para testear este tipo de desarrollos.

Es una API muy sencilla donde hay dos métodos GET que devuelven el valor de la variable de entorno.

Podéis ver el código en su GitHub https://github.com/enriquecatala/fastapi-helloworld

Usando el secret provider que hemos generado anteriormente, montamos un volumen con el driver de secrets-store que ya tenemos configurado.

Hará uso de la identidad que le estamos poniendo al pod en el label aadpodidbinding: gperez-demo-kv-identity-binding-selector y será accesible dentro del contenedor en la ruta /mnt/secrets-store.

Para hacer referencia cargar uno de los secretos como variable de entorno utilizaremos el atributo key que hemos establecido en el secretsObjects.data del Secret Provider

Una vez tenemos desplegado el Pod podemos ver que el Secret kv-secret se ha generado cuando el primer pod lo ha solicitado, no cuando hemos desplegado el Secret Provider.

name

Si lanzamos un comando ls sobre la ruta en la que hemos montado el secret store, podemos ver que están los secretos que hemos definido

AKS y Azure Key Vault – Parte 1: Secrets, Identities y variables de entorno

Y si usamos el comando port-forward para acceder a la API que el pod tiene desplegada en el puerto 5000, podemos comprobar que el valor de la variable de entorno es que le tenemos definido en el Key Vault:

kubectl port-forward pod/gperez-demo-kv-test-pod :5000
 
helloworld

Conclusión

Haciendo uso de Azure Key Vault hemos conseguido sacar fuera del cluster el almacenamiento de secretos de nuestras aplicaciones además de quitar a los equipos de desarrollo la necesidad de crear, administrar y mantener los valores correctos para cada uno de los entornos en los que la aplicación será desplegada.

Los equipos de desarrollo solo necesitarán conocer en que ruta o con que nombre recibirán estos valores y no tendrán que preocuparse de desarrollar el acceso a un Key Vault, sea cual sea el que escojamos finalmente haciendo a la solución agnóstica de la infraestructura que tenemos detrás.

Esto nos facilita las tareas sobre todo cuando contamos con equipos de desarrollos externos o queremos evitar que los desarrolladores puedan acceder a las credenciales de los entornos productivos. Aunque para esto último tendremos que limitar los permisos sobre los elementos de producción en nuestro cluster/namespaces que los desarrolladores tienen.

En la siguiente entrega veremos cómo hacer que nuestros Ingress, utilicen los certificados que tenemos alojados en un Azure Key Vault.

¡Estate atento!

¡Sigue Aprendiendo!

Si quieres que te ayudemos a poner en marcha este tipo de proyecto, no dudes en contactar con nosotros. También puedes aprovechar las formaciones existentes para ampliar tus conocimientos 👇🏼

>> Más info
0 Shares:
Deja una respuesta

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

You May Also Like
Implementando Azure databricks
Leer más

Implementando Databricks (SaaS) en Azure para evitar accesos no autorizados a los datos

Cuando trabajamos con Azure o la nube en general, tenemos que ser muy cuidadosos con la seguridad de nuestros datos y más si son datos confidenciales o que entran en el ámbito de la RGPD, por lo que en este articulo os damos unas pautas a seguir para trabajar con datos utilizando el servicio de Databricks que nos ofrece Azure, evitando que estos viajen por fuera de la red privada.
Leer más

Excel Power BI – Herramientas y sistemas BI

En esta entrada dedicamos el espacio del blog a descubrir las capacidades que nos ofrece Power BI como plataforma de Selfservice BI (BI de Autoservicio). Presentamos Power Query, Power Pivot, Power View y Power Map. Por ultimo comentamos las opciones colaborativas que presenta esta plataforma.
Leer más

Expresiones, parámetros y funciones en Azure Data Factory

Hay ocasiones, cuando estamos construyendo pipelines con Azure Data Factory, que queremos repetir patrones para extraer y procesar la información cambiando de manera dinámica, en tiempo de ejecución, valores, orígenes/destinos de los datasets, incluso los mismos linked services. Esto es posible mediante el uso de parámetros, expresiones y funciones. Vamos a ver cómo implementarlo con un ejemplo práctico en el que se nos plantea el siguiente supuesto. Se nos ha pedido que extraigamos todos los días los datos del día anterior de distintas tablas del DW a ficheros en un blob storage que además se nombre como la tabla de origen. Si no pudiéramos utilizar contenido dinámico tendríamos que crear dos datasets (uno de origen y otro de destino) y añadir una actividad de copia por cada tabla a exportar.