[AzureScript][T1:E4] ¡Enmascarando contraseñas!

¡Hola! Ésta será la última parte de esta serie, por si no recordas bien o queres repasar las anteriores, acá están los links:

Haciendo un breve repaso de la serie, básicamente hemos visto las librerías básicas para interactuar con Azure utilizando PowerShell. Vimos ejemplos de éstas interacciones y la forma de automatizar 100% nuestros scripts para que no requieran interacción alguna con el usuario.

En esta última parte de la serie, vamos a abordar un tema que quedó pendiente en la anterior: no exponer nuestras credenciales a simple vista en el Script. Imagínense lo poco seguro que sería tener la contraseña a simple vista en nuestro script, algo como  $password = "martin123" probablemente nos llevaría (con suerte) a un reto en una inspección de auditoria. Incluso si somos cuidadosos con el script, nos restringe la posibilidad de compartirlo para mostrar la lógica, o subirlo a un repositorio público de github para compartir conocimiento. Por esta razón, el broche de oro de esta serie tendrá foco en formas comunes de evitar exponer nuestras credenciales. Para esto veremos 2 formas, cada una con sus ventajas y desventajas.

Una particularidad de esta entrada en el blog, es que finalmente me mude definitivamente a Linux. Por lo que verán que las rutas a los archivos no comienzan con C:/ como en windows, pero a los fines prácticos es lo mismo. También mencionaré que para esta oportunidad estaré usando el módulo Az para comunicarme con Azure, en lugar de AzureRM como venia haciéndolo en entregas anteriores (ya expliqué sus diferencias, y como llevar los comandos de uno a otro de forma simple).

Primera forma

Ésta es la mas obvia quizás, la primera que se nos ocurriría: guardar la contraseña en un archivo separado y encriptado. Por suerte, esto es sencillo de hacer con PowerShell. Primero deberíamos abrir una nueva consola y crear este archivo, para luego llamarlo desde nuestro script. Abrimos PowerShell y tipeamos:

$mypass = "martin123" | ConvertTo-SecureString -AsPlainText -Force
$mypass = Read-Host -AsSecureString
$mypass | ConvertFrom-SecureString | Set-Content "/home/martin/python/Investigacion/Powershell/creds.txt"

¿Que hemos hecho acá? En la primera linea simplemente creamos un objeto de powershell conocido como SecureString, que básicamente almacena una variable tipo string encriptada y no puede ser leída fácilmente. En la segunda linea simplemente almacenamos el contenido de esta variable en el archivo creds.txt. Esto lo haríamos por única vez, y no estaría incluido en el script final. Es, simplemente, para generar el archivo. Si abrimos este archivo de texto, no veremos la contraseña sino una cadena de caracteres encriptados que no nos permitirán saber la contraseña original, en mi caso decía algo así: 

6d0061007200740069006e00310032003300.

Luego, para tomar el contenido del archivo simplemente ejecutamos. Esto SI estaría en nuestro script final:

$mypass = Get-Content "/home/martin/python/Investigacion/Powershell/creds.txt" | ConvertTo-SecureString

De este modo, habremos tomado el contenido encriptado del archivo, y lo almacenamos en una variable de powershell en un objeto tipo SecureString que podemos utilizar como nuestra contraseña al crear el objeto PSCredential (explicado en la parte 3 de esta serie).

Podríamos llevar esto un paso mas avanzado en la seguridad, teniendo una clave propia para desencriptar la password en otro archivo separado, con la desventaja de que esto nos lleva a tener 2 archivos ademas del script, pero con la ventaja de que nosotros manejamos la clave de encriptacion con SHA-256. Veamos como hacerlo.

El primer paso sera crear el archivo con la llave de encriptacion (recuerden cambiar la ruta de archivo):

$Key = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($Key)
$Key | out-file /home/martin/python/Investigacion/Powershell/key.key

De este modo habremos creado un archivo con la clave de encriptacion que usaremos para encriptar nuestra password en el archivo creds.txt. Ahora, volvamos a generar creds.txt:

$mypass = Read-Host -AsSecureString
$mypass | ConvertFrom-SecureString -Key (Get-Content /home/martin/python/Investigacion/Powershell/key.key) | Set-Content "/home/martin/python/Investigacion/Powershell/creds.txt"

Así, creamos un archivo que tendrá nuestra password encriptada según la clave que creamos previamente. Para recuperar esta contraseña, usamos:

$password = Get-Content "/home/martin/python/Investigacion/Powershell/creds.txt" | ConvertTo-SecureString -Key (Get-Content "/home/martin/python/Investigacion/Powershell/key.key")

¡Listo! De este modo, no alcanza solo con tener el archivo con la contraseña encriptada, sino que también tendremos que utilizar el archivo .key para poder desencriptar el primer archivo, y crear satisfactoriamente el objeto SecureString (el cual tampoco nos mostrara la contraseña en texto plano).

Segunda forma

Otra manera de no exponer nuestras contraseñas, seria mediante el uso de un servicio de Azure llamado KeyVault. En este servicio podemos almacenar claves, y recuperarlas de un modo seguro, pudiendo acceder a ellas solo quienes estén autorizados en Azure para hacerlo. Para esto, primero logueamos en Azure y creamos un recurso KeyVault (cambia el nombre del grupo de recursos según lo que tengas creado en tu suscripción):

Login-AzAccount
New-AzKeyVault -Name 'LaDataKeys' -ResourceGroupName 'Wasteland' -Location 'East US'

Después, generamos el objeto SecureString y lo agregamos como un secreto:

$mypass = Read-Host -AsSecureString
Set-AzKeyVaultSecret -VaultName 'LaDataKeys' -Name 'TutorialPassword' -SecretValue $mypass

Para recuperar el objeto SecureString, usamos:

$password = (Get-AzKeyVaultSecret -vaultName "LaDataKeys" -name "TutorialPassword").SecretValue

¡Listo! Mucho más fácil ¿verdad? Es que ese es el objetivo y uno de los principales beneficios de los servicios cloud. Simplificarnos la vida. En este caso mediante la protección de nuestras claves en un llavero.

Por supuesto que necesitaremos darle permisos a nuestro Service Principal sobre el KeyVault que acabamos de crear, de otro modo ¡no podrá acceder al secreto! Para cualquier trabajo que tenga que quedar productivo, recomiendo mezclar ambos métodos y nunca mostrar en texto plano el SecretId, menos ahora que sabemos encriptarlo con SHA-256 ;)

Con esto cierro este ciclo de PowerShell con Azure, espero les haya sido de utilidad, ¡sigan leyendo y aprendiendo contenido en LaDataWeb!

Escrito por Martin Zurita