AKS Architecture Fundamentals

In the previous post From Containers to Kubernetes Architecture, we walked through the evolution from client/server to containers, and from Docker to Kubernetes. We looked at how orchestration became necessary once we stopped deploying single applications to single servers.

Now it’s time to move from history to design, and in this post we’re going to dive into the practical by focusing on:

How Azure Kubernetes Service (AKS) is actually structured — and what architectural decisions matter from day one.


Control Plane vs Data Plane – The First Architectural Boundary

In line with the core design of a vanilla Kubernetes cluster, every AKS cluster is split into two logical areas:

  • The control plane (managed by Azure)
  • The data plane (managed by you)
Image Credit – Microsoft

We looked at this in the last post, but lets remind ourselves of the components that make up each area.

The Control Plane (Azure Managed)

When you create an AKS cluster, you do not deploy your own API server or etcd database. Microsoft runs the Kubernetes control plane for you.

That includes:

  • The Kubernetes API server
  • etcd (the cluster state store)
  • The scheduler
  • The controller manager
  • Control plane patching and upgrades

This is not just convenience — it is risk reduction. Operating a highly available Kubernetes control plane is non‑trivial. It requires careful configuration, backup strategies, certificate management, and upgrade sequencing.

In AKS, that responsibility shifts to Azure. You interact with the cluster via the Kubernetes API (through kubectl, CI/CD pipelines, GitOps tools, or the Azure Portal), but you are not responsible for keeping the brain of the cluster alive.

That abstraction directly supports:

  • Operational Excellence
  • Reduced blast radius
  • Consistent lifecycle management

It also empowers Operations to enable Development teams to start their cycles earlier in the project as opposed to waiting for the control plane to be stood up and functionally ready.

The Data Plane (Customer Managed)

The data plane is where your workloads run. This consists of:

  • Virtual machine nodes
  • Node pools
  • Pods and workloads
  • Networking configuration

You choose:

  • VM SKU
  • Scaling behaviour
  • Availability zones
  • OS configuration (within supported boundaries)

This is intentional. Azure abstracts complexity where it makes sense, but retains control and flexibility where architecture matters.


Node Pools – Designing for Isolation and Scale

One of the most important AKS concepts is the node pool. A node pool is a group of VMs with the same configuration. At first glance, it may look like a scaling convenience feature. In production, it is an isolation and governance boundary.

There are 2 different types of node pool – System and User.

System Node Pool

Every AKS cluster requires at least one system node pool, which is a specialized group of nodes dedicated to hosting critical cluster components. While you can run application pods on them, their primary role is ensuring the stability of core services.

This pool runs:

  • Core Kubernetes components
  • Critical system pods

In production, this pool should be:

  • Small but resilient
  • Dedicated to system workloads
  • Not used for business application pods

In our first post, we took the default “Node Pool” option – however you do have the option to add a dedicated system node pool:

It is recommended that you create a dedicated system node pool to isolate critical system pods from your application pods to prevent misconfigured or rogue application pods from accidentally deleting system pods.

You don’t need the system node pool SKU size to be the same as your user node Pool SKU size – however its recommended that you make both highly available.

User Node Pools

User node pools are where your applications and workloads run. You can create multiple pools for different purposes within the same AKS cluster:

  • Compute‑intensive workloads
  • GPU workloads
  • Batch jobs
  • Isolated environments

Looking at the list, traditionally these workloads would have lived on their own dedicated hardware or processing areas. The advantage of AKS is that this enables:

  • Better scheduling control – the scheduler can control the assignment of resources to workloads in node pools.
  • Resource isolation – resources are isolated in their own node pools.
  • Cost optimisation – all of this runs on the same set of cluster VMs, so cost is predictive and stable.

In production, multiple node pools are not optional — they are architectural guardrails.


Regional Design and Availability Zones

Like all Azure resources, when you create an AKS cluster you choose a region. That decision impacts latency, compliance, resilience, and cost.

But production architecture requires a deeper question:

How does this cluster handle failure?

Azure supports availability zones in many regions. A production AKS cluster should at a bare minimum:

  • Use zone‑aware node pools
  • Distribute nodes across multiple availability zones

This ensures that a single data centre failure does not bring down your workloads. It’s important to understand that:

  • The control plane is managed by Azure for high availability
  • You are responsible for ensuring node pool zone distribution

Availability is shared responsibility.


Networking Considerations (At a High Level)

AKS integrates into an Azure Virtual Network. That means your cluster:

  • Has IP address planning implications
  • Participates in your broader network topology
  • Must align with security boundaries

Production mistakes often start here:

  • Overlapping address spaces
  • Under‑sized subnets
  • No separation between environments

Networking is not a post‑deployment tweak – its a day‑one design decision that you make with your wider cloud and architecture teams. We’ll go deep into networking in the next post, but even at the architecture stage, you need to make conscious choices.


Upgrade Strategy – Often Ignored, Always Critical

Kubernetes evolves quickly. AKS supports multiple Kubernetes versions, but older versions are eventually deprecated. The full list of supported AKS versions can be found at the AKS Release Status page

A production architecture must consider:

  • Version lifecycle
  • Upgrade cadence
  • Node image updates

In AKS, control plane upgrades are managed by Azure — but you control when upgrades occur and how node pools are rolled. When you create your cluster, you can specify the upgrade option you wish to use:

Its important to pay attention to this as it may affect your workloads. For example, starting in Kubernetes v1.35, Ubuntu 24.04 because the default OS SKU. What this means if you are upgrading from a lower version of Kubernetes, your node OS will be auto upgraded from Ubuntu 22.04 to 24.04.

Ignoring upgrade planning is one of the fastest ways to create technical debt in a cluster. This is why testing in lower environments to see how your workloads react to these upgrades is vital.


Mapping This to the Azure Well‑Architected Framework

Let’s anchor this back to the bigger picture and see how AKS maps to the Azure Well-Architected Framework.

Operational Excellence

  • AKS’s managed control plane reduces operational complexity.
  • Node pools introduce structured isolation.
  • Availability zones improve resilience.

Designing with these in mind from the start prevents reactive firefighting later.

Reliability

Zone distribution, multiple node pools, and scaling configuration directly influence workload uptime. Reliability is not added later — it is designed at cluster creation.

Cost Optimisation

Right‑sizing node pools and separating workload types prevents over‑provisioning. Production clusters that mix everything into one large node pool almost always overspend.


Production Guardrails – Early Principles

Before we move into deeper topics in the next posts, let’s establish a few foundational guardrails:

  • Separate system and user node pools
  • Use availability zones where supported
  • Plan IP addressing before deployment (again, we’ll dive into networking and how it affects workloads in more detail in the next post)
  • Treat upgrades as part of operations, not emergencies
  • Avoid “single giant node pool” design

These are not advanced optimisations. They are baseline expectations for production AKS.


What Comes Next

Now that we understand AKS architecture fundamentals, the next logical step is networking.

In the next post, we’ll go deep into:

  • Azure CNI and networking models
  • Ingress and traffic flow
  • Internal vs external exposure
  • Designing secure network boundaries

Because once architecture is clear, networking is what determines whether your cluster is merely functional or truly production ready.

See you on the next post!

From Containers to Kubernetes Architecture

In the previous post, What Is Azure Kubernetes Service (AKS) and Why Should You Care?, we got an intro to AKS, compared it to Azure PaaS services in terms of asking when is the right choice, and finally spun up an AKS cluster to demonstrate what exactly Microsoft exposes to you in terms of responsibilities.

In this post, we’ll take a step back to first principles and understand why containers and microservices emerged, how Docker changed application delivery, and how those pressures ultimately led to Kubernetes.

Only then does Kubernetes and by extension AKS architecture fully make sense.


From Monoliths to Microservices

If you rewind to the 1990s and early 2000s, most enterprise systems followed a fairly predictable pattern: client/server.

You either had thick desktop clients connecting to a central database server, or you had early web applications running on a handful of physical servers in a data centre. Access was often via terminal services, remote desktop, or tightly controlled internal networks.

Applications were typically deployed as monoliths. One codebase. One deployment artifact. One server—or maybe two, if you were lucky enough to have a test environment.

Infrastructure and application were deeply intertwined. If you needed more capacity, you bought another server. If you needed to update the application, you scheduled downtime. And this wasn’t like the downtime we know today – this could run into days, normally public holiday weekends where you had an extra day. Think you’re going to be having Christmas dinner or opening Easter eggs? Nope – thtere’s an upgrade on those weekends!

This model worked in a world where:

  • Release cycles were measured in months
  • Scale was predictable
  • Users were primarily internal or regionally constrained

But as the web matured in the mid-2000s, and SaaS became mainstream, expectations changed.


Virtualisation and Early Cloud

Virtual machines were the first major shift.

Instead of deploying directly to physical hardware, we began deploying to hypervisors. Infrastructure became more flexible. Provisioning times dropped from weeks to hours, and rollback of changes became easier too which de-risked the deployment process.

Then around 2008–2012, public cloud platforms began gaining serious enterprise traction. Infrastructure became API-driven. You could provision compute with a script instead of a purchase order.

Despite these changes, the application model was largely the same. We were still deploying monoliths—just onto virtual machines instead of physical servers.

The client/server model had evolved into a browser/server model, but the deployment unit was still large, tightly coupled, and difficult to scale independently.


The Shift to Microservices

Around the early 2010s, as organisations like Netflix, Amazon, and Google shared their scaling stories, the industry began embracing microservices more seriously.

Instead of a single large deployment, applications were broken into smaller services. Each service had:

  • A well-defined API boundary
  • Its own lifecycle
  • Independent scaling characteristics

This made sense in a world of global users and continuous delivery.

However, it introduced new complexity. You were no longer deploying one application to one server. You might be deploying 50 services across 20 machines. Suddenly, your infrastructure wasn’t just hosting an app—it was hosting an ecosystem.

And this is where the packaging problem became painfully obvious.


Docker and the Rise of Containers

Docker answered the packaging problem.

Containers weren’t new. Linux containers had existed in various forms for years. But Docker made them usable, portable, and developer-friendly.

Instead of saying “it works on my machine,” developers could now package:

  • Their application code
  • The runtime
  • All dependencies
  • Configuration

Into a single container image. That image could run on a laptop, in a data centre, or in the cloud—consistently. This was a major shift in the developer-to-operations contract.

The old model:

  • Developers handed over code
  • Operations teams configured servers
  • Problems emerged somewhere in between

The container model:

  • Developers handed over a runnable artifact
  • Operations teams provided a runtime environment

But Docker alone wasn’t enough.

Running a handful of containers on a single VM was manageable. Running hundreds across dozens of machines? That required coordination.

We had solved packaging. We had not solved orchestration. As container adoption increased, a new challenge emerged:

Containers are easy. Running containers at scale is not.


Why Kubernetes Emerged

Kubernetes emerged to solve the orchestration problem.

Instead of manually deciding where containers should run, Kubernetes introduced a declarative model. You define the desired state of your system—how many replicas, what resources, what networking—and Kubernetes continuously works to make reality match that description.

This was a profound architectural shift.

It moved us from:

  • Logging into servers via SSH
  • Manually restarting services
  • Writing custom scaling scripts

To:

  • Describing infrastructure and workloads declaratively
  • Letting control loops reconcile state
  • Treating servers as replaceable capacity

The access model changed as well. Instead of remote desktop or SSH being the primary control mechanism, the Kubernetes API became the centre of gravity. Everything talks to the API server.

This shift—from imperative scripts to declarative configuration—is one of the most important architectural changes Kubernetes introduced.


Core Kubernetes Architecture

To understand AKS, you first need to understand core Kubernetes components.

At its heart, Kubernetes is split into two logical areas: the control plane and the worker nodes.

The Control Plane – The Brain of the Cluster

The control plane is the brain of the cluster. It makes decisions, enforces state, and exposes the Kubernetes API.

Key components include:

API Server

The API server is the front door. Whether you use kubectl, a CI/CD pipeline, or a GitOps tool, every request flows through the API server. It validates requests and persists changes.

  • Entry point for all Kubernetes operations
  • Validates and processes requests
  • Exposes the Kubernetes API

Everything—kubectl, CI/CD pipelines, controllers—talks to the API server.

etcd

Behind the scenes sits etcd, a distributed key-value store that acts as the source of truth. It stores the desired and current state of the cluster. If etcd becomes unavailable, the cluster effectively loses its memory.

  • Distributed key-value store
  • Holds the desired and current state of the cluster
  • Source of truth for Kubernetes

If etcd is unhealthy, the cluster cannot function correctly.

Scheduler

The scheduler is responsible for deciding where workloads run. When you create a pod, the scheduler evaluates resource availability and constraints before assigning it to a node.

  • Decides which node a pod should run on
  • Considers resource availability, constraints, and policies

Controller Manager

The controller manager runs continuous reconciliation loops. It constantly compares the desired state (for example, “I want three replicas”) with the current state. If a pod crashes, the controller ensures another is created.

  • Runs control loops
  • Continuously checks actual state vs desired state
  • Takes action to reconcile differences

This combination is what makes Kubernetes self-healing and declarative.


Worker Nodes – Where Work Actually Happens

Worker nodes are where your workloads actually run.

Each node contains:

kubelet

Each node runs a kubelet, which acts as the local agent communicating with the control plane. It ensures that the containers defined in pod specifications are actually running.

  • Agent running on each node
  • Ensures containers described in pod specs are running
  • Reports node and pod status back to the control plane

Container Runtime

Underneath that sits the container runtime—most commonly containerd today. This is what actually starts and stops containers.

  • Responsible for running containers
  • Historically Docker, now containerd in most environments

kube-proxy

Networking between services is handled through Kubernetes networking constructs and components such as kube-proxy, which manages traffic rules.

  • Handles networking rules
  • Enables service-to-service communication n

Pods, Services, and Deployments

Above this infrastructure layer, Kubernetes introduces abstractions like pods, deployments, and services. These abstractions allow you to reason about applications instead of machines.

Pods

  • Smallest deployable unit in Kubernetes
  • One or more containers sharing networking and storage

Deployments

  • Define how pods are created and updated
  • Enable rolling updates and rollback
  • Maintain desired replica counts

Services

  • Provide stable networking endpoints
  • Abstract away individual pod lifecycles

You don’t deploy to a server. You declare a deployment. You don’t track IP addresses. You define a service.

How This Maps to Azure Kubernetes Service (AKS)

AKS does not change Kubernetes—it operationalises it. The Kubernetes architecture remains the same, but the responsibility model changes.

In a self-managed cluster, you are responsible for the control plane. You deploy and maintain the API server. You protect and back up etcd. You manage upgrades.

In AKS, Azure operates the control plane for you.

Microsoft manages the API server, etcd, and control plane upgrades. You still interact with Kubernetes in exactly the same way—through the API—but you are no longer responsible for maintaining its most fragile components.

You retain responsibility for worker nodes, node pools, scaling, and workload configuration. That boundary is deliberate.

It aligns directly with the Azure Well-Architected Framework:

  • Operational Excellence through managed control plane abstraction
  • Reduced operational risk and complexity
  • Clear separation between platform and workload responsibility

AKS is Kubernetes—operationalised.


Why This Matters for Production AKS

Every production AKS decision maps back to Kubernetes architecture:

  • Networking choices affect kube-proxy and service routing
  • Node pool design affects scheduling and isolation
  • Scaling decisions interact with controllers and the scheduler

Without understanding the underlying architecture, AKS can feel opaque.

With that understanding, it becomes predictable.


What Comes Next

Now that we understand:

  • Why containers emerged
  • Why Kubernetes exists
  • How Kubernetes is architected
  • How AKS maps to that architecture

We’re ready to start making design decisions.

In the next post, we’ll move into AKS architecture fundamentals, including:

  • Control plane and data plane separation
  • System vs user node pools
  • Regional design and availability considerations

See you on the next post

What Is Azure Kubernetes Service (AKS) and Why Should You Care?

In every cloud native architecture discussion you have had over the last few years or are going to have in the coming years, you can be guaranteed that someone has or will introduce Kubernetes as a hosting option on which your solution will run.

There’s also different options when Kubernetes enters the conversation – you can choose to run:

Kubernetes promises portability, scalability, and resilience. In reality, operating Kubernetes yourself is anything but simple.

Have you’ve ever wondered whether Kubernetes is worth the complexity—or how to move from experimentation to something you can confidently run in production?

Me too – so let’s try and answer that question. For anyone who knows me or has followed me for a few years knows, I like to get down to the basics and “start at the start”.

This is the first post is of a blog series where we’ll focus on Azure Kubernetes Service (AKS), while also referencing the core Kubernetes offerings as a reference. The goal of this series is:

By the end (whenever that is – there is no set time or number of posts), we will have designed and built a production‑ready AKS cluster, aligned with the Azure Well‑Architected Framework, and suitable for real‑world enterprise workloads.

With the goal clearly defined, let’s start at the beginning—not by deploying workloads or tuning YAML, but by understanding:

  • Why AKS exists
  • What problems it solves
  • When it’s the right abstraction.

What Is Azure Kubernetes Service (AKS)?

Azure Kubernetes Service (AKS) is a managed Kubernetes platform provided by Microsoft Azure. It delivers a fully supported Kubernetes control plane while abstracting away much of the operational complexity traditionally associated with running Kubernetes yourself.

At a high level:

  • Azure manages the Kubernetes control plane (API server, scheduler, etcd)
  • You manage the worker nodes (VM size, scaling rules, node pools)
  • Kubernetes manages your containers and workloads

This division of responsibility is deliberate. It allows teams to focus on applications and platforms rather than infrastructure mechanics.

You still get:

  • Native Kubernetes APIs
  • Open‑source tooling (kubectl, Helm, GitOps)
  • Portability across environments

But without needing to design, secure, patch, and operate Kubernetes from scratch.

Why Should You Care About AKS?

The short answer:

AKS enables teams to build scalable platforms without becoming Kubernetes operators.

The longer answer depends on the problems you’re solving.

AKS becomes compelling when:

  • You’re building microservices‑based or distributed applications
  • You need horizontal scaling driven by demand
  • You want rolling updates and self‑healing workloads
  • You’re standardising on containers across teams
  • You need deep integration with Azure networking, identity, and security

Compared to running containers directly on virtual machines, AKS introduces:

  • Declarative configuration
  • Built‑in orchestration
  • Fine‑grained resource management
  • A mature ecosystem of tools and patterns

However, this series is not about adopting AKS blindly. Understanding why AKS exists—and when it’s appropriate—is essential before we design anything production‑ready.


AKS vs Azure PaaS Services: Choosing the Right Abstraction

Another common—and more nuanced—question is:

“Why use AKS at all when Azure already has PaaS services like App Service or Azure Container Apps?”

This is an important decision point, and one that shows up frequently in the Azure Architecture Center.

Azure PaaS Services

Azure PaaS offerings such as App Service, Azure Functions, and Azure Container Apps work well when:

  • You want minimal infrastructure management responsibility
  • Your application fits well within opinionated hosting models
  • Scaling and availability can be largely abstracted away
  • You’re optimising for developer velocity over platform control

They provide:

  • Very low operational overhead – the service is an “out of the box” offering where developers can get started immediately.
  • Built-in scaling and availability – scaling comes as part of the service based on demand, and can be configured based on predicted loads.
  • Tight integration with Azure services – integration with tools such as Azure Monitor and Application Insights for monitoring, Defender for Security monitoring and alerting, and Entra for Identity.

For many workloads, this is exactly the right choice.

AKS

AKS becomes the right abstraction when:

  • You need deep control over networking, runtime, and scheduling
  • You’re running complex, multi-service architectures
  • You require custom security, compliance, or isolation models
  • You’re building a shared internal platform rather than a single application

AKS sits between IaaS and fully managed PaaS:

Azure PaaS abstracts the platform for you. AKS lets you build the platform yourself—safely.

This balance of control and abstraction is what makes AKS suitable for production platforms at scale.


Exploring AKS in the Azure Portal

Before designing anything that could be considered “production‑ready”, it’s important to understand what Azure exposes out of the box – so lets spin up an AKS instance using the Azure Portal.

Step 1: Create an AKS Cluster

  • Sign in to the Azure Portal
  • In the search bar at the top, Search for Kubernetes Service
  • When you get to the “Kubernetes center page”, click on “Clusters” on the left menu (it should bring you here automatically). Select Create, and select “Kubernetes cluster”. Note that there are also options for “Automatic Kubernetes cluster” and “Deploy application” – we’ll address those in a later post.
  • Choose your Subscription and Resource Group
  • Enter a Cluster preset configuration, Cluster name and select a Region. You can choose from four different preset configurations which have clear explanations based on your requirements
  • I’ve gone for Dev/Test for the purposes of spinning up this demo cluster.
  • Leave all other options as default for now and click “Next” – we’ll revisit these in detail in later posts.

Step 2: Configure the Node Pool

  • Under Node pools, there is an agentpool automatically added for us. You can change this if needed to select a different VM size, and set a low min/max node count

    This is your first exposure to separating capacity management from application deployment.

    Step 3: Networking

    Under Networking, you will see options for Private/Public Access, and also for Container Networking. This is an important chopice as there are 2 clear options:

    • Azure CNI Overlay – Pods get IPs from a private CIDR address space that is separate from the node VNet.
    • Azure CNI Node Subnet – Pods get IPs directly from the same VNet subnet as the nodes.

    You also have the option to integrate this into your own VNet which you can specify during the cluster creation process.

    Again, we’ll talk more about these options in a later post, but its important to understand the distinction between the two.

    Step 4: Review and Create

    Select Review + Create – note at this point I have not selected any monitoring, security or integration with an Azure Container Registry and am just taking the defaults. Again (you’re probably bored of reading this….), we’ll deal with these in a later post dedicated to each topic.

    Once deployed, explore:

    • Node pools
    • Workloads
    • Services and ingresses
    • Cluster configuration

    Notice how much complexity is hidden – if you scroll back up to the “Azure-managed v Customer-managed” diagram, you have responsibility for managing:

    • Cluster nodes
    • Networking
    • Workloads
    • Storage

    Even though Azure abstracts away responsibility for things like key-value store, scheduler, controller and management of the cluster API, a large amount of responsibility still remains.


    What Comes Next in the Series

    This post sets the foundation for what AKS is and how it looks out of the box using a standard deployment with the “defaults”.

    Over the course of the series, we’ll move through the various concepts which will help to inform us as we move towards making design decisions for production workloads:

    • Kubernetes Architecture Fundamentals (control plane, node pools, and cluster design), and how they look in AKS
    • Networking for Production AKS (VNets, CNI, ingress, and traffic flow)
    • Identity, Security, and Access Control
    • Scaling, Reliability, and Resilience
    • Cost Optimisation and Governance
    • Monitoring, Alerting and Visualizations
    • Alignment with the Azure Well Architected Framework
    • And lots more ……

    See you on the next post!

    Azure Lab Services Is Retiring: What to Use Instead (and How to Plan Your Migration)

    Microsoft has announced that Azure Lab Services will be retired on June 28, 2027. New customer sign-ups have already been disabled as of July 2025, which means the clock is officially ticking for anyone using the service today.

    You can read the official announcement on Microsoft Learn here: https://learn.microsoft.com/en-us/azure/lab-services/retirement-guide

    While 2027 may feel a long way off, now is the time to take action!

    For those of you who have never heard of Azure Lab Services, lets take a look at what it was and how you would have interacted with it (even if you didn’t know you were!).

    What is/was Azure Lab Services?

    Image: Microsoft Learn

    Azure Lab Services allowed you to create labs with infrastructure managed by Azure. The service handles all the infrastructure management, from spinning up virtual machines (VMs) to handling errors and scaling the infrastructure.

    If you’ve ever been on a Microsoft course, participated in a Virtual Training Days course, or attended a course run by a Microsoft MCT, Azure Lab Services is what the trainer would have used to facilitate:

    • Classrooms and training environments
    • Hands-on labs for workshops or certifications
    • Short-lived dev/test environments

    Azure Lab Services was popular because it abstracted away a lot of complexity around building lab or classroom environments. Its retirement doesn’t mean Microsoft is stepping away from virtual labs—it means the responsibility shifts back to architecture choices based on the requirements you have.

    If you or your company is using Azure Lab Services, the transition to a new service is one of those changes where early planning pays off—especially if your labs are tied to academic calendars, training programmes, or fixed budgets.

    So what are the alternatives?

    Microsoft has outlined several supported paths forward. None are a 1:1 replacement, so the “right” option depends on who your users are and how they work. While these solutions aren’t necessarily education-specific, they support a wide range of education and training scenarios.

    Azure Virtual Desktop (AVD)

    Image: Microsoft Learn

    🔗 https://learn.microsoft.com/azure/virtual-desktop/

    AVD is the most flexible option and the closest match for large-scale, shared lab environments. AVD is ideal for providing full desktop and app delivery scenarios and provides the following benefits:

    • Multi-session Windows 10/11, which either Full Desktop or Single App Delivery options
    • Full control over networking, identity, and images. One of the great new features of AVD (still in preview mode) is that you can now use Guest Identities in your AVD environments, which can be really useful for training environments and takes the overhead of user management away.
    • Ideal for training labs with many concurrent users
    • Supports scaling plans to reduce costs outside working hours (check out my blog post on using Scaling Plans in your AVD Environments)

    I also wrote a set of blog posts about setting up your AVD environments from scratch which you can find here and here.

    Windows 365

    🔗 https://learn.microsoft.com/windows-365/

    Windows 365 offers a Cloud PC per user, abstracting away most infrastructure concerns. Cloud PC virtual machines are Microsoft Entra ID joined and support centralized end-to-end management using Microsoft Intune. You assign Cloud PC’s by assigning a license to that user in the same way as you would assign Microsoft 365 licences. The benefits of Windows 365 are:

    • Simple to deploy and manage
    • Predictable per-user pricing
    • Well-suited to classrooms or longer-lived learning environments

    The trade-off is that there is less flexibility and typically higher cost per user than shared AVD environments, as the Cloud PC’s are dedicated to the users and cannot be shared.

    Azure DevTest Labs

    Image: Microsoft Learn

    🔗 https://learn.microsoft.com/azure/devtest-labs/

    A strong option for developer-focused labs, Azure DevTest labs are targeted at enterprise customers. It also has a key difference to the other alternative solutions, its the only one that offers access to Linux VMs as well as Windows VMs.

    • Supports Windows and Linux
    • Built-in auto-shutdown and cost controls
    • Works well for dev/test and experimentation scenarios

    Microsoft Dev Box

    🔗 https://learn.microsoft.com/dev-box/

    Dev Box is aimed squarely at professional developers. It’s ideal for facilitating hands-on learning where training leaders can use Dev Box supported images to create identical virtual machines for trainees. Dev Box virtual machines are Microsoft Entra ID joined and support centralized end-to-end management with Microsoft Intune.

    • High-performance, secure workstations
    • Integrated with developer tools and workflows
    • Excellent for enterprise engineering teams

    However, its important to note that as of November 2025, DevBox is being integrated into Windows365. The service is built on top of Windows365, so Micrsoft has decided to unify the offerings. You can read more about this announcement here but as of November 2025, Microsoft are no longer accepting new DevBox customers – https://learn.microsoft.com/en-us/azure/dev-box/dev-box-windows-365-announcement?wt.mc_id=AZ-MVP-5005255

    When First-Party Options Aren’t Enough

    If you relied heavily on the lab orchestration features of Azure Lab Services (user lifecycle, lab resets, guided experiences), you may want to evaluate partner platforms that build on Azure:

    These solutions provide:

    • Purpose-built virtual lab platforms
    • User management and lab automation
    • Training and certification-oriented workflows

    They add cost, but also significantly reduce operational complexity.

    Comparison: Azure Lab Services Alternatives

    Lets take a look at a comparison of each service showing cost, use cases and strengths:

    ServiceTypical Cost ModelBest Use CasesKey StrengthWhen 3rd Party Tools Are Needed
    Azure Virtual DesktopPay-per-use (compute + storage + licensing)Large classrooms, shared labs, training environmentsMaximum flexibility and scalabilityFor lab orchestration, user lifecycle, guided labs
    Windows 365Per-user, per-monthClassrooms, longer-lived learning PCsSimplicity and predictabilityRarely needed
    Azure DevTest LabsPay-per-use with cost controlsDev/test, experimentation, mixed OS labsCost governanceFor classroom-style delivery
    Microsoft Dev BoxPer-user, per-monthEnterprise developersPerformance and securityNot typical
    Partner PlatformsSubscription + Azure consumptionTraining providers, certification labsTurnkey lab experiencesCore dependency

    Don’t Forget Hybrid Scenarios

    If some labs or dependencies must remain on-premises, you can still modernise your management approach by deploying Azure Virtual Desktop locally and manage using Azure Arc, which will allow you to

    • Apply Azure governance and policies
    • Centralise monitoring and management
    • Transition gradually toward cloud-native designs

    Start Planning Now

    With several budget cycles between now and June 2027, the smartest move is to:

    1. Inventory existing labs and usage patterns
    2. Map them to the closest-fit replacement
    3. Pilot early with a small group of users

    Azure Lab Services isn’t disappearing tomorrow—but waiting until the last minute will almost certainly increase cost, risk, and disruption.

    If you treat this as an architectural evolution rather than a forced migration, you’ll end up with a platform that’s more scalable, more secure, and better aligned with how people actually learn and work today.

    Maximizing Cloud Efficiency and Cost Savings with Azure FinOps

    Its Christmas time, and that means its time for another month of the always fantastic Festive Tech Calendar. This was one of the first events that I participated in when I was trying to break into blogging and public speaking and I’m delighted to be involved again this year.

    This year, the team are raising funds for Beatson Cancer Charity, and you can make donations via the Just Giving page.

    In this post, we’ll dive into Azure FinOps, explore tools and practices available to help you manage costs, look at real-world savings examples, and discuss how to integrate alerts into Service Management solutions for proactive monitoring.

    But before we dive in, lets set the scene with a real world example!

    The problem with wanting more …..

    We live in a world and a time in society where we all want more. We want it bigger and better. Bigger houses, bigger SUV’s, the highest performing laptop, the newest model phone.

    And of course because its Christmas, the biggest turkey you can find ….

    This is “Irish Mammy” syndrome, where we over cater to make sure there is enough for everyone at Christmas (and for my American readers, the same rules apply at Thanksgiving).

    And its not just Turkey – making sure there are lots of different vegetables as a supplement including multiple types of potatoes (roast, mashed, boiled with both skin on and off, chipped, gratin, croquette….). And don’t forget the Nut Roasts! You then get into Selection Boxes, Mince Pies, Puddings….. The list goes on.


    So aside from making you hungry, what has this got to do with Azure?

    Yes yes, I know I’ve been rambling on but I was getting to to the point.

    All of that food costs money and inevitably there is going to be some (or a lot of) wastage there. We can use the term “over-provisioning” to describe it.

    The same principle applies to Azure or any cloud provider when migrating new workloads into the cloud. No matter how much you try to “right-size”, there is a temptation to over-provision to make sure you have enough wiggle room due to increased demand.

    In my session for last years Festive Tech Calendar, I spoke about Azure Load Testing and how that can be used to not only “right-size” your environments, but also to test based on different patterns and unpredicatable spikes in demand that may happen.

    May happen …. or may not happen. You can only go so far in the science of predicting what might happen because there is always going to be a use case or usage pattern that you either didn’t consider.

    Regardless of all that you need to deploy your resources, but now comes the challenge – how do you monitor costs to ensure that there isn’t overspend? This is not just about Cost Management or Scaling, this is where the power of the entire suite of Azure FinOps can help.


    What is Azure FinOps?

    FinOps combines financial management practices with operations to ensure that cloud spending is transparent, accountable, and optimized. In the Azure ecosystem, FinOps helps businesses manage their cloud resources by giving visibility into spending patterns, offering optimization recommendations, and enabling financial governance.

    The FinOps lifecycle consists of three main phases:

    1. Inform: Understand and track cloud costs to ensure transparency.
    2. Optimize: Use insights to reduce unnecessary costs and improve efficiency.
    3. Operate: Continuously manage cloud costs to ensure ongoing financial efficiency.

    Azure provides a set of native tools designed to support FinOps practices and help organizations maximize cloud efficiency. Let’s look at each of these tools in detail:

    1. Azure Cost Management

    Azure Cost Management is the cornerstone of FinOps on Azure. It provides deep insights into cloud costs, allowing you to track, allocate, and analyze spend across your Azure resources.

    • Cost Analysis: Allows you to visualize and analyze costs over time by service, resource group, subscription, or department. This helps identify cost trends and usage patterns.
    • Budgets and Alerts: Set budgets for specific subscriptions or resources, and receive alerts if you’re approaching or exceeding budget limits.

    To give you a real world scenario, you can use Azure Cost Management to identify unnecessary resources running during off-peak hours, resulting in a significant cost reduction. By analyzing spending patterns, you can schedule workloads to scale down or shut down entirely during low-use periods.

    2. Azure Advisor

    Azure Advisor provides personalized recommendations to help optimize your Azure resources based on best practices. The Cost category of Azure Advisor focuses specifically on identifying opportunities to reduce spend by suggesting actions like right-sizing VMs, using Reserved Instances, and removing idle resources.

    In a real world scenario, you can use Advisor’s recommendations to optimize virtual machines , such as resizing underutilized VMs or applying Reserved Instances to resources that are in constant use, which can save thousands in annual costs.

    3. Azure Reservations

    Speaking of Azure Reservations, committing to reservations can provide significant cost savings by committing to a one or three-year terms for certain Azure resources, such as VMs, SQL Databases, and Cosmos DB.

    Reservations allow you to prepay for resources at a discounted rate, which is especially beneficial for predictable, long-term workloads. Depending on the Azure service, you can save up to 72% on reserved VMs and other services.

    4. Azure Spot Instances

    Azure Spot Instances allow you to purchase unused Azure compute capacity at a discount of up to 90%. These instances are ideal for workloads that are not time-sensitive and can tolerate interruptions, such as batch processing, development, and testing.

    An example would be running non-critical data processing workloads on Spot Instances during low-traffic hours, which drastically reduces operational expenses without impacting service.

    5. Azure Policy for Cost Management

    Azure Policy enforces rules and standards to keep resources compliant, including cost-related policies. You can set policies to control which resources can be deployed, prevent the use of expensive SKUs, and enforce resource tagging for accurate cost tracking.


    Using Alerts for Proactive Monitoring

    Setting up cost-related alerts is essential for proactive cost management. These alerts can notify relevant teams when spending thresholds are reached, helping prevent unexpected overspend. Here’s some examples and use cases for how you can configure alerts in Azure and integrate them into your Service Management solutions.

    1. Setting Budgets and Alerts

    With Azure Budgets, you can easily define the budgets in line with your predicted cloud spend based on amount, time period, and reset schedule to keep everything aligned.

    Once your budget is in place. Azure Budgets sends alerts the moment you hit a predefined threshold. Alerts can be customized to be sent via email or push notifications, ensuring you’re always in control of your cloud costs and never caught off guard.

    To create a budget:

    • In Azure Cost Management + Billing, navigate to Budgets, select your subscription, and create a new budget.
    • Set Thresholds: Define a monthly or quarterly budget and set alert thresholds (e.g., 50%, 75%, and 100% of the budget).
    • Configure Notifications: Specify recipients (e.g., Finance and Operations teams) for notifications via email or SMS.

    2. Integrating Alerts into Service Management Solutions

    For comprehensive monitoring, you can integrate Azure alerts with Service Management platforms like ServiceNow or Microsoft Teams.

    Azure Monitor allows you to create alerts based on various metrics, including cost. When this is integrated with Logic Apps, you can automate workflows to forward these alerts to a Service Management solution.

    An example would be generating an alert when spending hits 75% of the monthly budget. A Logic App workflow is triggered, creating a ServiceNow ticket for review and notifying the relevant team in Microsoft Teams.

    3. Real-Time Cost Alerts with Azure Monitor

    Azure Monitor’s integration with Azure Cost Management lets you create real-time alerts when costs increase unexpectedly. You can set up alerts based on specific metrics or thresholds for VM utilization, storage usage, and other cost-driving metrics.

    An example would be to use Azure Monitor to track VM utilization and generates alerts when the utilization exceeds a set threshold. The alert triggers a workflow to reduce resource allocation, leading to cost savings during non-peak hours.


    Real-World Savings with Azure FinOps

    Lets do a quick recap of some real-world examples where you can leverage Azure FinOps best practices to drive cost savings:

    1. Optimizing VM Costs
      • Challenge: High costs due to underutilized VMs during non-business hours.
      • Solution: Use Azure Advisor to right-size VMs and Azure Automation to shut down non-critical VMs during off-peak hours.
      • Result: In majority of cases, achieve between 20-30% reduction in monthly VM costs.
    2. Using Reserved Instances for Savings
      • Challenge: High costs from on-demand compute resources.
      • Solution: Purchase Azure Reserved Instances to lock in lower rates for long-term workloads.
      • Result: Depending on company size and size of cloud footprint, potential to save tens of thousands on your annual Azure bill by taking advantage of commitment-based discounts.
    3. Enhanced Governance with Azure Policy
      • Challenge: High operational costs and lack of visibility into resource usage.
      • Solution: Implement Azure Policy to enforce tagging and restrict expensive resources.
      • Result: Improved accountability and achieve savings on cloud spend by ensuring only necessary and approved resources were deployed.

    Best Practices

    Lets recap on the best practices for implementing Azure FinOps in your organization:

    1. Enforce Tagging: Use tags to categorize resources by cost center, department, or project, making it easier to track and allocate costs.
    2. Review Usage Regularly: Analyze reports from Azure Cost Management regularly to identify trends and patterns.
    3. Use Automation: Implement automation to shut down or scale down resources during low-usage periods.
    4. Educate Teams: Ensure that Finance, Operations, and Engineering teams understand FinOps principles and tools for more collaborative cost management.

    Conclusion

    Azure FinOps provides powerful tools and practices to optimize cloud spending, maximize efficiency, and achieve financial accountability across departments. Companies can not only achieve significant cost savings but also ensure their cloud environments are scalable, sustainable, and financially efficient.

    By combining Azure Cost Management, Azure Advisor, Reserved Instances, Spot Instances, and Azure Policy, you can effectively control and reduce your company’s Azure expenses. Integrating cost alerts into Service Management solutions allows for proactive cost management, ensuring that cloud spending remains transparent and aligned with organizational budgets.

    Top Highlights from Microsoft Ignite 2024: Key Azure Announcements

    This year, Microsoft Ignite was held in Chigaco for in-person attendees as well as virtually with key sessions live streamed. As usual, the Book of News was released to show the key announcements and you can find that at this link.

    From a personal standpoint, the Book of News was disappointing as at first glance there seemed to be very few key annoucements and enhancements being provided for core Azure Infrastructure and Networking.

    However, there were some really great reveals that were announced at various sessions throughout Ignite, and I’ve picked out some of the ones that impressed me.

    Azure Local

    Azure Stack HCI is no more ….. this is now being renamed to Azure Local. Which makes a lot more sense as Azure managed appliances deployed locally but still managed from Azure via Arc.

    So, its just a rename right? Wrong! The previous iteration was tied to specific hardware that had high costs. Azure Local now brings low spec and low cost options to the table. You can also use Azure Local in disconnected mode.

    More info can be found in this blog post and in this YouTube video.

    Azure Migrate Enhancements

    Azure Migrate is product that has badly needed some improvements and enhancements given the capabilities that some of its competitors in the market offer.

    The arrival of a Business case option enables customers to create a detailed comparison of the Total Cost of Ownership (TCO) for their on-premises estate versus the TCO on Azure, along with a year-on-year cash flow analysis as they transition their workloads to Azure. More details on that here.

    There was also an announcement during the Ignite Session around a tool called “Azure Migrate Explore” which looked like it provides you with a ready-made Business case PPT template generator that can be used to present cases to C-level. Haven’t seen this released yet, but one to look out for.

    Finally, one that may hae been missed a few months ago – given the current need for customers to migrate from VMware on-premises deployments to Azure VMware Solution (which is already built in to Azure Migrate via either Appliance or RVTools import), its good to see that there is a preview feature around a direct path from VMware to Azure Stack HCI (or Azure Local – see above). This is a step forward for customers who need to keep their workloads on-premises for things like Data Residency requirements, while also getting the power of Azure Management. More details on that one here.

    Azure Network Security Perimeter

    I must admit, this one confused me a little bit at first glance but makes sense now.

    Network Security Perimeter allows organizations to define a logical network isolation boundary for PaaS resources (for example, Azure Storage acoount and SQL Database server) that are deployed outside your organization’s virtual networks.

    So, we’re talking about services that are either deployed outside of a VNET (for whatever reason) or are using SKU’s that do not support VNET integration.

    More info can be found here.

    Azure Bastion Premium

    This has been in preview for a while but is now GA – Azure Bastion Premium offers enhanced security features such as private connectivity and graphical recordings of virtual machines connected through Bastion.

    Bastion offers enhanced security features that ensure customer virtual machines are connected securely and to monitor VMs for any anomalies that may arise.

    More info can be found here.

    Security Copilot integration with Azure Firewall

    The intelligence of Security Copilot is being integrated with Azure Firewall, which will help analysts perform detailed investigations of the malicious traffic intercepted by the IDPS feature of their firewalls across their entire fleet using natural language questions. These capabilities were launched on the Security Copilot portal and now are being integrated even more closely with Azure Firewall.

    The following capabilities can now be queried via the Copilot in Azure experience directly on the Azure portal where customers regularly interact with their Azure Firewalls: 

    • Generate recommendations to secure your environment using Azure Firewall’s IDPS feature
    • Retrieve the top IDPS signature hits for an Azure Firewall 
    • Enrich the threat profile of an IDPS signature beyond log information 
    • Look for a given IDPS signature across your tenant, subscription, or resource group 

    More details on these features can be found here.

    DNSSEC for Azure DNS

    I was surprised by this annoucement – maybe I had assumed it was there as it had been available as an AD DNS feature for quite some time. Good to see that its made it up to Azure.

    Key benefits are:

    • Enhanced Security: DNSSEC helps prevent attackers from manipulating or poisoning DNS responses, ensuring that users are directed to the correct websites. 
    • Data Integrity: By signing DNS data, DNSSEC ensures that the information received from a DNS query has not been altered in transit. 
    • Trust and Authenticity: DNSSEC provides a chain of trust from the root DNS servers down to your domain, verifying the authenticity of DNS data. 

    More info on DNSSEC for Azure DNS can be found here.

    Azure Confidential Clean Rooms

    Some fella called Mark Russinovich was talking about this. And when that man talks, you listen.

    Designed for secure multi-party data collaboration, with Confidential Clean Rooms, you can share privacy sensitive data such as personally identifiable information (PII), protected health information (PHI) and cryptographic secrets confidently, thanks to robust trust guarantees that safeguard your data throughout its lifecycle from other collaborators and from Azure operators.

    This secure data sharing is powered by confidential computing, which protects data in-use by performing computations in hardware-based, attested Trusted Execution Environments (TEEs). These TEEs help prevent unauthorized access or modification of application code and data during use. 

    More info can be found here.

    Azure Extended Zones

    Its good to see this feature going into GA and hopefully will provide a pathway for future AEZ’s in other locations.

    Azure Extended Zones are small-footprint extensions of Azure placed in metros, industry centers, or a specific jurisdiction to serve low latency and data residency workloads. They support virtual machines (VMs), containers, storage, and a selected set of Azure services and can run latency-sensitive and throughput-intensive applications close to end users and within approved data residency boundaries. More details here.

    .NET 9

    Final one and slightly cheating here as this was announced at KubeCon the week before – .NET9 has been announced. Note that this is a STS release with an expiry of May 2026. .NET 8 is the current LTS version with an end-of-support date of November 2026 (details on lifecycles for .NET versions here).

    Link to the full release announcement for .NET 9 (including a link to the KubeCon keynote) can be found here.

    Conclusion

    Its good to see that in the firehose of annoucements around AI and Copilot, there there are still some really good enhancements and improvements coming out for Azure services.

    Azure Networking Zero to Hero – Network Security Groups

    In this post, I’m going to stay within the boundaries of our Virtual Network and briefly talk about Network Security Groups, which filter network traffic between Azure resources in an Azure virtual network.

    Overview

    So, its a Firewall right?

    NOOOOOOOOOO!!!!!!!!

    While a Network Security Group (or NSG for short) contains Security Rules to allow or deny inbound/outbound traffic to/from several types of Azure Resources, it is not a Firewall (it may be what a Firewall looked like 25-30 years ago, but not now). NSG’s can be used in conjunction with Azure Firewall and other network security services in Azure to help secure and shape how your traffic flows between subnets and resources.

    Default Rules

    When you create a subnet in your Virtual Network, you have the option to create an NSG which will be automatically associated with the subnet. However, you can also create an NSG and manually associate it with either a subnet, or directly to a Network Interface in a Virtual Machine.

    When an NSG is created, it always has a default set of Security Rules that look like this:

    The default Inbound rules allow the following:

    • 65000 — All Hosts/Resources inside the Virtual Network to Communicate with each other
    • 65001 — Allows Azure Load Balancer to communicate with the Hosts/resources
    • 65500 — Deny all other Inbound traffic

    The default Outbound rules allow the following:

    • 65000 — All Hosts/Resources inside the Virtual Network to Communicate with each other
    • 65001 — Allows all Internet Traffic outbound
    • 65500 — Deny all other Outbound traffic

    The default rules cannot be edited or removed. NSG’s are created initially using a Zero-Trust model. The rules are processed in order of priority (lowest numbered rule is processed first). So you would need to build you rules on top of the default ones (for example, RDP and SSH access if not already in place).

    Configuration and Traffic Flow

    Some important things to note:

    • The default “65000” rules for both Inbound and Outbound – this allows all virtual network traffic. It means that if we have 2 subnets which each have a virtual machine, these would be able to communicate with each other without adding any additional rules.
    • As well as IP addresses and address ranges, we can use Service Tags which represents a group of IP address prefixes from a range of Azure services. These are managed and updated by Microsoft so you can use these instead of having to create and manage multiple Public IP’s for each service. You can find a full list of available Service Tags that can be used with NSG’s at this link. In the image above, “VirtualNetwork” and “AzureLoadBalancer” are Service Tags.
    • A virtual network subnet or interface can only have one NSG, but an NSG can be assigned to many subnets or interfaces. Tip from experience, this is not a good idea – if you have an application design that uses multiple Azure Services, split these services into dedicated subnets and apply NSG’s to each subnet.
    • When using a NSG associated with a subnet and a dedicated NSG associated with a network interface, the NSG associated with the Subnet is always evaluated first for Inbound Traffic, before then moving on to the NSG associated with the NIC. For Outbound Traffic, it’s the other way around — the NSG on the NIC is evaluated first, and then the NSG on the Subnet is evaluated. This process is explained in detail here.
    • If you don’t have a network security group associated to a subnet, all inbound traffic is blocked to the subnet/network interface. However, all outbound traffic is allowed.
    • You can only have 1000 Rules in an NSG by default. Previously, this was 200 and could be raised by logging a ticket with Microsoft, but the max (at time of writing) is 1000. This cannot be increased. Also, there is a max limit of 5000 NSG’s per subscription.

    Logging and Visibility

    • Important – Turn on NSG Flow Logs. This is a feature of Azure Network Watcher that allows you to log information about IP traffic flowing through a network security group,  including details on source and destination IP addresses, ports, protocols, and whether traffic was permitted or denied. You can find more in-depth details on flow logging here, and a tutorial on how to turn it on here.
    • To enhance this, you can use Traffic Analytics, which analyzes Azure Network Watcher flow logs to provide insights into traffic flow in your Azure cloud.

    Conclusion

    NSGs are fundamental to securing inbound and outbound traffic for subnets within an Azure Virtual Network, and form one of the first layers of defense to protect application integrity and reduce the risk of data loss prevention.

    However as I said at the start of this post, an NSG is not a Firewall. The layer 3 and layer 4 port-based protection that NSGs provide has significant limitations and cannot detect other forms of malicious attacks on protocols such as SSH and HTTPS that can go undetected by this type of protection.

    And that’s one of the biggest mistakes I see people make – they assume that NSG’s will do the job because Firewalls and other network security sevices are too expensive.

    Therefore, NSG’s should be used in conjunction with other network security tools, such as Azure Firewall and Web Application Firewall (WAF), for any devices presented externally to the internet or other private networks. I’ll cover these in detail in later posts.

    Hope you enjoyed this post, until next time!!

    Azure Networking Zero to Hero – Routing in Azure

    In this post, I’m going to try and explain Routing in Azure. This is a topic that grows in complexity the more you expand your footprint in Azure in terms of both Virtual Networks, and also the services you use to both create your route tables and route your traffic.

    Understanding Azure’s Default Routing

    As we saw in the previous post when a virtual network is created, this also creates a route table. This contains a default set of routes known as System Routes, which are shown here:

    SourceAddress prefixesNext hop type
    DefaultVirtual Network Address SpaceVirtual network
    Default0.0.0.0/0Internet
    Default10.0.0.0/8None (Dropped)
    Default172.16.0.0/12None (Dropped)
    Default192.168.0.0/16None (Dropped)

    Lets explain the “Next hop types” is in a bit more detail:

    • Virtual network: Routes traffic between address ranges within the address space of a virtual network. So lets say I have a Virtual Network with the 10.0.0.0/16 address space defined. I then have VM1 in a subnet with the 10.0.1.0/24 address range trying to reach VM2 in a subnet with the 10.0.2.0/24 address range. It know to keep this within the Virtual Network and routes the traffic successfully.
    • Internet: Routes traffic specified by the address prefix to the Internet. If the destination address range is not part of a Virtual Network address space, its gets routed to the Internet. The only exception to this rule is if trying to access an Azure Service – this goes across the Azure Backbone network no matter which region the service sits in.
    • None: Traffic routed to the None next hop type is dropped. This automatically includes all Private IP Addresses as defined by RFC1918, but the exception to this is your Virtual Network address space.

    Simple, right? Well, its about to get more complicated …..

    Additional Default Routes

    Azure adds more default system routes for different Azure capabilities, but only if you enable the capabilities:

    SourceAddress prefixesNext hop type
    DefaultPeered Virtual Network Address SpaceVNet peering
    Virtual network gatewayPrefixes advertised from on-premises via BGP, or configured in the local network gatewayVirtual network gateway
    DefaultMultipleVirtualNetworkServiceEndpoint

    So lets take a look at these:

    • Virtual network (VNet) peering: when a peering is created between 2 VNets, Azure adds the address spaces of each of the peered VNets to the Route tables of the source VNets.
    • Virtual network gateway: this happens when S2S VPN or Express Route connectivity is establised and adds address spaces that are advertised from either Local Network Gateways or On-Premises gateways via BGP (Border Gateway Protocol). These address spaces should be summarized to the largest address range coming from On-Premises, as there is a limit of 400 routes per route table.
    • VirtualNetworkServiceEndpoint: this happens when creating a direct service endpoint for an Azure Service, enables private IP addresses in the VNet to reach the endpoint of an Azure service without needing a public IP address on the VNet.

    Custom Routes

    The limitations of sticking with System Routes is that everything is done for you in the background – there is no way to make changes.

    This is why if you need to make change to how your traffic gets routed, you should use Custom Routes, which is done by creating a Route Table. This is then used to override Azure’s default system routes, or to add more routes to a subnet’s route table.

    You can specify the following “next hop types” when creating user-defined routes:

    • Virtual Appliance: This is typically Azure Firewall, Load Balancer or other virtual applicance from the Azure Marketplace. The appliance is typically deployed in a different subnet than the resources that you wish to route through the Virtual Appliance. You can define a route with 0.0.0.0/0 as the address prefix and a next hop type of virtual appliance, with the next hop address set as the internal IP Address of the virtual appliance, as shown below. This is useful if you want all outbound traffic to be inspected by the appliance:
    • Virtual network gateway: used when you want traffic destined for specific address prefixes routed to a virtual network gateway. This is useful if you have an On-Premises device that inspects traffic an determines whether to forward or drop the traffic.
    • None: used when you want to drop traffic to an address prefix, rather than forwarding the traffic to a destination.
    • Virtual network: used when you want to override the default routing within a virtual network.
    • Internet: used when you want to explicitly route traffic destined to an address prefix to the Internet

    You can also use Service Tags as the address prefix instead of an IP Range.

    How Azure selects which route to use?

    When outbound traffic is sent from a subnet, Azure selects a route based on the destination IP address, using the longest prefix match algorithm. So if 2 routes exist with 10.0.0.0/16 and a 10.0.0.0/24, Azure will select the /24 as it has the longest prefix.

    If multiple routes contain the same address prefix, Azure selects the route type, based on the following priority:

    • User-defined route
    • BGP route
    • System route

    So, the initial System Routes are always the last ones to be checked.

    Conclusion and Resources

    I’ve put in some links already in the article. The main place to go for a more in-depth deep dive on Routing is this MS Learn Article on Virtual Network Traffic Routing.

    As regards people to follow, there’s no one better than my fellow MVP Aidan Finn who writes extensively about networking over at his blog. He also delivered this excellent session at the Limerick Dot Net Azure User Group last year which is well worth a watch for gaining a deep understanding of routing in Azure.

    Hope you enjoyed this post, until next time!!

    Azure Networking Zero to Hero – Intro and Azure Virtual Networks

    Welcome to another blog series!

    This time out, I’m going to focus on Azure Networking, which covers a wide range of topics and services that make up the various networking capabilities available within both Azure cloud and hybrid environments. Yes I could have done something about AI, but for those of you who know me, I’m a fan of the classics!

    The intention is to have this blog series serve as both a starting point for anyone new to Azure Networking who is looking to start a learning journey towards that AZ-700 certification, or as an easy reference point for anyone looking for a list of blogs specific to the wide scope of services available in the Azure Networking family.

    There isn’t going to be a set number of blog posts or “days” – I’m just going to run with this one and see what happens! So with that, lets kick off with our first topic, which is Virtual Networks.

    Azure Virtual Networks

    So lets start with the elephant in the room. Yes, I have written a blog post about Azure Virtual Networks before – 2 of them actually as part of my “100 Days of Cloud” blog series, you’ll find Part 1 and Part 2 at these links.

    Great, so thats todays blog post sorted!!! Until next ti …… OK, I’m joking – its always good to revise and revisit.

    After a Resource Group, a virtual network is likely to be the first actual resource that you create. Create a VM, Database or Web App, the first piece of information it asks you for is what Virtual Network to your resource in.

    But of course if you’ve done it that way, you’ve done it backwards because you really should have planned your virtual network and what was going to be in it first! A virtual network acts as a private address space for a specific set of resource groups or resources in Azure. As a reminder, a virtual network contains:

    • Subnets, which allow you to break the virtual network into one or more dedicated address spaces or segments, which can be different sizes based on the requirements of the resource type you’ll be placing in that subnet.
    • Routing, which routes traffic and creates a routing table. This means data is delivered using the most suitable and shortest available path from source to destination.
    • Network Security Groups, which can be used to filter traffic to and from resources in an Azure Virtual Network. Its not a Firewall, but it works like one in a more targeted sense in that you can manage traffic flow for individual virtual networks, subnets, and network interfaces to refine traffic.

    A lot of wordy goodness there, but the easiest way to illustrate this is using a good old diagram!

    Lets do a quick overview:

    • We have 2 Resource Groups using a typical Hub and Spoke model where the Hub contains our Application Gateway and Firewall, and our Spoke contains our Application components. The red lines indicate peering between the virtual networks so that they can communicate with each other.
    • Lets focus on the Spoke resource group – The virtual network has an address space of 10.1.0.0/16 defined.
    • This is then split into different subnets where each of the components of the Application reside. Each subnet has an NSG attached which can control traffic flow to and from different subnets. So in this example, the ingress traffic coming into the Application Gateway would then be allows to pass into the API Management subnet by setting allow rules on the NSG.
    • The other thing we see attached to the virtual network is a Route Table – we can use this to define where traffic from specific sources is sent to. We can use System Routes which are automatically built into Azure, or Custom Routes which can be user defined or by using BGP routes across VPN or Express Route services. The idea in our diagram is that all traffic will be routed back to Azure Firewall for inspection before forwarding to the next destination, which can be another peered virtual network, across a VPN to an on-premises/hybrid location, or straight out to an internet destination.

    Final thoughts

    Some important things to note on Virtual Networks:

    • Planning is everything – before you even deploy your first resource group, make sure you have your virtual networks defined, sized and mapped out for what you’re going to use them for. Always include scaling, expansion and future planning in those decisions.
    • Virtual Networks reside in a single resource group, but you technically can assign addresses from subnets in your virtual network to resources that reside in different resource groups. Not really a good idea though – try to keep your networking and resources confined within resource group and location boundaries.
    • NSG’s are created using a Zero-Trust model, so nothing gets in or out unless you define the rules. The rules are processed in order of priority (lowest numbered rule is processed first), so you would need to build you rules on top of the default ones (for example, RDP and SSH access if not already in place).

    Hope you enjoyed this post, until next time!!

    The A-Z of Azure Policy

    I’m delighted to be contributing to Azure Spring Clean for the first time. The annual event is organised by Azure MVP’s Joe Carlyle and Thomas Thornton and encourages you to look at your Azure subscriptions and see how you could manage it better from a Cost Management, Governance, Monitoring and Security perspective. You can check out all of the posts in this years Azure Spring Clean here. For this year, my contribution is the A-Z of Azure Policy!

    Azure Policy is one of the key pillars of a Well Architected Framework for Cloud Adoption. It enables you to enforce standards across either single or multiple subscriptions at different scope levels and allows you to bring both existing and new resources into compliance using bulk and automated remediation.

    These policies enforce different rules and effects over your resources so that those resources stay compliant with your corporate standards and service level agreements. Azure Policy meets this need by evaluating your resources for noncompliance with assigned policies.

    Image Credit - Microsoft

    Image Credit: Microsoft

    Policies define what you can and cannot do with your environment. They can be used individually or in conjunction with Locks to ensure granular control. Let’s look at some simple examples where Policies can be applied:

    • If you want to ensure resources are deployed only in a specific region.
    • If you want to use only specific Virtual Machine or Storage SKUs.
    • If you want to block any SQL installations.
    • If you want to enforce Tags consistently across your resources.

    So that’s it – you can just apply a policy and it will do what you need it to do? The answer is both Yes and No:

    • Yes, in the sense that you can apply a policy to define a particular set of business rules to audit and remediate the compliance of existing resources against those rules.
    • No in the sense that there is so much more to it than that.

    There is much to understand about how Azure Policy can be used as part of your Cloud Adoption Framework toolbox. And because there is so much to learn, I’ve decided to do an “A-Z” of Azure Policy and show the different options and scenarios that are available.

    Before we start on the A-Z, a quick disclaimer …. There’s going to be an entry for every letter of the alphabet, but you may have to forgive me if I use artistic license to squeeze a few in (Letters like Q, X and Z spring to mind!).

    So, grab a coffee (or whatever drink takes your fancy) and let’s start on the Azure Policy alphabet!

    A

    Append is the first of our Policy Effects and is used to add extra fields to resources during update or creation, however this is only available with Azure Resource Manager (ARM). The example below sets IP rules on a Storage Account:

    "then": {
        "effect": "append",
        "details": [{
            "field": "Microsoft.Storage/storageAccounts/networkAcls.ipRules",
            "value": [{
                "action": "Allow",
                "value": "134.5.0.0/21"
            }]
        }]
    }

    Assignment is the definition of what resources or scope your Policy is being applied to.

    Audit is the Policy Effect that evaluates the resources and report a non-compliance in the logs. It does not take any actions; this is report-only.

    "then": {
        "effect": "audit"
    }

    AuditIfNotExists is the Policy Effect that evaluates whether a property is missing. So for example, we can say if the type of Resource is a Virtual Machine and we want to know if that Virtual Machine has a particular tag or extension present. If yes, the resource will be returned as Compliant, if not, it will return a non-compliance. The example below evaluates Virtual Machines to determine whether the Antimalware extension exists then audits when missing:

    {
        "if": {
            "field": "type",
            "equals": "Microsoft.Compute/virtualMachines"
        },
        "then": {
            "effect": "auditIfNotExists",
            "details": {
                "type": "Microsoft.Compute/virtualMachines/extensions",
                "existenceCondition": {
                    "allOf": [{
                            "field": "Microsoft.Compute/virtualMachines/extensions/publisher",
                            "equals": "Microsoft.Azure.Security"
                        },
                        {
                            "field": "Microsoft.Compute/virtualMachines/extensions/type",
                            "equals": "IaaSAntimalware"
                        }
                    ]
                }
            }
        }
    }

    B

    Blueprints – Instead of having to configure features like Azure Policy for each new subscription, with Azure Blueprints you can define a repeatable set of governance tools and standard Azure resources that your organization requires. This allows you to scale the configuration and organizational compliance across new and existing subscriptions with a set of built-in components that speed the development and deployment phases.

    Built-In –Azure provides hundreds of built-in Policy and Initiative definitions for multiple resources to get you started. You can find then both on the Microsoft Learn site or on GitHub.

    C

    Compliance State shows the state of the resource when compared to the policy that has been applied. Unsurprisingly this has 2 states, Compliant and Non-Compliant

    Costs – if you are running Azure Policy on Azure resources, then its free. However, you can use Azure Policy to cover Azure Arc resources and there are specific scenarios where you will be charged:

    • Azure Policy guest configuration (includes Azure Automation change tracking, inventory, state configuration): $6/Server/Month
    • Kubernetes Configuration: First 6 vCPUs are free, $2/vCPU/month

    Custom Policy definitions are ones that you create yourself when a Built-In Policy doesn’t meet the requirements of what you are trying to achieve.

    D

    Dashboards in the Azure Portal give you a graphical overview of the compliance state of your Azure environments:

    Definition Location is the scope to where the Policy or Initiative is assigned. This can be Management Group, Subscription, Resource Group or Resource.

    Deny is the Policy Effect used to prevent a resource request or action that doesn’t match the defined standards.

    "then": {
        "effect": "deny"
    }

    DeployIfNotExists is the Policy Effect used to apply the action defined in the Policy Template when a resource is found to be non-compliant. This is used as part of a remediation of non-compliant resources. Important point to note – policy assignments that use a DeployIfNotExists effect require a managed identity to perform remediation.

    Docker Security Baseline is a set of default configuration settings which ensure that Docker Containers in Azure are running based on a recommended set of regulatory and security baselines.

    E

    Enforcement Mode is a property that allows you to enable/disable enforcement of policy effects while still evaluating compliance.

    Evaluation is the process of scanning your environment to determine the applicability and compliance of assigned policies.

    F

    Fields are used in policy definitions to specify a property or alias. In the example below, the field property contains “location” and “type” at different stages of the evaluation:

    "if": {
            "allOf": [{
                    "field": "location",
                    "notIn": "[parameters('listOfAllowedLocations')]"
                },
                {
                    "field": "location",
                    "notEquals": "global"
                },
                {
                    "field": "type",
                    "notEquals": "Microsoft.AzureActiveDirectory/b2cDirectories"
                }
            ]
        },
        "then": {
            "effect": "Deny"
        }
    }

    G

    GitHub – you can use GitHub to build an “Azure Policy as Code” workflow to manage your policies as code, control the lifecycle of updating definitions, and automate the process of validating compliance results.

    Governance Visualizer – I have to include this because I think its an awesome tool – Julian Hayward’s AzGovViz tool is a PowerShell script which captures Azure governance capabilities such as Azure Policy, RBAC and Blueprints and a lot more. If you’re not using it, now is the time to start.

    Group – within an Initiative, you can group policy definitions for categorization. The Regulatory Compliance feature uses this to group definitions into controls and compliance domains.

    H

    Hierarchy – this sounds simple but is important. The location that you assign the policy should contain all resources that you want to target under that resource hierarchy. If the definition location is a:

    • Subscription – Only resources within that subscription can be assigned the policy definition.
    • Management group – Only resources within child management groups and child subscriptions can be assigned the policy definition. If you plan to apply the policy definition to several subscriptions, the location must be a management group that contains each subscription.

    I

    Initiative (or Policy Set) is a set of Policies that have been grouped together with the aim of either targeting a specific set of resources, or to evaluate and remediate a specific set of definitions or parameters. For example, you could group several tagging policies into a single initiative that is targeted at a specific scope instead of applying multiple policies individually.

    J

    JSON – Policy definitions are written in JSON format. The policy definition contains elements for:

    • mode
    • parameters
    • display name
    • description
    • policy rule
      • logical evaluation
      • effect

    An example of the “Allowed Locations” built-in policy is shown below

    {
      "properties": {
        "displayName": "Allowed locations",
        "policyType": "BuiltIn",
        "description": "This policy enables you to restrict the locations...",
        "mode": "Indexed",
        "parameters": {
          "listOfAllowedLocations": {
            "type": "Array",
            "metadata": {
              "description": "Locations that can be specified....",
              "strongType": "location",
              "displayName": "Allowed locations"
            }
          }
        },
        "policyRule": {
          "if": {
            "allOf": [
              {
                "field": "location",
                "notIn": "[parameters('listOfAllowedLocations')]"
              },
              {
                "field": "location",
                "notEquals": "global"
              },
              {
                "field": "type",
                "notEquals": "Microsoft.AzureActiveDirectory/b2cDirectories"
              }
            ]
          },
          "then": {
            "effect": "Deny"
          }
        }
      },
      "id": "/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c",
      "type": "Microsoft.Authorization/policyDefinitions",
      "name": "e56962a6-4747-49cd-b67b-bf8b01975c4c"
    }

    K

    Key Vault – you can integrate Key Vault with Azure Policy to audit the key vault and its objects before enforcing a deny operation to prevent outages. Current built-ins for Azure Key Vault are categorized in four major groups: key vault, certificates, keys, and secrets management.

    Kubernetes – Azure Policy uses Gatekeeper to apply enforcements and safeguards on your clusters (both Azure Kubernetes Service (AKS) and Azure Arc enabled Kubernetes). This then reports back into your centralized Azure Policy Dashboard on the following:

    • Checks with Azure Policy service for policy assignments to the cluster.
    • Deploys policy definitions into the cluster as constraint template and constraint custom resources.
    • Reports auditing and compliance details back to Azure Policy service.

    After installing the Azure Policy Add-on for AKS, you can apply individual policy definitions or initiatives to your cluster.

    L

    Lighthouse – for Service Providers, you can use Azure Lighthouse to deploy and manage policies across multiple customer tenants.

    Linux Security Baseline is a set of default configuration settings which ensure that Linux VMs in Azure are running based on a recommended set of regulatory and security baselines.

    Logical Operators are optional condition statements that can be used to see if resources have certain configurations applied. There are 3 logical operators – not, allOf and anyOf.

    • Not means that the opposite of the condition should be true for the policy to be applied.
    • AllOf requires all the conditions defined to be true at the same time.
    • AnyOf requires any one of the conditions to be true for the policy to be applied.
    "policyRule": {
      "if": {
        "allOf": [{
            "field": "type",
            "equals": "Microsoft.DocumentDB/databaseAccounts"
          },
          {
            "field": "Microsoft.DocumentDB/databaseAccounts/enableAutomaticFailover",
            "equals": "false"
          },
          {
            "field": "Microsoft.DocumentDB/databaseAccounts/enableMultipleWriteLocations",
            "equals": "false"
          }
        ]
      },
      "then": {

    M

    Mode tells you the type of resources for which the policy will be applied. Allowed values are “All” (where all Resource Groups and Resources are evaluated) and “indexed” (where policy is evaluated only for resources which support tags and location)

    Modify is a Policy Effect that is used to add, update, or remove properties or tags on a subscription or resource during creation or update. Important point to note – policy assignments that use a Modify effect require a managed identity to perform remediation. If you don’t have a managed identity, use Append instead. The example below is replacing all tags with a value of environment with a value of test:

    "then": {
        "effect": "modify",
        "details": {
            "roleDefinitionIds": [
                "/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
            ],
            "operations": [
                {
                    "operation": "addOrReplace",
                    "field": "tags['environment']",
                    "value": "Test"
                }
            ]
        }
    }

    N

    Non-Compliant is the state which indicates that a resource did not conform to the policy rule in the policy definition.

    O

    OK, so this is my first failure. Surprising, but lets keep going!

    P

    Parameters are used for providing inputs to the policy. They can be reused at multiple locations within the policy.

    {
        "properties": {
            "displayName": "Require tag and its value",
            "policyType": "BuiltIn",
            "mode": "Indexed",
            "description": "Enforces a required tag and its value. Does not apply to resource groups.",
            "parameters": {
                "tagName": {
                    "type": "String",
                    "metadata": {
                        "description": "Name of the tag, such as costCenter"
                    }
                },
                "tagValue": {
                    "type": "String",
                    "metadata": {
                        "description": "Value of the tag, such as headquarter"
                    }
                }
            },
            "policyRule": {
                "if": {
                    "not": {
                        "field": "[concat('tags[', parameters('tagName'), ']')]",
                        "equals": "[parameters('tagValue')]"
                    }
                },
                "then": {
                    "effect": "deny"
                }
            }
        }
    }

    Policy Rule is the part of a policy definition that describes the compliance requirements.

    Policy State describes the compliance state of a policy assignment.

    Q

    Query Compliance – While the Dashboards in the Azure Portal (see above) provide you with a visual method of checking your overall compliance, there are a number of command line and automation tools you can use to access the compliance information gnerated by your policy and initiative assignments:

    az policy state trigger-scan --resource-group "MyRG"

    • Azure PowerShell using the following command:

    Start-AzPolicyComplianceScan -ResourceGroupName 'MyRG'

    R

    Regulatory Compliance describes a specific type of initiative that allows grouping of policies into controls and categorization of policies into compliance domains based on responsibility (Customer, Microsoft, Shared). These are available as built-in initiatives (there are built-in initiatives from CIS, ISO, PCI DSS, NIST, and multiple Government standards), and you have the ability to create your own based on specific requirements.

    Remediation is a way to handle non-compliant resources. You can create remediation tasks for resources to bring these to a desired state and into compliance. You use DeployIfNotExists or Modify effects to correct violating policies.

    S

    Security Baseline for Azure Security Benchmark – this is a set of policies that comes from guidance from the Microsoft cloud security benchmark version 1.0. The full Azure Policy security baseline mapping file can be found here.

    Scope is the location where the policy definition is being assigned to. This can be Management Group, Subscription, Resource Group or Resource.

    T

    Tag Governance is a crucial part of organizing your Azure resources into a taxonomy. Tags can be the basis for applying your business policies with Azure Policy or tracking costs with Cost Management. The template shown below shows how to enforce Tag values across your resources:

    {
       "properties": {
          "displayName": "Require tag and its value",
          "policyType": "BuiltIn",
          "mode": "Indexed",
          "description": "Enforces a required tag and its value. Does not apply to resource groups.",
          "parameters": {
             "tagName": {
                "type": "String",
                "metadata": {
                   "description": "Name of the tag, such as costCenter"
                }
             },
             "tagValue": {
                "type": "String",
                "metadata": {
                   "description": "Value of the tag, such as headquarter"
                }
             }
          },
          "policyRule": {
             "if": {
                "not": {
                   "field": "[concat('tags[', parameters('tagName'), ']')]",
                   "equals": "[parameters('tagValue')]"
                }
             },
             "then": {
                "effect": "deny"
             }
          }
       },
       "id": "/providers/Microsoft.Authorization/policyDefinitions/1e30110a-5ceb-460c-a204-c1c3969c6d62",
       "type": "Microsoft.Authorization/policyDefinitions",
       "name": "1e30110a-5ceb-460c-a204-c1c3969c6d62"
    }

    U

    Understanding how Effects work is key to understanding Azure Policy. By now, we’ve listed all the effects out above. The key thing to remember is that each policy definition has a single effect, which determines what happens when an evaluation finds a match. There is an order in how the effects are evaluated:

    • Disabled is checked first to determine whether the policy rule should be evaluated.
    • Append and Modify are then evaluated. Since either could alter the request, a change made may prevent an audit or deny effect from triggering. These effects are only available with a Resource Manager mode.
    • Deny is then evaluated. By evaluating deny before audit, double logging of an undesired resource is prevented.
    • Audit is evaluated.
    • Manual is evaluated.
    • AuditIfNotExists is evaluated.
    • denyAction is evaluated last.

    Once these effects return a result, the following 2 effects are run to determine if additional logging or actions are required:

    • AuditIfNotExists
    • DeployIfNotExists

    V

    Visual Studio Code contains an Azure Policy code extension which allows you to create and modify policy definitions, run resource compliance and evaluate your policies against a resource.

    W

    Web Application Firewall – Azure Web Application Firewall (WAF) combined with Azure Policy can help enforce organizational standards and assess compliance at-scale for WAF resources.

    Windows Security Baseline is a set of default configuration settings which ensure that Windows VMs in Azure are running based on a recommended set of regulatory and security baselines.

    X

    X is for ….. ah come on, you’re having a laugh ….. fine, here you go (artistic license taken!):

    Xclusion – this of course should read Exclusion ….. when assigned, the scope includes all child resource containers and child resources. If a child resource container or child resource shouldn’t have the definition applied, each can be excluded from evaluation by setting notScopes.

    Xemption – this of course should read Exemption …. this is a feature used to exempt a resource hierarchy or individual resource from evaluation. These resources are therefore not evaluated and can have a temporary waiver (expiration) period where they are exempt from evaluation and remediation.

    Y

    YAML – You can use Azure DevOps to check Azure Policy Compliance using using YAML Pipelines. However, you need to use the AzurePolicyCheckGate@0 task. The syntax is shown below:

    # Check Azure Policy compliance v0
    # Security and compliance assessment for Azure Policy.
    - task: AzurePolicyCheckGate@0
      inputs:
        azureSubscription: # string. Alias: ConnectedServiceName. Required. Azure subscription. 
        #ResourceGroupName: # string. Resource group. 
        #Resources: # string. Resource name.

    Z

    Zero Non-Compliant – which is exactly the position you want to get to!

    Z is also for Zzzzzzzz, which may be the state you’re in if you’ve managed to get this far!

    Summary

    So thats a lot to take in, but it gives you an insight into the different options that are available in Azure Policy to ensure that your Azure environments can meet both governance and cost management objectives for your organization.

    In this post, I’ve stayed with the features of Azure Policy and apart from a few examples didn’t touch on the many different methods you can use to assign and manage policies which are:

    • Azure Portal
    • Azure CLI
    • Azure PowerShell
    • .NET
    • JavaScript
    • Python
    • REST
    • ARM Template
    • Bicep
    • Terraform

    As always, check out the official Microsoft Learn documentation for a more in-depth deep dive on Azure Policy.

    Hope you enjoyed this post! Be sure to check out the rest of the articles in this years Azure Spring Clean.