Securing Azure Web Apps – Part III VNET Integration

In previous articles (Part I and Part II) I’ve described how an Azure web application can be secured and isolated from Internet traffic using Private Integration Endpoints.

If the security requirements are not draconian, a simpler solution can provide the same results, meaning public internet access to web application is forbidden and traffic between web apps is routed only in the VNET.

Azure VNET integration for web applications
Azure web application isolation diagram

This is a simple use case, where I have a frontend web app and a backend one. Frontend web app is publicly accessible but the backend web app must be accessible only from the frontend and traffic to it must not be routed over public Internet.

Note: If you want additional protection for the frontend web app (like WAF, DDoS protection, rate limiting) an Azure Application Gateway can be placed in front of it and in Access restriction you will allow traffic only from Application Gateway IP.

The setup looks like below.

Securing access to Azure web applications
Securing Azure web applications diagram

Traffic from frontend web app to backend web app is no longer outed trough Internet but on the Azure subnet from within a VNET. In the same time, backend web app will have access restrictions in place to only allow incoming traffic from the VNET (so no Internet traffic allowed). In this way, the only publicly accessible web app is the frontend end one and traffic from the frontend to the backend will go only on Azure infrastructure.

Setup is pretty simple.

  1. Create a VNET, if don’t already have one.
  2. In the above mentioned VNET, create a subnet with enough IPs (/24).
  3. Go to created subnet and setup the following:
    1. Service endpoints: Select Microsoft.Web from the list of service endpoints.
    2. Subnet delegation: Select Microsoft.Web/serverFarms from dropdown
    3. Click Save
Configuring an Azure subnet for web application integration
Azure subnet configuration for web application VNET integration
  • 4. If you have an NSG for the subnet make sure you have the appropriate Allow rules in place to allow inbound/outbound traffic from the VNET you have created and also to allow outbound traffic to the Microsoft.Web service point.
  1. Once you have created the VNET and subnet, you can proceed to web app creation.
    1. Create the frontend web app and the associated service plan
    2. Create the backend web app and use the same service plan as in the frontend one
    3. For each of the web app, go to Networking->VNET Integration and integrate the web app with VNET created at Step 1 and subnet created at Step 2.
  2. Once created the web apps, proceed to access restrictions for the backend web app. From web app -> Networking -> Access restrictions create a new Allow rule and select Type as Virtual Network. Select Azure subscription in which you are working, select the VNET created at Step 1 and subnet created at Step 2. Give it a name (VNET Allow rule) and a priority (100) and click Save. Now, traffic to backend web app is restricted to only traffic coming from the VNET (when you create an Allow rule in Access restrictions, a default Deny All rule is created so all other traffic is now denied).
  3. In the same time, because both frontend and backend web apps are integrated with the same VNET and subnet, traffic from to another will not go over Internet but over the integrated VNET and subnet.
  4. If you have an Application Gateway in front of the frontend web app, then you can also restrict traffic to it by creating an Allow rule to permit inbound traffic only from Application Gateway IP. Frontend web app will no longer directly accessible from Internet, all traffic to it will have to pass by Application Gateway, providing additional protection (WAF, etc) and load balancing.

Setup is simpler, backend web applications are isolated from being directly accessible over internet, traffic is being redirected over Azure infrastructure (VNET and subnet).

UPDATE:

When I needed a VM to access to web app backend application, I’ve seen things getting a bit complicated. You cannot deploy the VM in the same subnet created above, where you have integrated backend web app, as the integration at web app service plan level kind of “blocks” the subnet for other deployments. So, for a setup like below:

VM accessing the back end web application

You need to create a second subnet and deploy the VM inside. After creating the subnet, also add Microsoft.Web service end point to it.

To force traffic from the VM to the web application on the web service points and subnets, VM should have a Deny rule for all outbound internet traffic. Otherwise, traffic will go over internet and it will never reach the backend web app because we have configured it to Deny all incoming traffic, except one coming from the VNET (and it’s subnets).

ADR – Architecture Decision Record

In an Agile work environment, architecture is described and handled a bit differently meaning that not all decisions will be made upfront, when the projects start nor at once (actually, one the benefits of having and architecture is the possibility of deferring decisions).

As Agile methods are not opposed to documentation (only to meaningless one), we need a way of keeping track of architecture decisions taken during a project or across the whole organisation and documenting them. As nobody likes large documents (and large documents are never kept up to date), a small, modular, “agile” document format would be desired.

In a world of evolutionary architecture it is important to record certain design decisions. Whenever you are going back to a certain project to review the architecture or somebody new joins the team, there is a strong possibility the rationales for past decisions are lost, forgotten or worst, propagated by the “word of mouth”, “we always did it this way” and in this case one can only blindly accept the decisions or change it. To avoid such a behaviour, a repository of past architecture decisions and rationales behind them must be kept in an orderly manner, either linking those decisions to past project or to organisational best practices.

Definitions

An architecture decision record (ADR) is a document that captures an important architectural decision made, along with it’s context, rationale and consequences.

An architecture decision (AD) is a software design choice (or project design choice) that address a significant requirement.

An architecture decision log (ADL) is the collections of all ADRs created and maintained for a project or organisation.

Decision

We keep a collection of records for architectural decisions; those that affects the structure, the composition, non-functional characteristics, interfaces, deployment strategies, etc.

An ADR is a short text file in a format similar to RFCs. Each record describes a set of constraints and assumptions and a single decision in response.

In my particular case, we keep the ADRs in a Confluence repository, with a naming convention like ADR-NNN-Subject, where NNN is a unique number. All ADRs are numbered sequentially and numbers will not be reused. Where an ADR is deprecated, then we mark this in the file name as ADR-NNN-Subject-Deprecated, at least to have a history of those decisions. In addition, when and ADR becomes deprecated because it was superseded by another ADR, we mention this in the file content.

ADR Structure

The ADR contains, at minimum, the following sections:

  • Title
    • A meaningful name for ADR
  • Status
    • What is the status of ADR, such as proposed, accepted, deprecated, superseded
  • Context
    • What is the problem we encounter that is motivating the change or the proposal. This section describes the forces at play, technological, projects, constraints.
  • Decision
    • What is the change or action we’re proposing
  • Consequences
    • This section describes the resulting context after applying the decision. All consequences should be listed, both negative and positive as each decision will have not only positive consequences but also negative and neutral that will affect the technological landscape from now on and fore coming projects.
    • All involved parties (developers, stakeholders, PMs) can see ADRs, even if the teams composition change over time and the motivation for previous decisions is visible for everyone.

Of course, you can include also other sections in the ADR, as it is fit for your practice. In my case, I preferred to keep them as simple as possible, until we need further sections.

Examples of ADRs, simple and complex, you can find here.

We use ADRs at the organisation level, to record important decisions for our architecture, like “ADR-002-SplitDNS” which states the problem we encountered, the rationale behind the decision of implementing SplitDNS and all the consequences we can foresee. Organisational level ADRs ar related to stuff like how do we publish an API, what is the naming convention for IT, what system is Master Data System for client data, what the client identity management architecture, and so on.

At the same time, I encourage development teams to keep their own internal ADRs for each project (especially in an Agile setup), where we can have a log of all design and architecture decisions for a software project made at team level and the rationale behind them.

Same important is to also document decisions that have not been taken. In my ADRs I usually write also what other options were on the table when the decision was made and the pros and cons for each one and why they weren’t chosen. Acting like this, allow us to later review a decision and if the circumstances have changed significantly, we can take a look at what other options we had, maybe something will fit now. Or maybe is time to come out with some new options.

When to write an ADR

An ADR should be written whenever a decision with a significant impact is made; it’s up to the organisation or team to decide what “significant impact” means. An example of such a decision was that databases for non critic applications will be MariaDB.

Sometimes a decision was made in the past, or an implicit decision was mutually taken but never documented (“we always did it this way”) and it’s not clear what the decision was and what was the rationale behind it. In such a situation, writing an ADR, formalizing an unofficial decision or standard it’s a must.

Whenever we are doing a change to a system (well, not for every system, for the moment only for critical ones) we are making also an impact assessment and document the change and impact in an ADR because it has to be clear for everyone how the system evolved during various changed, how the system was extended and more.

For short, whenever a technical decision is made, which has some impact, document it in an ADR.

Resources