Authorize a user for azure blob access - azure

I am authenticating the users to my web page using the microsoft login via adal-node library.
adal-node has an AuthenticationContext from which we can get a JWT token using acquireTokenWithAuthorizationCode.
So, the users of my active directory app can now successfully login with their Microsoft accounts.
Now, the question is how to get their RBAC roles for a specific storageaccount/container/blob using the above received JWT Token? Is that even possible?
Or should I be using a library like azure-arm-authorization for this purpose? I have set the RBAC roles for each storageaccount/container/blob but I am not finding any online documentation on how to get these roles for every logged in user of my app.
Any help would be invaluable.
TL;DR How do I authorize azure blobs?

According to my research, if we want to use Azure AD Authentication to acess Azure blob storage, we need to assign Azure RABC role for Azure storage account or container. For more details, please refer to here. Besides, we can use Azure CLI to assign role and get role assignment.
For example
# assign role
az role assignment create \
--role "Storage Blob Data Contributor" \
--assignee <email> \
--scope "/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>/blobServices/default/containers/<container>"
# list role assignment of the resource
az role assignment list --scope "/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>/blobServices/default/containers/<container>"
For further information, please read the article
Update1
If you want to use nodejs sdk to get the role assignment, please refer to the following code
const authorizationManagement = require('azure-arm-authorization');
const msrestAzure = require('ms-rest-azure');
const scope = '/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>/blobServices/default/containers/<container>';
const subscriptionId = 'e5b0fcfa-e859-43f3-8d84-5e5fe29f4c68';
msrestAzure.interactiveLogin().then(credentials => {
const client = new authorizationManagement(credentials, subscriptionId);
client.roleAssignments.listForScope(scope).then(result => {
result.forEach(element => {
client.roleDefinitions.getById(element.roleDefinitionId).then(result => {
console.log("principal ID: "+ element.principalId+"\nrole name: "+result.roleName)
});
});
});
})
For more details, please refer to Get access control list (IAM) of a resource group in Node.js
Update2
According to my test, if you want to use azure-arm-authorization with adal-node. Please refer to the following code
const authorizationManagement = require('azure-arm-authorization');
const TokenCredentials = require('ms-rest').TokenCredentials
const adal = require('adal-node').AuthenticationContext;
const scope = '/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>/blobServices/default/containers/<container>';
const subscriptionId = 'e5b0fcfa-e859-43f3-8d84-5e5fe29f4c68';
// use service principal to get access token with adal-node
/*
If you do not have a service principal, you can use the following Azure CLI command(https://learn.microsoft.com/en-us/cli/azure/ad/sp?view=azure-cli-latest#az-ad-sp-create-for-rbac) to create it
az ad sp create-for-rbac -n "MyApp" --role contributor
*/
const tenant = 'your-tenant-id';
const authorityUrl = "https://login.microsoftonline.com/" + tenant;
const clientId = 'your-client-id';
const clientSecret = 'your-client-secret';
const resource = 'https://management.azure.com/';
const context = new adal(authorityUrl);
context.acquireTokenWithClientCredentials(
resource,
clientId,
clientSecret,
(err, tokenResponse) => {
if (err) {
console.log(`Token generation failed due to ${err}`);
} else {
const credentials = new TokenCredentials(tokenResponse.accessToken);
const client = new authorizationManagement(credentials, subscriptionId);
client.roleAssignments.listForScope(scope).then(result => {
result.forEach(element => {
client.roleDefinitions.getById(element.roleDefinitionId).then(result => {
console.log("principal ID: " + element.principalId + "\nrole name: " + result.roleName)
});
});
});
}
}
);
Besides if you want to know how to use passport-azure-ad to get role assignment, you can use passport-azure-ad to get AD access token then call the Azure rest API. Regarding how to implement it, you can refer to the sample.

Related

Assigned Azure AD Roles missing in User Claims in Blazor Client App

I have created a role for within an Azure App registration and assigned to me.
This is the role
This is the assignment in the enterprise application
Now in the Blazor Client App,when i try to read the User roles assigned it is empty
var authstate = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authstate.User;
userName = user.Identity.Name;
var x = user.Claims.Where(t => t.Type == System.Security.Claims.ClaimTypes.Role).ToList();
The dependencyInjection is Program.cs looks like this
builder.Services.AddMsalAuthentication(options =>
{
builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);
options.ProviderOptions.DefaultAccessTokenScopes.Add("User.Read");
});
Update:
Program.cs
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "user.read" })
.AddInMemoryTokenCaches();
// Add services to the container.
//builder.Services.AddControllersWithViews();
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
})
// Add the Microsoft Identity UI pages for signin/out
.AddMicrosoftIdentityUI();
=====================================================
I can get the roles, as you can see, I have a role, and I assigned it to a user
To access the Azure AD API, you have to grant your app with right permissions. On your API Application go to API Permissions page, select Grant admin consent.

Create Azure AD Groups from Azure Functions

I need to create a NodeJS Azure Function that should create Azure AD Groups based on some logics. My question is which SDK to use for this scenario? I have been googling for the past few days and got lost in the Microsoft Documentation jungle.
My function will be called from a browser client with a parameter in the query which will be the Group name.
Thanks a lot for any advice!
We can use ms graph api to create azure ad group, and for nodejs, Microsoft also provide graph SDK for calling graph api. Here's the code snippet:
const options = {
authProvider,
};
const client = Client.init(options);
const group = {
description: 'Self help community for library',
displayName: 'Library Assist',
groupTypes: [
'Unified'
],
mailEnabled: true,
mailNickname: 'library',
securityEnabled: false
};
await client.api('/groups')
.post(group);
Here we also need to create an author provider so that it can give the authorization to graph client to create the group. Since this is an Azure function, we should use the client credential provider. Here's the code snippet:
const {
Client
} = require("#microsoft/microsoft-graph-client");
const {
TokenCredentialAuthenticationProvider
} = require("#microsoft/microsoft-graph-client/authProviders/azureTokenCredentials");
const {
ClientSecretCredential
} = require("#azure/identity");
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
const authProvider = new TokenCredentialAuthenticationProvider(credential, {
scopes: [scopes]
});
const client = Client.initWithMiddleware({
debugLogging: true,
authProvider
// Use the authProvider object to create the class.
});

How to use existing Container Registry when creating AKS cluster in Pulumi Azure Native

I created Azure Container Registry (ACR) and now need to create Managed Cluster (AKS). When we use Azure Portal or Azure CLI, we can integrate existing ACR. In Pulumi Azure Native, ManagedClusterArgs does not have any property to accept existing ACR.
How to attach already created ACR when creating Managed Cluster?
Or assigning AcrPull role to the automatically created User Assigned Managed Identity (<clsuter-name>-agentpool) will achieve the same?
Yes, you need to assign AcrPull role to managed identity of the cluster (VMSS).
(make sure that the Service Principal used by Pulumi CLI has User Access Administrator role, otherwise Pulumi would not be able to create role assignment)
Here is an example using a system-assigned managed identity in TypeScript:
const cluster = new containerservice.ManagedCluster("managedCluster", {
// ...
identity: {
type: "SystemAssigned",
},
});
const creds = containerservice.listManagedClusterUserCredentialsOutput({
resourceGroupName: resourceGroup.name,
resourceName: cluster.name,
});
const principalId = cluster.identityProfile.apply(p => p!["kubeletidentity"].objectId!);
// const registry = ...
// const subscriptionId = ...
const roleDefinitionId = `/subscriptions/${subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/7f951dda-4ed3-4680-a7ca-43fe172d538d`;
const assignment = new azure_native.authorization.RoleAssignment("acr-pull", {
properties: {
principalId: principalId,
roleDefinitionId: roleDefinitionId,
},
scope: registry.id,
});
C#:
// var mainAcr = new AzureNative.ContainerRegistry.Registry("MainContainerRegistry", new AzureNative.ContainerRegistry.RegistryArgs { // ... });
// var aksAppCluster = new ManagedCluster("AksAppplicationCluster", new ManagedClusterArgs { // ... });
var vmssManagedIdentityPrincipalId = aksAppCluster.IdentityProfile.Apply(identityProfile =>
{
var vmssManagedIdentityProfile = identityProfile!["kubeletidentity"];
return vmssManagedIdentityProfile.ObjectId;
});
var acrPullRoleDefinitionId = RoleUtil.GetAcrPullRoleDefinitionId();
// I created RoleUtil and GetAcrPullRoleDefinitionId() will return: "subscriptions/${subscriptionId}/providers/Microsoft.Authorization/roleDefinitions/7f951dda-4ed3-4680-a7ca-43fe172d538d"
var roleAssignment = new AzureNative.Authorization.RoleAssignment(AcrPullRoleAssignment, new AzureNative.Authorization.RoleAssignmentArgs
{
PrincipalId = vmssManagedIdentityPrincipalId!,
PrincipalType = AzureNative.Authorization.PrincipalType.ServicePrincipal,
RoleDefinitionId = acrPullRoleDefinitionId,
Scope = mainAcr.Id,
});
For built-in role ids: https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles

Is it possible to create a secret_id to use it in an approle automatically without the help of an administrator or kubernetes when using vault?

Recently searching the internet I found a good alternative to manage the secrets of my application created in node js with the help of hashicorp vault. I have investigated how it works and among the possible ways that this tool has to enter I found approle, which I consider an adequate form of authentication through my application. This form of authentication requires a role_id and a secret_id. The latter, as I see in the examples of the official vault page, needs an entity for its creation and then passes it to the application and in this way the application can receive the token to enter the vault. Currently I have this code in node js that receives a token wrapped with the secret_id to achieve access to the secrets with the role of the application:
//get the wrap token from passed in parameter
var wrap_token = process.argv[2];
if(!wrap_token){
console.error("No wrap token, enter token as argument");
process.exit();
}
var options = {
apiVersion: 'v1', // default
endpoint: 'http://127.0.0.1:8200',
token: wrap_token //wrap token
};
console.log("Token being used " + process.argv[2]);
// get new instance of the client
var vault = require("node-vault")(options);
//role that the app is using
const roleId = '27f8905d-ec50-26ec-b2da-69dacf44b5b8';
//using the wrap token to unwrap and get the secret
vault.unwrap().then((result) => {
var secretId = result.data.secret_id;
console.log("Your secret id is " + result.data.secret_id);
//login with approleLogin
vault.approleLogin({ role_id: roleId, secret_id: secretId }).then((login_result) => {
var client_token = login_result.auth.client_token;
console.log("Using client token to login " + client_token);
var client_options = {
apiVersion: 'v1', // default
endpoint: 'http://127.0.0.1:8200',
token: client_token //client token
};
var client_vault = require("node-vault")(client_options);
client_vault.read('secret/weatherapp/config').then((read_result) => {
console.log(read_result);
});
});
}).catch(console.error);
The problem is that I plan to upload the application in the cloud using docker and the idea is that the process of obtaining the secrets is automatic so I would like to know if when creating a token that lasts long enough that you only have the possibility of obtaining the secret_id of a role and saving it as environment variable is appropriate in this case or if there is any other alternative that can help me in automating this case.
Note: I don't plan to deploy in aws in this case.

PowerBI Client does not work with Azure AD service principals

I am trying to get data from PowerBI APIs (using Microsoft.PowerBI.Api.V2 client dlls). Below is my code:
private static async Task getEmbedTokens(string accessToken)
{
var tokenCredentials = new TokenCredentials(accessToken, "Bearer");
var client = new PowerBIClient(new Uri("https://api.powerbi.com/"), tokenCredentials);
var reports = await client.Reports.GetReportsInGroupAsync("<groupid here>");
// Get the first report in the group.
var report = reports.Value.FirstOrDefault();
if (report != null)
{
var generateTokenRequestParameters = new GenerateTokenRequest(accessLevel: "view");
var tokenResponse = await client.Reports.GenerateTokenInGroupAsync("<group id here>", "<report id here>", generateTokenRequestParameters);
if (tokenResponse != null)
{
// Generate Embed Configuration.
var embedConfig = new EmbedConfig()
{
EmbedToken = tokenResponse,
EmbedUrl = report.EmbedUrl,
Id = report.Id
};
}
}
}
Now I use ADAL to generate bearer tokens and I have tried below 2 scenarios:
Scenario 1: Use UserCredentials (Service account) to generate bearer tokens
HereI am using service account to generate bearer tokens. The service account has access to the powerbi dashboard.
var credential = new UserPasswordCredential("username#tenantname.onmicrosoft.com", "password");
Scenario 2: Use ClientCredentials (Service principal) to get bearer tokens
Here I am using client id , client secret of a service principal. The service principal has been granted all permissions for Power BI APIs in Azure AD app registration panel.
var clientCred = new ClientCredential(clientId, clientSecret);
Scenario 1 works fine, but scenario 2 I get unauthorized error. I have tried to check if there is any way to give the principal access to dashboard thru power bi portal, but could not find any.
I prefer to use service principal, but is it possible to use service principal?
currently Power BI doesn't support Service principal / app only tokens.

Resources