<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://woivre.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://woivre.com/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-09-10T17:08:27+00:00</updated><id>https://woivre.com/feed.xml</id><title type="html">Wilfried Woivré</title><subtitle>Personal Blog by Wilfried Woivré. My favorites subjects are Azure, Cloud, Serverless, Container, ...</subtitle><author><name>Wilfried Woivré</name></author><entry><title type="html">Implementing Azure Network Security Perimeter in a Real-World Azure Architecture</title><link href="https://woivre.com/blog/2026/08/implementing-azure-network-security-perimeter-in-a-real-world-azure-architecture" rel="alternate" type="text/html" title="Implementing Azure Network Security Perimeter in a Real-World Azure Architecture" /><published>2026-08-31T00:00:00+00:00</published><updated>2026-08-31T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/08/implementing-azure-network-security-perimeter-in-a-real-world-azure-architecture</id><content type="html" xml:base="https://woivre.com/blog/2026/08/implementing-azure-network-security-perimeter-in-a-real-world-azure-architecture"><![CDATA[<p>By the time you reach the implementation stage, Azure Network Security Perimeter becomes much more tangible. The real value appears when you apply it to an architecture that already includes shared services, workloads, and multiple teams.</p>

<p>A common scenario is a landing zone where several applications use Azure PaaS services such as Storage, Key Vault, and App Service. In that type of environment, NSP can help you define the trust boundary around sensitive resources and make access expectations more explicit.</p>

<h2 id="a-sample-architecture-pattern">A sample architecture pattern</h2>

<p>A practical pattern might look like this:</p>

<ul>
  <li>A shared platform layer with identity, monitoring, and shared services</li>
  <li>Application workloads deployed in different workspaces or subscriptions</li>
  <li>Protected services that should only be reachable from approved internal paths</li>
  <li>Access policies that align with business and security requirements</li>
</ul>

<p>In this kind of setup, NSP provides a way to enforce the boundary without forcing every resource to be redesigned from scratch.</p>

<h2 id="implementation-considerations">Implementation considerations</h2>

<p>When implementing NSP in a real environment, it helps to start with a small scope. Choose a few critical resources, define their expected access pattern, and validate the policy before expanding it further. This approach tends to be more manageable than trying to secure everything at once.</p>

<p>You should also involve the teams that own the resources. They often know the legitimate access flows better than anyone else, and that context is essential for building accurate policies.</p>

<h2 id="a-more-realistic-bicep-example">A more realistic Bicep example</h2>

<p>In a landing zone, you can start with a simple perimeter definition and then extend it as your access rules become clearer:</p>

<pre><code class="language-bicep">targetScope = 'resourceGroup'

@description('Name of the perimeter used in the landing zone')
param perimeterName string = 'landingzone-prod-nsp'

@description('Key Vault instance to protect within the perimeter')
param keyVaultId string = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-platform-prod/providers/Microsoft.KeyVault/vaults/kv-platform-prod'

@description('App Service that shares the same trust boundary')
param appServiceId string = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-app-prod/providers/Microsoft.Web/sites/app-prod-api'

resource perimeter 'Microsoft.Network/networkSecurityPerimeters@2024-05-01' = {
  name: perimeterName
  location: 'global'
  tags: {
    Environment: 'prod'
    Platform: 'LandingZone'
    Owner: 'Platform Engineering'
  }
  properties: {
    accessRules: [
      {
        name: 'allow-platform-operations'
        properties: {
          direction: 'Inbound'
          access: 'Allow'
          description: 'Allow platform operations and automation services'
          addressPrefixes: [
            '10.30.10.0/24'
          ]
          destinationPortRanges: [
            '443'
          ]
        }
      }
    ]
    // Link protected resources and define approved inbound sources here.
  }
}

output perimeterId string = perimeter.id
output protectedResources array = [
  keyVaultId
  appServiceId
]
</code></pre>

<p>This skeleton is a good starting point for a shared platform environment. From there, you can refine the rules so that only the intended apps, identities, and services are allowed into the protected boundary.</p>

<h2 id="the-long-term-benefit">The long-term benefit</h2>

<p>The main benefit of NSP is not only stronger security. It is also better consistency. When access control is expressed in a clear and reusable way, it becomes easier to maintain over time and much simpler to explain to other teams.</p>

<p>If you are planning to strengthen your Azure networking posture, NSP is worth exploring as part of a broader strategy that includes private connectivity, identity controls, and monitoring.</p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><category term="Network Security Perimeter" /><summary type="html"><![CDATA[By the time you reach the implementation stage, Azure Network Security Perimeter becomes much more tangible. The real value appears when you apply it to an architecture that already includes shared services, workloads, and multiple teams.]]></summary></entry><entry><title type="html">Azure Network Security Perimeter vs Private Endpoints - Which One Should You Use?</title><link href="https://woivre.com/blog/2026/08/azure-network-security-perimeter-vs-private-endpoints-which-one-should-you-use" rel="alternate" type="text/html" title="Azure Network Security Perimeter vs Private Endpoints - Which One Should You Use?" /><published>2026-08-24T00:00:00+00:00</published><updated>2026-08-24T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/08/azure-network-security-perimeter-vs-private-endpoints-which-one-should-you-use</id><content type="html" xml:base="https://woivre.com/blog/2026/08/azure-network-security-perimeter-vs-private-endpoints-which-one-should-you-use"><![CDATA[<p>Azure Network Security Perimeter and private endpoints are both powerful mechanisms for improving resource protection, but they are not interchangeable. Understanding their differences is essential when designing secure Azure architectures.</p>

<p>Private endpoints are mainly focused on creating a private network path to a specific Azure service. They are often used to ensure that traffic stays within a virtual network and avoids the public internet. In contrast, NSP focuses on the security boundary around a resource and provides a broader access-control model for protecting groups of resources.</p>

<h2 id="when-private-endpoints-are-a-strong-choice">When private endpoints are a strong choice</h2>

<p>Private endpoints are ideal when you want to:</p>

<ul>
  <li>Ensure a resource is reachable only through a private network path</li>
  <li>Reduce exposure to the public endpoint</li>
  <li>Build strong network isolation for a specific service</li>
</ul>

<h2 id="when-nsp-is-more-appropriate">When NSP is more appropriate</h2>

<p>NSP is usually more relevant when you want to:</p>

<ul>
  <li>Protect a set of related resources with shared access rules</li>
  <li>Apply resource-centric security policies consistently</li>
  <li>Improve governance across a broader Azure environment</li>
</ul>

<h2 id="a-practical-way-to-think-about-them">A practical way to think about them</h2>

<p>A useful way to frame the relationship is this: private endpoints focus on connectivity, whereas NSP focuses on perimeter-based access control. In many architectures, they complement each other rather than compete.</p>

<p>You might use private endpoints to isolate a critical service and NSP to enforce a consistent security boundary around a collection of resources that share the same protection requirements.</p>

<h2 id="a-bicep-comparison-example">A Bicep comparison example</h2>

<p>Here is a small example that shows the two patterns at a high level:</p>

<pre><code class="language-bicep">targetScope = 'resourceGroup'

@description('Storage account that should be reachable through a private path')
param storageAccountId string = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-data-prod/providers/Microsoft.Storage/storageAccounts/stdataprod001'

@description('Subnet used for the private endpoint')
param privateSubnetId string = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-network-prod/providers/Microsoft.Network/virtualNetworks/vnet-hub-prod/subnets/snet-private-endpoints'

resource privateEndpoint 'Microsoft.Network/privateEndpoints@2024-11-01' = {
  name: 'pe-stdataprod001'
  location: resourceGroup().location
  tags: {
    Environment: 'prod'
    Purpose: 'Private access'
  }
  properties: {
    subnet: {
      id: privateSubnetId
    }
    privateLinkServiceConnections: [
      {
        name: 'pe-stdataprod001-blob'
        properties: {
          privateLinkServiceId: storageAccountId
          groupIds: [ 'blob' ]
        }
      }
    ]
  }
}

resource perimeter 'Microsoft.Network/networkSecurityPerimeters@2024-05-01' = {
  name: 'app-prod-nsp'
  location: 'global'
  tags: {
    Environment: 'prod'
    SecurityBoundary: 'Shared services'
  }
  properties: {
    accessRules: [
      {
        name: 'allow-app-subnet'
        properties: {
          direction: 'Inbound'
          access: 'Allow'
          description: 'Allow application workloads to reach protected services'
          addressPrefixes: [
            '10.15.40.0/24'
          ]
          destinationPortRanges: [
            '443'
          ]
        }
      }
    ]
    // Use this when you need a resource-centric access control model
    // for a group of protected services.
  }
}
</code></pre>

<p>The private endpoint creates a private path, while the perimeter focuses on the access policy around protected resources. In many architectures, both are useful, but for different reasons.</p>

<h2 id="final-recommendation">Final recommendation</h2>

<p>If you are still deciding between the two, start by asking what problem you are trying to solve. If you need private connectivity, private endpoints are the natural answer. If you need stronger and more centralized access control for protected resources, NSP deserves serious consideration.</p>

<p>In the next article, I will show how to apply these concepts in a realistic Azure architecture.</p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><category term="Network Security Perimeter" /><summary type="html"><![CDATA[Azure Network Security Perimeter and private endpoints are both powerful mechanisms for improving resource protection, but they are not interchangeable. Understanding their differences is essential when designing secure Azure architectures.]]></summary></entry><entry><title type="html">How to Protect PaaS Resources with Azure Network Security Perimeter</title><link href="https://woivre.com/blog/2026/08/how-to-protect-paas-resources-with-azure-network-security-perimeter" rel="alternate" type="text/html" title="How to Protect PaaS Resources with Azure Network Security Perimeter" /><published>2026-08-17T00:00:00+00:00</published><updated>2026-08-17T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/08/how-to-protect-paas-resources-with-azure-network-security-perimeter</id><content type="html" xml:base="https://woivre.com/blog/2026/08/how-to-protect-paas-resources-with-azure-network-security-perimeter"><![CDATA[<p>Azure PaaS resources are often central to modern cloud applications, but they can also be difficult to secure because they are frequently accessed from different services, pipelines, and users. Azure Network Security Perimeter provides a useful way to define a tighter security boundary around these resources.</p>

<p>When you protect PaaS resources with NSP, you are not only controlling network paths. You are also shaping how the resource can be reached and by whom. This is especially valuable for services that store sensitive data or expose APIs to internal systems.</p>

<h2 id="typical-use-cases">Typical use cases</h2>

<p>NSP is a good fit when you want to:</p>

<ul>
  <li>Limit access to Azure Storage accounts used by critical workloads</li>
  <li>Protect Key Vault instances from unnecessary public access</li>
  <li>Reduce exposure for web apps and other managed services</li>
  <li>Enforce consistent access controls across multiple resources in the same environment</li>
</ul>

<h2 id="recommended-approach">Recommended approach</h2>

<p>A practical deployment usually starts with identifying the resources that need the highest level of protection. Then you define the perimeter and decide which identities or services are allowed to connect. The goal is to avoid overly broad access rules while keeping the environment operational.</p>

<p>In many cases, NSP works best when it is combined with other Azure security mechanisms such as private endpoints, role-based access control, and centralized monitoring.</p>

<h2 id="a-bicep-skeleton-for-a-protected-paas-perimeter">A Bicep skeleton for a protected PaaS perimeter</h2>

<p>A simple way to represent the perimeter in infrastructure as code is shown below:</p>

<pre><code class="language-bicep">targetScope = 'resourceGroup'

@description('Name of the perimeter protecting shared PaaS resources')
param perimeterName string = 'shared-paas-prod-nsp'

@description('Storage account that should be protected by the perimeter')
param storageAccountId string = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-app-prod/providers/Microsoft.Storage/storageAccounts/stappprod001'

resource perimeter 'Microsoft.Network/networkSecurityPerimeters@2024-05-01' = {
  name: perimeterName
  location: 'global'
  tags: {
    Environment: 'prod'
    Workload: 'FinanceApp'
    SecurityBoundary: 'PaaS'
  }
  properties: {
    accessRules: [
      {
        name: 'allow-shared-services'
        properties: {
          direction: 'Inbound'
          access: 'Allow'
          description: 'Allow requests from the shared services subnet'
          addressPrefixes: [
            '10.10.20.0/24'
          ]
          destinationPortRanges: [
            '443'
          ]
        }
      }
    ]
    // Link the protected resource and define any additional policy
    // associations as part of your deployment workflow.
  }
}

output perimeterResourceId string = perimeter.id
output protectedStorageAccountId string = storageAccountId
</code></pre>

<p>This shows the anchor point for your protected resource boundary. The next step is to define the specific rules that allow only the right identities and services to connect.</p>

<h2 id="what-to-watch-for">What to watch for</h2>

<p>One of the main challenges when implementing NSP is keeping the policy understandable. If a perimeter becomes too permissive, the benefit is reduced. It is better to start with a focused scope and expand it carefully as you validate the access pattern.</p>

<p>This makes NSP especially appealing for teams that want to apply network controls without turning every resource into a custom networking project.</p>

<p>In the next article, I will compare NSP with private endpoints and show where each approach is strongest.</p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><category term="Network Security Perimeter" /><summary type="html"><![CDATA[Azure PaaS resources are often central to modern cloud applications, but they can also be difficult to secure because they are frequently accessed from different services, pipelines, and users. Azure Network Security Perimeter provides a useful way to define a tighter security boundary around these resources.]]></summary></entry><entry><title type="html">Azure Network Security Perimeter - What It Is and Why It Matters</title><link href="https://woivre.com/blog/2026/08/azure-network-security-perimeter-what-it-is-and-why-it-matters" rel="alternate" type="text/html" title="Azure Network Security Perimeter - What It Is and Why It Matters" /><published>2026-08-10T00:00:00+00:00</published><updated>2026-08-10T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/08/azure-network-security-perimeter-what-it-is-and-why-it-matters</id><content type="html" xml:base="https://woivre.com/blog/2026/08/azure-network-security-perimeter-what-it-is-and-why-it-matters"><![CDATA[<p>Azure Network Security Perimeter, or NSP, is one of the most important additions to Azure’s network security model for organizations that want tighter control over access to their protected resources.</p>

<p>At a high level, NSP helps you define a boundary around a set of Azure resources and apply security rules that govern who and what can connect to them. Instead of relying only on traditional network controls, you can add an additional layer of protection that focuses on the resource itself.</p>

<p>This is especially useful when you are working with services such as Azure Storage, Azure Key Vault, or other PaaS resources that might otherwise be exposed by broad network access policies.</p>

<h2 id="why-nsp-matters">Why NSP matters</h2>

<p>The main benefit of NSP is simplicity. You can apply a consistent access model to a group of resources without having to redesign the entire network topology. It complements existing tools such as private endpoints, VNets, and firewalls by giving you a resource-centric control plane.</p>

<p>For many teams, this means:</p>

<ul>
  <li>Better control over inbound traffic to protected resources</li>
  <li>A clearer security posture for shared Azure environments</li>
  <li>Easier enforcement of least-privilege connectivity rules</li>
  <li>Stronger governance for multi-team or multi-subscription architectures</li>
</ul>

<h2 id="what-makes-nsp-different">What makes NSP different</h2>

<p>Traditional network security often focuses on network segments, subnets, or IP ranges. NSP shifts part of the conversation to the resources themselves. That makes it easier to reason about the security boundary around a target service and to prevent unnecessary exposure.</p>

<p>In practice, this can help organizations reduce the attack surface and make access decisions more explicit.</p>

<h2 id="a-simple-bicep-example">A simple Bicep example</h2>

<p>A minimal starting point for an NSP deployment can look like this:</p>

<pre><code class="language-bicep">targetScope = 'resourceGroup'

@description('Name of the network security perimeter')
param perimeterName string = 'contoso-platform-prod-nsp'

@description('Environment tag applied to the perimeter')
param environment string = 'prod'

@description('Resource IDs that should be protected by the perimeter')
param protectedResourceIds array = [
  '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-platform-prod/providers/Microsoft.Storage/storageAccounts/stprodshared001'
  '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-platform-prod/providers/Microsoft.KeyVault/vaults/kv-platform-prod'
]

resource perimeter 'Microsoft.Network/networkSecurityPerimeters@2024-05-01' = {
  name: perimeterName
  location: 'global'
  tags: {
    Environment: environment
    Owner: 'Platform Engineering'
    SecurityBoundary: 'Production'
  }
  properties: {
    // Example rule shape for a production deployment
    accessRules: [
      {
        name: 'allow-platform-engineering'
        properties: {
          direction: 'Inbound'
          access: 'Allow'
          description: 'Allow management traffic from the platform engineering subnet'
          addressPrefixes: [
            '10.20.30.0/24'
          ]
          destinationPortRanges: [
            '443'
          ]
        }
      }
    ]
    // In a production deployment, define resource links and policy
    // associations here as well.
  }
}

output perimeterId string = perimeter.id
output protectedResourceCount int = length(protectedResourceIds)
</code></pre>

<p>This example is intentionally simple. In a real deployment, you would extend it with the resources you want to protect and the access rules that define who can reach them.</p>

<h2 id="a-good-first-step">A good first step</h2>

<p>If you are evaluating Azure security controls, NSP is a strong topic to explore early. It is a practical feature for teams that want to modernize their Azure landing zone and strengthen protection around critical services without adding excessive operational complexity.</p>

<p>In the next article, I will focus on how to apply NSP to PaaS resources and what the first implementation steps look like.</p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><category term="Network Security Perimeter" /><summary type="html"><![CDATA[Azure Network Security Perimeter, or NSP, is one of the most important additions to Azure’s network security model for organizations that want tighter control over access to their protected resources.]]></summary></entry><entry><title type="html">Azure Keyvault - How to restore when you have Azure Policies</title><link href="https://woivre.com/blog/2026/06/azure-keyvault-how-to-restore-when-you-have-azure-policies" rel="alternate" type="text/html" title="Azure Keyvault - How to restore when you have Azure Policies" /><published>2026-06-26T00:00:00+00:00</published><updated>2026-06-26T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/06/azure-keyvault-how-to-restore-when-you-have-azure-policies</id><content type="html" xml:base="https://woivre.com/blog/2026/06/azure-keyvault-how-to-restore-when-you-have-azure-policies"><![CDATA[<p>For governance requirements, you may have Azure Policies applied to your Key Vaults.
For example:</p>

<ul>
  <li>Enable purge protection on your Key Vaults</li>
  <li>Enable soft delete on your Key Vaults</li>
  <li>Enforce network rules on your Key Vaults</li>
  <li>Deny creation of Key Vaults in specific regions</li>
  <li>Enforce the use of private endpoints on your Key Vaults</li>
</ul>

<p>You are usually very happy with these policies. But now consider the following use case: a Key Vault was deleted by mistake and you want to restore it.</p>

<p>It is very likely that when you try to restore it, you get an error like this:</p>

<pre><code class="language-powershell">➜  $removeKeyvault | Undo-AzKeyVaultRemoval
Undo-AzKeyVaultRemoval: Resource 'kvipbd7f00' was disallowed by policy. Policy identifiers: '[{"policyAssignment":{"name":"Deny Key Vaults without IP rules","id":"/subscriptions/subId/resourcegroups/rg-kv-iprules-lab-20260624/providers/Microsoft.Authorization/policyAssignments/assign-keyvault-ip-rule-deny"},"policyDefinition":{"name":"Key Vaults must define at least one IP rule","id":"/subscriptions/subId/providers/Microsoft.Authorization/policyDefinitions/deny-keyvault-without-ip-rules","version":"1.0.0"}}]'.
</code></pre>

<p>So you followed Microsoft documentation to restore your Key Vault, but it still fails because of a policy. In this case, the policy checks that at least one IP is configured in the Key Vault network rules.</p>

<p>To work around this issue, the simplest solution is to disable the policy that blocks the Key Vault restoration, restore the Key Vault, and then re-enable the policy. Of course, this only works if you have permissions to disable the policy, and disabling a policy can impact your governance, especially if it affects a large number of resources on a heavily used platform.</p>

<p>There is another solution that is less simple, but more elegant and does not require disabling the policy. It consists of recreating the Key Vault through an ARM or Bicep template. Here I will do it with ARM, but you can convert it to Bicep if you want.</p>

<p>Let’s start by looking at what a deleted Key Vault looks like in JSON.</p>

<pre><code class="language-json">{
  "Id": "/subscriptions/subId/providers/Microsoft.KeyVault/locations/westeurope/deletedVaults/kvipbd7f00",
  "DeletionDate": "2026-06-24T12:07:06Z",
  "ScheduledPurgeDate": "2026-09-22T12:07:06Z",
  "PublicNetworkAccess": null,
  "VaultUri": null,
  "TenantId": "00000000-0000-0000-0000-000000000000",
  "TenantName": null,
  "Sku": null,
  "EnabledForDeployment": false,
  "EnabledForTemplateDeployment": null,
  "EnabledForDiskEncryption": null,
  "EnableSoftDelete": null,
  "EnablePurgeProtection": true,
  "EnableRbacAuthorization": null,
  "SoftDeleteRetentionInDays": null,
  "AccessPolicies": null,
  "AccessPoliciesText": "",
  "NetworkAcls": null,
  "NetworkAclsText": "",
  "OriginalVault": null,
  "ResourceId": "/subscriptions/subId/resourceGroups/rg-kv-iprules-lab-20260624/providers/Microsoft.KeyVault/vaults/kvipbd7f00",
  "VaultName": "kvipbd7f00",
  "ResourceGroupName": null,
  "Location": "westeurope",
  "Tags": {},
  "TagsTable": null
}
</code></pre>

<p>As you can see, there is not much information about the deleted Key Vault. There are no networkAcls and no network rules. Clearly, a lot of information is missing to recreate the Key Vault.</p>

<p>This helps explain why the Key Vault is restored in public mode: that information is lost. Now, if we dig a bit into the API documentation, we find the <a href="https://learn.microsoft.com/en-us/rest/api/keyvault/vaults/create-or-update#vaultcreateorupdateparameters">createMode</a> option, which allows you to create a Key Vault in “Recover” mode.</p>

<p>So we can create a Key Vault using the following ARM template:</p>

<pre><code class="language-json">{
	"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
	"contentVersion": "1.0.0.0",
	"parameters": {
		"keyVaultName": {
			"type": "string",
			"metadata": {
				"description": "Name of the Azure Key Vault to create or recover."
			}
		},
		"location": {
			"type": "string",
			"defaultValue": "[resourceGroup().location]",
			"metadata": {
				"description": "Location for the Key Vault resource."
			}
		},
		"tenantId": {
			"type": "string",
			"defaultValue": "[subscription().tenantId]",
			"metadata": {
				"description": "Azure AD tenant ID for the Key Vault."
			}
		},
		"skuName": {
			"type": "string",
			"defaultValue": "standard",
			"allowedValues": [
				"standard",
				"premium"
			],
			"metadata": {
				"description": "SKU for the Key Vault."
			}
		},
		"ipRules": {
			"type": "array",
			"defaultValue": [],
			"metadata": {
				"description": "Array of public IPv4 CIDR strings allowed to access the Key Vault (for example: 203.0.113.10/32)."
			}
		},
		"defaultAction": {
			"type": "string",
			"defaultValue": "Deny",
			"allowedValues": [
				"Allow",
				"Deny"
			],
			"metadata": {
				"description": "Default network ACL action."
			}
		},
		"bypass": {
			"type": "string",
			"defaultValue": "AzureServices",
			"allowedValues": [
				"AzureServices",
				"None"
			],
			"metadata": {
				"description": "Traffic that can bypass network ACLs."
			}
		}
	},
	"variables": {
		"ipRuleObjects": "[map(parameters('ipRules'), lambda('ip', createObject('value', lambdaVariables('ip'))))]"
	},
	"resources": [
		{
			"type": "Microsoft.KeyVault/vaults",
			"apiVersion": "2023-07-01",
			"name": "[parameters('keyVaultName')]",
			"location": "[parameters('location')]",
			"properties": {
                "createMode": "recover",
				"tenantId": "[parameters('tenantId')]",
				"sku": {
					"family": "A",
					"name": "[parameters('skuName')]"
				},
				"enabledForDeployment": false,
				"enabledForDiskEncryption": false,
				"enabledForTemplateDeployment": false,
				"publicNetworkAccess": "Enabled",
				"networkAcls": {
					"bypass": "[parameters('bypass')]",
					"defaultAction": "[parameters('defaultAction')]",
					"ipRules": "[variables('ipRuleObjects')]",
				}
			}
		}
	],
	"outputs": {
		"keyVaultResourceId": {
			"type": "string",
			"value": "[resourceId('Microsoft.KeyVault/vaults', parameters('keyVaultName'))]"
		}
	}
}

</code></pre>

<p>This template can be called as follows:</p>

<pre><code class="language-powershell">New-AzResourceGroupDeployment -name "recover-keyvault" -ResourceGroupName $removekeyvault.ResourceId.split('/')[4] -TemplateFile .\recover-keyvault.json -keyvaultName $removeKeyVault.VaultName  -ipRules @("1.1.1.1/32")
</code></pre>

<p>Almost like magic, your Key Vault is properly restored without changing policies.
Of course, this template should be adapted to the policies you use.</p>

<p>There is no longer any excuse to disable governance in your production environments.
Of course, I recommend testing this template in a test environment before using it in production, especially not as an emergency fix in the middle of the night.</p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><category term="KeyVault" /><category term="Policy" /><summary type="html"><![CDATA[For governance requirements, you may have Azure Policies applied to your Key Vaults. For example:]]></summary></entry><entry><title type="html">Azure Monitor - Follow global storage you used</title><link href="https://woivre.com/blog/2026/05/azure-monitor-follow-global-storage-you-used" rel="alternate" type="text/html" title="Azure Monitor - Follow global storage you used" /><published>2026-05-27T00:00:00+00:00</published><updated>2026-05-27T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/05/azure-monitor-follow-global-storage-you-used</id><content type="html" xml:base="https://woivre.com/blog/2026/05/azure-monitor-follow-global-storage-you-used"><![CDATA[<p>As part of a governance approach, it can be useful to inventory everything you use in the public cloud.
And it is often a bit complicated to find everything on the platform, especially when it comes to service-related metrics.</p>

<p>Of course, there is the classic inventory needed to answer simple questions such as:</p>

<ul>
  <li>How many VMs are currently in use, by OS and SKU?</li>
  <li>How many databases are currently in production?</li>
  <li>How many storage accounts are available?</li>
</ul>

<p>All of these inventory questions are very easy to answer through Azure Resource Graph.</p>

<p>Now let’s consider the following question:</p>

<ul>
  <li>What is the total storage capacity across all Azure Storage accounts?</li>
</ul>

<p>Well, this is where it gets a bit more complicated, because although the metric is available, it is exposed per storage account and, by default, not aggregated.</p>

<p>You can find this answer by looking at each storage account and summing the results of the “Used Capacity” metric.</p>

<p>Otherwise, there is another way through Azure Workbook, which I will show you.</p>

<p>So let’s start by creating a new one (the default one does not suit me in this specific context). We’ll do it through the portal, because building a workbook via infrastructure as code is more of an epic journey than a walk in the park.</p>

<p>Let’s start by adding two filters for subscriptions and resources, as shown below:</p>

<p><img src="https://woivre.com/images/2026/05/27/azure-monitor-follow-global-storage-you-used-img1.png" alt="alt text" /></p>

<p>For the different resource pickers, make sure to select “Required” and “Allow multiple selection” for both filters, and include the “All” field.</p>

<p>Then it is possible to run a Kusto query to link resources and metrics.</p>

<p>Let’s start by generating a list with all the values for each storage account:</p>

<p><img src="https://woivre.com/images/2026/05/27/azure-monitor-follow-global-storage-you-used-img2.png" alt="alt text" /></p>

<p>To make it readable, go to the advanced settings and modify the <em>Value</em> field to change the format to <em>Bytes</em>.</p>

<p>And to get an aggregate of the used capacity, simply sum all values using the <em>Stat</em> visualization and select “Sum” in the aggregation options.</p>

<p><img src="https://woivre.com/images/2026/05/27/azure-monitor-follow-global-storage-you-used-img3.png" alt="alt text" /></p>

<p>There you go! If you would like me to write more articles related to workbooks, feel free to let me know in the comments.</p>

<p>And of course, here is a link to the workbook I created for this use case: <a href="https://github.com/wilfriedwoivre/azure-workbooks/tree/main/workbooks/storage/storage-size-monitoring">Github link</a></p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><category term="Monitoring" /><summary type="html"><![CDATA[As part of a governance approach, it can be useful to inventory everything you use in the public cloud. And it is often a bit complicated to find everything on the platform, especially when it comes to service-related metrics.]]></summary></entry><entry><title type="html">Azure - Find the availability zone for your subscription</title><link href="https://woivre.com/blog/2026/04/azure-find-the-availability-zone-for-your-subscription" rel="alternate" type="text/html" title="Azure - Find the availability zone for your subscription" /><published>2026-04-10T00:00:00+00:00</published><updated>2026-04-10T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/04/azure-find-the-availability-zone-for-your-subscription</id><content type="html" xml:base="https://woivre.com/blog/2026/04/azure-find-the-availability-zone-for-your-subscription"><![CDATA[<p>It is sometimes necessary to find the physical zone that matches the logical zone assigned to your Azure subscription.</p>

<p>Why, you may ask? For compliance, performance, or latency reasons, it can be crucial to know where your Azure resources are physically located. It can also be important for capacity planning, to verify whether the relevant zones have enough resources to host your infrastructure.</p>

<p>This also helps you manage your CI/CD settings to ensure resources are deployed in zones where capacity is available.</p>

<p>For example, Azure Firewall currently has capacity constraints, as shown here: <a href="https://learn.microsoft.com/en-us/azure/firewall/firewall-known-issues?WT.mc_id=AZ-MVP-4039694#current-capacity-constraints">Azure Documentation</a></p>

<p>You can find which zone your subscription uses with the following command:</p>

<pre><code class="language-bash">az account list-locations --query "[?availabilityZoneMappings].{availabilityZoneMappings: availabilityZoneMappings, displayName: displayName, name: name}"
</code></pre>

<p>This command returns a list of all regions available for your subscription, along with the availability zone mappings for each region. You can then identify the physical zone that matches the logical zone used by your Azure resources.</p>

<p>If you prefer a graphical interface, I recommend <a href="https://app.az-scout.com/">App Scout</a>, which lets you visualize different zones and their capacities in real time. It is a very practical tool for managing your Azure resources efficiently. Here is an example for the West Europe region:</p>

<p><img src="https://woivre.com/images/2026/04/10/azure-find-the-availability-zone-for-your-subscription-img0.png" alt="alt text" /></p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><summary type="html"><![CDATA[It is sometimes necessary to find the physical zone that matches the logical zone assigned to your Azure subscription.]]></summary></entry><entry><title type="html">Azure Sandbox - A small improvment for Copilot users through VSCode</title><link href="https://woivre.com/blog/2026/03/azure-sandbox-a-small-improvment-for-copilot-users-through-vscode" rel="alternate" type="text/html" title="Azure Sandbox - A small improvment for Copilot users through VSCode" /><published>2026-03-24T00:00:00+00:00</published><updated>2026-03-24T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/03/azure-sandbox-a-small-improvment-for-copilot-users-through-vscode</id><content type="html" xml:base="https://woivre.com/blog/2026/03/azure-sandbox-a-small-improvment-for-copilot-users-through-vscode"><![CDATA[<p>Like everyone else, you probably noticed the AI shift. I assume you are using it more and more, just like all of us.</p>

<p>A few years ago, I built an Azure Sandbox system that lets me create ephemeral resource groups. With a simple script, I could create a resource group, run my tests, and then deletion would happen automatically based on the date set in a tag. Nothing could be simpler.</p>

<p>Today, to do this, I mainly use a function in my PowerShell profile to create resource groups: the well-known <em>New-AzTestResourceGroup</em> function, which some of you may already have seen in my demos.</p>

<p>Now with AI, it is much faster to tell Copilot: “Create a resource group named <em>demo-rg</em> in <em>France Central</em> and add a storage account.” Great time savings, especially since it can also generate the deployment file for you. However, the resource group does not always include the right tags.</p>

<p>There is a very simple way to add this: just ask Copilot to add the tags you want each time you create a resource group. You can scope this to your workspace, or apply it globally by adding a file in your user directory.</p>

<p>Here is an example of a file you can add in your user directory so Copilot can automatically add tags whenever you create a resource group.</p>

<pre><code class="language-markdown"># Azure Resource Group Tagging Convention

## Mandatory Tags for Resource Groups
When creating Azure resource groups, always add the following tags:

- **AutoDelete**: `true`
- **ExpirationDate**: Current date in format `YYYY-MM-DD` (e.g., 2026-03-05)

## Implementation
- Apply these tags when using Bicep, Terraform, ARM templates, or Azure CLI
- Use `resourceGroup()` function in Bicep or equivalent in other IaC tools
- Set tags at resource group creation time, not as an afterthought
</code></pre>

<p>And the path is: <em>C:\Users\YourUserName\AppData\Roaming\Code\User\globalStorage\github.copilot-chat\memory-tool\memories</em></p>

<p>And to finish, here is the article link for the sandbox (in french sorry): <a href="https://woivre.fr/blog/2018/11/sandbox-azure-pour-tout-le-monde">https://woivre.fr/blog/2018/11/sandbox-azure-pour-tout-le-monde</a></p>

<p>That is a small tip so you do not forget to clean up your resources after your tests.</p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><summary type="html"><![CDATA[Like everyone else, you probably noticed the AI shift. I assume you are using it more and more, just like all of us.]]></summary></entry><entry><title type="html">Azure Advisor - Manage recommendations at scale</title><link href="https://woivre.com/blog/2026/02/azure-advisor-manage-recommendations-at-scale" rel="alternate" type="text/html" title="Azure Advisor - Manage recommendations at scale" /><published>2026-02-11T00:00:00+00:00</published><updated>2026-02-11T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/02/azure-advisor-manage-recommendations-at-scale</id><content type="html" xml:base="https://woivre.com/blog/2026/02/azure-advisor-manage-recommendations-at-scale"><![CDATA[<p>Azure Advisor is an Azure service that provides many recommendations for your environments, whether in terms of security, cost, or resilience. This tool is great, but it can be quite time-consuming to manage and account for all recommendations across an enterprise.</p>

<p>If you have an Azure environment that is fairly standardized and spans multiple subscriptions, you may want to dismiss some recommendations or at least postpone them.</p>

<p>You can do this quickly with a PowerShell script (or another automation approach).
To start, you can list the different recommendations with the following command:</p>

<pre><code class="language-powershell">Get-AzAdvisorRecommendation -SubscriptionId &lt;SubscriptionId&gt;
</code></pre>

<p>Then, you can filter the recommendations you want to dismiss or postpone. For example, if you want to postpone a recommendation for 90 days, you can use the following command:</p>

<pre><code class="language-powershell">Disable-AzAdvisorRecommendation -RecommendationName e33855d4-7579-e4d0-c459-23fad3665bd6 -Day 90
</code></pre>

<p>And if you simply want to postpone one recommendation type globally, you can use the following command:</p>

<pre><code class="language-powershell">get-azAdvisorRecommendation | Where { $_.RecommendationTypeId -eq $recommendationId } | % { $_ | Disable-AzAdvisorRecommendation -Day 120 }
</code></pre>

<p>Let’s make 2026 the year we manage recommendations at scale—and leave no active recommendation without a planned action!</p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><category term="Azure Advisor" /><summary type="html"><![CDATA[Azure Advisor is an Azure service that provides many recommendations for your environments, whether in terms of security, cost, or resilience. This tool is great, but it can be quite time-consuming to manage and account for all recommendations across an enterprise.]]></summary></entry><entry><title type="html">Azure VM - Update your boot diagnostics</title><link href="https://woivre.com/blog/2026/01/azure-vm-update-your-boot-diagnostics" rel="alternate" type="text/html" title="Azure VM - Update your boot diagnostics" /><published>2026-01-27T00:00:00+00:00</published><updated>2026-01-27T00:00:00+00:00</updated><id>https://woivre.com/blog/2026/01/azure-vm-update-your-boot-diagnostics</id><content type="html" xml:base="https://woivre.com/blog/2026/01/azure-vm-update-your-boot-diagnostics"><![CDATA[<p>As you all know, logs are important. One log that is often underestimated is boot diagnostics, at least to confirm whether the VM started correctly.
Previously in Azure, you could configure boot diagnostics by relying on a storage account to store the different data.</p>

<p>For some time now, Microsoft has updated the boot diagnostics configuration for Azure virtual machines. From now on, you can configure boot diagnostics without creating a dedicated storage account. In other words, it is now fully managed by Microsoft.</p>

<p>Here is a Graph query to detect all your VMs that have not yet switched to this new boot diagnostics mode:</p>

<pre><code class="language-kql">resources
| where type =~ "microsoft.compute/virtualMachines"
| where properties.diagnosticsProfile.bootDiagnostics.enabled == true
| where isnotnull(properties.diagnosticsProfile.bootDiagnostics.storageUri)
</code></pre>

<p>If this can help you avoid dedicated storage accounts for boot diagnostics, that is one less resource to manage and secure, and it simplifies the configuration of your virtual machines.</p>]]></content><author><name>Wilfried Woivré</name></author><category term="Azure" /><category term="Virtual Machines" /><summary type="html"><![CDATA[As you all know, logs are important. One log that is often underestimated is boot diagnostics, at least to confirm whether the VM started correctly. Previously in Azure, you could configure boot diagnostics by relying on a storage account to store the different data.]]></summary></entry></feed>