I am trying to author an application that allows a user to query a list of websites from their Azure subscription from within my application. I do not want to store their credentials in my app (nor should they want me to), but instead I would ask them them to register an Application from within their Azure AD instance, and then have them store the ClientID and TenantID generated in my app. I would give them a set of instructions on how to do this from their Azure Portal that uses the most restrictive permissions possible, and that they could turn off at anytime. They need to feel comfortable doing this, as I would.
I am trying to follow the plot of this article: Using Azure resource graph with .net SDK
It gets me very close, but when I run the app I get a "Forbidden" response from the Azure Resource Graph, so the call is getting through but is being rejected. I have also tried to add various API Permissions using my own Azure Portal for testing. The article says that I need to create a service principal using:
az ad sp create-for-rbac -n "MyApp" --role contributor --sdk-auth
Which I have not done, yet.
So my questions are:
Is this my problem?
Do I need to ask my user to create a service principal, and if so, what value goes into the "MyApp" variable in the example above?
Is there a better approach to doing this that expects less of the user?
I appreciate any guidance or article referrals anyone can provide.
Many thanks....
If you want to call Azure resource graph Rest API with service principal, you must assign Azure RABC Role to the sp. So you must run the following command
# it will create a service pricipal and assign a contributor rolen to the sp
az ad sp create-for-rbac -n "MyApp" --scope "/subscriptions/<subscription id>" --sdk-auth
# if you have a service principal, please run the following script
az ad sp list --display-name "{name}" --query [].objectId --output tsv
az role assignment create --assignee <sp object id> --role "Contributor " --scope "/subscriptions/<subscription id>"
Meanwhile, the detailed steps about how to run the sample are as below
az login
az ad sp create-for-rbac -n "MyApp" --scope "/subscriptions/<subscription id>" --sdk-auth
public async static Task Test() {
CustomLoginCredentials creds = new CustomLoginCredentials();
var resourceGraphClient = new ResourceGraphClient(creds);
var queryReq = new QueryRequest {
Subscriptions = new List<string> { "<the subscriptionId you copy>" },
Query = "where type == 'microsoft.web/sites'"
};
var result = await resourceGraphClient.ResourcesAsync(queryReq);
Console.WriteLine(result.Count);
}
class CustomLoginCredentials : ServiceClientCredentials {
private static string tenantId = "<the tenantId you copy >";
private static string clientId = "<the clientId you copy>";
private static string cert = "<the clientSecre tyou copy>";
private string AuthenticationToken { get; set; }
public override void InitializeServiceClient<T>(ServiceClient<T> client)
{
var authenticationContext =
new AuthenticationContext("https://login.microsoftonline.com/"+tenantId);
var credential = new ClientCredential(clientId: clientId, clientSecret: cert);
var result = authenticationContext.AcquireTokenAsync(resource: "https://management.azure.com/",
clientCredential: credential).Result;
if (result == null)
{
throw new InvalidOperationException("Failed to obtain the JWT token");
}
AuthenticationToken = result.AccessToken;
}
public override async Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
if (AuthenticationToken == null)
{
throw new InvalidOperationException("Token Provider Cannot Be Null");
}
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", AuthenticationToken);
await base.ProcessHttpRequestAsync(request, cancellationToken);
}
For more details, please refer to
https://learn.microsoft.com/en-us/cli/azure/ad/sp?view=azure-cli-latest#az-ad-sp-create
According to your needs, I think you can create a web application to call Azure Resource Graph API. If you do that, you can provide the url of web app then your customers can login your application and call the API by themselves.
Configure code. Please refer to the sample