Archives de catégorie : Azure

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.

Azure Managed Application – Astuces de debug

En ce moment, je passe beaucoup de temps dans Azure Managed Application. Pour les explications sur le sujet, je vous renvoie à mon billet « Publier une application Azure Managed Application avec BluePrint ». Pour rappel rapide, une Azure Managed Application est composée de deux fichiers :

  • Un template ARM décrivant l’interface graphique (createUiDefinition.JSON)
  • Un template ARM décrivant les ressources à déployer

 

Voilà deux astuces qui vont éviterons de perdre du temps.

 

Impossible de déployer

Vous tentez de déployer une nouvelle version de votre Managed Application, pourtant impossible de déclencher le déploiement. Dans le cas ci-dessous, il bloque sur l’interface de l’étape n°7 alors qu’il devrait commencer la validation des paramètres du template ARM.

clip_image002

 

On a beau cliquer sur OK, il refuse de passer à l’étape suivante. Le portail Azure n’affiche aucune information. Pour comprendre, il faut passer sous le capot et utiliser le mode Console de votre navigateur. Dans le cas ci-dessous, le problème se situe au niveau de ma section Output. Je tente de référencer une section « NetwSork » qui bien entendu n’existe pas. C’est fou le nombre de problème que cela m’a solutionné.

clip_image004

 

Erreur pendant le déploiement des ressources

Un des nombreux avantages de Azure Managed Applications, c’est que celui qui initie le déploiement n’a pas besoin de disposer des rôles nécessaires. C’est Managed Application qui se charge de réaliser le déploiement.

clip_image006

Donc si vous rencontrez des erreurs pendant le déploiement, demandez-vous de quelle permission dispose le Resource Provider Appliance Resource Provider ». Dans mon cas, je voulais utiliser un snapshot de Managed Disks pour construire des machines virtuelles. Problème pour réaliser un snapshot, il faut des permissions pour générer un disque à partir d’un snapshot. Regardons la liste des actions disponibles :

Get-AzResourceProviderAction | Where-Object {$_.operation -like « Microsoft.Compute/disks/* »} | select Operation, OperationName, ResourceName,Description

clip_image008

 

Deux permissions ont attiré mon attention :

  • Microsoft.Compute/disks/beginGetAccess/action
  • Microsoft.Compute/disks/endGetAccess/action

 

J’ai donc créé un Custom Role Azure AD contenant ces deux actions et je l’ai attribué au Service Principal associé à l’application « Appliance Resource Provider ».

 

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

Publier une application Azure Managed Application avec BluePrint

Après un premier billet sur la gouvernance on continue. BluePrint permet de standardiser nos souscriptions pour déployer des ressources (Templates ARM) et imposer des règles (Azure BluePrints). Combiné avec d’autres fonctionnalités, on peut encadrer l’usage qui est fait d’Azure en proposant nos propres services. C’est ce que je vous propose d’illustrer dans ce billet avec Azure Managed Application. Quand on développe des applications dans Azure, à un moment, il faut penser à les mettre à disposition, mieux les distribuer. C’est dans cette optique que Azure Managed Application a été développé. La fonctionnalité propose :

  • De packager notre application pour une mise à disposition au sein de notre souscription Azure (Service Catalog Managed Application
  • De devenir fournisseur de solution disponible sur le portail Azure (Marketplace Managed Application)

clip_image002

 

Voilà pour la version courte de Azure Managed Application. Pour la version longue, je vous renvoie vers la documentation officielle.

Pour ce billet, nous allons nous attarder sur la mise à disposition d’une application préalablement préparée au sein de notre souscription. Notre application sera relativement simple : Bastion as A Service. Je voulais fournir une machine virtuelle standardisée. A la base, je pensais utiliser DevTest pour proposer ce service. Cependant, DevTest ne respectait pas mes exigences de compliance. Je me suis donc rabattu sur Azure Managed Application pour proposer un service similaire. Cela présente que des avantages :

  • L’application sera instanciée à la demande. Pas d’usage, pas de machine virtuelle à sécuriser si elle n’existe pas
  • Les ressources composant la machine virtuelle ne doivent pas pouvoir être modifiées
  • Le consommateur doit cependant pouvoir supprimer l’application (même s’il n’a pas accès aux ressources mises à disposition par l’application)

 

Ce billet sera organisé en quatre étapes :

  • Etape n°1 : Mise à disposition des prérequis
  • Etape n°2 : Préparer notre application
  • Etape n°3 : Publication de notre application
  • Etape n°4 : Consommer notre application

 

Etape n°1 : Mise à disposition des prérequis

Notre Azure Managed Application va réutiliser le Virtual Network Spoke01Network mis à disposition dans le groupe de ressource du même nom dans ma souscription AzureTestLabs. Pour rappel, ce Virtual Network est configuré avec un accord de Peering vers un Virtual Network situé dans ma souscription « Hub ». Le Virtual Network comprend deux sous-réseaux :

  • Local
  • Spoke

C’est ce Virtual Network et ces subnets sur lesquels les futures cartes réseau pourront se raccorder.

 

Etape n°2 : Préparer notre application

Dans notre contexte, notre application est composée de deux éléments regroupés au sein d’un fichier ZIP nommé bastion.zip. Le package comprend :

C’est ce contenu que nous allons publier dans notre souscription. Du point de vue Azure, notre application sera un objet dans Azure. Nous allons donc créer un groupe de ressources nommé ManagedApplication dans notre souscription.

New-AzResourceGroup -ResourceGroupName ManagedApplication -Location WestEurope

clip_image004

 

Pour chaque application, nous devons associer une identité (utilisateur ou groupe) qui disposera d’un certain niveau de permissions sur les ressources déployées. Dans notre contexte, ce sera un groupe, qui disposera des permissions Azure les plus étendues sur les ressources liées aux machines virtuelles déployées.

$OwnerID = New-AzureADGroup -DisplayName « BastionOwners » -MailEnabled $false -SecurityEnabled $true -MailNickName « BastionOwners »

$OwnerID

clip_image006

 

Ce groupe devra disposer des privilèges, on va retenir Owner.

$roleid = (Get-AzRoleDefinition -Name Owner).id

$roleid

clip_image007

 

Le contenu de notre package est disponible sur ce repo Github : https://github.com/Benoitsautierecellenza/ManagedApplication/blob/master/Bastion.zip

La construction d’une interface graphique, c’est un fichier JSON : CreateUiDefinition elements. Ce qui est intéressant, c’est qu’il est possible de tester individuellement cette interface à l’aide du script SideLoad-CreateUIDefinition.ps1. Ce script va mettre à disposition notre fichier « createUiDefinition.json » dans un Storage Account accessible via une clé SAS. Nous serons directement connectés au portail Azure pour déployer notre application.

. .\SideLoad-CreateUIDefinition.ps1 -storageContainerName « test456 » -StorageResourceGroupLocation « WestEurope » -createUIDefFile .\createUiDefinition.JSON

clip_image009

 

L’instance de l’Azure Managed Application doit être hébergé dans un groupe de ressources dédié à cet usage (sans aucune autre ressources).

clip_image011

 

Mon application ayant pour objectif de mettre à disposition une machine virtuelle de type Bastion (sur socle Windows), le consommateur doit définir un compte Administrateur local ainsi que le mot de passe associé. Ce qui est intéressant à ce niveau, c’est que l’interface supporte les expressions régulières : CredentialsCombo.

clip_image013

 

Autre point intéressant, on peut filtrer la liste des tailles de machines virtuelles pour le SizeSelector. C’est plus intéressant que d’exprimer la limitation dans le template ARM.

clip_image015

 

Etape n°3 : Publication de notre application

L’application doit être mise à disposition dans notre application. En PowerShell, c’est la commande New-AzManagedApplicationDefinition qui va nous intéresser.

New-AzManagedApplicationDefinition -Name Bastion -ResourceGroupName ManagedApplications -DisplayName « Bastion as a service » -Description « Provide a bastion as a service » -Location « WestEurope » -LockLevel ReadOnly -PackageFileUri https://raw.githubusercontent.com/Benoitsautierecellenza/ManagedApplication/master/Bastion.zip -Authorization « $($ownerid.ObjectId):$RoleID »

clip_image017

 

Ça c’est pour la version simple (publier dans une souscription). Pour ceux qui veulent industrialiser le déploiement, un Export de BluePrint a été mis à disposition ici. Pour ceux que cela intéresse, un petit rappel : Découverte d’Azure BluePrint. Vu que c’est du déjà vu, on va se contenter de la version courte avec l’import avec Manage-AzureRmBluePrint. Après avoir cloné le repo depuis Azure Cloud Shell, ne reste plus qu’à réaliser l’import. C’est du prêt à consommer.

$SourceDirectory = « /home/by/ManagedApplication/DeployManagedApplications »

$DestinationSubscription = « <SubscriptionID> »

$Managementgroup = « <Management Group name> »

Manage-AzureRMBlueprint.ps1 -Mode Import -Module Az -ImportDir $SourceDirectory -SubscriptionID $DestinationSubscription -ManagementGroup $Managementgroup -Force

clip_image019

 

Je passe sur la publication du BluePrint pour m’attarder sur son assignation. Le template ARM qui est derrière (disponible ici) a besoin d’un certain nombre d’informations pour réaliser la publication, on retrouve donc les mêmes paramètres que pour la publication en PowerShell. Pour ceux que cela intéresse, c’est la classe ‘Microsoft.Solutions/applicationDefinitions’. Pour la structure du template ARM, c’est pas vraiment documenté en ARM, j’ai donc été chercher les informations à la source : Application Definitions – Create Or Update.

clip_image021

 

Avec le BluePrint mis à disposition ici, on devrait avoir un résultat comme illustré ci-dessous :

clip_image023

 

Etape n°4 : Consommer notre application

L’application étant représentée par un objet dans le portail Azure, on peut déclencher son déploiement à partir de là, avec le bouton « Deploy from definition ».

clip_image025

 

De là, on va retrouver l’interface de l’application (celle mise à disposition dans le fichier createUiDefinition.Json), je ne repasse donc pas dessus. Seul point d’attention, on doit déployer l’application dans un groupe de ressources vide.

clip_image026

 

Ce qui est intéressant, c’est le double déploiement qui va avoir lieu. Le premier déploiement, c’est l’application dans notre groupe de ressources.

clip_image028

 

Avec un peu de patience, on découvre notre application déployée. Un premier point d’attention avec la section « Parameters And Output.

clip_image030

 

Cette section référence les paramètres renseignés pendant le déploiement (qui en fait étaient des Outputs du fichier createUiDefinition.Json) pour alimenter en paramètres le template ARM mainTemplate.JSON)

clip_image032

 

Point intéressant dans ces paramètres, le paramètre expiration. Il référence une date à sept jours dans le futur. Cela me sera utile dans le template ARM mainTemplate.JSON pour positionner un tag de date d’expiration automatiquement. Le language utilisé pour générer l’interface graphique est assez riche : CreateUiDefinition functions. La section Output référence elle l’adresse IP privée de la carte réseau associée à la machine virtuelle nouvellement créée (aucune chance que la machine virtuelle soit exposée sur Internet).

Allons faire un tour dans le Managed Resource Group. C’est le groupe de ressources dans lequel toutes les ressources de notre application ont été déployées.

clip_image034

 

Ce qui est intéressant avec Azure Managed Application, c’est que même si nous avons la possibilité de supprimer l’instance de l’application déployée, nous ne pouvons en aucun cas toucher aux ressources mises à disposition. Dans mon contexte, je suis assuré que les caractéristiques des ressources liées à la machines virtuelles ne peuvent pas être altérées (ajout d’une adresse IP publique par exemple). Un Lock a été positionné sur le groupe de ressources mais même avec le rôle « Owner », je suis incapable de le supprimer.

 

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

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.

Découverte d’Azure BluePrint

Lorsqu’on consulte la documentation Azure sur le thème de la gouvernance, on constate que des services comme Azure BluePrint, Management Group et Azure Policies constituent un socle pour mettre en place nos infrastructures Azure en segmentant les périmètres en de multiples souscriptions. Mettre en œuvre ce type d’organisation implique d’industrialiser la mise en place des multiples souscriptions. C’est pour cela que la fonctionnalité BluePrint a été conçue.

Cette isolation implique de mettre à disposition des ressources partagées entre les multiples souscriptions. C’est le modèle Hub spoke network tologoly with shared services. Appliqué au niveau réseau, cela veut dire qu’on devra mettre en place des accords de Peerings entre un VNET dit « Hub » et les VNET dépendants des souscriptions. Selon la documentation Microsoft, cela se présente ainsi :

clip_image002

Dans ce billet, nous allons nous focaliser sur la mise en œuvre de l’interconnexion réseau en utilisant les Peerings ainsi qu’en s’assurant que tout le trafic sortant de ces nouveaux VNET soient automatiquement redirigés vers une instance du service Azure Firewall localisé dans notre souscription Hub. L’ensemble de ces opérations sera réalisé avec BluePrint.

Nous disposons d’un Virtual Network nommé « CoreNetwork » qui est localisé dans le Resource Group du même nom. Ce Groupe de ressource dépend de la souscription « Hub ». L’Azure BluePrint que nous allons mettre en œuvre va :

  • Créer le groupe de ressources « LocalNetwork » dans la souscription « Spoke »
  • Créer une instance de User-Defined Route Table pour envoyer le traffc sortant vers notre instance centrale d’Azure Firewall
  • Créer une instance de Virtual Network avec deux sous-réseaux pour lesquels la User-Defined Route aura été associée
  • Mettre en place un Peering entre ce nouveau Virtual Network et le « Core Network »
  • Verrouiller l’ensemble des ressources déployées

 

Etape n°1 : Le contexte avec Managed Identity

Le déploiement de ressources implique un contexte et donc une identité. Pour déployer nos ressources, nous allons utiliser une Managed Identity et plus particulièrement une identité de type « User-Assigned ». Nous allons commencer par créer cette identité qui sera ensuite utilisée lors de l’assignation de notre BluePrint. A ce jour, la fonctionnalité est encore en preview. C’est certainement pour cette raison que c’est encore un module AZ à part à installer avec la commande ci-dessous : install-module -Name Az.ManagedServiceIdentity

clip_image004

 

Ne nous reste plus qu’à mettre en œuvre notre User-Managed Idenity. C’est un objet au sens Azure, nous allons le créer dans la souscription « Hub » et plus particulièrement dans le groupe de ressources « CoreNetwork » à l’aide de la commande PowerShell suivante : New-AzUserAssignedIdentity -ResourceGroupName CoreNetwork -Name MIPeering

clip_image006

 

Notre identité devra disposer des permissions suivantes :

  • Souscription Hub : Network Contributor
  • Souscription Cible : Owner (car doit mettre en place des objets et assigner des permissions)

 

Nous allons donc commencer par nous positionner sur la souscription Hub

Set-AzContext -Subscriptionid <SubscriptionID for Hub subscription>

$identity = get-AzUserAssignedIdentity -ResourceGroupName CoreNetwork -name MIPeering

New-AzRoleAssignment -ResourceGroupName CoreNetwork -RoleDefinitionName « Network Contributor » -ObjectID $identity.PrincipalID

clip_image008

 

Puis nous allons nous repositionner sur la souscription « Hub » pour positionner les permissions :

Set-AzContext -Subscriptionid <SubscriptionID for Hub subscription>

New-AzRoleAssignment -RoleDefinitionName « Owner » -ObjectID $identity.PrincipalID -Scope « /subscriptions/$((get-azcontext).subscription.id) »

clip_image010

 

Etape n°2 : Manage-AzureRMBluePrint

A ce jour, Azure BluePrint est encore en Preview. Afin de palier à certains manques, la communauté a développé Manage-AzureRmBluePrint. Ce script permet d’importer/exporter des définitions de BluePrints entre différents environnements. Que ce soit dans CloudShell ou localement, nous devons commencer par déclarer la PSGallery de Microsoft comme une source d’installation sure à l’aide de la commande suivante :

Set-PSRepository -Name PSGallery -InstallationPolicy Trusted

clip_image012

 

Ne reste plus qu’à installer le script à l’aide de la commande suivante :

Install-script -Name Manage-AzureRmBluePrint

clip_image013

 

Maintenant, nous pouvons utiliser le script Manage-AzureRmBluePrint pour importer la définition qui a été mise à disposition ici. Avant de la rendre disponible sur Github, j’ai préparé la définition de ma Blueprint sur une souscription dédiée. Une fois au point, j’ai utilisé la fonctionnalité d’export de ManageAzurermBluePrint comme illustré ci-dessous :

$exportdir = « c:\temp\ »

manage-azurermblueprint -Mode Export -ModuleMode Az -ManagementGroupID « <Management Group> » -SubscriptionId « <SubscriptionID> » -BlueprintName SpokeCoreNetwork -ExportDir $ExportDir

clip_image015

 

Nous reviendrons sur le contenu de la BluePrint plus tard. Une fois uploadé sur Github, c’est prêt à consommer dans les autres souscriptions. Ce qui est bien c’est qu’on a GIT déjà présent dans CloudShell, pratique pour récupérer la dernière version de la politique mise à disposition. Pour faciliter les choses, le contenu est disponible à l’URL suivante : https://github.com/Benoitsautierecellenza/DemoBluePrint

clip_image017

 

Il ne nous reste plus qu’à importer notre BluePrint avec les commandes ci-dessous :

$SourceDirectory = « /home/by/DemoBluePrint/SpokeCoreNetwork »

$DestinationSubscription = « <Destination subscriptionID> »

$Managementgroup = « <Destination Management Group> »

Manage-AzureRMBlueprint.ps1 -Mode Import -Module Az -ImportDir $SourceDirectory -SubscriptionID $DestinationSubscription -ManagementGroup $Managementgroup -Force

clip_image019

 

Etape n°3 : Publication de notre Artefact BluePrint

Notre définition de BluePrint est maintenant disponible (dans le Management regroupant toutes mes souscriptions) sous forme de Draft.

clip_image021

 

Nous allons la publier en version 1.0. La notion de versionning deviendra importante dans BluePrint quand on procédera à des mises à jour.

clip_image023

 

Notre BluePrint est maintenant prête à l’emploi. Nous allons donc pouvoir l’assigner.

clip_image025

 

Etape n°4 : Assignation de Blueprint

Prochaine étape, c’est d’assigner ce BluePrint à une souscription dite « Spoke/Satellite » (Dépendant du même Tenant Azure AD). L’assignation sera réalisée :

  • Au niveau de la souscription dite « Spoke »
  • Dans une région azure donnée, en utilisant notre version précédemment publie de BluePrint
  • Le déploiement sera réalisé en utilisant notre User-Managed Identity

 

Une fois le déploiement terminé, les ressources seront lockées de manière à ce que même le owner la souscription dans laquelle on déploie ne puisse pas revoir la configuration des ressources

clip_image027

 

Le contenu du BluePrint est assez basique. Il créé un groupe de ressources et y déploie un Template ARM pour les ressources réseau. A ce jour, BluePrint prend en charge le déploiement des artefacts suivants :

  • Création de groupe de ressources
  • Assignation de rôles
  • Assignation de Policy Azure
  • Déploiement de templates ARM

 

Ce que nous voyons dans l’illustration ci-dessous, ce sont les paramètres de mon template ARM. On peut fournir les paramètres au niveau du BluePrint (donc commun à toutes les futures assignations) ou spécifique à chaque assignation, ce qui est mon cas. Le template ARM est disponible ici.

clip_image029

 

Si le déploiement se déroule normalement, on doit avoir le résultat ci-dessous :

clip_image031

 

A noter qu’il est possible de réaliser l’assignation en PowerShell avec le module AZ adéquat. Quand on voit sa version, on comprend qu’il est tout neuf et que c’est certainement pour cela qu’il n’est pas référencé en tant que dépendance AZ.

Install-Module -Name Az.Blueprint

Get-Command -Module Az.Blueprint

clip_image033

 

En termes de ressources, on doit avoir :

  • Un groupe de ressources nommé Spoke01Network
  • Un objet Route table pour mettre en place le routage des flux sortants vers une instance d’Azure Firewall situé dans notre souscription Hub
  • Un objet VNET comprenant deux sous-réseaux pour lesquels notre route table a été associée

clip_image035

 

Quand on creuse un peu plus la configuration, on retrouve bien les éléments configurés :

$vnet = Get-AzVirtualNetwork -ResourceGroupName Spoke01Network

$vnet | select-Object virtualNetworkPeerings -Expand virtualnetworkpeerings

$vnet.subnets | select name, routetable

clip_image037

 

Conclusion

BluePrint est certes encore en Preview mais il est déjà utilisable pour industrialiser la mise en place des socles infrastructure ainsi que pour la mise en place des Azure Policies. On attend le support de nouveaux artefacts prochainement. BluePrint nous offre la possibilité de travailler en mode « macro-management » à l’opposé des Resource Groups (Micro-Management).

 

BenoitS – 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.