Skip to content

Technical Architecture Notes: Layers and Firewall Rule Validation

Two design notes that explain why parts of the platform are built the way they are: how the hub deployment is divided into layers, and how firewall rule changes are validated in a pull request. For what the layers contain today and in which order they run, see Deployment layers.

Why the hub is split into layers

The deployment was restructured into layers after a layer assessment. The principle: split the hub into parts that each have one purpose, so complexity goes down and each part can be managed and changed without touching the others.

The assessment judged each layer on three things: its purpose, the components that belong to it, and the rationale for keeping it separate. The rationale came back to the same reasons every time:

Reason Meaning
Dependency Some things must exist before others can be built on them (management groups and policies before assignments, a hub before spokes)
Isolation A change to one layer must not affect the components of another
Speed Parts that change often (firewall rules, policies, monitoring) deploy faster when they have their own, smaller state
Ownership Components that belong to one concern (connectivity, management, identity) are easier to manage and review together

Layer by layer

Layer Purpose Why separate
foundation The baseline for the platform, per region. Region-wide components that the other layers build on: action groups, the DDoS protection plan, management groups (once per tenant), policy definitions and initiatives It is the first thing deployed in a region, and others use what it creates
connectivity Everything for connectivity inside Azure, between regions, and to on-premises: Virtual WAN and hub, gateways, ExpressRoute, DNS resolver, Bastion, Application Gateway and WAF, Azure Firewall and its policy, IP groups, route tables, network security groups One place to configure and check all network components
management The components that manage and monitor the environment: Log Analytics, Azure Monitor and alerts, Automation, Storage, Key Vault, Sentinel Monitoring and management components deploy quickly and are easier to keep running smoothly on their own
identity The network for legacy identity services such as Active Directory domain controllers: a virtual network with network security groups and route tables Identity components stay isolated from changes to other components, and domain controllers get their own subnet with the right rules
postdeployment Configuration after the environment exists: policy assignments and exemptions, diagnostic settings, Defender for Cloud Easier to configure the environment to the organisation's requirements, and to repeat that without redeploying infrastructure
firewall The firewall rule collection groups, rule collections and rules (network, application and NAT) Rules change often. A separate layer makes it easier to apply them correctly and makes a rule change much faster

Dependencies between layers decide the order: foundation first, then connectivity, then management, identity and firewall, then postdeployment (Deployment layers).

The code has moved since the assessment

The assessment lists the private DNS zones for private link in the foundation layer. The current code creates the zones in the connectivity layer and keeps only the private DNS policy definitions in foundation. Trust Deployment layers for the current content, and use this page for the reasoning.

How to use this when you add a component

When you add something new, ask where it belongs:

  1. What must exist before it can be created? It belongs in a later layer than that.
  2. Does it change often, or by a different team? Give it its own layer or put it with the layer that changes at the same pace.
  3. Would a mistake in it be able to hurt something unrelated? Then keep it out of that layer.
  4. Does the same concern already have a layer? Put it there.

See Building new functionality.

Validating firewall rules in a pull request

Firewall rules are JSON files in the configuration repository. A mistake in them is only found when hub runs, and a failed firewall apply can interrupt traffic (Known issues). A continuous integration (CI) pipeline on the pull request finds the mistakes early, before anything is deployed to Azure, and tells the requester what to fix.

How it works

  • The CI pipeline is a YAML pipeline stored in the configuration repository, next to the firewall rule files.
  • It runs a PowerShell script against the whole repository. The script selects the JSON files with a path filter, so that it looks only at firewall rule files and no other files.
  • If a check fails, the pipeline reports an error and the pull request cannot be completed.

What it checks

Check Why it matters
The rule priorities are within the limits of Azure An out-of-range priority fails at apply time
The priorities are unique Two rule collections with the same priority conflict
Referenced IP groups exist A rule that refers to a missing group fails the apply

The checks come from the reviewer's checklist in Pull request review: the pipeline automates the parts that a machine does better than a reviewer.

Set it up

  1. Put the pipeline file in the pipelines/ folder of the configuration repository, and the PowerShell script in the root folder, where the pipeline expects it.
  2. In the project, create a new pipeline from that YAML file. Rename it so that its name contains Firewall Rule validator.
  3. Add the pipeline as a build validation to the branch policy of the main branch of the configuration repository. The default parameter values are fine.

From then on, every pull request that targets main runs the validation. Review the result as part of the review (Making a change safely).

Status

This validation was developed and tested for a single platform. The intention was to make the pipeline and script part of the code repository so every platform gets them. Check whether your version of the code repository contains them, and note the file locations above may then differ. The code repository's own config tests run a similar check at the start of every hub run (Pipelines and workflows), which catches the same mistakes later, before Terraform starts. Known limits of the validators are in Known issues.