Archives de catégorie : Powershell

Forecast de consommation Azure

Pour beaucoup, le retour de vacances commence par un dépliage de mails en règle. Les mécanismes d’alertes d’Azure pouvant produire un grand nombre de messages (pas plus de 100 mails / heure quand même), on finit par ranger ces mails avec une règle automatique Outlook. Grave erreur car dans ces mails, il y avait aussi ceux en relation avec Azure Budget vous indiquant que vous venez de dépasser un seuil budgétaire. C’est en voyant un mail de votre DAF que vous avez commencé à comprendre la nature du problème et qu’il est trop tard.

Le portail Azure nous propose de d’évaluer le forecast de notre consommation Azure (Fonction Cost Management). Depuis peu, on peut même y associer un Azure Budget (fonctionnel pour les souscriptions de type EA). Le problème, c’est que le budget se base sur la consommation réelle passée. Tant qu’on n’a pas atteint le premier seuil de consommation, nous ne sommes pas alertés. Pour répondre à cette problématique, j’ai commencé à creuser le fonctionnement des API de billing et je suis tombé sur ces API : /Microsoft.Consumption/ForeCast/List. En creusant un peu le sujet, j’ai fini par produire le script AzureCostForecast.PS1. Celui-ci va commencer par rechercher un Azure Budget préalablement configuré nommé « SubscriptionLevel ». Je l’utilise pour récupérer le budget initialement envisagé ainsi que sa périodicité pour ensuite construire un tableau de la consommation Azure incluant à la fois la consommation constatée (passée) avec les estimations fournies par l’API. Cela produit le résultat ci-dessous :

clip_image002

L’API nous propose une hypothèse de consommation basse et haute (à nous de déterminer si nous voulons être optimiste ou pessimiste). De cette manière, nous allons très rapidement savoir si nous allons être hors budget ou non. C’est simple mais efficace pour formuler des hypothèses budgétaires pour notre consommation Azure dans les prochains mois.

Il reste encore pas mal de chose à creuser dans ce domaine (notion de burn rate, regroupements des coûts par tag, …), il y a de grandes chances qu’il y ait encore quelques billets sur ce sujet historie d’introduire doucement la gouvernance financière.

PS : A cette heure, les API utilisées ne fonctionnent que pou les souscriptions de type Enterprise Agreements.

Sur cette bonne vacance.

Benoît – Simple and Secure by design but Business compliant

Gestion de la sauvegarde de vos VM Azure avec des tags.

Après l’automatisation du Patch Management, nous allons nous attaquer au sujet de la sauvegarde. Si on doit raisonner de manière industrielle, on va continuer avec les Tags. Cette fois, le Tag se nommera BackupPolicy. Tout comme pour la gestion des Patchs, on va imposer :

  • La présence d’un Tag BackupPolicy avec une valeur par défaut
  • Deux valeurs autorisées (Yes/No)

La subtilité, c’est que dans Azure Site Recovery, nous n’avons pas de fonctionnalité équivalente à Dynamic group. Nous devrons donc gérer cela nous même. On y reviendra plus tard dans ce billet. Première étape : Imposer des valeurs par défaut pour notre Tag BackupPolicy.

 

Imposer les valeurs pour le Tag BackupPolicy

Je vais repartir sur une Azure Policy que j’ai déjà utilisée dans le billet Automatiser Azure Update Management avec Azure Policy. On va donc faire un peu de réuse. On pourrait penser qu’il serait une bonne idée d’assigner l’Azure Policy au niveau du Management Group et non de chaque souscription mais en fait, il n’en est rien. Il y a un ordre d’évaluation des Azure Policies : layering-policies. Assigné au niveau du Management group, elle obligera les consommateurs à déployer leurs machines virtuelles avec le tag BackupPolicy configuré. Assigné au niveau de la souscription, les consommateurs pourront ignorer la configuration et tag (et cependant avoir une valeur par défaut) et le reconfigurer plus tard. L’Azure Policy est disponible ici : AZ-ALLOWEDTAGVALUES. Le code PowerShell pour importer l’Azure Policy est sensiblement identique à celui utilisé dans le billet Automatiser Azure Update Management avec Azure Policy

[String]$ManagementGroupName = « MGMT01 »

[String]$PolicyDefinitionFileURI = « https://raw.githubusercontent.com/Benoitsautierecellenza/BackupPolicy/master/Policies/AZ-ALLOWEDTAGVALUES/AZ-ALLOWEDTAGVALUES-02-RULE.json« 

[String]$PolicyParameterFileURI = « https://raw.githubusercontent.com/Benoitsautierecellenza/BackupPolicy/master/Policies/AZ-ALLOWEDTAGVALUES/AZ-ALLOWEDTAGVALUES-02-PARAMETERS.json« 

[String]$PolicyName = « AllowedValues4BackupPolicy »

New-AzPolicyDefinition -Name $PolicyName `

-DisplayName $PolicyName `

-Policy $PolicyDefinitionFileURI `

-Parameter $PolicyParameterFileURI `

-ManagementGroupName $ManagementGroupName `

-Mode All

clip_image002

Pour l’assignation, nous allons travailler au niveau d’une souscription.

[String]$ManagementGroupName = « MGMT01 »

[String]$SubscriptionID = (Get-Azcontext).Subscription.id

[String]$BackupPolicyTagName = « BackupPolicy »

[String]$DefaultTagValue = « No »

[String]$PolicyName = « AllowedValues4BackupPolicy »

[String]$PolicyAssignName = « MGMT01-VM-P1 »

[array]$AllowedValues = @(« Yes », « No »)

[String]$Scope = « /subscriptions/$SubscriptionID »

$PolicyDefinition = Get-AzPolicyDefinition -ManagementGroupName $ManagementGroupName -Name $PolicyName

$AssignParameters = @{

‘BackupPolicyTagName’ = $BackupPolicyTagName;

‘BackupPolicyTagAllowedValues’= ($AllowedValues)

}

New-AzPolicyAssignment -Name $PolicyAssignname `

-PolicyDefinition $PolicyDefinition `

-Scope $Scope `

-PolicyParameterObject $AssignParameters

clip_image004


Imposer une valeur par défaut pour le tag BackupPolicy

Notre Tag BackupPolicy accepte maintenant deux valeurs. Il faut maintenant imposer sa présence à l’aide d’un Azure Policy de Type Append. La Policy AZ-DEFAULTTAG va permettre d’imposer notre valeur par défaut. Rien de bien compliqué dans le code PowerShell ci-dessous :

[String]$ManagementGroupName = « MGMT01 »

[String]$PolicyDefinitionFileURI = « https://raw.githubusercontent.com/Benoitsautierecellenza/BackupPolicy/master/Policies/AZ-DEFAULTTAG/AZ-DEFAULTTAG-01-RULE.json« 

[String]$PolicyParameterFileURI = « https://raw.githubusercontent.com/Benoitsautierecellenza/BackupPolicy/master/Policies/AZ-DEFAULTTAG/AZ-DEFAULTTAG-01-PARAMETERS.json« 

[String]$PolicyName = « DefaultValue4BackupPolicy »

New-AzPolicyDefinition -Name $PolicyName `

-DisplayName $PolicyName `

-Policy $PolicyDefinitionFileURI `

-Parameter $PolicyParameterFileURI `

-ManagementGroupName $ManagementGroupName `

-Mode All

clip_image006

Ne reste plus qu’à assigner. Réaliser l’assignation par défaut au niveau du Management Group impose la même valeur par défaut pour le tag BackupPolicy que la souscription soit de type DEV, UAT ou PROD. Or, ce n’est pas logique. Pour un environnement de production, il est logique de vouloir imposer la sauvegarde.

$SubscriptionID = (Get-AzContext).Subscription.id

[String]$ManagementGroupName = « MGMT01 »

[String]$BackupPolicyTagName = « BackupPolicy »

[String]$DefaultTagValue = « No »

[String]$PolicyName = « DefaultValue4BackupPolicy »

[String]$PolicyAssignName = « MGMT01-VM-P2 »

[String]$AllowedValues = « Yes »

[String]$Scope = « /subscriptions/$SubscriptionID »

$PolicyDefinition = Get-AzPolicyDefinition -ManagementGroupName $ManagementGroupName -Name $PolicyName

$AssignParameters = @{

‘BackupPolicyTagName’ = $BackupPolicyTagName;

‘DefaultTagValue’=($AllowedValues)

}

New-AzPolicyAssignment -Name $PolicyAssignname `

-PolicyDefinition $PolicyDefinition `

-Scope $Scope `

-PolicyParameterObject $AssignParameters

clip_image008

 

Un peu de travail avec Azure Automation

Contrairement à Update Management, ce ne sera pas automatique, on doit donc un peu aider. Deux Runbooks vont être mis à disposition :

Le fonctionnement des deux Runbooks est sensiblement identique, à savoir parcourir la liste des machines virtuelles de la souscription pour identifier la valeur du tag BackupPolicy. Si le tag est configuré à « Yes » et que la machine virtuelle n’est pas inscrite à un plan de protection, alors elle sera ajoutée. Si le tag est configuré à « No », alors on s’assure que la machine virtuelle n’est plus inscrite au plan de protection. On va mettre tout cela en place avec une exécution planifiée toutes les quatre heures. Commençons par l’import dans une instance Azure Automation nommé » « ManagementAutomation » contenue dans le groupe de ressources « Management” :

[String]$ResourceGroupName = « Management »

[String]$AutomationAccountName = « ManagementAutomation »

Import-AzAutomationRunbook -ResourceGroupName $ResourceGroupName `

-AutomationAccountName $AutomationAccountName `

-Path « C:\localgit\BackupPolicy\Runbooks\AutomaticBackupVMS-ON.PS1 » `

-Type PowerShell `

-Published

Import-AzAutomationRunbook -ResourceGroupName $ResourceGroupName `

-AutomationAccountName $AutomationAccountName `

-Path « C:\localgit\BackupPolicy\Runbooks\AutomaticBackupVMS-OFF.PS1 » `

-Type PowerShell `

-Published

clip_image010

Dernière étape, la planification de ces deux runbooks pour une exécution toutes les quatre heures :

[String]$ScheduleName = « FOUR_HOURS »

[DateTime]$StartTime = ((Get-date).date).AddDays(1)

[Int]$SchedulePeriodInHours = 4

[String]$TimeZoneName = ([System.TimeZoneInfo]::Local).Id

New-AzAutomationSchedule -ResourceGroupName $ResourceGroupName `

-AutomationAccountName $AutomationAccountName `

-Name $ScheduleName `

-StartTime $StartTime `

-HourInterval $SchedulePeriodInHours `

-TimeZone $TimeZoneName

Register-AzAutomationScheduledRunbook -ResourceGroupName $ResourceGroupName `

-AutomationAccountName $AutomationAccountName `

-RunbookName « AutomaticBackupVMS-ON » `

-ScheduleName $ScheduleName

Register-AzAutomationScheduledRunbook -ResourceGroupName $ResourceGroupName `

-AutomationAccountName $AutomationAccountName `

-RunbookName « AutomaticBackupVMS-OFF » `

-ScheduleName $ScheduleName

clip_image012

Note : Pour que les Runbooks fonctionnent, il est essentiel que votre instance Azure Automation fonctionne uniquement avec des modules AZ et non ARM : https://aka.ms/azps-migration-guide. Ci-dessous le résultat de l’exécution du runbook AutomaticBackupVMS-ON.

clip_image014

 

Conclusion

Ça demande un peu plus de travail mais cela contribue à réduire la charge de support sur la gestion du IaaS. Il aurait été possible de configurer la sauvegarde pendant le déploiement de la machine virtuelle mais ce choix implique que celui qui déploie dispose de permissions sur l’instance Azure Site Recovery, ce qui n’est pas nécessaire dans mon implémentation. C’est de l’exploitation « sans-couture », transparente pour vos consommateurs Azure.

Azure BluePrint Import/Export

Le principe des BluePrints est intéressant pour industrialiser la mise en place de différents artefacts (Azure Policies, Templates ARM, Custom Roles, …). On ne peut le consommer que dans le scope dans lequel ils ont été créés ou dans un scope inférieur (Management Group de niveau inférieur, souscription et même groupe de ressources). Problème, comment reproduire cet élément dans une souscription qui ne dépend pas de la même hiérarchie de Management Groups et donc du même Tenant Azure AD.

Historiquement, j’utilisais le script Manage-AzureRMBluePrint car le module Az.Blueprint (à installer manuellement) ne proposait pas d’équivalent. Ce n’est plus le cas depuis quelques jours

clip_image001

 

Après mise à jour, on constate qu’on a bien des commandes pour prendre en charge l’import / export des BluePrints sous forme JSON.

clip_image003

 

Bref, à vos updates de modules. Après, c’est à tester, BluePrint est toujours en Preview à cette heure.

Benoît – Simple and secure by design but business compliant

Automatiser Azure Update Management avec Azure Policy

Avoir de nombreuses machines virtuelles dans Azure implique de les gérer au niveau Patch Management. Sur le papier, on a un service nommé « Update Management » dans Azure Automation. Le problème, c’est que c’est nous qui devons associer chaque machine virtuelle à une politique de Patch Management. C’est une tâche rébarbative dont on se passerait bien. L’idéal serait que le propriétaire puisse inscrire lui-même sa machine virtuelle dans une politique de Patch Management sous forme de choix imposé.

 

Utilisation des tags dans le Patch Management des VM

Les tags permettent de gérer les ressources manière industrielle. Nous allons introduire un tag obligatoire sur les objets machines virtuelles nommé UpdatePolicy. Nous allons utiliser Azure Policy pour imposer deux règles :

  • La présence d’un tag UpdatePolicy
  • Les valeurs associées au tag UpdatePolicy doivent correspondre à une liste établie.

 

La première règle permet de m’assurer que toute machine virtuelle nouvellement créée ou mise à jour sera automatiquement associée à une politique de Patch Management. La seconde permet de s’assurer que seules les valeurs autorisées sont utilisées. Puis, nous allons réutiliser ces tags pour inscrire les machines virtuelles dans des Dynamic Groups au sein d’Update Management.

 

Imposer une politique de patching par défaut

Pour imposer une politique de Patching, nous avons besoin de mettre en place une Azure Policy en mode Append qui va vérifier que le tag UpdatePolicy est bien présent sur les ressources de Type VirtualMachines. Si ce n’est pas le cas, nous allons proposer une valeur par défaut. Une Azure Policy, c’est composé de deux parties. La première partie, c’est la règle en elle-même. La Policy en elle-même repose sur une double condition, à la fois sur le type de ressource impliquée (Microsoft.Compute/VirtualMachines) et l’absence d’un tag particulier dont son nom est précisé en paramètre. Si cette condition est remplie, un tag est ajouté avec une valeur par défaut.

clip_image002

 

Jusqu’à maintenant, on voit bien que la règle est générique, il nous manque des paramètres. C’est l’objectif du second fichier référençant les paramètres. Pas grand-chose à dire à son sujet.

clip_image003

 

Ne reste plus qu’à importer notre Policy au niveau du scope de notre souscription avec la commande New-AzPolicyDefinition

[String]$SubscriptionID = (Get-AzContext).Subscription.id

[String]$Scope = « /subscriptions/$SubscriptionID/ »

[String]$PolicyDefinitionFileURI = « https://raw.githubusercontent.com/Benoitsautierecellenza/DemoPolicy/master/Policies/AZ-DEFAULTTAG/AZ-DEFAULTTAG-01-RULE.json »

[String]$PolicyParameterFileURI = « https://raw.githubusercontent.com/Benoitsautierecellenza/DemoPolicy/master/Policies/AZ-DEFAULTTAG/AZ-DEFAULTTAG-01-PARAMETERS.json »

[String]$PolicyName = « DefautltValue4UpdatePolicy »

[String]$PolicyDisplayName = « $PolicyName »

New-AzPolicyDefinition -Name $PolicyName `

-DisplayName $PolicyDisplayName `

-Policy $PolicyDefinitionFileURI `

-Parameter $PolicyParameterFileURI `

-Subscription $SubscriptionID `

-Mode All

clip_image005

 

Notre Azure Policy est maintenant être à être assignée au niveau de la souscription (ou resource group au sein de la souscription) avec la commande New-AzPolicyAssignment.

[String]$UpdatePolicyTagName = « UpdatePolicy »

[String]$DefaultTagValue = « AlwaysReboot »

[String]$PolicyName = « DefautltValue4UpdatePolicy »

[String]$PolicyAssignname = « MGMT01-VM-P1 »

[String]$Scope = « /subscriptions/$SubscriptionID/ »

$PolicyDefinition = Get-AzPolicyDefinition -SubscriptionId $SubscriptionID -Custom | Where-Object {$_.name -eq $PolicyName}

$AssignParameters = @{

‘UpdatePolicyTagName’ = $UpdatePolicyTagName;

‘DefaultTagValue’=$DefaultTagValue

}

New-AzPolicyAssignment -Name $PolicyAssignname `

-PolicyDefinition $PolicyDefinition `

-Scope $Scope `

-PolicyParameterObject $AssignParameters

clip_image007

 

C’est lors de l’assignation qu’on renseigne les valeurs des paramètres que nous allons utiliser. Dans notre contexte, nous avons deux paramètres :

  • UpdatePolicyTagName : UpdatePolicy
  • DefaultTagValue : AlwaysReboot

 

Imposer un choix de politique de Patching

Si on laisse faire les consommateurs, ils peuvent renseigner une valeur pour notre tag UpdatePolicy mais encore faut-il que celle-ci correspondre à une liste de valeur préétablies que l’on pourra reconnaître. Problème, les valeurs des tags sont sensibles à la case, donc « AlwaysReboot » est différent de « Alwaysreboot ». Pour éviter ce type de problème, nous allons utiliser une seconde Azure Policy pour imposer une des valeurs ci-dessous pour notre tag « UpdatePolicy » :

  • AlwaysReboot
  • RebootIfRequired
  • OnlyReboot
  • NeverReboot

 

Notre Azure Policy reprend le même principe que pour la première avec la double condition. La subtilité, c’est que cette fois, nous savons que le tag existe forcément. Nous devons refuser toute mise à jour de celui-ci qui ne contiendrait pas une des valeurs correspondant à cette autorisée (d’où l’usage du « In »). Si les deux conditions sont remplies alors on refuse l’opération.

clip_image009

 

Le fichier de réponse correspond à peu de choses près à la Policy précédente, si ce n’est l’utilisation du type « Array » pour décrire non pas une chaine de caractère mais une liste.

clip_image011

 

Le processus d’importation de notre Azure Policy ne change pas.

[String]$SubscriptionID = (Get-AzContext).Subscription.id

[String]$Scope = « /subscriptions/$SubscriptionID/ »

[String]$PolicyDefinitionFileURI = « https://raw.githubusercontent.com/Benoitsautierecellenza/DemoPolicy/master/Policies/AZ-ALLOWEDTAGVALUES/AZ-ALLOWEDTAGVALUES-02-RULE.json »

[String]$PolicyParameterFileURI = « https://raw.githubusercontent.com/Benoitsautierecellenza/DemoPolicy/master/Policies/AZ-ALLOWEDTAGVALUES/AZ-ALLOWEDTAGVALUES-02-PARAMETERS.json »

[String]$PolicyName = « AllowedTagValues4UpdatePolicy »

[String]$PolicyDisplayName = « $PolicyName »

New-AzPolicyDefinition -Name $PolicyName `

-DisplayName $PolicyDisplayName `

-Policy $PolicyDefinitionFileURI `

-Parameter $PolicyParameterFileURI `

-Subscription $SubscriptionID `

-Mode All

clip_image013

Tout comme son assignation. La seule subtilité à ce niveau concerne le passage de la liste des valeurs autorisées pour notre tag.

[String]$PolicyAssignname = « Assign-$PolicyName »

$UpdatePolicyTagName = « UpdatePolicy »

$AllowedValues = @(« AlwaysReboot », »RebootIfRequired », »OnlyReboot », »NeverReboot »)

$PolicyDefinition = Get-AzPolicyDefinition -SubscriptionId $SubscriptionID | Where-Object {$_.Properties.displayname -eq $PolicyDisplayName}

$AssignParameters = @{

‘UpdatePolicyTagName’ = $UpdatePolicyTagName;

‘UpdatePolicyTagAllowedValues’=($AllowedValues)

}

New-AzPolicyAssignment -Name $PolicyAssignname `

-PolicyDefinition $PolicyDefinition `

-Scope $Scope `

-PolicyParameterObject $AssignParameters

clip_image015

 

Associer nos machines virtuelles à des groupes dynamiques

Maintenant, cela se passe dans Azure Automation. Je pars du principe que la fonctionnalité Update Management a été activée sur l’instance Automation. Nous allons créer des Deployment Schedules pour chaque type d’OS et chaque type de Policy. Finalement, on doit créer huit Deployment Schedules. Vu que c’est toujours les mêmes opérations, j’ai industrialisé avec le scripts CreateDeploymentSchedules.ps1. Je vous laisse le personnaliser mais dans l’ensemble, il fait le job et on obtient le résultat ci-dessous :

clip_image017

 

A ce stade, nous n’avons plus qu’à patienter un peu que les groupes dynamiques se peuplent

clip_image019

 

Conclusion

Félicitation, vous avez un exemple fonctionnel de service Patching as A Service. Le procédé est déclinable pour imposer la sauvegarde, il faudra juste un peu d’huile de coude et de Runbooks pour gérer l’enregistrement dans Azure Backup mais c’est le même principe. Ce sera certainement le thème du prochain billet.

Consommer un Storage Account avec une authentification Azure AD

Dans Azure, le service Storage Account est certainement le plus ancien de tous. En plus, il est consommé par tous les autres services. Dans Azure, c’est un service dit « Ring 0 », nécessaire à l’ouverture de toute nouvelle région Azure. Introduire des nouveautés pour ce service est extrêmement complexe. Pourtant, ça arrive de temps en temps. C’est jours-ci, c’est le support d’Azure AD pour l’authentification pour les Storage Accounts. C’est une évolution essentielle car elle nous permet de nous passer des clés primaires et secondaires. Vous savez, c’est celles qu’on obtient avec la commande Get-AzStorageAccountKey :

Get-AzStorageAccountKey -ResourceGroupName $ResourceGroupName -Name $StorageAccountName

clip_image002

Pour accéder à un Storage Account, nous avons besoin d’un contexte que nous allons négocier avec la commande New-AzStorageContext pour laquelle nous allons préciser le paramètre « -UseConnectedAccount » comme illustré ci-dessous :

$Context = New-AzStorageContext -StorageAccountName $storageaccountname -UseConnectedAccount

$Context | Gm

clip_image004

 

Donc plus besoin d’avoir une clé primaire / secondaire pour générer un contexte d’accès au stockage. Pour preuve, je consomme ce contexte immédiatement pour lister les conteneurs de mon Storage Account.

Get-AzStorageContainer -Context $context -Name *

clip_image006

 

Pour être complet, nous avons de nouveaux rôles Azure en relation avec le stockage :

Get-AzRoleDefinition | Where-Object {$_.name -Like « *Storage* »} | Select-Object name

clip_image008

 

Lorsqu’on détaille le rôle « Storage Blob Data Contributor », on découvre de nouvelles permissions liées aux données : DataActions & NotDataActions. C’est grâce à ces permissions que l’on va pouvoir déléguer l’accès au stockage.

clip_image010

 

Voilà, maintenant, plus d’excuse pour utiliser les clés primaires / secondaires pour accéder à vos Storage Accounts.

 

BenoîtS – Simple and Secure by design but Business compliant.

Migrer une machine virtuelle entre régions Azure

Voilà un cas client qui m’a occupé un certain temps. Mon client déploie une application basée sur des services IaaS à l’aide d’images préalablement générées. Mes images « sources » sont localisées dans la région Azure France Central et doivent être mise à disposition dans la région Brazil South. Voilà pour le besoin de base.

Mon premier réflexe a été de rechercher si un service de réplication d’images n’existait pas. On a bien un repository pour les images pour les conteneurs (Azure Contrainer Registry), on doit donc avoir le même type de service pour le IaaS. C’est effectivement le cas, cela se nomme Shared Image Gallery. Mais, j’ai tout de suite exclu ce choix car :

  • Service actuellement en Preview
  • Pas encore disponible dans les régions Azure qui me concernent

Second réflexe, Azure Site Recovery. Cela fait quelques temps que l’on peut utiliser le service pour « cloner » une machine virtuelle existante pour assurer un DRP vers une autre région Azure. Très rapidement, j’ai dû abandonner cette option car les régions Azure source et destination ne dépendent pas du même cluster géographique.

clip_image001

Source : https://docs.microsoft.com/en-us/azure/site-recovery/azure-to-azure-support-matrix

Pire, le cas de la région Azure Brazil South est un peu particulier car au sein de son Géo, il n’a pas de région Azure associée. Bref, pas la bonne solution.

En dernier ressort, je suis tombé sur cet article : Synchronously copy all managed disks of an Azure Virtual Machine to Azure Storage Accounts in multiple Azure regions. C’est presque ce qu’il me faut car il faudra reconstruire une image après. A mes yeux, la démarche proposée avait quelques défauts :

  • On paie une VM pour faire la copie avec AZCopy alors qu’on peut faire un job de copie
  • Elle est un peu salée la VM en SKU E pour de la copie de fichiers
  • Les opérations sont réalisées en séquentielle alors qu’on se contente de suivre un job.

J’avais déjà publié un billet pour cloner des machines virtuelles dans Azure. J’ai donc juste poussé la logique d’industrialisation jusqu’au bout. Cela va se dérouler en plusieurs étapes :

  • Etape n°1 : Initialisation
  • Etape n°2 : Génération des clés SAS pour les VHD
  • Etape n°3 : Initialisation des opérations de copie
  • Etape n°4 : Suivi des opérations de copie
  • Etape n°5 : Reconstruction des Managed Disks

 

Etape n°1 : Initialisation

Avant de commencer, on va poser quelques bases. J’ai déployé une machine virtuelle en utilisant mon image dans le groupe de ressources « FranceCentral ». L’objectif est d’obtenir des Managed Disks dans le groupe de ressources « BrazilSouth » dans lequel on va préalablement avoir créé un Storage Account qui va être utilisé pour réceptionner les VHD à copier.

$SourceResourceGroup = « FranceCentral »

$SourceVMName = « MASTER »

$dataDiskNames = New-Object System.Collections.ArrayList

$dataDiskSASes = New-Object System.Collections.ArrayList

$SasKeyDuration = 36000

$DestinationResourceGroup = « BrazilSouth »

$DestinationStorageAccount = « brazilreplication »

$Accounttype = ‘Standard_LRS’

$VM = Get-AzureRmVM -ResourceGroupName $SourceResourceGroup -Name $SourceVMName -Verbose

clip_image002

 

Etape n°2 : Génération des clés SAS pour les VHD

Pour chaque disque composant notre machine virtuelle, nous devons générer une clé SAS. J’ai volontairement configuré une durée de vie assez longue, ne voulant pas tomber dans une situation ou les clés SAS auraient échouées pour cause d’une copie beaucoup trop longue.

$osDiskName = $VM.StorageProfile.OsDisk.Name

$osDiskSAS = (Grant-AzureRmDiskAccess -Access Read -DiskName $osDiskName -ResourceGroupName $SourceResourceGroup -DurationInSecond $SasKeyDuration -Verbose).AccessSAS

foreach($dataDisk in $VM.StorageProfile.DataDisks)

{

$dataDiskNames.Add($dataDisk.Name) | Out-Null

}

foreach($dataDiskName in $dataDiskNames)

{

$dataDiskSASes.Add((Grant-AzureRmDiskAccess -Access Read -DiskName $dataDiskName -ResourceGroupName $SourceResourceGroup -DurationInSecond $SasKeyDuration -Verbose).AccessSAS) | Out-Null

}

clip_image003

 

A ce stade, si on observe un des objets Managed Disks dans le portail, on peut constater qu’une clé SAS a bien été générée pour chacun d’eux.

clip_image004

 

Etape n°3 : Initialisation des opérations de copie

C’est en ce point que je me suis différencié de l’article Synchronously copy all managed disks of an Azure Virtual Machine to Azure Storage Accounts in multiple Azure regions. Mon besoin n’étant pas de répliquer mes disques dans de multiples régions, pas besoin d’autant d’instance de la machine virtuelle Ubuntu pour réaliser les opérations de copies. En plus, on n’a pas besoin d’attendre. Ça fait bien longtemps qu’AZCopy.EXE supporte la notion de job pour les opérations de copies. En PowerShell, AZCOPY.EXE, c’est Start-AzureStorageBlobCopy. A ce stade, du contenu va commencer à apparaître dans le contenu prévu à cet effet dans le Storage Account localisé dans la région cible.

$DestStorageAccountKeys = Get-AzureRmStorageAccountKey -ResourceGroupName $DestinationResourceGroup -Name $DestinationStorageAccount

$DestStorageContext = New-AzureStorageContext -StorageAccountName $DestinationStorageAccount -StorageAccountKey $DestStorageAccountKeys[0].Value

Start-AzureStorageBlobCopy -AbsoluteUri $osDiskSAS -DestContainer $SourceVMName.ToLower() -DestContext $DestStorageContext -DestBlob $($osDiskName + « .VHD »)

$DatadiskCount = 0

foreach($dataDiskSAS in $dataDiskSASes)

{

Start-AzureStorageBlobCopy -AbsoluteUri $dataDiskSAS -DestContainer $SourceVMName.ToLower() -DestContext $DestStorageContext -DestBlob $(« datadisk-$DatadiskCount » + « .VHD »)

$DatadiskCount +=1

}

clip_image005

 

Etape n°4 : Suivi des opérations de copie

La commande PowerShell Start-AzureStorageBlobCopy initié un job que l’on va suivre. Avantage, on va paralléliser toutes les opérations de copie. Pour suivre cela, on dispose de la commande PowerShell Get-AzureStorageBlobCopyState. La durée des opérations de copie dépendra principalement de la volumétrie de données à répliquer. Pour mes tests, quarante-neuf minutes étaient nécessaires pour répliquer un Managed Disk SATA de 127Go et un autre de 1To.

$StartTime = Get-Date

$StorageOperations = Get-AzureStorageBlob -Container master -Context $DestStorageContext | Get-AzureStorageBlobCopyState

While ($StorageOperations | Where-Object {$_.status -eq « Pending »})

{

$StorageOperations | select-Object Copyid, Status

Start-Sleep -Seconds 10

$StorageOperations = Get-AzureStorageBlob -Container master -Context $DestStorageContext | Get-AzureStorageBlobCopyState

}

$CopyTimeSpan = New-TimeSpan -Start $StartTime -End (Get-Date)

$Totalcopyoperations ='{0:N0}’ -f $($CopyTimeSpan.TotalMinutes)

Write-Host « Copy operation completed in $Totalcopyoperations minutes. »

clip_image006

 

Etape n°5 : Reconstruction des Managed Disks

Il ne nous reste plus qu’à reconstruire des Managed Disks en commençant par construire un objet de type Managed Disk à l’aide de la commande PowerShell New-AzureRmDiskConfig. De, là, il n’y a plus qu’à créer la ressource Azure à l’aide de la commande PowerShell New-AzureRmDisk.

$Container = Get-AzureStorageContainer -Container master -Context $DestStorageContext

$ContainerBaseURI = ($Container.CloudBlobContainer).uri.absoluteuri

$ListVHDs = Get-AzureStorageBlob -Container master -Context $DestStorageContext

ForEach ($VHD in $ListVHDs)

{

$Disksize = ($vhd.Length/1GB) +1

$Vhduri = $ContainerBaseURI + « / » + $vhd.name

$diskName = ($vhd.name).Substring(0, ($vhd.name).lastindexof(« . »))

Write-Host « Creating Managed Disk $diskName in Resource Group $DestinationResourceGroup. »

$diskConfig = New-AzureRmDiskConfig -AccountType $Accounttype -Location ((get-azurermresourcegroup -Name $DestinationResourceGroup).location) -DiskSizeGB $Disksize -SourceUri $vhdUri -CreateOption Import

New-AzureRmDisk -DiskName $diskName -Disk $diskConfig -ResourceGroupName $DestinationResourceGroup

}

clip_image007

 

Maintenant, il y a plus qu’à reconstruire l’image de référence au brésil et supprimer les fichiers VHD.

 

Conclusion

La solution n’est pas parfaite, elle peut encore être améliorée. Si vous être plus de culture Linux, allez lire ce billet : Copy custom vm images on azure. L’approche est sensiblement identique.

 

Benoît – Simple and Secure by design but Business compliant.

Stocker des clés SAS de Storage Account dans un KeyVault

Voilà un peu plus d’un an, j’avais publié ce billet : Valet Key avec Azure Function App. Depuis ce temps, je l’utilise énormément. Ce n’est que très récemment en passant un peu de temps dans le KeyVault que j’ai découvert la commande PowerShell Set-AzureKeyVaultManagedStorageSasDefinition. Ça a un peu changé mon approche initiale. Avant, mon Azure Function retournait un clés SAS prête à consommer. Maintenant, j’utilise le Key-Valet pour stocker les clés SAS mises à disposition. Le KeyVault peut stocker ce type de secret (pas visible dans le portail à ce jour). On peut donc ainsi mettre à disposition des clés SAS pré-générées à des d’applications (limitées dans le temps évidement). Pour ce billet, on va se contenter de mettre en œuvre la fonctionnalité :

  • Etape n°1 : Initialisation de notre environnement
  • Etape n°2 : Génération du token SAS
  • Etape n°3 : Expérience côté consommateur

 

Etape n°1 : Initialisation de notre environnement

Pour initialiser notre environnement, nous allons commencer par définir quelques variables. La variable $KeyVaultConsumer désigne un utilisateur référencé dans notre Azure AD pour lequel nous allons mettre en place des permissions RBAC (pour accéder au KeyVault) ainsi que des Access-Policies pour accéder au secret mis à disposition.

$KeyVaultConsumer = « keyvaultconsumer@xxxxxxxxxx.xxx »

$random = Get-Random -Minimum 0 -Maximum 999

$AzureRegion = « WestEurope »

$vaultname = « keyvaultlab$random »

$ResourceGroupname = « KeyVaultLab$random »

$storageaccountname = « keyvaultlab$random »

$sastokenname = « sas$random »

$saspermission = « racwdlup »

$Sastokendurationinminutes = 15

$StorageSKUName = ‘Standard_LRS’

$StorageKind = ‘StorageV2’

$UserPrincipal = (Get-AzureRmContext).Account.id

clip_image002

 

Avec ces variables, nous allons pouvoir initialiser notre environnement comprenant un groupe de ressources contenant à la fois un Storage Account et une instance de Key Vault. Jusque-là rien de très nouveau.

New-AzureRmResourceGroup -name $ResourceGroupname -Location $AzureRegion

$StorageAccount = New-AzureRmStorageAccount -ResourceGroupName $ResourceGroupname -Name $storageaccountname `

-Location $AzureRegion `

-Kind $StorageKind `

-SkuName $StorageSKUName

$Keyvault = New-AzureRmKeyVault -ResourceGroupName $ResourceGroupname -Name $vaultname -Location $AzureRegion -Sku Standard

clip_image004

A ce jour, le portail Azure ne permet pas encore de gérer les permissions sur le Storage. On va donc commencer par se positionner des permissions pour ce type de secret puis référencer notre Storage Account comme « ManagedStorageAccount » auprès de notre instance KeyVault avec la commande Add-AzureKeyVaultManagedStorageAccount

Set-AzureRmKeyVaultAccessPolicy -ResourceGroupName $ResourceGroupname -VaultName $vaultname `

-PermissionsToStorage get,list,delete,set,update,regeneratekey,getsas,listsas,deletesas,setsas,recover,backup,restore,purge `

-UserPrincipalName $UserPrincipal

$keyVault = Get-AzureRmKeyVault -VaultName $vaultname -ResourceGroupName $ResourceGroupname

$Keyvault.AccessPoliciesText

Add-AzureKeyVaultManagedStorageAccount -VaultName $vaultname -AccountName $storageaccountname `

-AccountResourceId $storageaccount.id `

-ActiveKeyName key1 `

-DisableAutoRegenerateKey

$StorageContext = New-AzureStorageContext -StorageAccountName $storageaccountname -Protocol https -StorageAccountKey Key1

clip_image006

Pour ceux qui ont suivi mon billet « Sécuriser ses Storage Accounts dans Azure« , c’est pour l’instant très proche. On peut donc même cumuler les deux fonctionnalités.

 

Etape n°2 : Génération du token SAS

De là, nous pouvons générer notre clé SAS. Par rapport à une approche Valet-Key, le secret n’est pas retourné au demandeur mais directement stocké dans le KeyVault. Attention, ce n’est pas un secret mais un objet de type « ms-sastoken-storage »

$start = [System.DateTime]::Now.AddMinutes(-1)

$end = [System.DateTime]::Now.AddMinutes($Sastokendurationinminutes)

$AccessToken = New-AzureStorageAccountSasToken -Service blob,file,Table,Queue `

-ResourceType Service,Container,Object `

-Permission $saspermission `

-Protocol HttpsOnly `

-StartTime $start `

-ExpiryTime $end `

-Context $StorageContext

$AccessToken

Set-AzureKeyVaultManagedStorageSasDefinition -AccountName $storageaccountname `

-VaultName $vaultname `

-Name $sastokenname `

-TemplateUri $AccessToken `

-SasType ‘account’ `

-ValidityPeriod ([System.Timespan]::FromDays(30))

$secret = Get-AzureKeyVaultSecret -VaultName $vaultname -Name « $vaultname-$sastokenname »

$secret.SecretValueText

$secret.Attributes.ContentType

clip_image008

Pour qu’un consommateur puisse accéder à ce nouveau type de secret (ms-sastoken-storage), il convient de s’assurer qu’il puisse voir l’objet KeyVault dans notre groupe de ressource puis de lui assigner une Access Policy avec uniquement les permissions nécessaires.

New-AzureRmRoleAssignment -SignInName $KeyVaultConsumer -ResourceGroupName $ResourceGroupname -RoleDefinitionName Reader

set-AzureRmKeyVaultAccessPolicy -ResourceGroupName $ResourceGroupname -VaultName $vaultname `

-PermissionsToSecrets Get, List `

-UserPrincipalName $KeyVaultConsumer

Set-AzureRmKeyVaultAccessPolicy -ResourceGroupName $ResourceGroupname -VaultName $vaultname `

-PermissionsToStorage get, list, getsas, listsas -UserPrincipalName $KeyVaultConsumer

$keyVault = Get-AzureRmKeyVault -VaultName $vaultname -ResourceGroupName $ResourceGroupname

$Keyvault.AccessPoliciesText

clip_image010

Etape n°3 : Expérience côté consommateur

Stocker un nouveau type de secret, c’est bien. Maintenant, il faut pouvoir le consommer. Pour la suite de ce billet, je pars du principe que nous sommes connectés avec son identité ($KeyVaultConsumer).

$keyvault = Get-AzurermKeyVault | Out-GridView -Title « Select KeyVault containing SAS Key. » -PassThru

Get-AzureKeyVaultSecret -VaultName $Keyvault.VaultName | Select-Object Name

$secret = Get-AzureKeyVaultSecret -VaultName $Keyvault.VaultName -Name (Get-AzureKeyVaultSecret -VaultName $Keyvault.VaultName).Name

$secret.ContentType

$secret.SecretValueText

clip_image012

 

Maintenant, on peut imaginer des process qui vont automatiquement renouveler des clés pour des consommateurs. Si en plus on combine avec la rotation automatique des clés de Storage Account vu dans mon précédent article, il n’y a plus de raison d’utiliser les clés Full.

BenoîtS – Simple and secure by design but Business compliant (with disruptive flag enabled)

Sécuriser ses Storage Accounts dans Azure

Le stockage Azure est certainement le composant d’Azure le plus ancien. Nous avons actuellement un support Preview pour Azure AD en lieu et place des clés primaires / secondaires. Pourtant, aujourd’hui c’est d’elles que nous allons parler. Chaque Storage Account dispose de deux « Access Key » comme illustré ci-dessous. Notre ami le RSI/RSSI (c’est mieux de l’avoir comme ami que comme ennemi) est très sensible sur les sujets de chiffrement et de condition d’accès au stockage.

clip_image001

 

Il y a quelques bonnes pratiques autour de ces clés. La première est de ne pas les divulguer. A la place, on recommande un mécanisme de type Key-Valet comme illustré dans ce billet : Valet Key avec Azure Function App. La seconde est d’opérer une rotation des clés régulièrement. Notre ami le RSSI/ RSSI rêve d’un bouton rouge qui lui permettrait d’opérer une rotation des clés à loisir. Dans les faits, cela déroule de la manière suivante :

  • On identifie les applications consommant la clé primaire d’un Storage Account donné
  • On reconfigure les applications pour utiliser la clé secondaire
  • On opère une régénération de la clé primaire du Storage Account
  • On reconfigure les applications pour utiliser la nouvelle clé primaire

Voilà pour la théorie. Dans la pratique, c’est un peu plus compliqué que cela. Nous sommes capables de configurer nos applications / services Azure pour utiliser un secret dans un KeyVault, mais il manquait encore une rotation des clés pilotée depuis le KeyVault, c’est le sujet de ce billet.

Mise en place de l’environnement

Pour la mise en place de l’environnement, nous commencerons avec un Storage Account tout ce qu’il y a de plus classique. Sa seule réelle particularité est l’activation de la fonctionnalité Managed Service Instance (MSI). Celle-ci va générer une identité Azure AD qui permettra au Storage Account d’accéder à notre Key Vault pour accéder à sa clé de chiffrement. Au passage, on notera qu’à ce stade, les clés de chiffrement sont celles de Microsoft.

$resourcegroupName = ‘KeyVaultLab’

$StorageAccountname = ‘keyvaultlab994’

$Keyvaultname = ‘keyvaultlab994’

$location = ‘WestEurope’

$StorageSKU = ‘Standard_LRS’

$StorageKind = ‘StorageV2’

$StorageAccountKeyName = ‘key1’

$StorageAccountEncryptionKeyname = $StorageAccountname

New-AzureRmResourceGroup -Name $resourcegroupName -Location $location

$storageaccount = New-AzureRmStorageAccount -ResourceGroupName $resourcegroupName -Name $StorageAccountname -Location $location -SkuName $StorageSKU -Kind $StorageKind -AssignIdentity

$Storageaccount.Encryption

$Storageaccount.Encryption.KeySource

clip_image002

 

Pour compléter l’environnement, nous allons mettre en place une instance du service Key Vault. Celle-ci sera utilisée pour deux usages :

  • Le stockage de notre clé de chiffrement du contenu du KeyVault
  • La mise en place de la rotation automatique des clés
New-AzureRmKeyVault -ResourceGroupName $resourcegroupName –Name $Keyvaultname -Location $location -EnableSoftDelete -EnablePurgeProtection

Add-AzureKeyVaultKey -VaultName $Keyvaultname -Name $StorageAccountEncryptionKeyname -Destination ‘Software’

clip_image003

 

Au passage, on notera un type de permission qui à ce jour n’est pas encore visible dans le portail : Key Vault Managed Storage.

Pour ce Key Vault, nous avons créé un premier secret. Celui-ci sera utilisé pour le chiffrement du contenu du Storage Account avec notre clé.

$KeyvaultObject = Get-AzureRmKeyVault -VaultName $Keyvaultname

$KeyObject = Get-AzureKeyVaultKey -VaultName $Keyvaultname -KeyName $StorageAccountEncryptionKeyname

$KeyObject

clip_image004

 

Pour finir, nous allons mettre en place une « Access policy » au niveau de notre instance du service Key Vault. Cette permission va permet à l’identité Azure AD liée à notre Storage Account d’accéder au Key Vault pour récupérer la clé de chiffrement.

Set-AzureRmKeyVaultAccessPolicy -VaultName $Keyvaultname -ObjectId $Storageaccount.Identity.PrincipalId -PermissionsToKeys wrapKey, unwrapKey, get

(Get-AzureRmKeyVault -VaultName $Keyvaultname).AccessPoliciesText

clip_image005

 

Mise en place de « Customer Managed Key »

La mise en place de la fonctionnalité « Customer Managed Key » permet de ne plus utiliser les clés de chiffrement de Microsoft mais la nôtre, mise à disposition dans clé précédemment mise en œuvre. A ce jour des services comme Azure Table et Azure Queue ne permettent pas encore d’utiliser la fonctionnalité « Customer Managed Key ». Maintenant que notre Storage Account est capable d’accéder aux clés de l’instance Key Vault, nous allons utiliser la commande Set-AzureRmStorageAccount pour préciser les références de la clé de chiffrement à utiliser.

Set-AzureRmStorageAccount -ResourceGroupName $resourcegroupName -Name $StorageAccountname -KeyvaultEncryption -Keyname $KeyObject.Name -KeyVersion $KeyObject.Version -KeyVaultUri $KeyvaultObject.VaultUri

$Storageaccount = Get-AzureRmStorageAccount -ResourceGroupName $resourcegroupName -Name $StorageAccountname

$Storageaccount.Encryption

$Storageaccount.Encryption.KeySource

$Storageaccount.Encryption.KeyVaultProperties

clip_image006

 

Une fois la commande exécutée, on peut constater dans les caractéristiques de notre Storage Account que la clé de chiffrement est maintenant issue du Key Vault, donc sous notre responsabilité. Charge à nous d’en opérer la rotation. Dans le portail Azure, on peut maintenant constater que le paramètre « Encryption » référence bien l’utilisation d’un secret du Key Vault pour assurer le chiffrement des données.

clip_image007

 

Mise en place de la rotation automatique Access Key

C’est la partie la plus intéressante. La première « Access Key » sera stockée dans notre instance du service Key Vault. Techniquement, ce n’est pas l’identité de notre instance Key Vault qui réalisera l’opération mais le Resource Provider « Azure Key Vault ». J’ai passé beaucoup de temps avant de comprendre ce point particulier.

$KeyVaultServicePrincipal = Get-AzureRmADServicePrincipal | Where-Object {$_.displayname -like « Azure Key Vault »}

$KeyVaultServicePrincipal.id.Guid

clip_image008

Pour opérer la rotation des clés, le service Key Vault (au sens générique) doit pouvoir manipuler les Access Key de notre Storage Account. Cela tombe bien, il existe un rôle nommé « Storage Account Key Operator Role » qui remplit parfaitement cet usage. Nous allons assigner ce rôle sur le Storage Account pour l’identité de l’application Azure Key Vault.

Get-AzureRmRoleDefinition -Name ‘Storage Account Key Operator Service Role’

New-AzureRmRoleAssignment -ObjectId $KeyVaultServicePrincipal.id.Guid -RoleDefinitionName ‘Storage Account Key Operator Service Role’ -Scope $Storageaccount.Id

clip_image009

 

On peut constater la permission dans le portail Azure pour l’application « Azure Key Vault ».

clip_image010

 

Prochaine étape, nous allons nous attribuer de nouvelles permissions dans le Key Vault concernant le stockage. Au moment de l’écriture de ce billet, le portail ne permettait pas encore de manipuler ce nouveau type de permission. On va donc réaliser l’opération en PowerShell et ajouter une Access Policy à notre instance du service Key Vault.

Set-AzureRmKeyVaultAccessPolicy -VaultName $Keyvaultname -ResourceGroupName $resourcegroupName -UserPrincipalName (Get-AzureRmContext).account.id -PermissionsToStorage set, get, regeneratekey, list, getsas, setsas

clip_image011

 

Les plus attentifs auront noté les permissions « getsas » et « setsas ». C’est pour le prochain billet, une nouvelle approche du Key-Valet, …

Pour finir, nous allons configurer la rotation automatique de la première « Access Key » de notre Storage Account. L’opération sera réalisée tous les trente jours.

(Get-AzureRmKeyVault -VaultName $Keyvaultname).AccessPoliciesText

$RegenerationPeriod = [System.TimeSpan]::FromDays(30)

$parameters = @{

VaultName = $Keyvaultname

AccountResourceId = $StorageAccount.Id

AccountName = $StorageAccountname

ActiveKeyName = $StorageAccountKeyName

RegenerationPeriod = $RegenerationPeriod

}

Add-AzureKeyVaultManagedStorageAccount @Parameters

clip_image012

Afin de vérifier la bonne mise en place, nous allons opérer une première rotation avec les commandes PowerShell suivantes :

Get-AzureRmStorageAccountKey -ResourceGroupName $ResourceGroupName -Name $storageAccountName

Update-AzureKeyVaultManagedStorageAccountKey -VaultName $keyVaultName -AccountName $storageAccountName -KeyName $StorageAccountKeyName

Get-AzureRmStorageAccountKey -ResourceGroupName $ResourceGroupName -Name $storageAccountName

clip_image013

 

A noter que la rotation n’a été configurée que pour la première « Access Key », pas pour la seconde. Maintenant, vous connaissez la manœuvre.

Quelques notes

  • A ce jour, la fonctionnalité « Customer-Managed keys » ne concerne que les services Blog et File, pas Table et queue qui continuent à utiliser la clé de chiffrement gérée par Microsoft
  • L’utilisation de la fonctionnalité « Soft delete » sur le keyvault a pour conséquence qu’après avoir supprimé un KeyVault, son nom n’est pas réutilisable avant 90 jours, temps nous permettant de le restaurer. Il est vivement recommandé de l’activer.
  • Pour la rotation des clés, le nom de la clé est nécessairement Key1, Key2. N’essayez pas d’utiliser d’autres noms. Conséquence, on ne peut pas avoir tous les « Access Keys » dans un Key Vault unique. Il faut autant de Key Vault que de Storage Accounts

 

Conclusion

Normalement, avec ces deux opérations le RSI/RSSI de votre entreprise devrait apprécier. Il dispose maintenant d’un bouton rouge pour forcer la régénération des clés d’accès au stockage. Pour ne pas casser vos applications / ressources Azure, la prochaine étape sera de les reconfigurer pour extraire l’information du Key Vault et non continuer à coder l’information en dur dans le code ou dans une variable Application Settings dans Web App.

BenoîtS – Simple and secure by design but Business compliant (with disruptive flag enabled)

Générer un certificat auto-signé avec Key-Vault

Pour ceux qui comme moi génèrent des certificats depuis longtemps, je suis passé par toutes les étapes (OpenSSL, New-SelfSignedCertificate). Avec Azure, il était logique que je regarde comment générer un certificat auto-signé. Le problème des solutions citées précédemment, c’était que le certificat était généré localement, dans le magasin personnel de la machine. Combien de fois avez-vous oublié le certificat et sa clé privée sur un serveur ou pire sur votre portable.

Avec Azure, l’usage des certificats s’est banalisé. On associe des Service Principals aux applications déclarées dans Azure AD que l’on consomme ensuite dans différents services (Azure Automation aujourd’hui par exemple). Pour cette raison, j’avais rapidement cherché un moyen de générer mes certificats auto-signés directement dans Azure. Logiquement, j’ai commencé par regarder le KeyVault. Une recherche rapide dans le module PowerShell associé me confirme que c’est bien prévu dans les scénarios du produit.

clip_image001

J’ai donc creusé un peu le sujet et voilà la version courte. On commence par préparer un objet CertificatePolicy :

$AutomationcertificateName = « LabAutomation »

$AutomationcertSubjectName = « cn= » + $AutomationcertificateName

$AutomationCertificateLifetimePolicy = 36

$Policy = New-AzureKeyVaultCertificatePolicy -SecretContentType « application/x-pkcs12 » -SubjectName $AutomationcertSubjectName -IssuerName « Self » -ValidityInMonths $AutomationCertificateLifetimePolicy -ReuseKeyOnRenewal

$Policy

clip_image002

 

Vous l’avez bien compris, on peut personnaliser avec beaucoup d’autres paramètres, mais on va faire court. Pour la suite, cela se passe avec la commande Add-AzureKeyVaultCertificate. Point de détail, la commande retourne un status, à nous de suivre jusqu’à ce que le certificat soit délivré :

$AddAzureKeyVaultCertificateStatus = Add-AzureKeyVaultCertificate -VaultName ‘mykeyvaultforcert’ -Name $AutomationcertificateName -CertificatePolicy $Policy

$AddAzureKeyVaultCertificateStatus.status

While ($AddAzureKeyVaultCertificateStatus.Status -eq « inProgress »)

{

Start-Sleep -Seconds 10

$AddAzureKeyVaultCertificateStatus = Get-AzureKeyVaultCertificateOperation -VaultName ‘mykeyvaultforcert’ -Name $AutomationcertificateName

$AddAzureKeyVaultCertificateStatus.status

}

$AddAzureKeyVaultCertificateStatus

clip_image003

 

Notre certificat auto-signé est maintenant dans le KeyVault, pour l’utiliser, ne nous reste plus qu’à l’exporter. La ça se complique un peu, il faut en passer par un peu de Dot.Net avec la classe X509Certificate2Collection. Dans le code ci-dessous, nous générons un fichier PFX contenant, le certificat, sa clé privée, le tout sécurité par un mot de passe (merci de fermer la session PowerShell après usage !)

$PfxCertPathForRunAsAccount = « C:\TEMP\CERTIFICATE.PFX »

$PfxCertPlainPasswordForRunAsAccount = « P@ssw0rd12345 »

$secretRetrieved = Get-AzureKeyVaultSecret -VaultName ‘mykeyvaultforcert’ -Name $AutomationcertificateName

$pfxBytes = [System.Convert]::FromBase64String($secretRetrieved.SecretValueText)

$certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection

$certCollection.Import($pfxBytes, $null, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)

$protectedCertificateBytes = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12, $PfxCertPlainPasswordForRunAsAccount)

[System.IO.File]::WriteAllBytes($PfxCertPathForRunAsAccount, $protectedCertificateBytes)

Get-ChildItem -Path « c:\temp\cert*.* »

clip_image004

 

Ne reste plus qu’à consommer. Avantage de cette approche, le certificat est préservé dans notre KeyVault. Dans mon contexte, Azure Automation est partie intégrante d’une solution en cours de développement, nous réinstancions donc plusieurs fois par jour nos instances.

 

BenoitS – Simple and Secure by design but Business compliant (with disruptive flag enabled)

Ma session au Powershell Saturday 2018

Ce samedi s’est déroulé l’édition française du PowerShell Saturday dans les locaux de Cellenza. Pendant, cette édition, j’ai eu l’occasion de présenter l’avancement sur Resource Group As a Service. Resource Group As a Service est un sujet que j’avais déjà présenté lors du Global Azure Bootcamp de 2018.

clip_image001

A l’époque, on était plus proche du PoC of Concept, entre temps, le développement a beaucoup avancé. Aujourd’hui, nous sommes maintenant plus proche du Minimum Viable Product. L’objectif de cette session n’était pas de présenter la solution en elle-même mais ce que son développement m’a permis d’apprendre sur Azure Function, Azure Automation et sur PowerShell lui-même. C’est donc plus une session de retour sur expérience.

Pour ceux que cela intéresse, la présentation ainsi que les exemples PowerShell présentés sont disponibles à cette URL.

 

Benoît – Simple and Secure by Design but Business compliant