Wednesday, October 6, 2021

Accept only traffic from a specified service in front of backend services

Overview

The following great article is helpful for us when configuring Azure Front Door in front of API Management to accept only traffic from Azure Front Door at API Management.

 

Integrate Azure Front Door with Azure API Management - Microsoft Tech Community

 

I would like to add information in case of using Application Gateway.

 

Query from customer

 

As always, I received the following query from my customer.

 

Now they are trying to use Azure API Management and Azure Functions for backend services to expose APIs. They plan to use Application Gateway as a web application firewall (WAF) in front of API Management. As they don't use either premium SKU or developer SKU, however, their API Management instance is not permitted to access VNet. In this situation, how do they configure each component behind Application Gateway to avoid accessing it from Internet directly?

I illustrated their requirements.

Logico_jp_0-1633410480290.png

 

If they used premium SKU for both API Management and Azure Functions, they would not have to worry about that (as these services can access VNet when using Premium SKU). However, this customer uses Consumption SKU for Azure Functions, and Basic SKU for API Management.

 

Solution sample

Note: This is an example and is not the only one solution.

  1. As Application Gateway is already configured for public access, assigned public IP address is used to communicate API Management instance. Therefore, NAT Gateway for communication with API Management instance is optional (not required).
  2. Configure API Management instance to accept only traffic from Application Gateway instance. Along with source IP restriction, subscription key is also acceptable.
  3. Configure Function app to accept only traffic from API Management instance. Along with source IP restriction, API host key and authentication are also acceptable.

 

1. Application Gateway

As I mentioned above, public IP address is already assigned to Application Gateway instance and the IP address is also used for outbound communication. Therefore, we don't have to do anymore. 

 

Logico_jp_2-1633483418887.png

 

We can create a NAT Gateway, assign another public IP address (or IP address prefix) to the gateway, and deploy it to a subnet for outbound connection, of course. In this case, public IP address assigned to NAT Gateway is used to communicate with the API Management instance. 

Logico_jp_0-1633483273314.png

2. API Management

To accept only traffic from the Application Gateway instance, we can use ip-filter policy to restrict source IP in API Management. 

 

IP Filter policy

Azure API Management access restriction policies | Microsoft Docs

 

This policy should be defined in global scope as we have to check all traffics to the API Management instance.

 

Global scope

How to set or edit Azure API Management policies | Microsoft Docs

 

IP address(es) assigned to Application Gateway instance or NAT Gateway are filled in this field as permitted source IP address(es).

image-11

 

Policy configuration is as follows.

 

<policies>
    <inbound>
        <ip-filter action="allow">
            <address>xxx.xxx.xxx.xxx</address>
        </ip-filter>
    </inbound>
    <backend>
        <forward-request />
    </backend>
    <outbound />
    <on-error />
</policies>

 

We can also use original request IP addresses to filter requests through Application Gateway. For more details, check the following URL.  

Sample API management policy - Filter on IP Address when using Application Gateway - Azure API Management | Microsoft Docs

 

Enforcing using subscription key along with source IP address restriction would be much more strong restriction. When adding subscription key, configuration of HTTP header in Application Gateway is required.

 

3. Function app

 

In case of Function app, the following configuration should be done to avoid direct connection from the Internet.

  • IP address restriction
    Configure to accept only traffic from Public IP address assigned to the API Management instance.
  • Authentication
    Configure authentication in Function app to accept only accesses from resources in the same Azure AD tenant.
  • Host key enforcement
    Authorization level should be set to function.

IP address restriction and authentication would be sufficient, using host key along with them would be much better. In this section, I describe how to configure IP address restriction and authentication in Function app. Both configurations are the same as in case of App Service.

 

a) IP address restriction

 

Settings > Networking > Incoming Traffic and click "Access restriction".

 

Logico_jp_0-1633439758447.png

 

Click "+Add rule" on a tab whose name does not contain "scm".

Logico_jp_1-1633440832740.png

 

Specify the following properties in the "Add Access Restriction" window pane.

  • Rule name
  • Action ( Allow )
  • Priority (any value is okay)
  • Description (optional)
  • Source settings
    • Type (IPv4)
      Note: Service tag is not applicable in this case. Indeed we can choose the service tag ApiManagement or ApiManagement.{region} , but these represents source IP addresses used for administrative traffic when deploying artifacts to API Management instance. For more details, check the following URL.

      Available service tags
      Azure service tags overview | Microsoft Docs

  • IP Address block (specify public IP assigned to API Management instance)

Click "Add rule" button to complete entering all properties.

 

b) Authentication

 

These steps are required to configure authentication in both Function app and API Management.

 

Function App

 

Settings > Authentication and click "Add identity provider".

Logico_jp_0-1633440731941.png

 

Next, choose "Microsoft" for identity provider to authenticate identities against Azure AD.

Logico_jp_0-1633478820262.png

 

In "App registration", you can choose either registering your application to Azure AD or picking the existing application. In "Restrict access", choose "Require authentication" and enable token store (enabled by default). And click the button "Next: Permissions >".

 

Logico_jp_1-1633478944408.png

 

In "Microsoft Graph permissions", leave the default configuration and click "Add".

Logico_jp_2-1633479170299.png

 

The following screen should appear after entry is completed. If you register application to Azure AD in the previous step, you can find client ID for the Function app. This client ID is required for authentication at API Management instance. (Note: this client ID has been already disabled.:smile:)

 

Logico_jp_3-1633479418294.png

 

API Management

 

Security > Managed identities, and enable system-assigned managed identities of the API Management instance. we use this identity for authentication. 

 

Logico_jp_0-1633481547680.png

 

Next, APIs > APIs and choose not operation scope but API scope, and add authentication-managed-identity policy to inbound pipeline. Configuration of this policy is as follows.

 

<policies>
    <inbound>
        <base />
        <authentication-managed-identity resource="0399d0f3-479a-41eb-8628-2cd2572d7b1d" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

 

That's it!

 

4. Test

 

When invoking Function app directly, the app returns 403 due to IP address restriction.

image-32

 

When calling an API backed by Function app via API Management (with IP address restriction disabled on API Management), the API returns 200 with response body.

Note: you can pass subscription key to API Management in the form of query parameter (subscription-key) or HTTP header (Ocp-Apim-Subscription-Key).

image-22

Next, when calling the API directly with IP address restriction enabled on API Management, it returns 403 .

image-24

At last, when calling the API via Application Gateway, it returns 200 with response body. (in this case, HTTP instead of HTTPS is used for testing purpose.)

image-25

 

How about Azure Front Door?

 

In case of Front Door, we can add API Management instance(s) in backend pool(s).

 

Logico_jp_0-1633488007686.png

 

IP addresses Front Door uses for backend communication are different from front-end IP address(es) assigned to Front Door and the former is packed into the service tag AzureFrontDoor.Backend. However, when filling IP addresses in API Management ip-filter policy, the following limitation exists and additional tasks are required.

  • API Management ip-filter policy cannot accept any service tags. Therefore, we have to add all IP addresses packed in the service tag.
  • IP addresses contained in service tags are subject to change without notification. Indeed we might automate the task to download JSON file containing service tags, retrieve IP addresses, and update IP addresses in ip-filter policy. However, some might think that its cost is expensive...

In some circumstances, access restriction using X-Azure-FDID might be reasonable. However, we keep in mind that we cannot use only X-Azure-FDID to restrict access from other services than Front Door strictly. The best solution to accept only traffic from Front Door would be Private Link Service, which is available in Front Door Standard/Premium SKU, but this service does not support API Management as of now.

 

Summary

 

My customer understood my proposal mentioned above, and they followed my proposal to configure their environment. In case of Azure Front Door, cost for IP address restriction is expensive as API Management ip-filter policy accepts only IP address(es) instead of service tag AzureFrontDoor.Backend. Simply using X-Azure-FDID is less expensive but this does not work for some cases.

Posted at https://sl.advdat.com/3iAU9QU