{"id":3313,"date":"2023-01-13T17:11:59","date_gmt":"2023-01-13T23:11:59","guid":{"rendered":"https:\/\/microsoftgeek.com\/?p=3313"},"modified":"2023-01-13T17:11:59","modified_gmt":"2023-01-13T23:11:59","slug":"using-azure-policy-to-deny-public-ips-on-specific-vnets","status":"publish","type":"post","link":"https:\/\/microsoftgeek.com\/?p=3313","title":{"rendered":"Using Azure Policy to deny public IPs on specific VNETs"},"content":{"rendered":"\n<p>Azure Policy is a powerful tool in your Azure toolbox. It allows you to enforce specific governance principals you want to see implemented in your environment. Some key examples of what Azure Policy allows you to do is:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Automatically tag resources,<\/li>\n\n\n\n<li>Enforce specific regions,<\/li>\n\n\n\n<li>Enforce VM size \u2026<\/li>\n<\/ul>\n\n\n\n<p>I recently ran into a customer scenario, where they wanted to block VMs from having a public IP. If at possible, this should only apply to a select subset of VNETs \u2013 not to all VNETs.<\/p>\n\n\n\n<p>I\u2019ll walk you through on how this can be implemented, but why don\u2019t we start with an introduction on Azure Policy?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Azure Policy Introduction<\/h2>\n\n\n\n<p><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/governance\/policy\/overview\" target=\"_blank\" rel=\"noreferrer noopener\">Azure Policy<\/a>\u00a0is a (free) Azure service that allows you to enforce your governance rules on your subscriptions. The service itself has grown over the years that I\u2019ve worked with it. Back in the day, all policies needed to be implemented through PowerShell or CLI. This day, Policy is a full service, that comes with a bunch of pre-built policies and a schedule that regularly scans your environment.<\/p>\n\n\n\n<p>When talking about policies, there are two important terms you need to understand:&nbsp;<em>definitions&nbsp;<\/em>and&nbsp;<em>assignments<\/em>. A policy definition is a description of what you want your policy to be; a policy assignment implements a certain policy at a certain scope.<\/p>\n\n\n\n<p>A policy definition itself looks very similar to an ARM template. In the example we\u2019ll work through, we\u2019ll actually see that code. An ARM template can have parameters set, and a policy can have well. This means the same policy definition could be assigned multiple times, but with different parameters.<\/p>\n\n\n\n<p>In the policy definition, you define a certain logical operator (e.g. if this VM is deployed in West US2), and you define an action. These actions can be:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Append&nbsp;<\/strong>\u2013 append part of of the ARM template.<\/li>\n\n\n\n<li><strong>Audit<\/strong>&nbsp;\u2013 create an audit event in the Azure activity log<\/li>\n\n\n\n<li><strong>AuditIfNotExists&nbsp;<\/strong>\u2013 creates an audit event in the Azure activity log if the resource doesn\u2019t have the details mentioned in the \u2018then\u2019 clause<\/li>\n\n\n\n<li><strong>Deny&nbsp;<\/strong>\u2013 deny the request<\/li>\n\n\n\n<li><strong>DeployIfNotExists<\/strong>&nbsp;\u2013 can be used to deploy additional resources, e.g. a custom script extension<\/li>\n\n\n\n<li><strong>Disabled<\/strong>&nbsp;\u2013 Can be used for testing, this makes it possible to disable a single assignment, not all assignments<\/li>\n\n\n\n<li><strong>Modify \u2013&nbsp;<\/strong>used to modify tag information<\/li>\n\n\n\n<li><strong>EnforceRegoPolicy \u2013&nbsp;<\/strong>(in preview) is used with AKS.<\/li>\n<\/ul>\n\n\n\n<p>A Policy assignment links a definition with a certain scope. That scope could be a management group, a subscription or a resource group. Policies can overlap, e.g. you can have policies on both a subscription and a resource group.<\/p>\n\n\n\n<p>One final point on Policy is how it differs from role based access control (RBAC), as from a high level both share some similarities. Where Azure RBAC gives people access to a certain scope and gives them rights to make changes to that scope (create\/read\/update\/delete resources); Azure Policy limits some of these actions for a person with rights. I like to think of Azure RBAC as giving the ability to call a certain API on a certain scope, and Azure Policy as the bouncer on that API, making sure only those calls come through that you want to come through.<\/p>\n\n\n\n<p>And with that, let\u2019s start building our example:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Block public IPs for everything in our subscription<\/h2>\n\n\n\n<p>There is a built-in policy in the Azure Policy service that allows you to block public IPs on all NICs. Let us start with this policy, and then work on updating this policy to work with our \u2018only certain VNETs\u2019 example.<\/p>\n\n\n\n<p>To see this policy, head on over to the Policy blade in the Azure portal, head to definitions and search for \u2018public\u2019, That should return 1 policy:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-1024x352.png\" alt=\"\" class=\"wp-image-480\"\/><figcaption class=\"wp-element-caption\">This is the policy we\u2019ll use to work through this example.<\/figcaption><\/figure>\n\n\n\n<p>As we\u2019ll be making changes to this example, let\u2019s go ahead and duplicate this policy so we can make change to it down the line. To do this, open the policy and hit the duplicate button in the portal. You\u2019ll get a prompt asking you for a location \u2013 where you\u2019ll select your subscription \u2013 and for a new name. Then hit the save mark in the bottom.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-1-1024x684.png\" alt=\"\" class=\"wp-image-481\"\/><figcaption class=\"wp-element-caption\">We\u2019re going to duplicate the built-in policy and make changes down the line.<\/figcaption><\/figure>\n\n\n\n<p>Let\u2019s now go ahead and assign this policy to our subscription. Please be careful here, because this will deny everybody from creating a NIC with a public IP address. To do the assignment, go back to the all policy definitions, select the new policy we just created and hit the Assign button.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-2.png\" alt=\"\" class=\"wp-image-482\"\/><figcaption class=\"wp-element-caption\">Hit the assign button on our newly created policy<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-3-839x1024.png\" alt=\"\" class=\"wp-image-483\"\/><figcaption class=\"wp-element-caption\">Scope this to our full subscription.<\/figcaption><\/figure>\n\n\n\n<p>Now that the assignment is in place, let\u2019s try to add a public IP to an existing NIC.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-4-1024x335.png\" alt=\"\" class=\"wp-image-484\"\/><figcaption class=\"wp-element-caption\">Use a NIC without a public IP to test the assignment<\/figcaption><\/figure>\n\n\n\n<p>Head on over to the IP configurations, to add a public IP. Just select the first IP configuration, and add a public IP to that ipconfig.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-5.png\" alt=\"\" class=\"wp-image-485\"\/><figcaption class=\"wp-element-caption\">Open IP Configurations<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-8.png\" alt=\"\" class=\"wp-image-488\"\/><figcaption class=\"wp-element-caption\">Add a public IP to this IPconfig.<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-7.png\" alt=\"\" class=\"wp-image-487\"\/><figcaption class=\"wp-element-caption\">This error message tells us we cannot add a Public IP.<\/figcaption><\/figure>\n\n\n\n<p>Once you added that public IP and hit save, you should see an error message pop up describing that our policy is blocking the adding of this public IP address.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Editing the policy to only apply to certain VNETs<\/h2>\n\n\n\n<p>So, that was a good v1 of our policy. Let\u2019s now try to edit this so it only applies to certain VNETs and not all VNETs. At this point, I want to also take a second to explain why we applied this policy to the full subscription and not to resource of the VNET.<\/p>\n\n\n\n<p>If you read the policy definition, you\u2019ll see that the policy actually evaluates the NIC, and not the VNET. And NICs are allowed to be in separate resource groups from their VNET. This would make a scope of resource group quiet powerless.<\/p>\n\n\n\n<p>Hence, we\u2019ll edit our policy to take in a parameter of VNET name that will be blocked. This edited policy looks something like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>{\n  \"mode\": \"Indexed\",\n  \"policyRule\": {\n    \"if\": {\n      \"allOf\": &#91;\n        {\n          \"field\": \"type\",\n          \"equals\": \"Microsoft.Network\/networkInterfaces\"\n        },\n        {\n          \"not\": {\n            \"field\": \"Microsoft.Network\/networkInterfaces\/ipconfigurations&#91;*].publicIpAddress.id\",\n            \"notLike\": \"*\"\n          }\n        },\n        {\n          \"field\": \"Microsoft.Network\/networkInterfaces\/ipconfigurations&#91;*].subnet.id\",\n          \"contains\": \"&#91;parameters('vnets')]\"\n        }\n      ]\n    },\n    \"then\": {\n      \"effect\": \"deny\"\n    }\n  },\n  \"parameters\": {\n    \"vnets\": {\n      \"type\": \"String\",\n      \"metadata\": {\n        \"displayName\": \"Private VNET\",\n        \"description\": \"The VNET ID that cannot have public IPs\"\n      },\n      \"defaultValue\": \"\/subscriptions\/d19dddf3-9520-4226-a313-ae8ee08675e5\/resourceGroups\/KEDA\/providers\/Microsoft.Network\/virtualNetworks\/KEDA-vnet\/\"\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>As you can see in the code above, we added two elements to our policy:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Another field in the PolicyRule, that says that if the subnetID contains the VNET ID then public IPs should be blocked.<\/li>\n\n\n\n<li>A paramter that is a VNET ID. This way, we can assign this policy multiple times for multiple VNETs.<\/li>\n<\/ul>\n\n\n\n<p>Let\u2019s test this out. We don\u2019t need to update our existing Policy assignment, as that took the default parameter:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-9-1024x222.png\" alt=\"\" class=\"wp-image-490\"\/><figcaption class=\"wp-element-caption\">The existing policy assignment took the default VNET that we put in the policy.<\/figcaption><\/figure>\n\n\n\n<p>Let\u2019s however create a second assignment, for another VNET that cannot have public IP addresses:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-10-1024x438.png\" alt=\"\" class=\"wp-image-491\"\/><figcaption class=\"wp-element-caption\">We\u2019ll create a new assignment for a second VNET<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-11-1024x232.png\" alt=\"\" class=\"wp-image-492\"\/><figcaption class=\"wp-element-caption\">We\u2019ll input as a parameter the ID of another VNET<\/figcaption><\/figure>\n\n\n\n<p>Let\u2019s now test this out, first in my KEDA-VNET:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-12.png\" alt=\"\" class=\"wp-image-493\"\/><figcaption class=\"wp-element-caption\">The new policy successfully blocks the KEDA-VNET from having public IPs<\/figcaption><\/figure>\n\n\n\n<p>Let\u2019s also test this in my LFCE-VNET:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-13.png\" alt=\"\" class=\"wp-image-494\"\/><figcaption class=\"wp-element-caption\">It also fails in our LFCE VNET<\/figcaption><\/figure>\n\n\n\n<p>Let\u2019s now test this in an VNET not covered by the policy:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.nillsf.com\/wp-content\/uploads\/2019\/11\/image-14.png\" alt=\"\" class=\"wp-image-495\"\/><figcaption class=\"wp-element-caption\">A NIC in a VNET not covered by this policy can successfully get a public IP.<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>In this post we used Azure Policy to block public IPs from getting assigned to NICs. That way you can protect VMs from getting a direct public IP on the NIC. We slightly changed the default built-in policy, so it can be applied to a whole subscription but only cover a subset of the VNETs.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Azure Policy is a powerful tool in your Azure toolbox. It allows you to enforce specific governance principals you want to see implemented in your environment. Some key examples of what Azure Policy allows you to do is: I recently ran into a customer scenario, where they wanted to block VMs from having a public [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[69,35],"tags":[],"class_list":["post-3313","post","type-post","status-publish","format-standard","hentry","category-azure","category-cloud-computing"],"_links":{"self":[{"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/posts\/3313","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3313"}],"version-history":[{"count":1,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/posts\/3313\/revisions"}],"predecessor-version":[{"id":3314,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=\/wp\/v2\/posts\/3313\/revisions\/3314"}],"wp:attachment":[{"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3313"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3313"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/microsoftgeek.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3313"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}