Buenas tardes a tod@s,
En otra entrega más por este fabuloso y cambiante mundo del Cloud Computing, me gustaría presentaros un reto, el cual, en el momento que estoy escribiendo esta entrada 2 de los servicios que voy a enseñar se encuentran en modo Preview, pero… ¿quién dice que la proactividad e investigación no deba estar por delante para recomendar lo mejor a tus clientes, y más, cuando tratamos temas de seguridad?
¿Cuántas veces no hemos escrito credenciales hardcodeadas en un script/app al picar el código y se nos ha quedado ahí al compartirlo o simplemente al llevarlo a producción?
Por suerte a la hora de compartir, tenemos gracias a GIT un archivo brillante denominado .gitignore en el cual podemos almacenar nuestras credenciales y no se sincronizarán, pero, ¿y si quisiéramos dejar corriendo una aplicación o script en modo serverless? ¿y si me comprometen el acceso a la webapp o símplemente me consiguen impersonar el usuario?
Ya es hora de cambiar eso, así que, en esta entrada, vamos a mostrar la posibilidad de olvidarnos de credenciales en Azure Functions gracias a Management Service Identity y Key Vaults.
Para aquel o aquella que no sepa de qué hablo, pongo un poco en contexto:
- Azure Functions: Nos permite ejecutar código a petición sin necesidad de aprovisionar ni administrar explícitamente la infraestructura, ese código puede ser ejecutado mediante llamadas webhook, scheduler, etc.
Más info: https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview
- Managed Service Identity: Proporciona a los servicios de Azure una identidad administrada automáticamente en Azure Active Directory.
Más info y servicios disponibles actualmente: https://docs.microsoft.com/en-us/azure/active-directory/managed-service-identity/services-support-msi
- Key Vaults: Ayuda a proteger claves criptográficas y secretos usados por servicios y aplicaciones en la nube a través del uso de claves que están protegidas por módulos de seguridad de hardware (HSM).
Más info: https://docs.microsoft.com/en-us/azure/key-vault/key-vault-whatis
Ahora que nos hemos puesto un poco en contexto, comentar que los dos servicios en Preview actualmente son: Azure Functions haciendo uso de PowerShell y MSI (Managed Service Identity).
Pues bien, es hora de ponernos manos a la obra, mediante los siguientes pasos:
- Creamos nuestra aplicación de identidad administrada habilitando Managed Service Identity en nuestra función, dentro del mismo blade de Azure Functions:
- Una vez creada, procedemos a dar permisos a nuestra aplicación administrada sobre las políticas de acceso de nuestro Key Vault para poder así obtener los secretos:
- Imaginemos que hemos insertado 2 Secrets manualmente, por ejemplo, appId y appKey para que otro SPN realice la autenticación con Azure en nuestra aplicación, a continuación mostraremos el caso de appId:
- En este último punto, veremos cómo se realizaría la parte del código en PowerShell, pero de igual manera, al tratarse de un GET a la REST API de Azure podemos realizar de manera similar la llamada para obtener nuestro secreto deseado con cualquier lenguaje que soporte Azure Functions:
$vaultName = "z0"
$vaultSecretName = "appId"
$tokenAuthURI = $Env:MSI_ENDPOINT + "?resource=https://vault.azure.net&api-version=2017-09-01"
$tokenResponse = Invoke-RestMethod -Method Get -Headers @{"Secret"="$env:MSI_SECRET"} -Uri $tokenAuthURI
$accessToken = $tokenResponse.access_token
Write-Output $accessToken
$headers = @{ 'Authorization' = "Bearer $accessToken" }
$queryUrl = "https://$vaultName.vault.azure.net/secrets/" +$vaultSecretName + "?api-version=2016-10-01"
$keyResponse = Invoke-RestMethod -Method GET -Uri $queryUrl -Headers $headers
Write-Output $KeyResponse.value
Si nos fijamos en el código, estamos solicitando nuestro token a un audience diferente (https://vault.azure.net), nos ocurre algo parecido a la entrada anterior, debemos de tenerlo en cuenta para no llamar al audience por defecto.
Si decodificamos nuestro token con la herramienta proporcionada por jwt.io podemos ver que la estructura es correcta:
En la variable $KeyResponse.value ya tendríamos nuestro secret AppId, podemos ver su valor si activamos el trigger de la función:
No olvidéis que la seguridad sustenta uno de los pilares principales de toda empresa y desarrollador, saquemos ese perfil DevOps que llevamos dentro 🙂