Blog Arolla

Terraformer Azure Function et Vault avec MSI

Pour son fonctionnement, une application a besoin d’accéder à des services externes. Par exemple, on peut citer une base de données, du stockage ou un service de notification. Pour pouvoir utiliser ces services, elle a besoin de clés, de secrets ou de chaînes de connexion. Hors, ces informations sont amenées à changer en fonction de l’environnement. Une solution est d’externaliser toute la partie configuration d’une application dans un store centralisé. Pendant son exécution, l’application ira récupérer les informations dont elle a besoin. Il s’agit du pattern External Configuration Store.

Grâce à sa flexibilité, l’émergence du Cloud a multiplié le nombre d’environnement que l’on peut provisionner. Fini dev et prod, bonjour dev, test, intégration, qualif, homol, perfs, demo, pré-prod, prod, post-prod, prod-a-la-plage, prod-fait-du-ski, prod-contre-Dracula …

Ce bon vieux monolithe n’est lui aussi plus dans l’air du temps, et les architectures micro-services prennent le relais. Chaque micro-service a besoin d’information de configuration et il devient nécessaire de les centraliser, pour ne pas créer de redondance et une trop grande complexité.

 

Admin/Admin

 

Azure Key Vault

Azure Key Vault est un service de la plateforme Azure permettant de stocker de façon sécurisée, les clés, les secrets et les certificats. Un modèle RBAC (Roll Based Access Control) gère quant à lui les droits d’accès et les permissions. Il propose également de bénéficier d’un système d’audit et de traçabilité. Pour cela, il est possible d’activer l’historisation de tous les accès réalisés. Enfin, il offre la haute disponibilité et les SLA (Service Level Agreement) des services managés Azure.

Managed Service Identity

Managed Service Identity permet d’attribuer une identité aux services tels que Azure Functions, API Management etc, dans l’ Azure Active Directory. Cette identité peut être utilisée pour s’authentifier auprès d’autres services comme Key Vault, prenant en charge ce mode d’authentification.

Azure Function

Service Serverless permet l’exécution de code ou de script. Scalabilité, haute disponibilité, résilience, micro-service friendly, Azure Function fait aujourd’hui partie du paysage Azure. Il est possible pour ce service d’avoir un identité de service managé.

 

Et comment fait-on marcher tout ça ensemble ?

En premier lieu, on va déployer l’ensemble des ressources Azure nécessaires. À savoir :

  • Un groupe de ressources, pour regrouper tout ce que l’on va faire (et que vous puissiez le supprimer facilement après. Je prends soin de vos crédits Azure)
  • Un Storage Account
  • Un Azure App Service Plan
  • Une Azure Function App, utilisant le Storage et l’App Service Plan précédemment créés
  • Un Azure Key Vault, avec son Access Policy pour l’Azure Function App, dans lequel on ajoutera un secret

Plusieurs solutions possibles pour le faire

  1. Le portail Azure. On clique, on clique, on clique, on clique … trop long.
  2. Un script Powershell. Infra as Code, répétable, c’est mieux. Mais ça fait encore pas mal de lignes à écrire, surtout si l’on veut de l’idempotence.
  3. Un template ARM, idempotent mais un peu verbeux
  4. Terraform. Infra as Code encore, mais un template plus court, et l’idempotence en prime.

Terraformer les services Azure

Comme vous l’avez compris, on va prendre l’option 4.

Il y a 2 pré-requis :

  1. Un Service principal, avec sa clé, qui à le rôle de contributeur sur la souscription où l’on va déployer
  2. Installer Terraform (La marche à suivre ici)

Terraform permet de déployer tout une infrastructure en utilisant un template, et des fichiers de variables pour la configuration. Les possibilités sont nombreuses (création de module pour plus de ré-utilisabilité, de workspace pour du travail collaboratif, d’un backend pour stocker les fichiers d’états tfstate). Un système d’interpolation permet d’exploiter les variables passées en entrée au sein du template. Si vous n’êtes pas familier avec l’outil, je vous invite à le découvrir.

Le template et la documentation d’utilisation est disponible sur https://github.com/chatoninthecloud/azure-function-key-vault

Une fois le template lancé, voila ce qu’on obtient dans le portail Azure

ResourceGroup

Un Resource Group qui contient l’ensemble des ressources Azure.

Au niveau de l’Azure Function, on peut voir en particulier que Managed Service Identity est activé

MSI Function App Activated

Et au niveau du Vault, on a bien une Access Policy pour notre Azure Function

Vault Access Policy

Depuis le portail, pour pouvoir ajouter un secret dans le Vault, il faudra créer une Access Policy avec les permissions idoines au niveau de la gestion des secrets pour votre compte. Un fois cela fait, vous pouvez ajouter un nouveau secret, dont on pourra récupérer la valeur depuis une Azure Function.

Azure Function

On va maintenant pouvoir créer une fonction, qui pourra lire les secrets du Vault en utilisant sa propre identité, sans passer par un compte de service. En ce moment, je travaille beaucoup en Powershell, L’exemple qui suit sera donc dans ce langage. Il est également possible de faire une implémentation en C#, Javascript ou tout autre langage supporté.

Le code est également disponible sur le Github.

Tout d’abord, il faut créer la Function dans le portail

Azure Function

 

Dans l’éditeur, copier le code du fichier GetSecretFromVault.ps1 présent dans le repo https://github.com/chatoninthecloud/azure-function-key-vault

Au niveau du code, on exploite simplement ce que l’on a déployé précédemment.

# Get MSI Endpoint and MSI Secret from environment variables

$MSIEndpoint = $env:MSI_ENDPOINT

$MSISecret = $env:MSI_SECRET

MSI_ENDPOINT et MSI_SECRET sont deux variables d’environnement définies automatiquement, qui vont nous permettre d’obtenir un token pour accéder au Vault.

$vaultName = $env:key_vault_name

Le nom du vault est ajouté par le template Terraform dans les settings de l’App Function. Nous allons en avoir besoin par la suite.

$secretName = "iamasecret"

Le nom du secret. Remplacez le par le nom du secret que vous avez créé.

$vaultTokenUri = $MSIEndpoint + "?resource=https://vault.azure.net&api-version=2017-09-01"

$authenticationResult = Invoke-RestMethod -Method Get -Headers @{"Secret" = $MSIsecret} -Uri $vaultTokenUri

$accessToken = $authenticationResult.access_token

Obtention du token d’accés au Vault.

$vaultSecretURI = "https://$vaultName.vault.azure.net/secrets/$secretName/?api-version=2015-06-01"

$secretResult = Invoke-RestMethod -Method GET -Uri $vaultSecretURI -ContentType "application/json" -Headers @{ Authorization = "Bearer $accessToken" }

Appel au Vault, en utilisant une authentification par token, passé dans le header de la request

Write-Output "Secret $secretName value is ""$($secretResult.Value)"""

On affiche la valeur du secret dans les logs. C’est juste pour une démo, ne faites pas ça dans la vrai vie (Ou faites le, mais ne dites pas que vous êtes passé sur mon article)

Au final

Nous avons maintenant :

  • Un store, Azure Key Vault, qui peut contenir la configuration de plusieurs environnements, pour plusieurs applications, de façon centralisée et sécurisée.
  • Managed Service Identity, qui propose un mécanisme simple et efficace pour s’authentifier et accéder aux secrets du store
  • Azure Function : Un exemple de service qui a besoin de configuration pour pouvoir s’exécuter.

En conclusion, cette combinaison implémente le pattern External Configuration Store rapidement et efficacement. En plus d’Azure Key Vault, dans les services Azure permettant une authentification par Managed Service Identity, on retrouve notamment Azure Storage, Service Bus, Event Hub et Azure SQL Database.

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *