Mi compañía está buscando informes sobre Azure. Solo queremos que nuestros clientes nos den credenciales de solo lectura para que las usemos. Hice algunas investigaciones y parece que Azure Active Directory hace precisamente eso. Así que estoy buscando autenticar usando una aplicación de directorio de Azure de solo lectura.
Para comenzar, estaba siguiendo este blog sobre el uso de la API de administración a través de Azure Active Directory.
https://msdn.microsoft.com/en-us/library/azure/dn722415.aspx
Aparte de que el enfoque de aproximación es muy antipático, no funciona = (
Recibo este error después de iniciar sesión como administrador global:
“AADSTS90014: el cuerpo de la solicitud debe contener el siguiente parámetro: ‘client_secret o client_assertion’.”
Hice algunas investigaciones y descubrí que este estilo de autenticación era para aplicaciones nativas y NO para aplicaciones web (a pesar de lo que la publicación del blog decía de otra manera …). Así que hice un ajuste. My GetAuthorizationHeader ahora se ve así:
private static string GetAuthorizationHeader() { AuthenticationResult result = null; var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]); string clientId = ConfigurationManager.AppSettings["clientId"]; string clientSecret = ConfigurationManager.AppSettings["clientSecret"]; ClientCredential clientCred = new ClientCredential(clientId, clientSecret); var thread = new Thread(() => { result = context.AcquireToken( "https://management.core.windows.net/", clientCred); }); thread.SetApartmentState(ApartmentState.STA); thread.Name = "AquireTokenThread"; thread.Start(); thread.Join(); if (result == null) { throw new InvalidOperationException("Failed to obtain the JWT token"); } string token = result.AccessToken; return token; }
Puedo obtener el token de acceso (yay). Pero ahora, cuando trato de usar esto con el cliente de la biblioteca de gestión de Azure, aparece este error:
“ForbiddenError: el servidor no pudo autenticar la solicitud. Verifique que el certificado sea válido y esté asociado a esta suscripción”.
Revisé dos veces mis permisos en mi aplicación. Se veía bien. Traté de dar acceso completo a todo para ver si eso hubiera marcado la diferencia.
Comprobé dos veces mi ID de inquilino, ID de cliente y suscripción, todo se veía bien.
Me aseguré de que la suscripción que estoy utilizando apunta al AD en el que está mi aplicación.
Traté de hacer una nueva clave secreta.
Creo que este es el problema: Sin embargo, en esta interfaz de usuario no puedo seleccionar ningún valor para esa propiedad. No estoy seguro si esto es el resultado de un error o una característica sin terminar. ¿Me estoy perdiendo de algo?
Gracias
Aquí está mi código completo para referencia:
class Program { static void Main(string[] args) { var token = GetAuthorizationHeader(); var credential = new TokenCloudCredentials(ConfigurationManager.AppSettings["subscriptionId"], token); using (var computeClient = new ComputeManagementClient(credential)) { var images = computeClient.VirtualMachineOSImages.List(); } } private static string GetAuthorizationHeader() { AuthenticationResult result = null; var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]); string clientId = ConfigurationManager.AppSettings["clientId"]; string clientSecret = ConfigurationManager.AppSettings["clientSecret"]; ClientCredential clientCred = new ClientCredential(clientId, clientSecret); var thread = new Thread(() => { result = context.AcquireToken( "https://management.core.windows.net/", clientCred); }); thread.SetApartmentState(ApartmentState.STA); thread.Name = "AquireTokenThread"; thread.Start(); thread.Join(); if (result == null) { throw new InvalidOperationException("Failed to obtain the JWT token"); } string token = result.AccessToken; return token; } }
EDITAR: se ha avanzado. Cuando hablé con Gaurav, tuve que deshacerme de la Biblioteca de administración de Azure porque ahora mismo no parece ser compatible con la API de Azure Resource Manager (ARM). Entonces, en cambio, hice solicitudes web sin formato. Y funciona según lo previsto. Si elimino el acceso a las funciones de mi aplicación AD, se me niega el acceso. Cuando lo tengo, recupero los datos.
Una cosa de la que no estoy seguro es hacerlo para que mi aplicación agregue automáticamente nuevos recursos.
Además, ¿hay alguna manera de enumerar los grupos de recursos accesibles para mi aplicación AD?
Nuevo código:
class Program { static void Main(string[] args) { var token = GetAuthorizationHeader(); string subscriptionId = ConfigurationManager.AppSettings["subscriptionId"]; string resourceGroupName = ConfigurationManager.AppSettings["resourceGroupName"]; var uriListMachines = string.Format("https://management.azure.com/subscriptions/{0}/resourceGroups/{1}/providers/Microsoft.Compute/virtualmachines?api-version=2015-05-01-preview", subscriptionId, resourceGroupName); var t = WebRequest.Create(uriListMachines); t.ContentType = "application/json"; t.Headers.Add("Authorization", "Bearer " + token); var response = (HttpWebResponse)t.GetResponse(); string result = ""; using (var reader = new StreamReader(response.GetResponseStream())) { result = reader.ReadToEnd(); } //Original Attempt: //var credential = new TokenCloudCredentials(ConfigurationManager.AppSettings["subscriptionId"], token); //using (var client = CloudContext.Clients.CreateComputeManagementClient(credential)) //{ // var images = client.VirtualMachineVMImages.List(); //} } private static string GetAuthorizationHeader() { AuthenticationResult result = null; var context = new AuthenticationContext("https://login.windows.net/" + ConfigurationManager.AppSettings["tenantId"]); string clientId = ConfigurationManager.AppSettings["clientId"]; string clientSecret = ConfigurationManager.AppSettings["clientSecret"]; ClientCredential clientCred = new ClientCredential(clientId, clientSecret); var thread = new Thread(() => { result = context.AcquireToken( "https://management.core.windows.net/", clientCred); }); thread.SetApartmentState(ApartmentState.STA); thread.Name = "AquireTokenThread"; thread.Start(); thread.Join(); if (result == null) { throw new InvalidOperationException("Failed to obtain the JWT token"); } string token = result.AccessToken; return token; } }
EDITAR EDITAR: Me di cuenta de que colgué. Los recursos creados en el portal OLD obtendrán su propio grupo de recursos.
Por lo que puedo decir, no puede agregar un recurso creado en el grupo de recursos existente del portal anterior (boooo). Los recursos creados en el nuevo portal podrán asignar el recurso a un grupo existente (también conocido como uno que da acceso a un rol a mi aplicación AD).
¡Esto es un desastre! Pero al menos sé lo que está pasando ahora.
Creo que estás en el camino correcto para saber por qué te encuentras con este problema.
Esto es lo que está pasando:
Básicamente, el permiso para ejecutar la Service Management API
es un delegated permission and not an application permission
. En otras palabras, la API se ejecuta en el contexto del usuario para el que se adquiere el token. Ahora está obteniendo este token para su aplicación (especificado por id / secreto del cliente). Sin embargo, su aplicación no tiene acceso a su suscripción de Azure porque el registro de usuario creado para esta aplicación en su Azure AD es de tipo Service Principal
. Como este Director de Servicio no tiene acceso a su Suscripción Azure, está obteniendo este Forbidden Error
(debo decir que el error es engañoso porque no está usando ningún certificado).
Hay algunas cosas que podrías hacer:
Azure Portal
. Consulte este enlace para obtener más detalles al respecto: https://azure.microsoft.com/en-in/documentation/articles/resource-group-create-service-principal-portal/ . Co-Admin
en su suscripción a Azure y tendrá pleno acceso a su suscripción a Azure, ya que con la API SM no existe el concepto de Role-based access control
.