"Permissions for service are set to internal but this request was external" for app in same resource group - azure-api-apps

The Azure API app documentation briefly describe three methods of protecting the API app. One of them is the internal accessibility settings: “Internal - Only other API apps or web apps in the same resource group are allowed to call the API app.”
I have create another Azure API app in the same resource group and hosting plan. But a get a HTTP 403 authorization failure with the following error message when I try to connect to the interal API app from the Web App:
“Permissions for service are set to internal but this request was external.”
Has anyone been able to use the internal settings between API Apps in the same Resource Group?

We will be documenting this soon. in the meantime, what you need to do is the following. You need to install nuget package Microsoft.Azure.AppService.ApiApps.Service. Then, create a delegating handler as follows:
class InternalCredentialHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
Runtime.FromAppSettings(request).SignHttpRequest(request);
return base.SendAsync(request, cancellationToken);
}
}
Then when you use HttpClient or a generated client to connect to another internal API, simply pass in the delegating handler. For example:
MySampleClient client = new MySampleClient(new DelegatingHandler[] { new InternalCredentialHandler() });
Thanks,
Mohit
Edit: the documentation for this is now available at https://azure.microsoft.com/documentation/articles/app-service-api-dotnet-consume-internal/

Related

Calling WebApi from Azure function securely

I have a scenario where I have asp.net core web api and a azure function. I call web api from azure time triggered function for every 1 hour. I do not have authentication enabled on the web api and I do not want public to access it. Only my azure function should be able to access the web api. How can I restrict web api to access from public but only from azure function with out implementing authentication.
I tried the below,
In webapi appsettings file, I updated "AllowedHosts":"https://testfuntionapp.azurewebsites.net". My testfuntionapp is unable to access web api with this change.
I am trying for a cost effective solution.
Please check if my findings help to:
How can I restrict web api to access from public but only from azure function without implementing authentication.
This is where the Azure Virtual Networks comes to.
Create the Virtual Network, configure the Azure Function to only be callable on this VNet and also can configure your core app access to the VNet.
By using Private Endpoints, resources are accessible only via your Virtual Network.
If Virtual Network Integration enabled, then the Azure Function is able to access the designated resource via the configured private endpoints, which is a higher level of security.
References:
Michael S Collier's article on Azure Functions with Private Endpoints.
Access an App Service integrated with a Virtual Network from other Azure resources like Azure Functions
I would also recommend private endpoints as suggested by HariKrishnaRajoli.
In theory it would also suffice to just configure http header filtering for access restriction rules and only allow requests containing a secret header known only to your azure function code. This is probably comparable to "basic" HTTP authentication security, and weaker than the other options.
As an alternative, you can use AAD authentication without really "implementing" much authentication code.
Configure Easy Auth on the WebApi
Configure ManagedIdentity for your Azure Function
Give your the Managed Identity access to call the WebApi using "App Role Assignments"
Extend your Azure Function to acquire and pass access token when calling the WebApi
If you only want your Azure function to be able to access your web API, you can restrict access to your web API by IP address.
In your web API's appsettings.json file, add the following:
"AllowedHosts": "https://testfuntionapp.azurewebsites.net"
This will restrict access to your web API to only requests coming from the specified Azure function.
The fastest and "dirtiest" way to do this, is to pass an API key as a header to your REST API from the function.
You can hardcode the API key to your config file or load it from your DB.
My implementation:
namespace CoreApi.Middleware
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequirePartnerApiKeyAttribute : Attribute, IAsyncActionFilter
{
private const string ApiKeyHeaderName = "x-partner-apikey";
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
//----------------------------------------------------
// Validate Api Key
//----------------------------------------------------
if (!context.HttpContext.Request.Headers.TryGetValue(ApiKeyHeaderName, out var apiKey) ||
string.IsNullOrEmpty(apiKey))
{
context.Result = new UnauthorizedResult();
return;
}
var partnerService = context.HttpContext.RequestServices.GetRequiredService<IPartnerService>();
var apiRequest = new PartnerAuthenticateRequest { PartnerApiKey = apiKey };
var partner = partnerService.Authenticate(apiRequest, new CancellationToken()).Result;
if (partner == null)
{
context.Result = new UnauthorizedResult();
return;
}
else
{
if (Enum.IsDefined(typeof(ApiKeyTypes), partner.PartnerName))
context.HttpContext.Items["APIKeyName"] = Enum.Parse(typeof(ApiKeyTypes), partner.PartnerName);
}
//----------------------------------------------------
await next();
}
}
}
You can access the API key from any middleware by calling: context.HttpContext.Items["APIKeyName"]

How can we secure API to serve only whitelisted clients? Communication between Azure function and Web API

I am using the below design to secure communication between Azure Function and Web API
Step 1 - Request token from AD
Step 2 - Use token to request web api
Code to call the API
public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
var endpoint = Environment.GetEnvironmentVariable("IDENTITY_ENDPOINT");
var identity_header = Environment.GetEnvironmentVariable("IDENTITY_HEADER");
var resource = "4df52c7e-3d6f-4865-a499-cebbb2f79d26"; //how to secure this ID
var requestURL = endpoint + "?resource=" + resource + "&api-version=2019-08-01";
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("X-IDENTITY-HEADER", identity_header);
HttpResponseMessage response = await httpClient.GetAsync(requestURL);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
var access_token = JsonConvert.DeserializeObject<TokenResp>(responseBody).access_token;
var APIURL = "https://frankapp.azurewebsites.net";
HttpClient callAPI = new HttpClient();
callAPI.DefaultRequestHeaders.Add("Authorization","Bearer "+ access_token);
HttpResponseMessage APIResponse = await callAPI.GetAsync(APIURL);
return new OkObjectResult(APIResponse.StatusCode);
}
Question
The solution works as planned, However, I see a security loophole here. That is, any azure function that has the above code or resource id can call this API!!!
How can I solve this security issue? How can I make only listed azure functions to call the API?
There are several solutions to secure the API App, as mentioned in the comment, you could validate the token via the claims, use the access restriction rules, etc.
From your code, it uses the MSI(managed identity) to get the token for the AD App of the API App, then uses the token to call the API. In this case, I recommend you to use User assignment required setting to restrict the access of the API App, after doing the steps below, just the MSI of the function can get the token for the API App, no need to do anything else.
1.Navigate to the AD App of your API App in the Azure Active Directory in the portal -> click the Managed application in local directory -> Properties -> set the User assignment required to Yes.
2.Create a security group in AAD and add the MSI service principal as a member to it, then add the group to the Users and groups, then the MSI will also be able to call the function.(For the user, it can be added directly, MSI is different, you need to use this nested way, or leverage the App role)
After the steps above, just the MSI added to the Users and groups can get the token successfully and call the API, there are two similar issues I have answered, here and here. In the two posts, they want to secure the function app, in your case, it is the same logic.
Security between Azure Function and API app using AAD can be done in multiple ways:
Claims in access token
Whitelist all the IP range where azure function is hosted, deny others.
Users and group policy in AAD as security group.
Put App service and AF in a single VNET (though that restricts multi-region)
Object ID verification
Read more: https://www.tech-findings.com/2020/01/securing-function-app-with-azure-active-directory.html

How to use AD authentication while developing Azure Functions through Visual Studio 2019 using .NET Core 3.1

I'm developing Azure Functions using Visual Studio 2019 in .NET Core 3.1. I have to implement Azure AD authentication for these functions. I'm aware of how to use AD authentication in an ASP.NET Core 3.1 web app. But as there is no startup class provided by default in an Azure Function, how to implement the same logic?
I'm using this code in an ASP.NET Core 3.1 web app:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration, "AzureAd");
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseAuthentication();
app.UseAuthorization();
}
and adding [Authorize] tags in controller methods. But, I'm not able to figure out how to implement the same in an Azure Function. Here, I've currently set the authorization level as Anonymous like below
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, ILogger log)
{
}
How to implement the Azure AD authentication here?
----UPDATE----
After adding the configurations suggested by Tiny-wa, still not able to figure out why is the Api responding with a 401 when I send a bearer token with it
I have a function contains an http trigger in it, before I enable authentication for the function, I can get response directly by calling url.
And I follow this document to enable the azure ad authentication for it.
Choose your function -> press into Authentication/Authorization tab -> check 'On'.
Then choose 'Log in with azure ad', click azure ad as Authentication providers, jump to a new page, choose express and create a new ad application.
After saving all configurations, it asks me to sign in when I call the url methoned above.
===============================UPDATE====================================
Http trigger can set different auth level by adding configuration and those are setting a different level as Anonymous, we need to add parameter in the request url. This document offers a sample and this one from microsoft offers detail.
=============================update2=============================
I have found another solution which may suitable for you. Here's the sample.
After adding authenticate module in function code, you can expose the function as an api in azure ad. This makes your function app called with an access token. Of course I have tried the sample, here's my experience.
First, modify the configuration in Constants.cs, then create an azure ad app and expose an api. Next, add api permiss which exposed just now. Finally add client secret which is used to generate access token. Below are some screenshot about my action.

How to ensure user identity in Azure Function Call? ASP NET Core Web App

I am building an ASP NET Core web application that will perform a delete operation for a user on a remote datastore. Currently, I have a frontend web app that communicates with Azure Functions to delete a user. I have a concern with security. How can I make sure the user is the logged-in user? Currently, in my ASP Net Core Web App, I have the user authenticate with AAD using Microsoft as an Identity Provider. From a client-side, the user is verified and taken care of. However, my app calls the Azure Functions endpoints. Is there an extra level of security that I could add. I only want to give my web app (registered in Azure) the ability to call the endpoints.
There are two main ways to authenticate your users. One is to use the App Services authentication options: https://learn.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad. This is by far the easier method.
If you need more control over things than what is available in the service, then you can implement validation within the Function itself as Thiago mentioned. Ben Morris did a fairly detailed post on how to implement your own OAUTH provider inside your Function App with C#: https://www.ben-morris.com/custom-token-authentication-in-azure-functions-using-bindings/ If you can take care of the validation in the Function's DI container, validation inside a specific function is fairly clean as seen in the post:
public class ExampleHttpFunction
{
private readonly IAccessTokenProvider _tokenProvider;
public ExampleHttpFunction(IAccessTokenProvider tokenProvider)
{
_tokenProvider = tokenProvider;
}
[FunctionName("ExampleHttpFunction")]
public IActionResult Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "example")] HttpRequest req, ILogger log)
{
var result = _tokenProvider.ValidateToken(req);
if (result.Status == AccessTokenStatus.Valid)
{
log.LogInformation($"Request received for {result.Principal.Identity.Name}.");
return new OkResult();
}
else
{
return new UnauthorizedResult();
}
}
}

How does [Authorize] attribute enhance Azure App Service (web app) authentication/authorization

I published a web app to Azures App Services. I used the App Service's Authentication/Authorization feature to provide security. I successfully added Active Directory features to my web service (and desktop client). It seemed to work very well. Couldn't access data from a browser or desktop client without signing in to the AD.
This was all before I added the [Authorize] attribute to any of the controllers in the API!
So, what will [Authorize] do (or add) to security in my web api. It seems to already be locked up by configuring the Authentication/Authorization features of the web app in Azure.
So, what will [Authorize] do (or add) to security in my web api.
Using ILSpy, you could check the source code about AuthorizeAttribute under System.Web.Mvc.dll. The core code for authorization check looks like this:
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
{
throw new ArgumentNullException("httpContext");
}
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
{
return false;
}
if (_rolesSplit.Length > 0)
{
string[] rolesSplit = _rolesSplit;
IPrincipal principal = user;
if (!rolesSplit.Any(principal.IsInRole))
{
return false;
}
}
return true;
}
The main process would check httpContext.User.Identity.IsAuthenticated, then check whether the current user name, user role is authorized or not when you specifying the allowed Users,Roles.
For Authentication and authorization in Azure App Service(Easy Auth) which is implemented as a native IIS module. Details you could follow Architecture of Azure App Service Authentication / Authorization.
It seemed to work very well. Couldn't access data from a browser or desktop client without signing in to the AD.
This was all before I added the [Authorize] attribute to any of the controllers in the API!
Based on your description, I assumed that you set Action to take when request is not authenticated to Log in with Azure Active Directory instead of Allow Anonymous requests (no action) under your Azure Web App Authentication/Authorization blade.
Per my understanding, you could just leverage App Service Authentication / Authorization which provides built-in authentication and authorization support for you without manually adding middleware in your code for authentication. App service authentication would validate the request before your code can process it. So, for additional custom authorization check in your code, you could define your custom authorize class which inherits from AuthorizeAttribute to implement your custom processing.
public class CustomAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//TODO:
}
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
//TODO:
}
}
Then, decorate the specific action(s) or controller(s) as follows:
[CustomAuthorize]
public class UsersController : Controller
{
//TODO:
}
App Service's Authentication/Authorization feature is Based on IIS Level. [Authorize] attribute is based on our code level. Both of this can do Authentication, if you used both of them, it means that there are two levels of authentication in your web app.
Here is a picture that helps you understand them:

Resources