Añadir usuario de Azure AD como administrador en una VM de Azure

Leyendo el título de esta entrada algunos dirán que porque me complico tanto la vida y no agrego a los usuarios como administradores de las VM mediante GPO si estas van a estar en dominio.

Pues bien, pongámonos en el caso que necesitamos agregar al responsable del despliegue de la VM como administrador (o a cualquier otro usuario) de manera automatizada y esta persona no debe tener permisos como admin local en ninguna otra VM que no sea esta.

La solución con la que di pese a que pueda parecer rebuscada, es la más sencilla de todas. Inyectar una extensión que incluya un custom script.

A continuación os muestro el proceso:

En primer lugar debemos generar y guardar un script que añadirá a un usuario como administrador local y que queremos añadir como extensión, en una Storage Account de Azure (En mi caso he creado un contenedor llamado Scripts dentro de la Storage Account y lo he guardado con el nombre de add_localAdmin.ps1). Si buscamos por Internet encontraremos cientos de ellos, como por ejemplo:

param(
[parameter(Mandatory=$true)]
 [String] $UPN
) 

$User = $UPN.split('@')[0]
$domain = $UPN.split('@')[-1]
$group = [ADSI]"WinNT://$ENV:COMPUTERNAME/Administrators,group"
$group.Add("WinNT://XxxDOMINIOxxX/$User,user") 

En este script se pasa por parámetro el User Principal Name ($UPN) de un usuario y este es añadido al grupo de Administradores locales del equipo (Este parámetro será proporcionado por el runbook que lo añadirá como extensión en la VM).

Seguidamente se debe crear el runbook  siguiente:

param(
 [parameter(Mandatory=$true)]
 [String] $Usermail,
 [parameter(Mandatory=$true)]
 [String] $vmname,
 [parameter(Mandatory=$true)]
 [String] $RGNAME
)
$connectionName = "AzureRunAsConnection"
try
{
 # Get the connection "AzureRunAsConnection "
 $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName
"Logging in to Azure..."
 Add-AzureRmAccount `
 -ServicePrincipal `
 -TenantId $servicePrincipalConnection.TenantId `
 -ApplicationId $servicePrincipalConnection.ApplicationId `
 -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
}
catch {
 if (!$servicePrincipalConnection)
 {
 $ErrorMessage = "Connection $connectionName not found."
 throw $ErrorMessage
 } else{
 Write-Error -Message $_.Exception
 throw $_.Exception
 }
}
$StorageAccountName = "XxxNombreStorageAccountxxX"
$filename = "add_localAdmin.ps1"
$StorageAccountKey = Get-AzureRMStorageaccountKey -StorageAccountName $StorageAccountName -ResourceGroupName "XxxRGDeLaStorageAccountxxX"
Get-AzureRmVM -Name $vmname -ResourceGroupName $RGNAME | Set-AzureRmVMCustomScriptExtension -Name CustomScript -VMName $vmname -ResourceGroupName $RGNAME -StorageAccountName $StorageAccountName -StorageAccountKey $storageAccountKey.Key1 -ContainerName "scripts" -FileName $fileName -Run $fileName -Argument $usermail 

Donde podemos observar que se proporciona por parámetro el nombre de la VM sobre la que queremos añadir el usuario local ($vmname), el Resource group al que pertenece ($RGNAME) y el UPN del usuario en cuestión ($Usermail).

Seguidamente haciendo uso del CMDLET Get-AzureRMVM y combinándolo con  Set-AzureRmVMCustomScriptExtension introducimos como extensión el script que hemos alojado en nuestra Storage Account (add_localAdmin.ps1) y con el parámetro -Argument enviamos el usuario que queremos añadir como administrador.

Una vez ejecutado el runbook, ya tenemos un usuario de nuestro AzureAD agregado como Administrador local de una VM de Azure.

Decir que como mejora a este script le podríamos añadir una validación previa donde se comprueba si el usuario introducido existe o no en el Azure AD, pero esta comprobación debería ser lanzada con un usuario del dominio y no con una RunAsAccount.

$user = get-azurermaduser -Mail $usermail
if ($user -eq $null){
 write-output "-----> El usuario introducido NO existe en el AD"
 exit
} else{
 write-output "-----> El usuario $usermail introducido existe en el AD"
}

 

Programar Azure Runbooks desde Powershell ISE

Seguramente cuando vamos a programar un script en Azure Automation pensais que la interfaz disponible actualmente no es del todo cómoda, dado que en muchos casos programar desde el navegador puede dar algún que otro dolor de cabeza, ya que no es tan completo como el PowerShell Integrated Scripting Environment (ISE para los amigos).

integrationrunbooksise3

Pues bien, la solución es un Addon que ofrece el mismo ISE para poder crear, programar y testear runbooks directamente en nuestra suscripción de Azure. Para añadir esta funcionalidad debemos instalarla desde el mismo terminal con los siguientes comandos:

Install-Module AzureAutomationAuthoringToolkit -Scope CurrentUser
Install-AzureAutomationIseAddOn 

integrationrunbooksise

integrationrunbooksise4

Una vez importado el modulo debemos hacer sign in en nuestra suscripción, seleccionar la Automation Account pertinente y ya tendremos a nuestra disposición los runbooks y los Assets existentes.

En caso de cerrar y abrir de nuevo el ISE debemos importar de nuevo el modulo desde la linia de comando, o bien añadirlo desde la pestaña Addons:

 Import-Module AzureAutomationAuthoringToolkit 

Es importante recordar que cada vez que editemos un runbook o lo testemos debemos subirlo (Upload Draft) y publicarlo (Publish Draft) para que los cambios sean aplicados en la suscripción.

Añadir cmdlets a Azure Automation

Hoy hablaré de Azure Automation, esta herramienta que nos ofrece Azure para ejecutar runbooks desde nuestra propia suscripción.

Como muchos de vosotros sabréis, los cmdlets disponibles que aparecen por defecto en vuestra Automation Account son bastante escasos, ya que por defecto cada cuenta solo tiene agregados 15 módulos al ser creada.

Para añadir nuevas funcionalidades a Azure Automation podemos agregar módulos según nos convenga. Tan solo tenemos que dirigirnos a la sección Assets y seleccionar Modules.

automationmodules

No obstante, es importante tener en cuenta las dependencias entre ellos, dado que si actualizamos uno de los módulos existentes probablemente debamos actualizar algunos más para no perder funcionalidad en esos. O bien, si agregamos uno nuevo, es posible que solo funcione con una versión determinada de otros módulos que actualmente ya poseemos.

Así pues, para agregar un modulo debemos pulsar Browse Gallery y seguidamente seleccionar el que deseamos agregar de todos los módulos disponibles que nos aparecen. Una vez escogido, tan solo debemos pulsar Import y en unos minutos ya tendremos disponible todo el conjunto de cmdlets que aparecen en la sección Content.

automationmodules2.PNG

Como se observa en la imagen, las dependencias entre módulos son importantes, así que previamente a la importación del modulo AzureRM.Keyvault deberíamos actualizar el AzureRM.Profile a una versión igual o superior a la 2.5 o nos encontraremos con el error siguiente:

automationmodules3

Una vez actualizadas las dependencias ya podremos agregar sin problemas el modulo y en unos minutos ya podremos usar los cmdlets importados.

automationmodules4

Como obtener una template de DevTest Lab y customizarla

Debido al post de ayer algunos compañeros me han expresado la dificultad para encontrar una template de un devtest lab o bien, no saben que parámetros pueden ser usados para cumplimentar el JSON. A continuación os mostraré el procedimiento que utilizo para obtener los templates y editarlos a mi gusto.

En primer lugar la base la extraigo de github, donde tenemos unas templates bastante completas (También podríamos obtenerla extrayendo el template de un devtest lab que hayamos creado previamente en nuestra suscripción). En caso de querer añadir algún parámetro más y no encontrar su definición por ningún sitio, como por ejemplo los tamaños de VM disponibles, podemos usar a las Dev Tools (tecla F12) de nuestro navegador mientras estamos en el portal de azure:

devteslab

Como podéis observar en la imagen, al modificar cualquier apartado se genera un Put que manda un JSON. En mi ejemplo, al editar los tamaños que vamos a permitir en nuestro devtest lab y pulsar guardar.

Si analizamos el body de esta petición observamos los posibles valores que pueden ser ser añadidos al JSON. En este caso se deberían añadir en la sección que se muestra a continuación:

 "allowedVmSizes": {
 "type": "string",
 "defaultValue": "\"Standard_DS1_v2\", \"Standard_DS3_v2\", \"Standard_DS11_v2\"",
 "minLength": 3,
 "metadata": {
 "description": "Set 'allowed VM sizes' policy: A comma-separated list of VM sizes that are allowed in the lab."
 }

Despliegue de DevTest Labs en Azure

Para realizar el despliegue de un DevTest Lab en Azure, actualmente no existe ningún cmdlet que realice esta tarea, por lo que la deberemos realizar mediante el comando New-AzureRmResourceGroupDeployment del modo que se muestra a continuación, definiendo previamente la plantilla del DevTest Lab en un JSON.

New-AzureRmResourceGroupDeployment -Name deployNameDemoLab -ResourceGroupName $RG -Templateuri $TemplateuriX -TemplateParameterObject $Params -Verbose

Donde las variables son:

  • $RG: Nombre del Resource Group (String).
  • $TemplateuriX: variable que contiene la URI del JSON donde hemos definido los parámetros del DevTest Lab (String).
  • $Params: objeto previamente definido que inyecto al JSON (Objeto).
$params = @{}
$params.add("maxAllowedVmsPerUser",$NumVMUser)
$params.add("maxAllowedVmsPerLab",$NumVMLab)
$params.add("newLabName",$newLabName)

Es importante destacar porque realizo la inyección de un objeto $params en lugar de una URI hacia un JSON donde están definidos los parámetros que seria lo más común. El motivo es porque prefiero añadir los parámetros mediante un Asset definido en mi Automation Account, o bien, por código de Azure powershell/Azure automation.