GuilleSQL :: Microsoft SQL Server, SSIS, y más !!

Service Principals en Azure: los amas y los odias a la vez


Si trabajáis con Azure, antes o después os tendréis que enfrentar a los Service Principals, para utilizarlos como cuentas de servicio, de tal modo que una persona, proceso o aplicación pueda autenticarse utilizando un Service Principal para acceder a los recursos de Azure a los que tiene acceso. Otro caso típico, al empezar en el mundo DevOps para montar procesos de integración continua, y poder conseguir del despliegue automatizado de infraestructura y aplicaciones, pudiendo necesitar no sólo usarlos sino también crearlos de forma automatizada (desde otro Service Principal).

El problema del mal uso de los Service Principals

Los Service Principals, en este sentido son algo parecidos a los usuarios de Azure AD, pero hay matices. Por poner un ejemplo, un Service Principal puede tener asociado ninguna, una, o varias contraseñas (cada una con su propia expiración), y además también podría tener asociado ninguno, uno, o varios certificados (igualmente, cada uno con su propia expiración). Esto permite, que diferentes personas, procesos, o aplicaciones, puedan utilizar el mismo Service Principal, pero autenticándose de forma diferente, y en consecuencia, pudiendo revocarles el acceso por separado. Podrías crear una contraseña nueva temporal de un día (sin tocar las existentes para no impactar) para hacer una prueba o resolver una incidencia, etc. Interesante. Esto mola.

Por el contrario, un usuario de Azure AD puede tener asociado una autenticación de doble factor (como un SMS a su móvil de empresa), que garantice la identidad de la persona que intenta realizar el acceso. Esto también mola. Un usuario de tu empresa, puede acceder a los recursos que necesita, porque tiene permisos, y sabes que es él por la autenticación de doble factor. Además, como administrador, puedes forzar la renovación de contraseñas. Tiene su puntito de seguridad, aunque como todo, hay que conocérselo muy bien.

Aquí llega el sabor agridulce de los Service Principals. Ahora yo dejo mi empresa, me deshabilitan mi usuario, y pierdo el acceso a los recursos… pero sorpresa, que tengo una excel con todos los Service Principals de mi proyecto, así que no pasa nada, desde casita, me conecto a donde quiero y cuando me da la gana. Bueno, quizás desde una red pública, o robando una Wifi, para que no sea tan fácil que me identifiquen. Esto ya no mola. Pero nada. Y además se aplica a más cosas, como las Key y los Tokens de las Storage Accounts, etc., aunque en este caso nos centraremos sólo en los Service Principals, que en muchos casos, no caducan, o caducan en un año o más.

La conclusión es clara. Los Service Principals son una responsabilidad, y es muy importante gestionarlos bien, y reciclar sus credenciales de acceso.

Una solución candidata

Es importante seguir un mínimo de buenas prácticas, para conseguir tener bien gestionados nuestros Service Principals.

  • Usar un Service Principal para cada cosa, con los permisos mínimos necesarios.
  • Almacenar sus contraseñas o certificados en Azure Key Vault.
  • Inventariar los Service Principals, en qué Key Vault se utiliza, su propósito, etc.
  • Y lo más importante: reciclarlos

Una aproximación, podría ser tener un proceso, que cada día genere nuevas contraseñas (ej: que expiren en 7 días) a los Service Principals, y las guarde en Azure Key Vault. Los procesos y los usuarios que necesiten utilizar los Service Principals, tendrán que acudir al Azure Key Vault. Cada día tendremos una contraseña diferente, pero como dicha contraseña expira en 7 días, si lanzo un proceso largo de más de 24h en el que utilizo el mismo Service Principal, no tendré problema. Además, si una persona deja la compañía, aunque tenga en una Excel las contraseñas de los Service Principals, ya se puede dar prisa en hacer maldades, porque todos expirarán como mucho en 7 días. En cierto modo, estamos tokenizando su acceso. No es ideal, pero infinitamente mejor que no rotar las contraseñas, y además, también podríamos acortar la expiración y el rotado, según nuestro nivel de paranoia.

En esta aproximación, sigue habiendo riesgos, pero están más controlados. Por ejemplo, el Service Principal que se encargue de cambiar las contraseñas del resto de Service Principals, en caso de verse comprometido, tenemos un riesgo alto, por lo que será necesario tratarle con especial atención. Sin embargo, el resto de Service Principals, estarían más protegidos.

Análisis técnico y primeros problemas

Supongamos que nos ha convencido esta aproximación, y lo queremos implementar en nuestra compañía. Vamos a ver con qué piedras nos encontramos en el camino.

Por defecto un Service Principal (llamémosle Padre) no puede crear otro Service Principal, ni puede crear/cambiar/borrar la contraseña de otro Service Principal, ni puede conceder permisos sobre un recurso de Azure (aunque sea propietario de dicho recurso)

Esto lo podemos solucionar dando los siguientes permisos a un Service Principal (el Padre), de tal modo que podrá crear nuevos Service Principals (de los cuales será Owner), y además al ser Owner de ellos, les podrá cambiar la contraseña. Para los Service Principals que ya existían, tendremos que configurarles para añadirles como Owner a nuestro Service Principal (Padre).

Los permisos que tendremos que dar al Service Principal, sobre la API de Windows Azure Active Directory, son los siguientes, y necesitaremos consentimiento de un Administrador de Azure AD:

  • Application Permission - Read directory data
  • Application Permission - Manage apps that this app creates or owns
  • Delegated Permission - Sign in and read user profile

No podemos añadir como Owner de un Service Principal a otro Service Principal

Bueno, si podemos. Desde el Portal no se puede, o al menos, yo no he encontrado la opción. Pero sí es posible mediante código, siempre que tengas permisos suficientes (ej: seas owner del Service Principal al que quieres añadir el nuevo Owner). De este modo, un Service Principal puede tener varios Owners, su creador, y otros que añadamos para delegar su administración.

A continuación se muestra un ejemplo con Azure CLI, teniendo en cuenta que: --owner-object-id es el Object Id del Service Principal (el Padre) asociado al App Registration (lo podemos obtener ejecutando algo como az ad sp show --id 1f60bf1a-6a59-4d6b-bb4a-6369152a2e7b pero especificando el App Id del Padre), y --id es el Object Id ó App Id del App Registration del Hijo

az ad app owner add --id c75d6721-a9af-4d24-bd9e-4d2718501bc7 --owner-object-id 55438bd7-195a-4435-9392-7e7de3dd8041

Nota aclaratoria. Aunque estamos hablando todo el rato de Service Principals, en la práctica, lo que se hace es crear un App Registration, que tiene asociado un Service Principal, es decir, se trata de dos objetos diferentes, aunque relacionados. El App Id en una propiedad del App Registration, y ambos objetos tienen una propiedad Object Id. Por eso, tenemos que tener claro, que Object Id necesitamos, el del App Id o el del Service Principal. Esto genera algo de confusión, porque muchas veces acabamos hablando de Service Principals, para referirnos indistintavemente a uno u otro.

Permisos necesarios en las Subscripciones de Azure

Para poder crear un Service Principal, necesitaremos tener permisos en la Subscripción de Azure. En las pruebas que hemos realizado, al Service Principal (el Padre) que hemos usado para crear otros Service Principal, le hemos dado permisos de Read en la Subscripción. Con esto, al intentar crear un Service Principal, mostrará un mensaje de error, pero lo creará. Si damos permisos de Owner en la Subscripción, al crear el Service Principal desde Azure CLI, le hará Contributor de la Subscripción, algo que queremos evitar.

Expiración de las Contraseñas de los Service Principals

Por defecto las contraseñas de un Service Principal caducan al año, al crearlas desde Azure CLI. Si bien, con Azure CLI sólo es posible especificar múltiplos de 1 año, tendríamos la posibilidad de borrar las contraseñas antiguas. Otra alternativa, crearlas desde Powershell.

Al intentar cambiar crear una nueva contraseña obtenemos el error Update to existing credential with KeyId 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' is not allowed

Este error lo he encontrado al intentar crear un nueva contraseña con --append y la solución fué crear un nueva contraseña sin --append, después de lo cual, podía crear nuevas contraseñas tanto con --append como sin él. Un poco raro, la verdad, pero al menos con este fix, problema solucionado.

Versión de Azure CLI

Para que todo esto nos funcione, necesitamos tener una versión reciente de Azure CLI.

Depurar la ejecución de comandos Azure CLI

Si nos atascamos, en ocasiones resulta útil el parámetro --debug de los comandos az

Ejemplo de código

Y ya para terminar, sólo queda añadir algún ejemplo de código, en este caso con Azure CLI, para que nos sea más fácil poner todo esto en práctica.

# Logarse con un Service Principal
az login --service-principal -u "2f60bf1a-6a59-4d6b-bb4a-636915ba2f7b" -p "iQIsa2ZcLEwXc6eK1vSzssnEJWjLZ5vHvRKLwGxM==" --tenant "a737a526-0f4a-4f8e-a1ed-58c951d983d5" --subscription a5e0c2ff-ab76-44be-a513-9a6e38d48f47

# Mostrar el Service Principal asociado al App Registration (observar el ObjectId)
az ad sp show --id 2f60bf1a-6a59-4d6b-bb4a-636915ba2f7b

# Crear un Service Principal
az ad sp create-for-rbac -n "sq_guillesql"

# Listar Service Principals
az ad sp list

# Mostrar un Service Principal
az ad sp show --id f75d67a1-a96f-4d24-bd9e-4d2718501bc0

# Dar permisos a un Service Principal
az role assignment create --scope /subscriptions/a5e0c2ff-ab76-44be-a513-9a6e38d48f47/resourceGroups/guillesql --role Reader --assignee f75d67a1-a96f-4d24-bd9e-4d2718501bc0

# Listar constraseñas de un Service Principal
az ad sp credential list --id f75d67a1-a96f-4d24-bd9e-4d2718501bc0

# Borrar una contraseña de un Service Principal
az ad sp credential delete --id f75d67a1-a96f-4d24-bd9e-4d2718501bc0 --key-id 288d1adc-fa1f-474a-bc54-9ffcdf0ffc40

# Crear nueva contraseña (aleatoria) a un Service Principal, con un año de validez
az ad sp credential reset --name "sq_guillesql" --append --years 1 --credential-description "first-password"

# Crear nueva contraseña (pre-establecida) a un Service Principal, con un año de validez (DEPRECATED)
az ad sp credential reset --name "sq_guillesql" --append --years 1 --credential-description "first-password" --password 12.34.56.789.Ab

# Añadir un Owner (de tipo Service Principal) a un Service Principal del que ya se es Owner
# --owner-object-id (el padre) => Object Id del Service Principal asociado al App Registration
# --id (el hijo) => Object Id del App Registration
az ad app owner add --id f75d67a1-a96f-4d24-bd9e-4d2718501bc0 --owner-object-id 25438bd7-195a-4435-9392-7e7de3dd804d

# Hacer a un Service Principal owner de sí mismo
# Nota: Este comando tiene que se ejecutado por un usuario o Service Principal que sea Owner del Service Principal al que se le quiere añadir un nuevo Owner
az ad app owner add --id 2f60bf1a-6a59-4d6b-bb4a-636915ba2f7b --owner-object-id 46e0ca5e-53d3-4e79-9782-7d96e7506f47

# Borrar un Service Principal
az ad sp delete --id 357933e5-6a84-4580-957d-7e855da8fd81

Poco más por hoy. Como siempre, confío que la lectura resulte de interés.


Miembros de
Miembros de GITCA (Global IT Community Association)

Menu de Usuario
  Iniciar Sesión
  Registrarse
  Restablecer Contraseña
  Ventajas de Registrarse

Acerca de
  Contigo desde Oct 2007
  771 usuarios registrados
  86146 pageloads/mes
  Ranking Alexa 498160

Social Networks
Sigue a Portal GuilleSQL en Linkedin !!
Sigue a Portal GuilleSQL en Twitter !!



Archivo

Marzo de 2019 (1)
Octubre de 2018 (1)
Julio de 2018 (1)
Junio de 2018 (4)
Mayo de 2018 (5)
Abril de 2018 (3)
Marzo de 2018 (2)
Febrero de 2018 (7)
Enero de 2018 (1)
Diciembre de 2017 (15)
Noviembre de 2017 (7)
Junio de 2017 (3)
Mayo de 2017 (1)
Marzo de 2017 (3)
Enero de 2017 (4)
Junio de 2016 (1)
Mayo de 2016 (2)
Abril de 2016 (2)
Septiembre de 2015 (2)
Agosto de 2015 (2)
Junio de 2015 (10)
Mayo de 2015 (4)
Abril de 2015 (8)
Marzo de 2015 (11)
Octubre de 2014 (3)
Septiembre de 2014 (7)
Agosto de 2014 (5)
Julio de 2014 (2)
Mayo de 2014 (4)
Abril de 2014 (4)
Marzo de 2014 (4)
Febrero de 2014 (1)
Enero de 2014 (5)
Diciembre de 2013 (8)
Noviembre de 2013 (2)
Octubre de 2013 (7)
Septiembre de 2013 (6)
Agosto de 2013 (1)
Julio de 2013 (6)
Junio de 2013 (11)
Mayo de 2013 (7)
Abril de 2013 (6)
Febrero de 2013 (5)
Enero de 2013 (7)
Diciembre de 2012 (12)
Noviembre de 2012 (13)
Octubre de 2012 (5)
Septiembre de 2012 (3)
Agosto de 2012 (6)
Julio de 2012 (4)
Junio de 2012 (1)
Mayo de 2012 (2)
Abril de 2012 (7)
Marzo de 2012 (16)
Febrero de 2012 (9)
Enero de 2012 (5)
Diciembre de 2011 (10)
Noviembre de 2011 (10)
Octubre de 2011 (4)
Septiembre de 2011 (5)
Agosto de 2011 (2)
Julio de 2011 (2)
Junio de 2011 (4)
Mayo de 2011 (2)
Abril de 2011 (6)
Marzo de 2011 (4)
Febrero de 2011 (10)
Enero de 2011 (5)
Diciembre de 2010 (6)
Noviembre de 2010 (4)
Octubre de 2010 (8)
Septiembre de 2010 (4)
Agosto de 2010 (1)
Julio de 2010 (3)
Mayo de 2010 (5)
Abril de 2010 (6)
Marzo de 2010 (8)
Febrero de 2010 (3)
Enero de 2010 (1)
Diciembre de 2009 (9)
Noviembre de 2009 (14)
Octubre de 2009 (2)
Septiembre de 2009 (8)
Agosto de 2009 (2)
Julio de 2009 (10)
Junio de 2009 (9)
Mayo de 2009 (10)
Abril de 2009 (9)
Marzo de 2009 (3)
Febrero de 2009 (2)
Enero de 2009 (3)
Noviembre de 2008 (2)
Octubre de 2008 (2)
Septiembre de 2008 (2)
Agosto de 2008 (5)
Julio de 2008 (5)
Junio de 2008 (1)
Mayo de 2008 (3)
Abril de 2008 (2)
Marzo de 2008 (2)
Febrero de 2008 (2)
Enero de 2008 (5)
Noviembre de 2007 (2)
Octubre de 2007 (2)






Copyright © 2007 GuilleSQL, todos los derechos reservados.