Rotation des clés CosmosDB
Qui n’a pas été confronté un jour à une ressource inaccessible suite à la régénération de la clé d’accès par Douby le stagiaire ? Douby ou michel d’ailleurs peu importe…
La bonne pratique voudrait que nous n’utilisions pas la clé en direct dans notre code (ce que je recommande fortement) mais alors comment faire ? Certains types de ressources proposent des solutions via Key Vault, par exemple la fonctionnalité du managed storage qui permet au Key Vault d’auto regénéré la clé d’un storage account et de la référencer en tant que secret : https://docs.microsoft.com/en-us/azure/key-vault/key-vault-overview-storage-keys-powershell
Vous faites donc référence directement au secret au sein du Key Vault et donc plus besoin de renseigner une clé en dur dans votre code, de plus la clé étant régénérée automatiquement vous évitez qu’une clé divulgué se retrouve utilisable sur le long terme.
Malheureusement cette fonctionnalité n’est pas disponible pour toutes les ressources proposant des clés et c’est notamment le cas de CosmosDB.
D’où ma réflexion, comment référencer au sein d’un key vault les master keys de ma CosmosDB à chaque fois que Doubby régénère celles-ci ?
Premièrement comment détecter la regénération des clés ?
Réponse simple, Activity Logs !
Ok mais ensuite comment récupérer les nouvelles clés et surtout comment les ajouter à mon Key Vault ?
J’ai évidemment pensé à PowerShell mais au sein de Functions ce n’est pas encore ça… J’ai donc opté pour Logic App, plus graphique certes mais tout aussi efficace pour cette tâche.
Voyons comment cela a été mis en place.
J’ai tout d’abord créé ma Logic App en utilisant un trigger HTTP, le schéma à utiliser est le suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
{ "properties": { "data": { "properties": { "context": { "properties": { "activityLog": { "properties": { "authorization": { "properties": { "action": { "type": "string" }, "scope": { "type": "string" } }, "type": "object" }, "caller": { "type": "string" }, "channels": { "type": "string" }, "claims": { "type": "string" }, "correlationId": { "type": "string" }, "description": { "type": "string" }, "eventDataId": { "type": "string" }, "eventSource": { "type": "string" }, "eventTimestamp": { "type": "string" }, "level": { "type": "string" }, "operationId": { "type": "string" }, "operationName": { "type": "string" }, "resourceGroupName": { "type": "string" }, "resourceId": { "type": "string" }, "resourceProviderName": { "type": "string" }, "resourceType": { "type": "string" }, "status": { "type": "string" }, "subStatus": { "type": "string" }, "submissionTimestamp": { "type": "string" }, "subscriptionId": { "type": "string" } }, "type": "object" } }, "type": "object" }, "properties": { "properties": {}, "type": "object" }, "status": { "type": "string" } }, "type": "object" }, "schemaId": { "type": "string" } }, "type": "object" } |
On va ensuite récupérer le nom de la CosmosDB qui a déclenchée notre Logic App au sein d’une variable, pour cela on va spliter le resourceId :
1 |
split(triggerBody()?['data']?['context']?['activityLog']?['resourceId'],'/')[8] |
On va ensuite définir le nom du Key Vault à utiliser et plutôt que de le renseigner en dur nous allons utiliser une variable :
Nous avons alors les éléments nécessaire pour aller récupérer les clés via API mais il nous manque cependant un élément à savoir l’authentification !
Plutôt que d’utiliser un SPN nous allons utiliser MSI (Managed Service Identity)
L’activation se fait simplement comme ceci au sein de notre Logic App:
Notre Logic App possède désormais une identité que nous allons pouvoir utiliser pour lui assigner des droits, chose que nous allons faire afin de lui permettre de récupérer les clés de notre CosmosDB par API, pour se faire nous allons lui attribuer le rôle DocumentDB Account Contributor
On va ensuite créer une access policy afin de l’authoriser à créer / updater les secrets au sein de notre Key Vault:
Désormais notre Logic App sera capable à la fois de récupérer les clés puis de créer des secrets au sein de notre Key Vault.
L’étape de récupération des clés de notre CosmosDB se fera en utilisant les API de cette manière :
Nous allons ensuite parser le résultat afin de réutiliser les clés pour pouvoir créer nos secrets. :
Le Schema à utiliser est le suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
{ "properties": { "primaryMasterKey": { "type": "string" }, "primaryReadonlyMasterKey": { "type": "string" }, "secondaryMasterKey": { "type": "string" }, "secondaryReadonlyMasterKey": { "type": "string" } }, "type": "object" } |
Il ne nous reste plus qu’à créer un secret ou à l’updater pour chacune des clés à savoir les 2 clés master (primaire et secondaire) puis les 2 clés Read Only
Pour se faire nous utiliserons encore une fois les API :
Attention à bien configurer l’audience sans quoi vous aurez une erreur (https://vault.azure.net)
Dans mon cas je récupère la valeur “Caller” afin de la rentrer dans un tag nommé updatedBy afin de savoir quel utilisateur est à l’origine de la régénération de mes clés.
Vous n’avez plus qu’à répéter l’étape pour les autres clés :
Voila pour mon Logic App, désormais voyons comment déclencher celle-ci à chaque régénération d’une de mes clés !
Pour se faire nous allons utiliser les alertes de la manière suivante, tout d’abord je vais créer une nouvelle alerte :
Je vais ensuite sélectionner la condition suivante :
On créé ensuite un action group :
Il ne reste plus qu’à entrer un nom et une description :
Vous pouvez ensuite tester le déclenchement an régénérant une des clés :
L’alerte est déclenchée :
Puis déclenche la Logic App :
Il ne nous reste plus qu’a valider que les secrets soient bien au sein de notre Key Vault :
Voila vous n’avez désormais plus qu’à faire référence à un de ces secrets plutôt que d’utiliser la clé en dur pour vos appels à CosmosDB.
Vous pouvez également tout en vous basant sur cette exemple imaginer une solution d’auto régénération des clés !