3

I'm trying to secure an application, deployed in Azure, consisting of an Angular frontend and a Node (Nest.js) backend. I want the frontend to be accessible via the internet unlike the backend which should only be accessible from the frontend (without being accessible via the internet). The backend seems to restrict access by taking the client's IP instead of the frontend's IP which causes a 403 IP Forbidden error.

In summary (version with path to Bicep file below)

To do this, I created:

  • 1 App Service for the frontend
  • 1 App Service for the backend
  • 1 VNet with 2 subnets:
    • 1 Subnet for 1 private endpoint
    • 1 Subnet for the frontend App Service
  • 1 Private DNS Zone for Private Endpoint routing (created automatically when creating the Private Endpoint)

And I made the following configuration:

  • App Service frontend > Networking >
    • Access restriction: Allow public access
    • VNet integration: added the app service to the previously created subnet
  • App Service backend > Networking > Access restriction: Allow Public Access but "Deny" all "Unmatched rule action". I added a rule allowing access to the frontend subnet (Action: Allow, type: select VNet, subnet: select the subnet on which the frontend is) Like this
  • App Service backend > CORS: Added frontend URL

Results

On my frontend, I make an HTTP request to my backend API. The backend responds to me ERR_FAILED 403 (Ip Forbidden). In the response headers, I see "x-ms-forbidden-ip: xxx.xxx.xx.xx" (the public ip of my company's network that my PC is on). See here. Shouldn't I see my frontend App Service IP?

For Information, if in App Service backend > Networking > Access restriction, I add a rule authorizing the public IP of my company, the request returns me a code 200 and no longer 403.

How do I block public access to the backend but still manage to perform requests from the frontend? (After many research, I haven't found any successful answers to solve this yet).

Version with Bicep file

I followed this tutorial. At the end of the article, a Bicep file is available.

So I did the following:

  • az group create --name SecureNTierApp --location "France Central"
  • az deployment group create --name DeployementSecureNTierApp --resource-group SecureNTierApp --template-file <file-name>.bicep
  • Reactivate basic auth for deploy with Azure DevOps:
    • az resource update --resource-group SecureNTierApp --name scm --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/<frontend-name> --set properties.allow=true
    • az resource update --resource-group SecureNTierApp --name scm --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/<backend-name> --set properties.allow=true
    • In Access Restrictions > Advanced tool site (on both App Service) : add a new rule (action: Allow, type: Service Tag, service tags: AzureCloud)
  • App Service backend > CORS: Added frontend URL
  • Note that the bicep file configures the backend > Networking > Access restriction to Allow public access: false
T.Dev
  • 33
  • 1
  • 4

1 Answers1

2

From what I see you have your Azure environment set up correctly. I suspect the code in your Angular frontend is asking your web browser to make direct calls to the backend. You probably want your browser to make calls to the front end, which will then be routed or passed on to the back end.

You can confirm the current behavior by running Wireshark on the machine you're using your browser to access the website. You'll see traffic going to your backend IPs.

Narthring
  • 1,124
  • 18
  • 32
  • Thanks. Indeed, it is always the client's IP that is sent to the backend. Azure recommends the architecture that I put in place via their blog (see link), so I should be able to make my backend private (keeping communication between the front and the back). Denying all unmatched rules in the backend, while accepting traffic from the frontend subnet via a rule, should work. Using a server acting as a proxy between the 2 does not seem to me to be the optimal solution. this would make me add a publicly accessible server behind the frontend (which is precisely what I want to avoid). – T.Dev Mar 15 '23 at 16:19
  • That confirms that the clients are making direct calls to the backend. That's why the client's IP is showing up at the backend and it's getting the HTTP 403. The firewall/access restrictions are blocking those client calls. The clients are initially going to the frontend to load resources, but those resources tell the browser to contact the backend directly. If you want to expose the backend and allow these calls you can open up the access list. The other solution is to use the frontend to proxy the calls to the backend, which allows the backend to remain "hidden". – Narthring Mar 15 '23 at 16:35
  • To put it another way, I believe you have everything set up correctly with the Azure architecture, but all client calls from the browser need to be directed to the front end site. That could be as simple as a software configuration setting in Angular. The frontend will act as the proxy in this case. – Narthring Mar 15 '23 at 16:40
  • Thanks. I did some research. With Angular, I saw the possibility of using a proxy.conf.json but unfortunately this solution is not usable in production. I also thought that using an Azure App Gateway could allow changing the IP received by the frontend by functioning as a proxy but I still receive the IP from the frontend in the backend. Do you have any idea of possible solution in my case? I'm out of ideas – T.Dev Mar 20 '23 at 09:12
  • Are you trying to restrict who can connect to the backend for security reasons? Many modern frameworks (including Angular I assume, but I may be wrong) authenticate users and serve up the initial static content from the frontend, but then have authenticated users directly contact the backend services. As long as the backend can verify that the calls are coming from a user who has been authenticated already there is no security issue with opening up the backend's access list to public traffic. – Narthring Mar 20 '23 at 15:04
  • Azure API Management may work in your case. The basic and above tiers allow you to have a specific IP, so if you added your backend to an API you'd just have to whitelist the IP to API Management. It doesn't solve the "I want to restrict who can use the backend" question though; it just shuffles the IP around. – Narthring Mar 20 '23 at 15:07
  • Yes I's for security reason. I wanted to be able to restrict access at the network layer. Indeed, API Management seems to be able to restrict IP. I will look at this, thanks. – T.Dev Mar 27 '23 at 08:37