diff --git a/helpers/GenerateResourcesAndImage.ps1 b/helpers/GenerateResourcesAndImage.ps1 index 921650010..9e88e8a8d 100644 --- a/helpers/GenerateResourcesAndImage.ps1 +++ b/helpers/GenerateResourcesAndImage.ps1 @@ -132,150 +132,172 @@ Function GenerateResourcesAndImage { [bool] $EnableHttpsTrafficOnly = $False ) - $builderScriptPath = Get-PackerTemplatePath -RepositoryRoot $ImageGenerationRepositoryRoot -ImageType $ImageType - $ServicePrincipalClientSecret = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper() - $InstallPassword = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper() - - if ([string]::IsNullOrEmpty($AzureClientId)) - { - Connect-AzAccount - } else { - $AzSecureSecret = ConvertTo-SecureString $AzureClientSecret -AsPlainText -Force - $AzureAppCred = New-Object System.Management.Automation.PSCredential($AzureClientId, $AzSecureSecret) - Connect-AzAccount -ServicePrincipal -Credential $AzureAppCred -Tenant $AzureTenantId - } - Set-AzContext -SubscriptionId $SubscriptionId - - $alreadyExists = $true; try { - Get-AzResourceGroup -Name $ResourceGroupName - Write-Verbose "Resource group was found, will delete and recreate it." + $builderScriptPath = Get-PackerTemplatePath -RepositoryRoot $ImageGenerationRepositoryRoot -ImageType $ImageType + $ServicePrincipalClientSecret = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper() + $InstallPassword = $env:UserName + [System.GUID]::NewGuid().ToString().ToUpper() + + if ([string]::IsNullOrEmpty($AzureClientId)) + { + Connect-AzAccount + } else { + $AzSecureSecret = ConvertTo-SecureString $AzureClientSecret -AsPlainText -Force + $AzureAppCred = New-Object System.Management.Automation.PSCredential($AzureClientId, $AzSecureSecret) + Connect-AzAccount -ServicePrincipal -Credential $AzureAppCred -Tenant $AzureTenantId + } + Set-AzContext -SubscriptionId $SubscriptionId + + $alreadyExists = $true; + try { + Get-AzResourceGroup -Name $ResourceGroupName + Write-Verbose "Resource group was found, will delete and recreate it." + } + catch { + Write-Verbose "Resource group was not found, will create it." + $alreadyExists = $false; + } + + if ($alreadyExists) { + if($Force -eq $true) { + # Cleanup the resource group if it already exitsted before + Remove-AzResourceGroup -Name $ResourceGroupName -Force + New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation + } else { + $title = "Delete Resource Group" + $message = "The resource group you specified already exists. Do you want to clean it up?" + + $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` + "Delete the resource group including all resources." + + $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", ` + "Keep the resource group and continue." + + $stop = New-Object System.Management.Automation.Host.ChoiceDescription "&Stop", ` + "Stop the current action." + + $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $stop) + $result = $host.ui.PromptForChoice($title, $message, $options, 0) + + switch ($result) + { + 0 { Remove-AzResourceGroup -Name $ResourceGroupName -Force; New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation } + 1 { <# Do nothing #> } + 2 { exit } + } + } + } else { + New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation + } + + # This script should follow the recommended naming conventions for azure resources + $storageAccountName = if($ResourceGroupName.EndsWith("-rg")) { + $ResourceGroupName.Substring(0, $ResourceGroupName.Length -3) + } else { $ResourceGroupName } + + # Resource group names may contain special characters, that are not allowed in the storage account name + $storageAccountName = $storageAccountName.Replace("-", "").Replace("_", "").Replace("(", "").Replace(")", "").ToLower() + $storageAccountName += "001" + + + # Storage Account Name can only be 24 characters long + if ($storageAccountName.Length -gt 24){ + $storageAccountName = $storageAccountName.Substring(0, 24) + } + + New-AzStorageAccount -ResourceGroupName $ResourceGroupName -AccountName $storageAccountName -Location $AzureLocation -SkuName "Standard_LRS" -AllowBlobPublicAccess $AllowBlobPublicAccess -EnableHttpsTrafficOnly $EnableHttpsTrafficOnly + + if ([string]::IsNullOrEmpty($AzureClientId)) { + # Interactive authentication: A service principal is created during runtime. + $spDisplayName = [System.GUID]::NewGuid().ToString().ToUpper() + $startDate = Get-Date + $endDate = $startDate.AddYears(1) + + if ('Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential' -as [type]) { + $credentials = [Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential]@{ + StartDate = $startDate + EndDate = $endDate + Password = $ServicePrincipalClientSecret + } + $sp = New-AzADServicePrincipal -DisplayName $spDisplayName -PasswordCredential $credentials + $spClientId = $sp.ApplicationId + $azRoleParam = @{ + RoleDefinitionName = "Contributor" + ServicePrincipalName = $spClientId + } + } + + if ('Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential' -as [type]) { + $credentials = [Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential]@{ + StartDateTime = $startDate + EndDateTime = $endDate + } + $sp = New-AzADServicePrincipal -DisplayName $spDisplayName + $appCred = New-AzADAppCredential -ApplicationId $sp.AppId -PasswordCredentials $credentials + $spClientId = $sp.AppId + $azRoleParam = @{ + RoleDefinitionName = "Contributor" + PrincipalId = $sp.Id + } + $ServicePrincipalClientSecret = $appCred.SecretText + } + + Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup + New-AzRoleAssignment @azRoleParam + Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup + $sub = Get-AzSubscription -SubscriptionId $SubscriptionId + $tenantId = $sub.TenantId + + # Remove ADPrincipal after the script completed + $isCleanupADPrincipal = $true + } else { + # Parametrized Authentication via given service principal: The service principal with the data provided via the command line + # is used for all authentication purposes. + $spClientId = $AzureClientId + $credentials = $AzureAppCred + $ServicePrincipalClientSecret = $AzureClientSecret + $tenantId = $AzureTenantId + } + + Get-LatestCommit -ErrorAction SilentlyContinue + + $packerBinary = Get-Command "packer" + if (-not ($packerBinary)) { + throw "'packer' binary is not found on PATH" + } + + if($RestrictToAgentIpAddress -eq $true) { + $AgentIp = (Invoke-RestMethod http://ipinfo.io/json).ip + Write-Host "Restricting access to packer generated VM to agent IP Address: $AgentIp" + } + + & $packerBinary build -on-error=ask ` + -var "client_id=$($spClientId)" ` + -var "client_secret=$($ServicePrincipalClientSecret)" ` + -var "subscription_id=$($SubscriptionId)" ` + -var "tenant_id=$($tenantId)" ` + -var "location=$($AzureLocation)" ` + -var "resource_group=$($ResourceGroupName)" ` + -var "storage_account=$($storageAccountName)" ` + -var "install_password=$($InstallPassword)" ` + -var "allowed_inbound_ip_addresses=$($AgentIp)" ` + $builderScriptPath } catch { - Write-Verbose "Resource group was not found, will create it." - $alreadyExists = $false; + Write-Error $_ } + finally { + # Remove ADServicePrincipal and ADApplication + if ($isCleanupADPrincipal) { + Write-Host "`nRemoving ${spDisplayName}/${spClientId}:" + if (Get-AzADServicePrincipal -DisplayName $spDisplayName) { + Write-Host " [+] ADServicePrincipal" + Remove-AzADServicePrincipal -DisplayName $spDisplayName -Confirm:$false + } - if ($alreadyExists) { - if($Force -eq $true) { - # Cleanup the resource group if it already exitsted before - Remove-AzResourceGroup -Name $ResourceGroupName -Force - New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation - } else { - $title = "Delete Resource Group" - $message = "The resource group you specified already exists. Do you want to clean it up?" - - $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", ` - "Delete the resource group including all resources." - - $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", ` - "Keep the resource group and continue." - - $stop = New-Object System.Management.Automation.Host.ChoiceDescription "&Stop", ` - "Stop the current action." - - $options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $stop) - $result = $host.ui.PromptForChoice($title, $message, $options, 0) - - switch ($result) - { - 0 { Remove-AzResourceGroup -Name $ResourceGroupName -Force; New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation } - 1 { <# Do nothing #> } - 2 { exit } + if (Get-AzADApplication -DisplayName $spDisplayName) { + Write-Host " [+] ADApplication" + Remove-AzADApplication -DisplayName $spDisplayName -Confirm:$false } } - } else { - New-AzResourceGroup -Name $ResourceGroupName -Location $AzureLocation } - - # This script should follow the recommended naming conventions for azure resources - $storageAccountName = if($ResourceGroupName.EndsWith("-rg")) { - $ResourceGroupName.Substring(0, $ResourceGroupName.Length -3) - } else { $ResourceGroupName } - - # Resource group names may contain special characters, that are not allowed in the storage account name - $storageAccountName = $storageAccountName.Replace("-", "").Replace("_", "").Replace("(", "").Replace(")", "").ToLower() - $storageAccountName += "001" - - - # Storage Account Name can only be 24 characters long - if ($storageAccountName.Length -gt 24){ - $storageAccountName = $storageAccountName.Substring(0, 24) - } - - New-AzStorageAccount -ResourceGroupName $ResourceGroupName -AccountName $storageAccountName -Location $AzureLocation -SkuName "Standard_LRS" -AllowBlobPublicAccess $AllowBlobPublicAccess -EnableHttpsTrafficOnly $EnableHttpsTrafficOnly - - if ([string]::IsNullOrEmpty($AzureClientId)) { - # Interactive authentication: A service principal is created during runtime. - $spDisplayName = [System.GUID]::NewGuid().ToString().ToUpper() - $startDate = Get-Date - $endDate = $startDate.AddYears(1) - - if ('Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential' -as [type]) { - $credentials = [Microsoft.Azure.Commands.ActiveDirectory.PSADPasswordCredential]@{ - StartDate = $startDate - EndDate = $endDate - Password = $ServicePrincipalClientSecret - } - $sp = New-AzADServicePrincipal -DisplayName $spDisplayName -PasswordCredential $credentials - $spClientId = $sp.ApplicationId - $azRoleParam = @{ - RoleDefinitionName = "Contributor" - ServicePrincipalName = $spClientId - } - } - - if ('Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential' -as [type]) { - $credentials = [Microsoft.Azure.PowerShell.Cmdlets.Resources.MSGraph.Models.ApiV10.MicrosoftGraphPasswordCredential]@{ - StartDateTime = $startDate - EndDateTime = $endDate - } - $sp = New-AzADServicePrincipal -DisplayName $spDisplayName - $appCred = New-AzADAppCredential -ApplicationId $sp.AppId -PasswordCredentials $credentials - $spClientId = $sp.AppId - $azRoleParam = @{ - RoleDefinitionName = "Contributor" - PrincipalId = $sp.Id - } - $ServicePrincipalClientSecret = $appCred.SecretText - } - - Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup - New-AzRoleAssignment @azRoleParam - Start-Sleep -Seconds $SecondsToWaitForServicePrincipalSetup - $sub = Get-AzSubscription -SubscriptionId $SubscriptionId - $tenantId = $sub.TenantId - # "", "Note this variable-setting script for running Packer with these Azure resources in the future:", "==============================================================================================", "`$spClientId = `"$spClientId`"", "`$ServicePrincipalClientSecret = `"$ServicePrincipalClientSecret`"", "`$SubscriptionId = `"$SubscriptionId`"", "`$tenantId = `"$tenantId`"", "`$spObjectId = `"$spObjectId`"", "`$AzureLocation = `"$AzureLocation`"", "`$ResourceGroupName = `"$ResourceGroupName`"", "`$storageAccountName = `"$storageAccountName`"", "`$install_password = `"$install_password`"", "" - } else { - # Parametrized Authentication via given service principal: The service principal with the data provided via the command line - # is used for all authentication purposes. - $spClientId = $AzureClientId - $credentials = $AzureAppCred - $ServicePrincipalClientSecret = $AzureClientSecret - $tenantId = $AzureTenantId - } - - Get-LatestCommit -ErrorAction SilentlyContinue - - $packerBinary = Get-Command "packer" - if (-not ($packerBinary)) { - throw "'packer' binary is not found on PATH" - } - - if($RestrictToAgentIpAddress -eq $true) { - $AgentIp = (Invoke-RestMethod http://ipinfo.io/json).ip - Write-Host "Restricting access to packer generated VM to agent IP Address: $AgentIp" - } - - & $packerBinary build -on-error=ask ` - -var "client_id=$($spClientId)" ` - -var "client_secret=$($ServicePrincipalClientSecret)" ` - -var "subscription_id=$($SubscriptionId)" ` - -var "tenant_id=$($tenantId)" ` - -var "location=$($AzureLocation)" ` - -var "resource_group=$($ResourceGroupName)" ` - -var "storage_account=$($storageAccountName)" ` - -var "install_password=$($InstallPassword)" ` - -var "allowed_inbound_ip_addresses=$($AgentIp)" ` - $builderScriptPath }