Es obvio, pero actualmente, muchos de nosotros estamos utilizando cada vez más Azure AD para integrarlo con nuestras aplicaciones. ¿Cómo estamos haciendo esta integración?
La mayoría de ellas con App Registrations, que no deja de ser una combinación de permisos que le damos a dicha aplicación, para que se autentique en el servicio (de forma impersonada o no), y podamos realizar ciertas acciones contra las APIs a las cuales les hayamos dado permisos.
Este tipo de solución tiene una pequeña limitación, que es la expiración de los secretos o los certificados que van asociados a este tipo de aplicaciones. ¿Qué provoca este tipo de situaciones? Pues a mi forma de ver, uno de los problemas en la autenticación de aplicaciones, con lo que la aplicación no puede autenticarse contra el servicio configurado, y se pierden acceso a los recursos a los cuales previamente habíamos dado permisos.
Como hacíamos en el mundo OnPrem, reemplazar un certificado o bien un secreto, no es una tarea compleja, siempre y cuando la hagamos a tiempo. El problema empieza cuando este tipo de tareas no se realizan, y descubrimos que una aplicación ha dejado de funcionar repentinamente, y lo peor es cuando no sabemos que hay por debajo configurado.
Por lo que tenemos una serie de puntos clave:
¿Cómo podemos hacer seguimiento de las fechas de expiración de certificados y secretos?
¿Cómo podemos montar una solución que nos ayude a ello?
¿Cómo podemos estar notificados del número de días restantes?
La idea de este artículo es ver en detalle la solución de AzGovADvertiser y ver cómo nos puede ayudar en situaciones del gobierno de aplicaciones en AzureAD
En mi día a día, posiblemente esta es una de las piezas que podemos tener montadas en nuestros entornos, llegando inclusive a montar otras piezas con PowerShell, Runbooks, LogicApps, que nos den un punto más de inteligencia y automaticen cosas por nosotros.
Pero, antes de nada, hagamos un breve repaso a lo que son secretos y certificados en Azure AD:
Secretos de cliente: es una cadena secreta que la aplicación utiliza para probar su identidad al solicitar un token. También podemos llamarlo una contraseña de aplicación.
Certificados: los certificados se pueden usar como secretos para probar la identidad de la aplicación al solicitar un token. También se puede denominar claves públicas.
En este punto, también necesitamos entender dos conceptos que harán posible la integración y construcción de la solución:
App registration: Es necesario registrar una aplicación en Azure Portal y elegir el tipo de tenant para habilitar la administración de identidades y accesos. A partir de ese momento, es posible integrar su aplicación con Azure AD.
Application Object: El Application Object describe cómo el servicio puede emitir tokens para tener acceso a la aplicación, los recursos necesarios y las acciones que puede realizar la aplicación.
Las aplicaciones se comunican de forma independiente, como daemons o cuentas de servicio. Una aplicación envía sus propias credenciales (el identificador de cliente y el secreto de cliente) al proveedor de identidades que está configurado para generar un token de acceso. Si las credenciales son válidas, el proveedor de identidades devuelve un token de acceso a la aplicación cliente. Y aquí es donde entra en juego, el App Registration, los secrets, certificados, etc...
Como es un engorro el tener que crear los secretos con una caducidad máxima de 24 meses, hay una opción por PowerShell, que nos permite crear AppRegistrations con mayor caducidad:
1$startDate = Get-Date2$endDate = $startDate.AddYears(99)34$aadAppsecretName = New-AzureADApplicationPasswordCredential5 -ObjectId YOURAPPID -StartDate $startDate -EndDate $endDate -CustomKeyIdentifier YOURSECRETNAME6
En un mundo ideal, el propietario de la App, debería de ser el responsable de tener procedimientos para monitorizar que las credenciales van a expirar, etc... pero si has llegado hasta aquí, ya sabes que no es el caso.
Ahora bien, ¿qué podemos hacer? Obviamente, monitorizar nuestro entorno, y para ello haremos uso de una herramienta llamada AzADServicePrincipalInsights (GitHub - JulianHayward/AzADServicePrincipalInsights: Insights and change tracking on Azure Active Directory Service Principals (Enterprise Applications and Applications) que nos ayudará muchísimo a dar un poco más de visibilidad de las aplicaciones, permisos y propietarios de nuestro Azure AD.
Primero de todo, vayamos a ver en detalle qué información nos proporciona la herramienta:
ServicePrincipals by type
ServicePrincipal owners
Application owners
ServicePrincipal owned objects
Managed Identity User Assigned - associated Azure Resources
ServicePrincipal AAD Role assignments
ServicePrincipal AAD Role assignedOn
Application AAD Role assignedOn
App Role assignments (API permissions Application)
App Roles assignedTo (Users and Groups)
Oauth permission grants (API permissions delegated)
Azure Role assignments (Azure Resources; Management Groups, Subscriptions, Resource Groups, Resources)
ServicePrincipal Group memberships
Application Secrets
Application Certificates
Application Federated Identity Credentials
HiPo Users (wip)
Ya vemos que la lista de cosas y objetos que vamos a obtener es extensa, así que vayamos a ver como se ejecuta y el resultado final. Es una herramienta que podemos ejecutar dentro de nuestros pipelines de Azure DevOps, pero en mi caso y para hacerlo sencillo, lo he ejecutado de la forma más simple que existe: creando un AppRegistration y ejecutándolo como tal.
En mi caso, he ido al portal y he creado un nuevo AppRegistration y le he dado permisos de:
Microsoft Graph API | Application | Application.Read.All
Microsoft Graph API | Application | Group.Read.All
Microsoft Graph API | Application | RoleManagement.Read.Directory
Microsoft Graph API | Application | User.Read.All
Y he creado un secreto para esta App (igual alguien se está empezando a preguntar: ¿quién vigila a los vigilantes?). Le damos acceso al ServicePrincipal creado a nivel de Root Management Group (ojo que para ello debemos tener acceso a nivel de AAD):
Si tuvierais algún problema con esto, revisad a nivel de AAD la propiedad siguiente:
Una vez hecho esto, me he descargado el repo anterior y he creado una variable y me he autenticado, tal y como se indica en el repo de GitHub:
1*#USER: 'Application (client) ID' of the App registration OR2'Application ID' of the Service Principal (Enterprise Application)3#PASSWORD: Secret of the App registration*45$pscredential = Get-Credential67Connect-AzAccount -ServicePrincipal -TenantId <tenantId> -Credential $pscredential89.pwshAzADServicePrincipalInsights.ps110
Y el script empezará a ejecutarse y a sacar alguna que otra información en pantalla:
Una vez, tengamos el output, veremos que, en la misma raíz, nos habrá generado una serie de ficheros con un reporte HTML interactivo:
Aquí podremos empezar a navegar y ver algunos detalles de nuestras aplicaciones, inclusive, se generan unos CSV, donde podremos ver cierta información de la caducidad de nuestros secretos y certificados:
Trabajando el fichero csv de salida, podríamos a llegar a generarnos avisos en función del estado de la columna AppSecretExpiryInfo (aunque como comentaba al principio, existen muchas soluciones para hacer un seguimiento más exhaustivo de estos campos). Ya vemos que tenemos a la salida diferentes ficheros, por lo que esto nos dará muchas ideas de lo que podemos trabajar a posteriori con ello:
O si bien lo queremos integrar en un reporte y pintarlo de forma más bonita.
Claro que sí, por Internet hay multitud de alternativas para este tipo de implementaciones, a mí me gusta la opción de KISS (keep it simple stupid), así que vamos a ello:
1#fecha expiración secretos (por ejemplo 30 días)23$LimitExpirationDays = 3045#sacamos la lista de secretos que expiran en esas fechas anteriormente6definidas78$SecretsToExpire = Get-AzureADApplication -All:$true |9ForEach-Object {1011$app = $_1213@(1415Get-AzureADApplicationPasswordCredential -ObjectId $_.ObjectId1617Get-AzureADApplicationKeyCredential -ObjectId $_.ObjectId1819) | Where-Object {2021$_.EndDate -lt (Get-Date).AddDays($LimitExpirationDays)2223} | ForEach-Object {2425$id = "Not set"2627if($_.CustomKeyIdentifier) {2829$id =30[System.Text.Encoding]::UTF8.GetString($_.CustomKeyIdentifier)3132}3334[PSCustomObject] @{3536App = $app.DisplayName3738ObjectID = $app.ObjectId3940AppId = $app.AppId4142Type = $_.GetType().name4344KeyIdentifier = $id4546EndDate = $_.EndDate4748}4950}5152}5354#sacamos la lista de secretos que van a expirar pronto5556if($SecretsToExpire.Count -EQ 0) {5758Write-Output "No secrets found that will expire in this range"5960}6162else {6364Write-Output "Secrets that will expire in this range:"6566Write-Output $SecretsToExpire.Count6768Write-Output $SecretsToExpire6970}71
Y con esto, tendríamos una salida parecida a la siguiente:
Ya veis que este método es sencillo pero efectivo, ahora lo suyo sería ejecutar esto en un runbook y enviarnos el resultado por correo, eso ya depende de cada uno.
Como hemos visto, esta es una posible solución para conocer un poco más nuestro entorno y empezar a gobernarlo de una forma más efectiva, empezando en este caso con toda la parte de aplicaciones, que nos acaban facilitando mucho la vida para las conexiones, pero que, en términos de gobierno, siguen siendo un gran desconocido.
¡hasta la próxima!
Alberto Andrés Rodríguez
Cloud Solutions Architect @ Seidor
@albandrod | Alberto Andrés Rodríguez - | LinkedIn