Q: Multi-Tenant Azure API Management Design - azure

I have implemented a number of APIs on Azure APIM which are protected by a subscription key, and it all works fine.
I do have a constraint though, as the client application cannot be modified(*) and I can only set the URL as parameter (ie: no additional headers). I have worked around that limitation by implementing a small proxy app that customers can deploy locally and which adds the subscription key. In other words, the client app connects to a local URL, then the proxy calls the API. That also works fine.
I would like however to offer a simpler evaluation for prospects, without the need to deploy the proxy. I thought I could provide each customer their own tenant URL (eg: guid.mydomain.com) and then use that information on Azure APIM to look-up the auth key and call the backend API. That is the part I can't figure out.
I am looking for either alternative design ideas or tips on how to make it work.
Any idea?
Marco
(*) it belongs to another company.

For those that may be interested, I solved the problem by adding a new set of azure functions and a custom wildcard certificate for the subdomain.
In the azure function, the domain and subdomain info can be found in the HttpRequest.Host property. In my case, the subdomain equates to the tenant id, which I can then use to retrieve the subscription key and call the APIM API.

Related

SubscriptionKeyInvalid in Azure API Management for an endpoint in a product that does not require subscription?

I have a very strange issue with Azure API Management, that I don't seem to figure out...
We have an API operation that is part of an APIM API that is linked with a Product that does not require a subscription. The intention is that this API endpoint is publicly available for consumers, without requiring any subscription keys, headers, etc...
When I call this endpoint from Postman, it works.
When I just do a GET to the endpoint in a private browser session (so nothing added in headers, etc), it works.
When I execute the API operation from the Azure APIM portal, without selecting a product, it works.
But, when I call the endpoint from a deployed web app in Azure App Service, I get a 401 back?!
So, the obvious thing is that something is misconfigured, but I cannot get my head around it...
When looking in Application Insights, linked to the APIM instance, this is the trace, I see:
But in the following screenshot, I get a hint of the mismatch, though I don't understand how this happens... If I copy the full url to a browser private session, I get back a 200 with successful data.
But the root cause of the 401 is probably in the yellow box, where there is an API product dev-product-admin, which indeed requires a subscription (and has JWT token policies configured). So, what I need to find out now, is how I can make sure that APIM is linking my incoming request to the right product, which doesn't require a subscription. Any hints?
And two minutes after writing down the question, you get your own insight...
I checked the code and I was adding a SubscriptionKey header to that specific call (because of a configuration issue). And that subscription key was obviously making the link to the specific Product (which indeed requires more authorization)

How does authentication work on Azure Functions

I have a .Net 5 Web API hosted on Azure App Service.
The API has three Background services running as hosted services, which perform long running processes such as bulk emailing and SMSing, as well as other functionality that runs once a day on a timer.
I am thinking about moving out these hosted/background services into separate Azure Functions, which I would then call / trigger from my API via an HTTP request (except for the one that runs on a timer)
My concern is regarding authentication. How does that work with Azure Functions? Currently, my Web API is using Auth0 as the authentication server. So, when the user uses the front-end web app (Angular), he logs in (via Auth0's login form) and then the front-end retrieves an access/bearer token from AUth0, which it then includes in every call to the API (in an Authentication header).
Now, obviously I don't want just anyone to be able to call the Azure Functions - only my Web API should be able to do so. But how does that work? Does the API need to forward the access token it received from the front end to the Azure Function when calling it? Or is there something I need to set up in Azure Portal to tell it that my API must be allowed access to the Azure Function (and block any requests from any other origin)?
I've never used Azure Functions or even WebJobs before, so I'm a bit lost.
Thanks
When creating an HTTP-triggered Azure Function, by default it is set to have authorization level = Function, which means that any app trying to invoke that function via its URL needs to know the specific access key that is generated for that function upon creation.
In your example, your web API would store that function's invocation URL and access key in its configuration, and invoke your function with that key. Since the key remains entirely server-side on Azure, nothing else can access it, so it's completely secure.
Depending on your requirements, you can then also layer other types of authorization/authentication (e.g. bearer token) on top of the access key mechanism, or use those instead of access keys (by setting the function to allow anonymous access).
For maximum security, I would recommend using both the function access key as a first step to ensure that nobody except your apps can successfully invoke the function, and then passing along and authenticating the bearer token to ensure that the app trying to invoke that function is indeed permitted to do so.
Just be aware that Azure Functions is a slightly different beast to standard ASP.NET Core, particularly in regards to middleware which it doesn't really support yet, so you'll likely need to roll your own code for reading the bearer token from the incoming HTTP request's headers, and verifying that it's valid.
Reference: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=csharp#authorization-keys
For this requirement, you just need to enable "Authentication/Authorization" of your function app.
Follow the steps in the screenshot above and when you click the forth red box, choose "Express" tab and click "ok" at the bottom of the page without do anything. It will create an application in your Azure AD which has same name with your function app.
After that, when you request the function app url in browser, it will ask you to login.
For more details of the steps, you can refer to this document.
Hury's guidance is best - you want to avoid using API keys on your production functions and use this just for testing. Official guidance is here:
https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=in-process%2Cfunctionsv2&pivots=programming-language-csharp#secure-an-http-endpoint-in-production
Configure your Functions for AuthorizationLevel.Anonymous, and require Authentication on your Function as Hury describes. This will not only require end users to authenticate, but supports System Assigned Managed Identity when your function is called from other App Services. Less keys to vault or configure means less to steal.
Depends on what you mean by authentication.
If you just want to secure your functions you can use the authorization level = function.
However, if you need authentication with login, and you need to know the user making the request, you have to use bearer token with OpenIDConnect server.
Always use stateless authentication regardless your method.

When registering an app on Azure Active Direct, what "redirect URI" or "Sign-on URL" should I use?

Might seem a silly question, but Microsoft's documentation isn't very beginner friendly, I think. It uses as examples "http://localhost:31544" for the sign-on url and "http://MyFirstAADApp" for the redirect URI, but although I understand what a local host is I can't figure out what exactly the numbers on it are and how I define them for my application, and absolutely zero clue of what the redirect URI is supposed to do for a native application and how should I define a URI for my own.
To be more clear on what kind of app I'm trying to add, I merely want to acess the Office 365 management API tools and get some data from it, so I imagine a native app would fulfill my needs for now. Registering the app on Azure AD is required to do so according to Microsoft's documentation.
So expanding on the title, how to define an URI for my native app is what I would mainly like to know. Some further clarification on what exactly is the purpose of this URI as well as to how to use and/or define a localhost URL for an Web app would also be much appreciated.
I know this is ancient, but I don't see a satisfying answer here, and maybe someone will come across this and find it useful. To answer the question asked, unless you're going to work outside of the default MSAL handling of the server responses, and I don't expect you would from your description, I'd just go ahead and use the default:
https://login.microsoftonline.com/common/oauth2/nativeclient
When you go into the Azure AD portal, go to your application and, from the Overview, select the "Set RedirectURL" option, you'll add a platform and select the "Mobile and Desktop Applications" and you'll be provided with the choice of 3 URLs to choose from. My understanding is this is just there for custom handling of authorization tokens and is telling MS where to send those tokens. The MSAL library functions seem to use this link as well, so they're probably handling this in the backend.
I agree with the OP though, the MS docs are severely lacking for newcomers and I wasn't able to find an end-to-end description of what needs to happen to get, in my case, a desktop application to send email through Office365 using 2FA. I would forge ahead as best I could until I hit the next error, then explore that, sort it, then slam into the next one. Rinse and repeat. This was made extra tedious as I had to go through a 3rd party IT group to get the 2FA access codes every time I wanted to test.
Best of luck, hope this helps someone!
how to define an URI for my native app is what I would mainly like to
know.
You should provide a Redirect URI that is unique to your application as it will return to this URI when authentication is complete.
In your application, you will need to add a class level variables that are required for the authentication flow, include ClientId and Redirect URI.
Here is the diagram:
Native application makes a request to the authorization endpoint in Azure AD, this request includes the Application IP ,Redirect URI and application ID URI for the web api.
After user signed in, Azure AD issues an authorization code response back to the client application's redirect URI. After that, the client application stops browser interaction and extracts the authorization code from the response.
Then the client app use this code to sends a request to Azure AD's token endpoint. upon successful validation, Azure AD returns two tokens.
Over HTTPS, the client app uses the returned JWT access token to add the JWT string with a “Bearer” designation in the Authorization header of the request to the web API. The web API then validates the JWT token, and if validation is successful, returns the desired resource.
More information about it, please refer to this article.
For native you can set redirect to be equal to the Application ID URI, which now defaults to look like //app:{ApplicationId}
Redirect uri be starts with SSL URL, so select your project, enable SSL URL and use this auto generated SSL URL (for example : https://localhost:port#) as redirect uri , same to be updated in the azure app registration as additional redirect URIs

Multi Instance Apps and Azure Authentication Best Practices

We have a multi-instance Saas Application:
Each of our clients is given their own instance and their own subdomain for the site.
Our application (Web app & API) is protected by Azure, currently with the ADAL javascript libraries
We also have a second API for system-level integration that needs to be protected, currently using a second 'native' azure app, but this is likely incorrect and we want to consolidate
Our application reads and writes to the Azure AD both through the AzureAD Graph API and Microsoft Graph API (including password reset calls)
We're looking at Azure AD application configuration options and want to make sure we're building the most sensible and secure Azure AD Application. Here are some of the documentation we've been looking at:
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-integrating-applications
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-protocols-oauth-client-creds
https://learn.microsoft.com/en-us/azure/architecture/multitenant-identity/
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-compare
We want the application to be multi-tenant to ease configuration, and allow availability in the Gallery; but when looking into doing so we're left with some security questions.
A. Which application version to use
1) v1. Allows access to both Graph API. And as suggested by Microsoft we should use this when we're not concerned with Microsoft Accounts.
2) v2. When looking at the MS Graph API documentation it recommends using v2. Reportedly doesn't work for AzureAD Graph API? Allows the same app to be of multiple types (Web App/API and native), which we may or may not need to protect both our web api and our system api (which we're still trying to model).
B. How to manage the reply URL when our clients have different sub-domains?
I've noted the following options:
1) On the app registry, we add the reply urls for all of our customers. This seems okay because we only need to do it once, but feels odd. Is there a limit to the number of reply urls?
2) Have one reply url, but manage an external tool to route the responses to the correct instance, leveraging the state url parameter. Microsoft seems to be suggesting that in this link: https://learn.microsoft.com/en-us/azure/architecture/multitenant-identity/authenticate I'm not sure if ADAL allows us to set the state for a return subdomain url though. Is this approach common?
3) Is it possible for each ServiceProvider instance in our client's directories to configure the reply url to their own subdomain? I feel like this would be the cleanest approach, but I don't see documentation for it. It would be nice if we could set the replyURL programmatically as well.
C. How to manage authorization to the Graph APIs (AzureAD and Microsoft Graph)
I've noted the following options:
1) Use the client credential flow, with a single application key (used for all clients). As clients subscribe they will admin consent with our app to give the application permission to their directory. Of course we'd do our best to keep that key secure. But if for some reason it was compromised this would put all of our clients at risk, not just the one instance that was compromised.
2) Same as 1, but use a certificate instead of a secret key. I understand this could be a little more secure, but I don't see how it wouldn't suffer from the same issue as 1.
3) Instead of using application permissions, use delegated permissions with an admin user. This would be good, in that it inherently prevents one instance of our app from talking to the wrong directory. However changes to the administrator may interrupt service; and I think it is best audit-wise that our application is responsible for the changes it makes. (Also, do delegated permissions allow for password resetting? I know for app permissions you need to run powershell script to upgrade the application's directory role)
4) Is there some way for the service principal to generate a unique key for it's directory on creation? can this be handed back to our app programmatically? Perhaps during admin consent?
Really good questions. I'll try to answer each to the best of my knowledge, but if someone has other ideas, feel free to comment/add your own answer.
A. Which application version to use
v2 should allow you to call Azure AD Graph API. The documentation you linked shows an example of specifying Azure AD Graph scopes:
GET https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=2d4d11a2-f814-46a7-890a-274a72a7309e&scope=https%3A%2F%2Fgraph.windows.net%2Fdirectory.read%20https%3A%2F2Fgraph.windows.net%2Fdirectory.write
The main decision point if you should use v2 is: Do you need to support Microsoft accounts which are not in an Azure AD? If yes, you need to use v2. Otherwise there is no problem using v1 (well, lack of dynamic permissions).
Since you are using Azure AD Graph to modify things, I'm going to guess pure Microsoft accounts will not work for you. I would recommend sticking with v1.
v2 also has some limits: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-limitations
B. How to manage the reply URL when our clients have different sub-domains?
I could not find documentation on a limit for URLs. It could be that you can add however many you want. But I am not sure :)
If your subdomains look like this: https://customer.product.com, you can configure the reply URL as:
https://*.product.com
It will then allow any subdomain to be specified in the redirect_uri.
Though note that at the time of writing this, wildcard reply URLs are not supported in v2.
C. How to manage authorization to the Graph APIs (AzureAD and Microsoft Graph)
Using multiple keys makes no sense as they are all equal anyway :) Any of them could be used to call another tenant.
You can store the secret/certificate in an Azure Key Vault, and then use Azure AD Managed Service Identity to get it on app startup.
I would prefer using delegated permissions, but if the users of the app won't have the rights to do the things your app needs to do then that does not work.
I would just make sure it is not possible for a customer's instance to call to the APIs with another tenant id. And also make sure token caches are separated in such a way that it is not possible to get another tenant's access token (an in-memory cache on the instance would be good).

Given Azure Endpoint Domains: Hash versus *.onmicrosoft

I'm creating a web app to work with Azure AD.
I'm going through the process of making the REST requests, etc., and I'm a bit confused as to the endpoint URL parameters given by AD versus those given in the help documentation versus what I'm given in the AD console online. On some of the documentation pages, the endpoints are given as "https://login.windows.net/[some domain].onmicrosoft/...", where on the AD console, I'm given a long hash, with no ".onmicrosoft/..." present. I'm having problems with both (something else is obviously wrong), but I can't proceed debugging that until I know which I should proceed with, so I know that this isn't causing the problem.
The "hash" is actually a GUID, and is your tenant ID - the unique identifier for your Azure AD tenant. When constructing the login.windows.net endpoints you can use the tenant ID and the domain name (yourtenant.onmicrosoft.com) interchangeably.
See this post from Vitorrio Bertocci for more details on the subject.
This is indeed confusing and not well hashed out in the documentation.
I've created a web-app that also uses Office 365 authentication with Azure AD, and I am using the hash generated by the Azure AD console for my endpoint URLs, and everything is functioning well. Whatever the AD console gives you online is correct, and will work for your particular app (the hash given is in fact replacing a .onmicrosoft domain, and will work well).

Resources