Automatiser les demandes de rôles élevés pour les ressources Azure avec Power Automate et Azure Automation

Automatiser les demandes de rôles élevés pour les ressources Azure avec Power Automate et Azure Automation

Adam MaurerTechnical Leave a Comment

Image
1. Dans un abonnement Azure de votre choix, créez une ressource Compte d'automatisation en visitant portal.azure.com, sélectionnez Toutes les ressources et cliquez sur Ajouter.

a. Rechercher "Automatisation" et cliquer sur Créer.

Automatisation

Remplissez tous les champs nécessaires du formulaire de création d'une automatisation et cliquez sur Créer

Image

b. Importer les modules AzureAD
c. Pour ce faire, ouvrez le compte d'automatisation que nous venons de créer, sélectionnez Modules situé sous Ressources partagées, sélectionnez Parcourir la galerieet rechercher AzureAD.

Modules

d. Importer le AzureAD et attendez que le processus se termine avec succès.

2. Créer Cahiers d'adresses

a. Accédez à votre compte d'automatisation, sélectionnez Cahiers d'adresseset cliquez sur Créer un Runbook.

Rubooks

b. Lorsque le Runbook est créé, cliquez sur Editer et collez votre script PowerShell puis cliquez sur Économiser et Publier.


3. Le script ci-dessous peut être utilisé pour élever l'accès d'un utilisateur au rôle de contributeur et déclenche des courriels en cas d'erreur. Le script vérifie d'abord si l'utilisateur a déjà un rôle de lecteur attribué à l'abonnement pour lequel il souhaite obtenir un accès élevé. Si ce n'est pas le cas, il se trompe. Si l'utilisateur a déjà un rôle de contributeur sur la ressource demandée, il y aura également une erreur.

Les zones mises en évidence doivent être adaptées aux détails de votre environnement.

param (
[Paramètre(Obligatoire = $true)]
[string] $subscriptionId,
[Parameter(Mandatory = $true)]
[string] $resourceGroupName,
[Parameter(Mandatory = $true)] [string] $resourceGroupName, [Parameter(Mandatory = $true)]
[string] $resourceName,
[Paramètre(Obligatoire = $true)]
[string] $resourceType,
[Parameter(Mandatory = $true)] [string] $resourceType, [Parameter(Mandatory = $true)]
[string] $userPrincipalName,
[Paramètre(Obligatoire = $false)]
[string] $linkUrl
)
$ErrorActionPreference = "Continuer" $errors = @() function Send-Email($subject, $body, $to, $cc = $null, $isBodyHtml = $false) { $credential = Get-AutomationPSCredential -Name 'SMTP Relay' (Relais SMTP) $smtpServer = 'smtp.example.com' $smtpPort = <Int32> $from = example@examplecompany.com $mailParams = @{ To = $to Objet = $subject Corps = $body SmtpServer = $smtpServer Credential = $credential Port = $smtpPort UseSsl = $true From = $from BodyAsHtml = $isBodyHtml } if ($cc) { $mailParams['Cc'] = $cc } Send-MailMessage @mailParams -ErrorAction Stop } try { $connection = Connect-AzAccount -Identity } catch { $errors += "Échec de l'authentification auprès d'Azure à l'aide de Managed Identity :$_" } try { Set-AzContext -SubscriptionId $subscriptionId } catch { $errors += "Échec de la définition du contexte d'abonnement Azure :$_" } $roleDefinitionName = 'Contributor' $readerRoleDefinitionName = 'Lecteur' try { $user = Get-AzADUser -UserPrincipalName $userPrincipalName -ErrorAction Stop } catch { $errors += "Échec de la récupération de l'objet utilisateur pour l'UPN '$userPrincipalName' : $_" } # Vérifier si l'utilisateur a le rôle de lecteur au niveau de l'abonnement $readerRoleAssignment = Get-AzRoleAssignment -ObjectId $user.Id -RoleDefinitionName $readerRoleDefinitionName -Scope "/subscriptions/$subscriptionId" -ErrorAction SilentlyContinue if (-not $readerRoleAssignment) { $noReaderRoleHtml = @" <h2>Pas dans le rôle de lecteur</h2>
<p>Utilisateur <strong>$userPrincipalName</strong> ne dispose pas de la <strong>$readerRoleDefinitionName</strong> au niveau de l'abonnement et ne peut pas être ajouté au rôle de <strong>$roleDefinitionName</strong> pour la ressource.</p> "@ $noReaderRoleHtml += $signature Send-Email -subject "Missing Reader Role" -body $noReaderRoleHtml -to $userPrincipalName -cc "itadministrator@examplecompany.com"-isBodyHtml $true retour } # Vérifier si le groupe de ressources existe $resourceGroupExists = $true $resourceGroup = Get-AzResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue if (-not $resourceGroup) { $errors += "Le groupe de ressources '$resourceGroupName' n'existe pas." $resourceGroupExists = $false } # Vérifier si la ressource existe dans le groupe de ressources $domain = "votredomaine.onmicrosoft.com"# remplacer par votre domaine de locataire AAD réel # Vérifier si la ressource existe dans le groupe de ressources en utilisant à la fois le nom et le type $resourceExists = $false $resourceUrl = "" if ($resourceGroupExists) { $resources = Get-AzResource -ResourceGroupName $resourceGroupName -ResourceType $resourceType -Name $resourceName -ErrorAction SilentlyContinue $resource = $resources | Where-Object { $_.ResourceType -eq $resourceType -and $_.Name -eq $resourceName } if ($resource) { $resourceExists = $true # Construire l'URL à l'aide du domaine, du groupe de ressources, du type de ressource et du nom de la ressource $resourceUrl = "https://portal.azure.com/#@$domain/resourcegroups/$resourceGroupName/providers/$($resource.ResourceType)/$resourceName" } else { $errors += "La ressource de type '$resourceType' avec le nom '$resourceName' n'existe pas dans le groupe de ressources '$resourceGroupName'." } } # Tentative d'attribution de rôle uniquement si le groupe de ressources et la ressource existent if ($resourceGroupExists -and $resourceExists) { try { $roleAssignment = New-AzRoleAssignment -ObjectId $user.Id -RoleDefinitionName $roleDefinitionName -Scope $resource.ResourceId -ErrorAction Stop } catch { if ($_.Exception -match 'Conflict') { # L'utilisateur a déjà le rôle de contributeur, envoyer un email spécifique $alreadyContributorHtml = @" <h2>Utilisateur Déjà un contributeur</h2>             <p>Utilisateur<strong>$userPrincipalName</strong>dispose déjà de la<strong>$roleDefinitionName</strong>rôle pour la ressource<strong>$resourceName</strong>.</p>             <p>URL de la ressource :<a href='$linkUrl'>$linkUrl</a></p> "@ $alreadyContributorHtml += $signature Send-Email -subject "User Already Has Contributor Role" -body $alreadyContributorHtml -to $userPrincipalName -cc "itadministrator@examplecompany.com"-isBodyHtml $true } else { $errors += "Échec de l'attribution du rôle '$roleDefinitionName' à l'utilisateur '$userPrincipalName' : $_" } } } $signature = @" <p>Je vous prie d'agréer, Madame, Monsieur, l'expression de mes salutations distinguées,</p> <p><strong>Votre équipe informatique</strong></p> <p><em>Il s'agit d'un message automatisé, veuillez ne pas répondre directement à cet e-mail.</em></p> "@ if ($errors) { $errorMessageHtml = "<h2>Problèmes détectés lors de l'attribution des rôles dans Azure</h2><ul>" foreach ($errorItem in $errors) { $errorMessageHtml += "<li>$errorItem</li>" } $errorMessageHtml += "</ul>$signature" Send-Email -subject "Azure Role Assignment Issues" -body $errorMessageHtml -to $userPrincipalName -cc "itadministrator@examplecompany.com"-isBodyHtml $true elseif ($roleAssignment) { # L'attribution de rôle a réussi, envoyer un e-mail de réussite $successMessageHtml = @"<h2>Succès de l'attribution des rôles</h2>     <p>Utilisateur<strong>$userPrincipalName</strong>s'est vu attribuer avec succès le<strong>$roleDefinitionName</strong>rôle pour la ressource<strong>$resourceName</strong>.</p>     <p>URL de la ressource :<a href='$linkUrl'>$linkUrl</a></p> "@ $successMessageHtml += $signature Send-Email -subject "Azure Role Assignment Success" -body $successMessageHtml -to $userPrincipalName -cc "itadministrator@examplecompany.com"-isBodyHtml $true }

Veuillez noter que les scripts PowerShell ci-dessus et ci-dessous prennent environ 5 minutes avant de se terminer, car les modules AzureAD prennent du temps à se charger.

Notez également que lors de l'ajout d'un nouveau rôle tel que celui de contributeur, l'utilisateur doit se déconnecter et se reconnecter à Azure ou utiliser une fenêtre Incognito/Privée pour que le nouveau rôle prenne effet.

4. Un second Runbook doit être créé pour supprimer le rôle de contributeur au terme d'une période définie.

Voici un exemple de script PowerShell :

  param (
[Paramètre(Obligatoire = $true)]
[string] $subscriptionId,
[Parameter(Mandatory = $true)]
[string] $resourceGroupName,
[Parameter(Mandatory = $true)] [string] $resourceGroupName, [Parameter(Mandatory = $true)]
[string] $resourceName,
[Paramètre(Obligatoire = $true)]
[string] $resourceType,
[Parameter(Mandatory = $true)] [string] $resourceType, [Parameter(Mandatory = $true)]
[string] $userPrincipalName,
[Paramètre(Obligatoire = $false)]
[string] $linkUrl
)

$ErrorActionPreference = "Continue"
$errors = @()
$signature = @" 

<p>Je vous prie d'agréer, Madame, Monsieur, l'expression de mes salutations distinguées,</p> <p><strong>Votre équipe informatique</strong></p> <p><em>Il s'agit d'un message automatisé, veuillez ne pas répondre directement à cet e-mail.</em></p> "@ function Send-Email($subject, $body, $to, $cc = $null, $isBodyHtml = $false) { $credential = Get-AutomationPSCredential -Name 'SMTP Relay' (Relais SMTP) $smtpServer = 'smtp.example.com' $smtpPort =<int 32> $from = 'example@examplecompany.com' $mailParams = @{ To = $to Sujet = $subject Corps = $body SmtpServer = $smtpServer Credential = $credential Port = $smtpPort UseSsl = $true From = $from BodyAsHtml = $isBodyHtml } if ($cc) { $mailParams['Cc'] = $cc } Send-MailMessage @mailParams -ErrorAction Stop } try { $connection = Connect-AzAccount -Identity } catch { $errors += "Échec de l'authentification auprès d'Azure à l'aide de Managed Identity :$_" } try { Set-AzContext -SubscriptionId $subscriptionId } catch { $errors += "Échec de la définition du contexte d'abonnement Azure :$_" } $roleDefinitionName = 'Contributor' try { $user = Get-AzADUser -UserPrincipalName $userPrincipalName -ErrorAction Stop } catch { $errors += "Échec de la récupération de l'objet utilisateur pour l'UPN '$userPrincipalName' : $_" }

Pas dans le rôle de lecteur

# Vérifier si le groupe de ressources existe et obtenir la ressource
$resourceGroupExists = $resourceExists = $false
if ((Get-AzResourceGroup -Name $resourceGroupName -ErrorAction SilentlyContinue)) {
$resourceGroupExists = $true
$resources = Get-AzResource -ResourceGroupName $resourceGroupName -ResourceType $resourceType -Name $resourceName -ErrorAction SilentlyContinue
$resource = $resources | Where-Object { $_.ResourceType -eq $resourceType -and $_.Name -eq $resourceName }

if ($resource) {

$resourceExists = $true

} else {
$errors += "La ressource de type '$resourceType' avec le nom '$resourceName' n'existe pas dans le groupe de ressources '$resourceGroupName'."
}
} else {

$errors += "Le groupe de ressources '$resourceGroupName' n'existe pas."
}

# Tentative de suppression de l'attribution de rôle si le groupe de ressources et la ressource existent

if ($resourceGroupExists -and $resourceExists) {
try {

$roleAssignments = Get-AzRoleAssignment -ObjectId $user.Id -RoleDefinitionName $roleDefinitionName -Scope $resource.ResourceId -ErrorAction SilentlyContinue

foreach ($roleAssignment in $roleAssignments) {

# Remarque : la suppression de la confirmation fonctionnera si la cmdlet la prend en charge.
Remove-AzRoleAssignment -ObjectId $user.Id -RoleDefinitionName $roleDefinitionName -Scope $resource.ResourceId -Confirm:$false

}

# Vérifier si les attributions de rôle ont été supprimées avec succès
if (-not (Get-AzRoleAssignment -ObjectId $user.Id -RoleDefinitionName $roleDefinitionName -Scope $resource.ResourceId -ErrorAction SilentlyContinue)) {

# Si la suppression est réussie, envoyer un courriel de réussite
$successMessageHtml = @"<h2>Succès du retrait des rôles</h2> 
            <p>Utilisateur<strong>$userPrincipalName</strong>a été supprimée avec succès de la base de données<strong>$roleDefinitionName</strong>rôle pour la ressource<strong>$resourceName</strong>.</p>
            <p>URL de la ressource :<a href='$linkUrl'>$linkUrl</a></p> 
"@
$successMessageHtml += $signature
  Send-Email -subject "Azure Role Removal Success" -body $successMessageHtml -to $userPrincipalName -cc "itadministrator@examplecompany.com "-isBodyHtml $true
} else {
$errors += "Le rôle '$roleDefinitionName' existe toujours pour l'utilisateur '$userPrincipalName' après une tentative de suppression."
}

} } catch {
$errors += "Échec de la suppression du rôle '$roleDefinitionName' de l'utilisateur '$userPrincipalName' : $_"
}

}

if ($errors) {
$errorMessageHtml = "<h2>Problèmes détectés lors de la suppression d'un rôle dans Azure</h2><ul>"
foreach ($errorItem in $errors) {
$errorMessageHtml += "<li>$errorItem</li>"
}
$errorMessageHtml += "</ul>$signature"
  Send-Email -subject "Azure Role Removal Issues" -body $errorMessageHtml -to $userPrincipalName -cc "itadministrator@examplecompany.com"-isBodyHtml $true

} 

5. Attribuez au compte d'automatisation le rôle d'administrateur d'accès utilisateur par abonnement.

a. Pour que le script PowerShell puisse être exécuté, le compte d'automatisation doit avoir le rôle d'administrateur d'accès utilisateur.
b. Ajouter un rôle dans chaque abonnement où vous souhaitez que l'accès élevé soit demandé.
c. Dans la section Rôle, sélectionnez Accès utilisateur Administrateur puis cliquez sur Suivant.

add-role-assignment

d. Dans la section Membres, sélectionnez Gestion de l'identité puis + Sélectionner les membres, sélectionnez l'option Abonnement où le compte d'automatisation est en cours d'exécution, sélectionnez l'identité gérée et le membre dans le champ Select.

e. Le membre sélectionné apparaît en bas de l'écran, puis cliquez sur Sélectionner et Réviser + assigner.

Image

f. L'application Automation Account Enterprise sera désormais visible dans le(s) abonnement(s) comme ayant le rôle d'administrateur d'accès de l'utilisateur sous le nom de Contrôle d'accès (IAM)

Image

6. Créez un formulaire Microsoft demandant l'URL de la ressource et toute autre information requise en fonction de vos besoins professionnels. Dans l'exemple ci-dessous, nous demandons la raison de l'activité et le nombre d'heures d'accès à la ressource, avec un maximum de 8 heures à sélectionner dans la liste déroulante.

azure-subscription-access-request

7. Configurer un Groupe de sécurité dans Office Admin

a. Attribuez les membres autorisés à faire la demande d'accès élevé. (Facultatif mais fortement recommandé - Si vous ne souhaitez pas effectuer ce contrôle de sécurité, passez à la création du flux ci-dessous - Étape 9)

équipes et groupes actifs

b.Une fois le groupe de sécurité créé, notez l'identifiant du groupe de sécurité situé dans l'URL. Par exemple, l'identifiant du groupe de sécurité est le GUID situé ici :

https://admin.microsoft.com/Adminportal/Home#/groups/:/GroupDetails/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/1

8. Enregistrer une application dans portal.azure.com

a. Consentement de l'administration de la subvention à la suivante Microsoft Graph Permissions API avec type Application:

      • Répertoire.Lire.tout
      • Groupe. Lire.Tout
      • Utilisateur.Lire.tout
config-permissions

b. Créer un Secret du client pour l'application et prendre note de la ID du locatairel ID de l'application (client) et le secret Valeur pour le flux.

secret-client

8. Configurez maintenant un flux pour traiter les données du formulaire et exécuter les scripts PowerShell :

a. Déclencheur Microsoft Forms - Lorsqu'une nouvelle réponse est soumise

b. Action Microsoft Forms - Obtenir les détails de la réponse à partir du déclencheur responseId

c. Si vous avez ignoré la recommandation relative au groupe de sécurité, passez à l'étape 10 ci-dessous.

I. Obtenir le profil de l'utilisateur (v2) en utilisant le déclencheur comme utilisateur (UPN)

II. Pour valider que l'utilisateur fait partie du groupe de sécurité, créez une requête HTTP GET à l'URI : https://graph.microsoft.com/v1.0/groups/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx/transitiveMembers?$filter=id eq 'outputs('Get_user_profile_(V2) ') ?['body/id']'&$select=id

graphique-part01

III. Dans la requête HTTP GET, développez la section Authentification et assurez-vous que le type d'authentification est bien Active Directory OAuthLe public est https://graph.microsoft.com/et que les valeurs notées lors de l'enregistrement de l'application dans Azure sont ajoutées aux champs respectifs :

formulaire

IV. Send an email to IT Admin if request rejected (Envoyer un courriel à l'administrateur informatique si la demande est rejetée) est activé si la validation du groupe de sécurité ne permet pas d'obtenir un enregistrement. Un courriel est alors envoyé au demandeur pour l'informer qu'il ne fait pas partie du groupe de sécurité autorisé à faire une telle demande.

Image

V. Il convient de noter que le contrôle de sécurité susmentionné peut également être géré directement dans l'accès au formulaire Microsoft, mais le groupe de sécurité est la solution la plus sûre, qui nécessite moins de maintenance :

paramètres

10. Créez une condition pour vérifier si les URL fournies pour obtenir un accès élevé figurent dans la liste des abonnements pour lesquels vous les autoriserez à demander un accès élevé.

Image

a. Pour analyser l'abonnement à partir de l'URL fournie, utilisez l'expression suivante, en remplaçant la valeur Get_response_details mise en évidence, qui pointe vers le champ URL de votre formulaire :

first(split(last(split(body('Get_response_details') ?['URLfieldID'],'/resource/subscriptions/')),'/resourceGroups/'))

b. Si l'URL correspond à un abonnement qui ne figure pas dans la liste, envoyer un courriel de rejet à l'auteur de la demande.

c. Si l'URL contient un abonnement dans la liste, passez à la section Création d'une tâche Azure Automation.

11. Dans l'action Azure Automation, assurez-vous de remplir toutes les valeurs surlignées, en pointant vers le Runbook qui accorde l'accès élevé de Contributeur.

a. Abonnement = L'abonnement dans lequel le Runbook est

b. Resource Group = Groupe de ressources dans lequel le Runbook se trouve

c. Compte d'automatisation = Le compte d'automatisation qui a été configuré précédemment b

d. Nom du Runbook = Nom du Runbook auquel le rôle Contributeur doit être attribué

e. Une fois le Runbook sélectionné, les paramètres du script PowerShell s'affichent pour que vous puissiez ajouter les détails nécessaires. Pour analyser ces informations à partir de l'URL fournie lors de la soumission du formulaire :

I. AbonnementId

first(split(last(split(body('Get_response_details') ?['URLfieldID'],'/resource/subscriptions/')),'/resourceGroups/'))

II. Nom du groupe de ressources

first(split(last(split(body('Get_response_details') ?['URLfieldID'],'/resourceGroups/')),'/providers/'))

III. Nom du groupe de ressources

first(split(first(split(last(split(body('Get_response_details') ?['URLfieldID'],'/providers/')),concat('/',last(split(body('Get_response_details') ?['URLfieldID'],'/'))))),concat('/',last(split(first(split(last(split(body('Get_response_details') ?['URLfieldID'],'/providers/')),concat('/',last(split(body('Get_response_details') ?['URLfieldID'],'/'))))),'/')))))

IV. Nom de l'utilisateur

body('Get_response_details') ?['responder']

V. Nom de la ressource

last(split(first(split(last(split(body('Get_response_details') ?['URLfieldID'],'/providers/')),concat('/',last(split(body('Get_response_details') ?['URLfieldID'],'/'))))),'/'))

VI. Lien (LinkUrl)

body('Get_response_details') ?['URLfieldID']

formulaire02
Notez que le type de ressource n'est techniquement pas nécessaire pour que le script s'exécute. uniquement si vous disposez d'une convention de dénomination garantissant que chaque nom de ressource au sein d'un groupe de ressources est unique. Pour éviter les erreurs dans l'attribution du rôle de contributeur, il est recommandé de le conserver dans le script.

12. Dans cet exemple, nous permettons à l'utilisateur de définir la durée pendant laquelle il a besoin d'un accès en hauteur. Dans le délai, le compte est défini par le nombre d'heures indiqué dans le champ du formulaire, tandis que l'unité est l'heure.

13. Après le délai, nous créons une nouvelle action Azure Automation, pointant cette fois vers le Runbook qui supprime le rôle de Contributeur pour l'utilisateur sur cette ressource particulière.

a. Les champs sont identiques à ceux permettant d'attribuer le rôle de contributeur, de même que l'analyse des paramètres respectifs.

Voici quelques idées qui peuvent être adaptées ou ajoutées à ce flux et que nous n'aborderons pas :

  1. Utilisez votre système de billetterie interne comme déclencheur plutôt que Microsoft Forms.
  2. Permettre à l'utilisateur de sélectionner le groupe de ressources et/ou le niveau d'accès à l'abonnement, en fonction de ses besoins. Il est à noter que certaines expressions d'analyse seront modifiées à cette occasion.
  3. Ajouter un flux d'approbation envoyé à une personne ou un groupe de personnes ayant la possibilité d'approuver ou de refuser la demande.

Laisser un commentaire

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

For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.