Trying to use Managed Identity with Azure Service Bus - azure

I've tried following this tutorial in order to authenticate my service bus against DefaultAzureCredentials, however, I get a 401.
I'm using the following code in the set-up:
services.AddAzureClients(x =>
{
x.AddServiceBusClientWithNamespace("myns.servicebus.windows.net")
.WithCredential(new Azure.Identity.DefaultAzureCredential());
});
I then call the SB client like this:
var sender = client.CreateSender("myqueue");
var message = new ServiceBusMessage(Encoding.UTF8.GetBytes("test"));
await sender.SendMessageAsync(message);
When I call SendMessageAsync I get a 401 error:
fail: Azure-Messaging-ServiceBus[82]
An exception occurred while creating send link for Identifier: myqueue-578624f3-f732-4a9b-2ab0-9adc01949a5a. Error Message:
'System.UnauthorizedAccessException: Put token failed. status-code:
401, status-description: InvalidIssuer: Token issuer is invalid.
TrackingId:cde3a89c-8108-48d1-8b8f-dacde18e176f,
SystemTracker:NoSystemTracker, Timestamp:2021-05-19T07:18:44.
Before I run this, I call az login. I have access to the the namespace to both send and receive. My guess is that I need to allocate some kind of permission between the service bus and ... something - but since I'm running this as a console app, I'm running with my own credentials. Clearly there's something about managed identity that I don't understand.
EDIT:
Following advice from #juunas, I tried the following:
services.AddHostedService<ConsoleHostedService>();
services.AddAzureClients(x =>
{
//var creds = new Azure.Identity.EnvironmentCredential(); // 1st - EnvironmentCredential authentication unavailable. Environment variables are not fully configured.'
//var creds = new Azure.Identity.ManagedIdentityCredential(); // 2nd - No Managed Identity endpoint found
//var creds = new Azure.Identity.SharedTokenCacheCredential(); // 3rd - 'SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.'
//var creds = new Azure.Identity.VisualStudioCodeCredential(); // 4th - 'Stored credentials not found. Need to authenticate user in VSCode Azure Account.'
//var creds = new Azure.Identity.AzureCliCredential(); // 5th
var creds = new Azure.Identity.DefaultAzureCredential();
x.AddServiceBusClientWithNamespace("myns.servicebus.windows.net")
.WithCredential(creds);

It says the "token issuer is invalid".
That means it got an access token, but it was issued by the wrong Azure AD tenant.
The Az CLI allows you to specify the Azure AD tenant id with the -t tenant-id-here argument on az login.
DefaultAzureCredential could also be using some other credential (it attempts multiple credentials like VisualStudioCredential before the AzureCliCredential).
You could instead try to use AzureCliCredential directly and see if it works.
That of course won't use Managed Identity so you'd need to use ChainedTokenCredential with the AZ CLI credential + ManagedIdentityCredential to support both.

Related

Unauthorize Error to Azure App Configuration with Azure Functions

I'm using App Configuration and Key Vault for store my config. Firstly, I used access key where was Endpoint, Id and Secret. That is working fine, but it isn't secure, because Id and Secret are sensitive data.
I tried to use value after 'Endpoint=' and in Startup.cs set DefaultAzureCredential(), but always when I launch my Azure Function, I get 401 (Unauthorize error). Why do I get this and how could I fix that?
ConfigureAppConfiguration in Startup
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
base.ConfigureAppConfiguration(builder);
var configurationBuilder = builder.UseAppSettings().ConfigurationBuilder.AddEnvironmentVariables().Build();
var connectionString = configurationBuilder["appConfiguration"];
builder.ConfigurationBuilder.AddAzureAppConfiguration(options =>
{
var credentials = new DefaultAzureCredential();
options.Connect(new Uri(connectionString), credentials)
.Select(KeyFilter.Any, LabelFilter.Null)
.Select(KeyFilter.Any, builder.GetContext().EnvironmentName)
.ConfigureKeyVault(kv =>
{
kv.SetCredential(new DefaultAzureCredential());
});
});
}
appConfiguration from appsettings
"appConfiguration": "https://rta-dev-edu-app-config.azconfig.io"
Error
A host error has occurred during startup operation '9467e813-9979-44b9-8ecf-3d956fbaf72e'.
Azure.Data.AppConfiguration: Service request failed.
Status: 401 (Unauthorized)
WWW-Authenticate: HMAC-SHA256,Bearer error="invalid_token", error_description="The access token is from the wrong issuer. It must match the AD tenant associated with the subscription, to which the configuration store belongs. If you just transferred your subscription and see this error message, please try back later.
P.S. I already added my account to IAM for my App Configuration.
The access token is from the wrong issuer. It must match the AD tenant associated with the subscription, to which the configuration store belongs. If you just transferred your subscription and see this error message, please try back later.
As Mentioned in this MS Doc of Accessing the Key Vault from the Dot Net Core Application,
you have to check that your account should have the multiple tenants access and then Set the Credential types such as SharedTokenCacheTenantId, VisualStudioTenantId to the DefaultAzureCredentialOptionswhile using the DefaultAzureCrendential in the required tenant.
Your Azure Account should be logged in the Same tenant level as you're trying to access the app configuration resource from the same tenant.
Refer to the GitHub Issue #14867.

How can I resolve an unauthorized error when using Azure Management API?

How can I resolve an unauthorized error when using Azure Management API?
Note:
I would prefer to resolve this programmatically (in code) instead of running commands/scripts.
Objective:
I need to retrieve function names from a Function App in Azure.
Example:
var current = Pulumi.Azure.Core.GetClientConfig.InvokeAsync().Result;
var subscriptionId = current.SubscriptionId;
var appName = functionApp.Name;
var url = $"GET https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{appName}/functions?api-version=2022-03-01";
var httpClient = new HttpClient();
var result = await httpClient.GetAsync(url);
if (!result.IsSuccessStatusCode) throw new Exception($"Error: Failed to retrive Azure function names from {appName}");
var json = result.Content.ReadAsStringAsync();
Thoughts:
I think I need to create a bearer token but do not know the steps required.
I tried to reproduce the same in my environment via Postman and got same error as below:
GET https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{appName}/functions?api-version=2022-03-01
To resolve the error, you need to generate bearer token for the service principal and include it in headers section with Authorization parameter.
I registered one Azure AD application in my tenant like this: Go to Azure Portal -> Azure Active Directory -> App registrations -> New registration
Now, create one client secret in that application and copy its value like below:
Make sure to assign proper role based on your requirement. I assigned Reader role to the above service principal under my subscription like below:
Go to Azure Portal -> Subscriptions -> Your Subscription -> Access control (IAM) -> Add role assignment
In my function app, I created one HTTP function named SriHTTP like below:
Now, I generated access token via Postman with below parameters:
POST https://login.microsoftonline.com/<tenantID>/oauth2/v2.0/token
grant_type:client_credentials
client_id: <appID>
client_secret: <secret_value>
scope: https://management.azure.com/.default
Response:
I got the results successfully when I used the above token to call management API like below:
GET https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Web/sites/{appName}/functions?api-version=2022-03-01
Authorization: Bearer <token>
Response:

Get Secret from Azure Keyvault using nodejs

I need to read the list of users in the Azure active directory. The client has created a Graph API application but they do not want to share the client secret of the application, instead they asked us to use the Key vault. How to access from the node.js application the key to retrieve the list of users?
I tried the below one but gave error and I am not sure how to authenticate.
const { DefaultAzureCredential } = require("#azure/identity");
const { SecretClient } = require("#azure/keyvault-secrets");
const credential = new DefaultAzureCredential();
const vaultName = "lsm-keyvault";
const url = `https://${vaultName}.vault.azure.net`;
const client = new SecretClient(url, credential);
const secretName = "Demo";
async function main() {
const result = await client.setSecret(secretName, "MySecretValue", {
enabled: false
});
console.log(result)
}
Well, if you run the code in local, the DefaultAzureCredential will use the environmental variables automatically.
So in your case, you need to register an application with Azure AD, and get the tenant id, client id(i.e. application id), client secret(i.e. application secret), set the environmental variables, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID.
For the 403 error you got, I notice you said It added as a compound entity, based on my experience, you did not add the correct service principal related to the AD App correctly to the Access policies of the keyvault. If you add it correctly, it will appear as APPLICATION, not COMPOUND IDENTITY.
So when you add it, you could search for the client Id(i.e. application Id) or the name of your App Registration directly, make sure you add the correct one. I gave the details in this similar issue, you could refer to it.
To retrieve the secret, the Get permission is enough, the code should be
const retrievedSecret = await client.getSecret(secretName);
I notice you use client.setSecret in your code, it is used to save a secret, to use it, you may need the Set permission.
For more details, see Quickstart: Azure Key Vault client library for Node.js (v4).
Update:
I have to eventually need to deploy this but not in azure but in another environment. How do I set the environment variables and access it.
If so, you need to change your code to authenticate, use the three values directly in the code.
Change the lines
const { DefaultAzureCredential } = require("#azure/identity");
const credential = new DefaultAzureCredential();
To
const { ClientSecretCredential } = require("#azure/identity");
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
See - https://www.npmjs.com/package/#azure/identity/v/1.0.3#authenticating-as-a-service-principal
All you need to do is follow the below steps:
Create an App in the Azure Active Directory (Service Principal) from App Registrations.
Go to Key Vault resource, Access Policy blade, assign read access to this Azure AD App (Service Principal) that we created in the above step.
Set these 3 Environment variables AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_CLIENT_SECRET in your App Service. Get the values of these variables from the app that we created in step 1.
Use DefaultAzureCredential that we are already using now. This will automatically pick the credentials from the environment variables that we defined in App Service for the authentication.
Another way is to obtain Key Vault token dynamically and use that token to get the secrets from the Key Vault - https://learn.microsoft.com/en-us/samples/azure-samples/app-service-msi-keyvault-node/app-service-msi-keyvault-node/
Helpful Reference:
https://www.rahulpnath.com/blog/defaultazurecredential_from_azure_sdk/

Retrieve Azure KeyVault secret using client secret

I'm experimenting with various Azure features and currently want to retrieve a secret from KeyVault.
Straight to the case:
I'm using this nuget package to interact with my azure resources.
I've developed a simple .NET Core console app and run it locally.
I have a KeyVault resource with one secret defined which is active and not expired.
I've registered an App in AAD so my locally shipped .NET Core console app has an identity within AAD.
Than I've created a "client secret" within this registered app in AAD to use it to authenticate myself as an app.
After that I've added access policy in my KeyVault resource to allow GET operation for secrets for this registered app:
Then I've developed a small piece of code which should retrieve the desired secret:
public class AzureAuthentication
{
public async Task<string> GetAdminPasswordFromKeyVault()
{
const string clientId = "--my-client-id--";
const string tenantId = "--my-tenant-id--";
const string clientSecret = "--my-client-secret--";
var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
var client = new SecretClient(new Uri("https://mykeyvaultresource.vault.azure.net"), credentials);
var secret = await client.GetSecretAsync("admincreds");
return secret.Value.Value;
}
}
However when I'm trying to do this I'm getting an AccessDenied error:
Am I missing something painfully obvious here? Or there is some latency (>30 min for this moment) for which changes from Access policies screen in KeyVault resource are applied?
I test your code and Get permission, it works fine.
From your screenshot, it looks you didn't add the correct service principal related to the AD App to the Access policies.
If you add the service principal related to the AD App, it will appear as APPLICATION, not COMPOUND IDENTITY.
So when you add it, you could search for the client Id(i.e. application Id) or the name of your App Registration directly, make sure you add the correct one.
Make sure your AD App(service principal) has the correct permission in your keyvault -> Access policies

OAuth Authentication fails with error AADSTS65005 in ios Xamarin

The authentication used to work for us earlier but has stopped suddenly.
We have an app built in Xamamin iOs and have registered the application in Azure AD account, provided the ClientID and redirect URL as specified. But it throws an error when "authContext.AcquireToken" is being called
Exception: Microsoft.IdentityModel.Clients.ActiveDirectory.AdalServiceException: AADSTS65005: The client application has requested access to resource 'example.com/'. This request has failed because the client has not specified this resource in its requiredResourceAccess list.
Trace ID: ea22c27c-9913-4423-92dc-6fff1cf9904d
Correlation ID: 4c19258b-2391-4585-911e-853157dde073
Timestamp: 2017-01-24 09:28:49Z
Code we are using to acquire token:
var authContext = new AuthenticationContext(authority);
if (authContext.TokenCache.ReadItems().Any())
authContext = new AuthenticationContext(authContext.TokenCache.ReadItems().First().Authority);
var authResult = await authContext.AcquireTokenAsync(resource, clientId, new Uri(returnUri),
new PlatformParameters(UIApplication.SharedApplication.KeyWindow.RootViewController));
And for authority variable, we are using "https://login.microsoftonline.com/common" to authenticate. We also tried "https://login.windows.net/common" but with no luck.
Has there been any microsoft updates lately which could have stopped this code from running?
Based on the error message, you were trying to access the resource example.com/.
However this resource was removed to grant to that app.
To fix this issue, you can login the Azure portal to grant this resource to your app again like figure below(switch your Azure AD->App registrations->You App->Settings->Required permissions->Add):

Resources