Azure Function App access to its own storage account with Shared Key Authentication disabled - azure-active-directory

In my organization I have a requirement to set "Allow storage account key access" on a storage account to Disabled, such that Primary and Secondary Access keys cannot be used to connect to the storage account:
When I create a simple Consumption based .NET 3.1 Function App in Azure Portal and create a sample Queue Triggered function directly in the Portal, my Function App cannot access anything on its own storage account when I have this "Allow storage account key access" set to Disabled.
I can understand that it cannot access its own binary files which are stored in the storage account's fileshare. I have created a Managed Identity for my Function App and assigned it all these RBAC roles on its own storage account:
Why can't the Function App not read its own files when I have given all these permissions?
My Configuration uses this syntax AzureWebJobsStorage__accountName:
Application Insights is also not available:
If I set "Allow storage account key access" to Enabled then everything works:
So how do I go about this simple scenario of having to fulfil the requirement to have "Allow storage account key access" set to Disabled and use a .NET Consumption based Function App?
UPDATE: I've now created a .NET 6 Isolated C# Function and deployed the code to a new FunctionApp with .NET 6 support and used the notation "AzureWebJobsStorage__accountName" in my Configuration and it still doesn't work for me.
UPDATE2: I have managed to get it to work. The trick was to use Microsoft.Azure.WebJobs.Extensions.Storage.Queues version 5.x+ as this supports AAD Authentication: Microsoft.Azure.WebJobs.Extensions.Storage.Queues
You cannot use the Developer Portal under Functions in Function App to test this out. You need to test it out in code.

For an Azure Function to read from a Storage Account and its Queue, you need to provide the Storage Queue Data Contributor role on the Storage Account for the Azure Function's Managed Identity.
In order to use Managed Identity and thus AAD Authentication the Azure Function code needs to use version 5.x+ of this package: Microsoft.Azure.WebJobs.Extensions.Storage.Queues
The .NET 6 Isolated Azure Function that is Queue Triggered looks like this:
public class Function1
{
private readonly ILogger _logger;
public Function1(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<Function1>();
}
[Function("Function1")]
public void Run([QueueTrigger("myqueue01")] string myQueueItem)
{
_logger.LogInformation($"C# Queue trigger function processed: {myQueueItem}");
}
}
and the local.settings.json looks like this:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage__accountName": "<storage-account-name-here>",
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
}
}
and when it is Published to an Azure Function App you can just have this configuration: AzureWebJobsStorage__accountName

Related

How to update Secret Token property in Azure AD Synchronization API?

I am trying to find a way how to programmatically change properties of Enterprise Application (non-catalogue app), specifically Secret Token and Tenant ULR in 'Provisioning' blade, allowing to synchronize user/group objects between AAD and an external app (e.g. SaaS app) that supports it.
My customer has a strict policy to rotate all secrets and keys in Azure in regular intervals, so they want to be able to have an automation runbook that would change that token in the app (it is actually an Azure Databricks instance that supports this sync) as well as in AAD.
I checked whether there was a direct PowerShell support but I couldn’t find a specific cmdlet for this scenario (tried both GA and preview versions of AAD PowerShell 2.0).
I found a good documentation page describing AAD Synchronization API - https://learn.microsoft.com/en-us/graph/api/resources/synchronization-overview?view=graph-rest-beta – however, I am unable to find, how to update the Secret Token property.
Ideally, I would like to see a code sample of a REST call on how change that specific property using Synchronization API. A PowerShell example would be even better. Any help is much appreciated. Thanks.
Here's how to do it for non-gallery SCIM apps:
PUT https://graph.microsoft.com/beta/servicePrincipals/99abefe8-3ad8-488f-b14f-df209cbc1ab3/synchronization/secrets
{
value: [
{ key: "BaseAddress", value: "xxxxxxxxxxxxxxxxxxxxx" },
{ key: "SecretToken", value: "xxxxxxxxxxxxxxxxxxxxx" }
]
}
Replace the GUID after servicePrincipals with your real servicePrincipal object ID.
For apps that aren't non-gallery SCIM apps, the credential names required can be discovered in the metadata -> configurationFields part of the synchronizationTemplate object:
https://learn.microsoft.com/en-us/graph/api/resources/synchronization-synchronizationtemplate?view=graph-rest-beta

How do I get the "Assigned Role" of a User in Azure Active Directory?

I am using Azure AD with a registered Application and I am using the Microsoft Graph API to query the AD.
The following code below tells which groups the User is Assigned to
var memberof = await graphClient.Users[xxx].MemberOf.Request().GetAsync();
I am using standard AD package and it seems that groups are somewhat restricted and I need to buy the "Premium AD Package" to use them fully.
So I don't want to use the group information. I am interested in the roles that I assign my users that I have put into my application manifest.
e.g
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Case Manager",
"id": "{A_Guid}",
"isEnabled": true,
"description": "Case Manager's can create and assign Cases to other users",
"value": "CaseManager"
},
So, how can I use the Graph Api to tell me if a user has a particular role ?
1. Microsoft Graph API
The ability to read all application specific roles assigned to a user (i.e. AppRoleAssignments) is only available as part of Microsoft Graph API beta endpoint currently AFAIK. This is not available as part of v1.0. You can read about versions here
As evident from name "beta", it's not expected to be a stable version that can be relied upon for production applications. Read more specific points in this SO Post by Marc LaFleur
Exact API (Microsoft Docs Reference):
GET https://graph.microsoft.com/beta/users/{id | userPrincipalName}/appRoleAssignments
I tried using GraphServiceClient (.NET SDK for Microsoft Graph) but wasn't able to find anything related to AppRoleAssignments. (probably because SDK uses metadata from stable 1.0 version and not the beta version)
In any case, if you can still test this, use Microsoft Graph Explorer or directly call the endpoint from C# code
string graphRequest = $"https://graph.microsoft.com/beta/users/{my user GUID}/appRoleAssignments";
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, graphRequest);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken);
HttpResponseMessage response = await client.SendAsync(request);
2. Windows Azure AD Graph API
Even though it's recommended to use Microsoft Graph API whenever possible, there are still some cases where Microsoft Graph hasn't caught up yet so you are forced to use Azure AD Graph API. Application management related cases are some of those.
So you could use this Azure AD Graph API. I quickly tested this from Azure AD Graph Explorer and it works fine.
https://graph.windows.net/{yourtenantid}/users/{id}/appRoleAssignments?api-version=1.6
Just like Microsoft Graph Library for .NET you can use Azure AD Graph Client Library for .NET and your code would look something like this..
aadgraphClient.Users["<user guid>"].AppRoleAssignments;
On a side note, since you've asked the question specifically for Microsoft Graph API, I've answered it accordingly.
At least for the currently signed in user for an application, you can always find the Application Roles assigned to them from the Role claims available as part of the access token from Azure Active Directory.
This although only helps with roles for current user and not in management sort of scenarios if you're trying to go across all users for an application. Here's a sample that reads role claims and does authorization based on App Roles for currently signed in user.
Authorization in a web app using Azure AD application roles & role claims
I just found a way to get roles of an user at an application level.
You can create application level roles by updating the manifest's appRoles array.
[azure/app registrations/<your-app>/manifest)]
I used Microsoft.Graph.Beta, to get access to service principals api.
var userRoles = await _client.Me.AppRoleAssignments.Request().GetAsync();
The above query would fetch all the application roles for the user.
var appRoleAssignments = await _Client.ServicePrincipals[<<application_objectId>>].Request().GetAsync();
The above query would fetch all the roles of an application assigned at manifest level.
And application object Id could be found at [azure/app registrations/<your-app>)] -> Object ID
And execute the below to get list of user roles
var roles = new List<string>();
if (appRoleAssignments != null && appRoleAssignments.AppRoles.Any())
{
var userRolesOfCurrentResource = userRoles.First(role => role.ResourceId == Guid.Parse(<<application object id>>));
if(userRolesOfCurrentResource!=null)
{
var role = appRoleAssignments.AppRoles.First(role => role.Id == userRolesOfCurrentResource.AppRoleId);
if (role!=null)
{
roles.Add(role.Value);
}
}
}

Identityserver and SQL server Database

we are looking for brand new implementation for Identityserver4,
I wnet thru the documentation and install the Project on VS2017 and DB in sqlserver.
Database is created with the default migration script provided for bot ConfigurationData as well as Operational DAta.
I am very much confused , where the user will be how the clients will be add etc?
Also in the startup the default ASPNEtIdentity is add, but in database there is no ApplicationUser table, so where the userdata will be?
My requirement is simple - User will be aple to login to application by his credentials(or may be by 3rd party application) and will use the application or
API will directly use Identity server to with clientcredential scope,
Here please do let me know:
Should I introduce AspNetIdentity or Not, and Why?
Where is the user table and Password of the user in the database generated by the migration.
How we can add User clients and resources to the Created Database
Do I need to add Login/Logout page ?
In API APIResource is used to defined the Resources "api1" and same is used by the client code to get the access but this "api1" is not used anywhere with the definition/signature of the Method, so ow will it be correlated?
First off, IdentityServer4 on it's own does not handle users or authentication thereof - you either need to use ASP.Net Identity and the integration library that hooks it up to IdentityServer4 or build all of that stuff yourself.
So to sum up:
Yes you'll need to use that or roll your own user store and authentication logic
Either provided by ASP.Net Identity or built yourself
https://www.identityserver.com/documentation/admin-ui/ may fit your needs or you could build your own tooling and/or scripts to do so
Yes although the quickstart samples provide good basic starting points
The bearer token middleware by default will validate the audience (ApiResource.Name) but I prefer to enforce scope at a more granular controller or action level using a filter (e.g. [ScopeAuthorize("my.api")] public MyResult ApiAction() { ... }). This filter will check that the specified scope is defined in the set of claims in the ClaimsPrincipal).

App engine project-1 trying to access BQ in project-2?

My App engine is running in project-1. I want to access the BQ present in project-2. How can i make app engine in project-1 access the BQ present in project-2?
You should request "can view" (or "can edit") permissions on the dataset of your interest. Owner of project-2 (or respective dataset) will be able to do so.
You don't need to be present on project level and in some cases it is not even appropriate - but you must have appropriate permissions on dataset level
If, by chance, you are the owner of project-2 or respective dataset - you can easily do this by following below instructions
https://cloud.google.com/bigquery/bigquery-web-ui#sharedataset
The easiest way to accomplish this is to add the default service account of "project-1" to the permissions list of "project-2":
within the cloud console go to the permissions section of project-1
select the service accounts sub tab
look for the default service account (or create a new one)
add the service account to the permissions of project-2
EDIT
You need to create your client in a fashion that uses the applications default service account. For example if you're using python it would look something like:
# Grab the application's default credentials from the environment.
credentials = GoogleCredentials.get_application_default()
# Construct the service object for interacting with the BigQuery API.
bigquery_service = build('bigquery', 'v2', credentials=credentials)
Now with your PK file you can launch the dev appserver in a fashion that the same client client will work correctly: Unable to access BigQuery from local App Engine development server

User.IsInRole("fake group") results in "The trust relationship between the primary domain and the trusted domain failed"

I have an MVC 3 app, using Windows Authentication with Claims using WIF 4.5.
Access to the application is controlled (currently) via membership in an AD group:
<deny users="?" />
<allow roles="domain\somegroup" />
<deny users="*" />
In addition to the AD groups, we have custom roles that need to be added. (This app is being converted from Forms to Windows authentication)
To support these custom roles (until they are managed in AD), we are adding them as ClaimTypes.GroupSid claims to the user, so that existing code utilizing [Authorize("ADMIN")] and User.IsInRole("ADMIN") continues to function:
Application_PostAuthenticateRequest(object sender, EventArgs e)
{
var identity = ClaimsPrincipal.Current.Identity as WindowsIdentity;
var roles = userDAL.GetRoles(identity.Name);
foreach(var role in roles)
{
identity.AddClaim(new Claim(ClaimTypes.GroupSid, role));
}
}
And this is all working as expected.
Except when the current user is NOT a member of some custom role (like ADMIN) and that role also doesn't exist in AD
We use [Authorize("ADMIN")] on Controller Action Methods, as well as various instances of User.IsInRole("ADMIN") depending in the scenario. It's in those instances where the error occurs and the app blows up.
The AD infrastructure is in the midst of an upgrade/migration. I'm not privy to all the details there, but I do know there are a handful of domains, supposedly with trust between them, and it's been alluded to me by the infrastructure folks that these trust relationships are up and running.
So really I guess I'm wondering 2 things:
This really doesn't seem like something our code should have to handle. So what could really be wrong with the domain? Can I find out what 'trusted' domain the trust relationship is failing for?
What is the best way to work around this? I dislike the idea of writing helper methods & Authorize() subclasses just to trap this exception.
Please go to inetmgr, sites, default web site, site name, iis group, double-click authentication, disable anonymous authentication, then reset the app pool.
This appears to happen when windows cannot decipher the roles defined under the 'authorization, allow roles' tag in the web.config file. For testing comment out the custom roles tags from the web.config file. The issue appears to be caused when mixing up Forms authentication and Windows authentication. The magic happens in the Global.asax file Application_PostAuthenticateRequest method, when using Forms authentication you can Cast the User.Identity as FormsIdentity, then create the custom identity from the FormsIdentity Ticket, then create the custom principle from the custom identity, you will then be able to attach the CustomPrincipal to the Current User and Current Principal, ie.
Dim fIdent As FormsIdentity = CType(User.Identity, FormsIdentity)
Dim ci As New CustomIdentity(fIdent.Ticket)
Dim cp As New CustomPrincipal(ci)
HttpContext.Current.User = cp : Thread.CurrentPrincipal = cp
For IIS you want to enable Forms authentication and anonymous authentication, everything else should be disabled. When using Windows authentication the Global.asax file Application_PostAuthenticateRequest method can create the custom principle directly from the User.Identity ie.
Dim cp As New CustomPrincipal(User.Identity)
HttpContext.Current.User = cp : Thread.CurrentPrincipal = cp
In this case the IIS settings should be Windows authentication and ASP.Net Impersonation is enabled and everything else is disabled.
Getting these authentication methods mixed up results in the 'The trust relationship between the primary domain and the trusted domain failed' error because if your Application_PostAuthenticateRequest method is not implementing the CustomPrinciple for some reason then windows will try to use the built in IsInRole function that checks the role against the domain roles instead of using your custom IsInRole that is in your CustomPrinciple code behind file.
Here is a useful article and links:
http://www.codeproject.com/Articles/8819/Authorize-and-authenticate-users-with-AD
https://msdn.microsoft.com/en-us/library/ff647405.aspx
https://support.microsoft.com/en-us/kb/306359
This happens if you have a trusted domain configuration that is not available, IsInRole searches the group in the trusted doamins as well, and if the trusted domain is not available, throws the Trust exemption.

Resources