<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CSE Dev Crews</title>
    <description>The latest articles on DEV Community by CSE Dev Crews (@cse).</description>
    <link>https://dev.to/cse</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3328%2F154c1f2d-df08-409b-b8e0-7d1dfd4762d4.png</url>
      <title>DEV Community: CSE Dev Crews</title>
      <link>https://dev.to/cse</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cse"/>
    <language>en</language>
    <item>
      <title>Secure Azure as Code</title>
      <dc:creator>Andrew Fryer</dc:creator>
      <pubDate>Thu, 10 Dec 2020 12:44:46 +0000</pubDate>
      <link>https://dev.to/cse/secure-azure-as-code-5d9i</link>
      <guid>https://dev.to/cse/secure-azure-as-code-5d9i</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Large organisations will typically have many, sometimes hundreds of Azure subscriptions. The challenge here is to secure and manage without slowing down the agility the cloud offers.  What's need is a process to be able to stamp out subscriptions with security and monitoring baked in using devops pipelines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who we are
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;If you have an Azure problem, if no one else can help, and if you can engage them, maybe you can hire a dev crew&lt;/em&gt; (after the &lt;a href="https://www.imdb.com/title/tt0429493/taglines?ref_=tt_stry_tg"&gt;A-Team&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Our dev crew were recently tasked to make this a reality using our twin philosophies of "&lt;em&gt;engineering excellence&lt;/em&gt;" and "&lt;em&gt;code with&lt;/em&gt;". Code with means we work alongside our customers in a joint team pair programming against an agreed backlog.  Engineering excellence is all about details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use of pipelines to deploy any code&lt;/li&gt;
&lt;li&gt;use PR with at least to reviewers&lt;/li&gt;
&lt;li&gt;solid documentation&lt;/li&gt;
&lt;li&gt;testing rigor in this case with Terratest and Go
.. and many more!&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Design Goals
&lt;/h2&gt;

&lt;p&gt;We had the following design goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if the rules change we wanted the revised rules to be applied to all subscriptions not just new ones&lt;/li&gt;
&lt;li&gt;Everything can be deployed from a pipeline&lt;/li&gt;
&lt;li&gt;A mechanism to test the rules work by applying them to a test subscription&lt;/li&gt;
&lt;li&gt;Default logging to be enabled for all resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The Solution
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;A central &lt;em&gt;management&lt;/em&gt; subscription with 

&lt;ul&gt;
&lt;li&gt;a key vault for tenant-based secrets &lt;/li&gt;
&lt;li&gt;a central container registry &lt;/li&gt;
&lt;li&gt;a central key vault for tenant based secrets about any of the managed subscriptions&lt;/li&gt;
&lt;li&gt;Security Center to show alerts across the tenant&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Each &lt;em&gt;managed&lt;/em&gt; subscription would just have a small set of default resources:

&lt;ul&gt;
&lt;li&gt;key vault &lt;/li&gt;
&lt;li&gt;log storage &lt;/li&gt;
&lt;li&gt;custom roles &lt;/li&gt;
&lt;li&gt;a budget&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We used several repos for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tenant with the terraform to create the management subscription&lt;/li&gt;
&lt;li&gt;Subscription with the terraform to create a subscription&lt;/li&gt;
&lt;li&gt;Policies all policies were described in Terraform in a standard way and put in here.&lt;/li&gt;
&lt;li&gt;Custom Roles. Azure Custom roles described in Terraform are stored here &lt;/li&gt;
&lt;li&gt;Docs. We wanted to control the approval of designs and architecture so we used a PR process to control docs going into the main branch of this repo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We used a number of pipelines in the project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CI/CD to create the management subscription&lt;/li&gt;
&lt;li&gt;CI to create a managed subscription for testing&lt;/li&gt;
&lt;li&gt;CD to create a managed subscription in live which would be called from a Jira ticket via an Azure function&lt;/li&gt;
&lt;li&gt;CI/CD for applying policy changes to the Management Group
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technology
&lt;/h2&gt;

&lt;p&gt;We meet the customer where they are and use whatever tooling they are comfortable the only constraint being we only work on Azure projects. In this case we did our CI/CD in Azure devops but in such a way that all the flow control was handled in bash to make it as easy as possible to port pipelines to other tooling.  The customer was already using Terraform for IaC.&lt;/p&gt;

&lt;p&gt;The key to securing Azure is Policies.  These can be grouped into Blueprints (if you're using ARM) or Initiatives which work for Terraform - for example we created one Policy initiative for the &lt;a href="https://www.cisecurity.org/benchmark/azure/"&gt;CIS benchmarks&lt;/a&gt;.Subscriptions can also be grouped into Management Groups both of which make all of this a lot simpler.&lt;/p&gt;

&lt;p&gt;We also allowed users to create &lt;a href="https://github.com/azure/caf-terraform-landingzones"&gt;Policy Exceptions&lt;/a&gt; for example a contributor might want to create a VM without an encrypted disk, but if they do this then it'll be flagged in Security Center and they'll have to justify this to their security team.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;We took 10 sprints to get this done and documented and then took two weeks out to share what we learnt more widely.  For sharing we have contributed to the Terraform AzureRM provider, to the &lt;a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/terraform-landing-zone#:~:text=The%20Cloud%20Adoption%20Framework%20foundations%20landing%20zone%20for,enforce%20consistency%20across%20resources%20deployed%20in%20the%20environment"&gt;Cloud Adoption Framework&lt;/a&gt; and have written up the more interesting parts of this project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/cse/contributing-to-the-azure-terraform-provider-bm6"&gt;Contributing to the Azure Terraform Provider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cse/test-your-azure-policies-in-parallel-5g2k"&gt;Test your Azure policies in parallel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cse/terraform-module-for-custom-azure-policies-1oek"&gt;Terraform module for custom Azure policies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cse/auto-start-collection-of-azure-diagnostic-telemetry-468k"&gt;Auto-start collection of Azure diagnostic telemetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cse/terraform-bootstrap-backend-state-in-azure-5b73"&gt;Terraform Bootstrap &amp;amp; Backend State in Azure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cse/standardize-resource-names-in-terraform-scripts-1pl2"&gt;Standardize resource names in Terraform scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cse/bypassing-policies-in-azure-29fc"&gt;Bypassing policies in Azure&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/cse/calling-azure-apis-with-rest-extension-for-vs-code-bhn"&gt;Calling Azure APIs with the REST Extension for VS Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>tooling</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Contributing to the Azure Terraform Provider</title>
      <dc:creator>Ben Coleman</dc:creator>
      <pubDate>Wed, 02 Dec 2020 17:21:11 +0000</pubDate>
      <link>https://dev.to/cse/contributing-to-the-azure-terraform-provider-bm6</link>
      <guid>https://dev.to/cse/contributing-to-the-azure-terraform-provider-bm6</guid>
      <description>&lt;p&gt;Ok so you're using Terraform to deploy and manage your Azure resources? It's pretty neat, but at some point it's likely you will stumble over an Azure resource or configuration that's not available in Terraform. The &lt;a href="https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs" rel="noopener noreferrer"&gt;Terraform Provider for Azure&lt;/a&gt; covers a huge number of resources in Azure, but there's always going to be gaps, given how quickly Azure evolves.&lt;/p&gt;

&lt;p&gt;So what can you do? Well, you can find a workaround (like using Azure CLI or even ARM Templates), or raise an issue on the &lt;a href="https://github.com/terraform-providers/terraform-provider-azurerm" rel="noopener noreferrer"&gt;Azure Provider GitHub project&lt;/a&gt; and hope some kind soul picks it up, or &amp;lt;deep intake of breath&amp;gt; roll up your sleeves, open your IDE of choice (VS Code of course!) and start work on adding yourself.&lt;/p&gt;

&lt;p&gt;In this post I'll talk through some of the planning, pre-work and other technical investigation you're going to need to do, before you go diving headfirst into the code base. This is a replay of my own journey of adding to the provider, and trust me this isn't something you want to start doing without more than a little planning.&lt;/p&gt;

&lt;h1&gt;
  
  
  Basics &amp;amp; Pre-reqs
&lt;/h1&gt;

&lt;p&gt;In Dante's Inferno, he describes hell having nine different layers or circles. Thankfully we have just five to worry about, however the amount of suffering involved might be the same as a trip through Dante's vision of unending torment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fef6vminzj5epal3baany.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fef6vminzj5epal3baany.jpg" alt="The Nine Circles of Hell"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our layers are a little different, but no less infernal 😉&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Azure REST API Spec&lt;/strong&gt; - &lt;a href="https://github.com/Azure/azure-rest-api-specs" rel="noopener noreferrer"&gt;This repo contains OpenAPI specifications for all the Azure APIs&lt;/a&gt;. These specs are OpenAPI/Swagger definitions which describe shape of every API in Azure. Despite being at the top of this stack, most of the time you can pretty much ignore this, unless you think you've hit a bug with the way the API is behaving.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Azure REST API&lt;/strong&gt; - This is the main management interface to Azure and implements the above API spec. This is going to dictate &amp;amp; shape everything else we touch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure SDK for Go&lt;/strong&gt; - This wraps the above Azure API with a set of packages &amp;amp; client code making it "easier" than calling the API directly. Easier is matter of some debate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform Provider for Azure&lt;/strong&gt; - Also called 'azurerm' (which is the provider name), this in turn wraps the Go SDK, with a set of CRUD operations that Terraform understands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Terraform&lt;/strong&gt; - The Azure provider is a plugin and extension to the core Terraform system&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Needless you say you're going to need some Terraform experience, at least with the basics. It's also worth reading the &lt;a href="https://www.terraform.io/docs/plugins/provider.html" rel="noopener noreferrer"&gt;docs on provider plugins&lt;/a&gt; to get familiar with the concepts and main interfaces around providers.&lt;/p&gt;

&lt;p&gt;You're also going to need to be able to program in Go. You won't need to be a Go uber-coder, but if you've never touched it, you're going to have a very rough time, this is not the sort project in which I would advise you start learning Go with.&lt;/p&gt;

&lt;p&gt;It also helps if you've some prior experience with the Azure REST APIs (also called the ARM APIs), such as how they are versioned, the sorts of operations you can perform and concepts such as authentication, resource providers, scopes etc.&lt;/p&gt;

&lt;p&gt;So brave traveller, are you ready to descend?&lt;/p&gt;

&lt;h1&gt;
  
  
  The Azure API
&lt;/h1&gt;

&lt;p&gt;First you need to identify the API or APIs in Azure that are going plug the gap you need. This might be something you can deploy or configure from the Azure portal, the CLI but not through Terraform. You're going to spend a &lt;em&gt;lot&lt;/em&gt; of time in this section of the Azure docs &lt;a href="https://docs.microsoft.com/en-us/rest/api/azure/" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/rest/api/azure/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's assume you find what you need (if you didn't your journey has been a short one!)&lt;/p&gt;

&lt;p&gt;Take &lt;strong&gt;plenty&lt;/strong&gt; of time to research the API, try it out &amp;amp; experiment with it. My suggestion is to use the fantastic &lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" rel="noopener noreferrer"&gt;REST Client for VS Code&lt;/a&gt;. Build up a set of calls in a &lt;code&gt;.http&lt;/code&gt; or &lt;code&gt;.rest&lt;/code&gt; file which you can refer back to&lt;/p&gt;

&lt;p&gt;I wrote a short post on using this extension to authenticate and call Azure APIs, and how easy it makes it - so it's worth referring to that&lt;br&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/cse" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__org__pic"&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F3328%2F154c1f2d-df08-409b-b8e0-7d1dfd4762d4.png" alt="CSE Dev Crews"&gt;
      &lt;div class="ltag__link__user__pic"&gt;
        &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F264118%2F3eecd3aa-0e3d-4b2f-bbe4-f014eb764b5a.jpg" alt=""&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/cse/calling-azure-apis-with-rest-extension-for-vs-code-bhn" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Calling Azure APIs with the REST Extension for VS Code &lt;/h2&gt;
      &lt;h3&gt;Ben Coleman for CSE Dev Crews ・ Nov 18 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#azure&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#rest&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#vscode&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#api&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;Test the API thoroughly, time spent here will time well spent later. Poke at all the edge cases, "what if that array is empty?", "what if I put an invalid string here?", "if I remove that value, what is the default?". The docs will be some help, but generally are pretty bare bones.&lt;/p&gt;

&lt;p&gt;Once you're happy that you've got good a handle on calling the API directly, it's time to move on to the next layer...&lt;/p&gt;

&lt;p&gt;So traveller, I see you are prepared to descend deeper, let us journey on?&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkyc785geazeqg1m2y2dd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkyc785geazeqg1m2y2dd.jpg" alt="Gustave Dore illustration from the Divine Comedy"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Build Go Prototype / Code Spike
&lt;/h1&gt;

&lt;p&gt;The temptation might be to now jump into the Terraform provider code, but I'd hold off. Next it's worth spending some time working with the Azure SDK for Go to call the API in question&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Azure" rel="noopener noreferrer"&gt;
        Azure
      &lt;/a&gt; / &lt;a href="https://github.com/Azure/azure-sdk-for-go" rel="noopener noreferrer"&gt;
        azure-sdk-for-go
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      This repository is for active development of the Azure SDK for Go. For consumers of the SDK we recommend visiting our public developer docs at:
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The Go SDK is auto-generated from the aforementioned Azure REST API Spec, this means it's not exactly the most friendly SDK to work with. And with extremely rigid adherence to having everything well typed, means it can be laborious work to even see what the API is returning.&lt;/p&gt;

&lt;p&gt;I would suggest using a &lt;a href="https://en.wikipedia.org/wiki/Spike_(software_development)" rel="noopener noreferrer"&gt;code spike approach&lt;/a&gt; and build a simple console Go app, and in doing so take a look at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which package in the SDK you need, as they are versioned to match the Azure API versions, but it can be a challenge to even find the right package in the complex tree within the SDK.&lt;/li&gt;
&lt;li&gt;How the API client in that package is instantiated, normally with a subscription ID and possibly location, but each client is different.&lt;/li&gt;
&lt;li&gt;Make calls to the create, update and get operations. It's important you know how to build the input struct for a create operation, which might not be as trivial as it sounds. Also how to extract data from the response, which can often involve some "walking" down through all the properties and casting/asserting as you go&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This might seem like busy work and a waste of time, but you'll learn a lot in doing this, and it's much easier to test at this point before needing to go through an entire Terraform plan &amp;amp; apply loop. In addition a lot of this code you'll be able to copy and paste into the provider code.&lt;/p&gt;

&lt;p&gt;Are you confident to push on, to our final infernal layer?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbnb5y8mq0pwyhhn9bnef.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbnb5y8mq0pwyhhn9bnef.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The Azure Terraform Provider
&lt;/h1&gt;

&lt;p&gt;The final part of the "journey", but there's still a long way to go - as this part will by far take the longest. I'm not going to go super deep into the low level code &amp;amp; implementation specifics in this section, that could fill another post (or in fact several!), instead I want to focus on the design, approach &amp;amp; thinking you'll need to do.&lt;/p&gt;

&lt;p&gt;Start with designing the shape of your resource, sketch out some pseudo code HCL. By now you've probably got a good idea what this will look like based on the body of your API requests, but think about if you can make it a little more user friendly. For example where it comes to field names, think what does the end user likely know this field/feature by? There can often be a disconnect between the "internal" names used in the API and the "external" names used in the Portal &amp;amp; CLI&lt;/p&gt;

&lt;p&gt;One area to consider is where the API accepts an array of objects, this can be simplified in the HCL as a repeated block with the same name, this will automatically become an array. Therefor you will need to switch from a pluralized name to a singular. For example&lt;/p&gt;

&lt;p&gt;Example API JSON payload&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"rules"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rule 1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rule 2"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Example equivalent Terraform HCL&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="nx"&gt;azurerm_amazing_new_thing&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rule 1"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;rule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"rule 2"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Moving onward finally to the provider code itself which is hosted here:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/hashicorp" rel="noopener noreferrer"&gt;
        hashicorp
      &lt;/a&gt; / &lt;a href="https://github.com/hashicorp/terraform-provider-azurerm" rel="noopener noreferrer"&gt;
        terraform-provider-azurerm
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Terraform provider for Azure Resource Manager
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;You're contributing to a public open source project on GitHub, ultimately ending with a pull request which (hopefully!) will be merged into in main codebase and released. There's a certain way of working when contributing to OSS projects, there's plenty of guides online to help with this, e.g. &lt;a href="https://github.com/firstcontributions/first-contributions" rel="noopener noreferrer"&gt;first-contributions&lt;/a&gt; and &lt;a href="https://github.com/MarcDiethelm/contributing" rel="noopener noreferrer"&gt;MarcDiethelm/contributing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take plenty of time to explore the codebase, but thankfully you don't need to understand it all, focus on digging into the &lt;a href="https://github.com/terraform-providers/terraform-provider-azurerm/tree/master/azurerm/internal/services" rel="noopener noreferrer"&gt;azurerm/internal/services&lt;/a&gt; tree. Take some time to look at some Azure resources you are familiar with, try to find something not too complex (e.g. App Service) but not so simple it's trivial.&lt;/p&gt;

&lt;p&gt;The resources are grouped by their Azure Provider API, and under each group there will be some shared code common to all resources in that package. The key ones being:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;registration.go&lt;/code&gt; - This should be a short file containing a &lt;code&gt;SupportedResources()&lt;/code&gt; function which maps the Terraform resource names e.g. &lt;code&gt;azurerm_new_thing&lt;/code&gt; to the Go function that provides that resource, e.g &lt;code&gt;resourceArmNewThing()&lt;/code&gt;. You should be able to copy and paste an existing line in here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;client/client.go&lt;/code&gt; - This is where all the API clients from the SDK are created for the given API package, really it's another case of copy and pasting an existing one as there's a clear pattern to things.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementing your resource will be a matter of copying an existing one and making a LOT of changes. There will be a set of callback functions for the CRUD operations &lt;code&gt;Create&lt;/code&gt;, &lt;code&gt;Read&lt;/code&gt;, &lt;code&gt;Update&lt;/code&gt; and &lt;code&gt;Delete&lt;/code&gt;, implementing those functions is the heart of the task at hand, and &lt;a href="https://www.terraform.io/docs/plugins/provider.html" rel="noopener noreferrer"&gt;detailed here&lt;/a&gt;. Also the Schema is defined in here, this is the implementation of the HCL design we discussed a moment ago. You can &lt;a href="https://www.terraform.io/docs/extend/schemas/index.html" rel="noopener noreferrer"&gt;read the docs&lt;/a&gt; also take a good look at how other resources define their schemas, and learn by example&lt;/p&gt;

&lt;p&gt;Testing your code will take two shapes, informal testing locally with some Terraform HCL is the first place to start. In order to load your locally built version of the provider there's some hoops to jump though, which have been made a lot more difficult since Terraform 0.13.&lt;/p&gt;

&lt;p&gt;The script below I created helps with this, it builds the azurerm code, and then copies the resulting provider binary to where the Terraform CLI can find it. Runs &lt;code&gt;terraform init&lt;/code&gt; with &lt;code&gt;-plugin-dir&lt;/code&gt; set and then does a standard Terraform plan &amp;amp; apply&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build provider &amp;amp; load plugin test harness script:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/benc-uk/terraform-sandbox/blob/master/provider-test-harness/run.sh" rel="noopener noreferrer"&gt;https://github.com/benc-uk/terraform-sandbox/blob/master/provider-test-harness/run.sh&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note. In the script I pick a deliberately out of range version for the plugin as a belt and braces to make sure my copy is really being picked up, so the version of azurerm in your test Terraform would need to be &lt;code&gt;version = "&amp;gt;=99.0.0"&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You'll run this inner loop test many, MANY times until you get things working. The next set of tests are more formal acceptance tests. These live in the tests folder of the tree you are working in. All acceptance tests start with &lt;code&gt;TestAcc&lt;/code&gt; this means they won't run in the standard unit test cycle, they all contain embedded inline HCL which defines the test resources to create &amp;amp; destroy.&lt;/p&gt;

&lt;p&gt;These tests are only run when certain flags are specified, namely calling &lt;code&gt;make acctest&lt;/code&gt;. Again I suggest learning by example, copy some existing tests and build on what you find. Note these tests will deploy real resources in Azure which means they can be very slow to run and incur costs!&lt;/p&gt;

&lt;p&gt;The final stage before submitting your PR is to run though the test/check suite locally. This is done automatically in the &lt;a href="https://github.com/terraform-providers/terraform-provider-azurerm/actions" rel="noopener noreferrer"&gt;CI pipeline of the project in GitHub Actions&lt;/a&gt; however there's no point submitting your PR if the CI validation is going to fail, so get it working locally first, the main checks to run locally are:&lt;br&gt;&lt;br&gt;
&lt;code&gt;make tools&lt;/code&gt;, &lt;code&gt;make test&lt;/code&gt;, &lt;code&gt;make lint&lt;/code&gt;, &lt;code&gt;make tflint&lt;/code&gt;, &lt;code&gt;make depscheck&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;These scripts can take a little while to run and tend hit your machine quite hard, but once they are passing, you can finally submit your PR! Sit back and wait for the team to check it over, and get back to your with feedback. Be patient they are a very busy team!&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;PHEW! What a journey, but hopefully like Dante's Virgil you made it through unscathed! Undoubtedly you learned a lot in the process. Contributing to the Azure Terraform Provider isn't something you do lightly, but can be very rewarding.&lt;/p&gt;

&lt;p&gt;Your addition can make Terraform just a little bit better for everyone using Terraform with Azure, and for that reason alone it's sometimes worth going on a bit of an adventure&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>azurerm</category>
      <category>restapi</category>
    </item>
    <item>
      <title>Test your Azure policies in parallel</title>
      <dc:creator>Greg Oliver</dc:creator>
      <pubDate>Wed, 02 Dec 2020 15:46:50 +0000</pubDate>
      <link>https://dev.to/cse/test-your-azure-policies-in-parallel-5g2k</link>
      <guid>https://dev.to/cse/test-your-azure-policies-in-parallel-5g2k</guid>
      <description>&lt;p&gt;&lt;em&gt;This blog resulted from a customer development engagement. Want to read related blogs?  &lt;a href="https://dev.to/cse/secure-azure-as-code-5d9i"&gt;Secure Azure as Code&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Testing a policy is done with a few steps, each of which is a Terraform script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Test the positive case, where the bad outcome the policy protects against is not challenged&lt;/li&gt;
&lt;li&gt;Test the negative case, where the bad outcome is attempted (and hopefully audited or denied)&lt;/li&gt;
&lt;li&gt;Both create and update use cases&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If each test case requires creating a few Azure resources, the time to run these tests one after the other grows rapidly, especially in the case of testing policies. Having &amp;gt;100 policies to test is not unusual. Also, policies are normally defined at the management group level. This step can be done independently of the tests to set the context. Running the tests probably starts out by assigning policies to the test environment - a lower level management group or a subscription. Then the individual tests run on that test environment before it's reset with "terraform destroy".&lt;/p&gt;

&lt;h3&gt;
  
  
  Define policies and policy initiative in the management group
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"diagnostic_policies"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github.com/Nepomuceno/terraform-azurerm-monitoring-policies.git?ref=main"&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"DiagnosticsInitiative"&lt;/span&gt;
  &lt;span class="nx"&gt;management_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;definition_management_group&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Terraform script in the root folder of the &lt;a href="https://github.com/sebastus/icy-landscape"&gt;github repo&lt;/a&gt; fully implements this step. It's done once before running any tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run tests
&lt;/h3&gt;

&lt;p&gt;In the tests folder of the &lt;a href="https://github.com/sebastus/icy-landscape"&gt;github repo&lt;/a&gt; there are two approaches to this. One is implemented serially, the other in parallel. Both run the Terraform in the tests folder to do the policy assignment to the test environment. It also creates a couple of resources to use during tests that will follow.&lt;/p&gt;

&lt;h4&gt;
  
  
  Serial
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestSerial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// setup the environment by assigning policy to the subscription&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;TerraformDir&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InitAndApply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// run the first test&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"terraform_init_should_succeed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;terraformTestOptions&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;TerraformDir&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"./test-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="c"&gt;// and so on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Parallel
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;TestParallel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// setup the environment by assigning policy to the subscription&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;TerraformDir&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InitAndApply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"group"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;                 &lt;span class="c"&gt;// &amp;lt;-- group the tests&lt;/span&gt;
        &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"terraform_init_should_succeed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Parallel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;                                &lt;span class="c"&gt;// &amp;lt;-- invoke Parallel()&lt;/span&gt;
            &lt;span class="n"&gt;terraformTestOptions&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;terraform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;TerraformDir&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"./test-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="c"&gt;// and so on&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>azure</category>
      <category>go</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Terraform module for custom Azure policies</title>
      <dc:creator>Isabel Andrade</dc:creator>
      <pubDate>Wed, 02 Dec 2020 15:46:14 +0000</pubDate>
      <link>https://dev.to/cse/terraform-module-for-custom-azure-policies-1oek</link>
      <guid>https://dev.to/cse/terraform-module-for-custom-azure-policies-1oek</guid>
      <description>&lt;p&gt;Terraform modules are used to create reusable components that include groups of resources meant to be deployed together. This is a natural fit for custom Azure policies and initiatives since it allows organizations to implement all those definitions in a centralized component.&lt;/p&gt;

&lt;p&gt;This post goes through an example that shows how to implement and test a Terraform module that defines custom Azure policies and initiatives. The full version of the code can be found in the following repo: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/beandrad" rel="noopener noreferrer"&gt;
        beandrad
      &lt;/a&gt; / &lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample" rel="noopener noreferrer"&gt;
        terraform-azurerm-policy-sample
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Minimal Terraform module defining Azure policies and initiatives
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Module structure
&lt;/h1&gt;

&lt;p&gt;Hashicorp published a set of &lt;a href="https://www.terraform.io/docs/modules/index.html" rel="noopener noreferrer"&gt;guidelines on module definitions&lt;/a&gt; stating some naming conventions and the general module structure.&lt;/p&gt;

&lt;p&gt;According to those guidelines, module repository names follow the format &lt;code&gt;terraform-&amp;lt;PROVIDER&amp;gt;-&amp;lt;NAME&amp;gt;&lt;/code&gt;, where &lt;code&gt;PROVIDER&lt;/code&gt; in our case is AzureRM and &lt;code&gt;NAME&lt;/code&gt; is a label describing the infrastructure provided. In our case, the Terraform module is called &lt;code&gt;terraform-azurerm-policy-sample&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The module structure follows the standard practices recommended by Hashicorp; note, however, that some of the paths defined are specific to this module.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/blob/main/main.tf" rel="noopener noreferrer"&gt;&lt;code&gt;main.tf&lt;/code&gt;&lt;/a&gt;. Defines the configuration requirements. It may also configure other resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/blob/main/variables.tf" rel="noopener noreferrer"&gt;&lt;code&gt;variables.tf&lt;/code&gt;&lt;/a&gt;. Declares the module input variables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/blob/main/outputs.tf" rel="noopener noreferrer"&gt;&lt;code&gt;outputs.tf&lt;/code&gt;&lt;/a&gt;. Declares the module outputs; in this case, the initiative IDs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/tree/main/policies" rel="noopener noreferrer"&gt;&lt;code&gt;/policies&lt;/code&gt;&lt;/a&gt;. (Module specific) Includes the definitions of custom Azure policies. Each policy has its own folder, where the file &lt;code&gt;policy-rule.json&lt;/code&gt; has the definition and &lt;code&gt;policy-parameters.json&lt;/code&gt;, the parameters if applicable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;&amp;lt;label&amp;gt;-initiative.tf&lt;/code&gt;. (Module specific) Configures the definition of policies and initiatives in Azure. Policies are grouped into initiatives based on the resources they affect and/or by industry-level standards (such as the CIS Hardening Guidelines).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/blob/main/initiative-parameters.json" rel="noopener noreferrer"&gt;&lt;code&gt;initiative-parameters.tf&lt;/code&gt;&lt;/a&gt;. (Module specific) Declares the input parameters of all the initiatives defined in the module.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/tree/main/tests" rel="noopener noreferrer"&gt;&lt;code&gt;/tests&lt;/code&gt;&lt;/a&gt;. Implements the module acceptance tests.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Definition of policies and initiatives
&lt;/h1&gt;

&lt;p&gt;This module defines custom policies and initiatives under a management group (&lt;code&gt;definition_management_group&lt;/code&gt; in &lt;code&gt;variables.tf&lt;/code&gt;) or current subscription if the management group name is not defined.&lt;/p&gt;

&lt;p&gt;Custom policy definitions are created using the &lt;code&gt;azurerm_policy_definition&lt;/code&gt; resource and built-in policies are imported using the &lt;code&gt;azurerm_policy_definition&lt;/code&gt; data resource. Both resources are included in the corresponding initiatives Terraform configuration files; unless they are shared across initiatives, in which case they are defined in the &lt;code&gt;main.tf&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;It is important to note that policy data resources should be imported using its policy &lt;code&gt;name&lt;/code&gt; (as opposed to the &lt;code&gt;displayName&lt;/code&gt;). The reason is that the &lt;code&gt;displayName&lt;/code&gt; is not unique and it may change, whereas the &lt;code&gt;name&lt;/code&gt; is unique and it remains the same until the policy is deleted. In the configuration, the &lt;code&gt;displayName&lt;/code&gt; appears commented out as it describes the policy being imported.&lt;/p&gt;

&lt;h1&gt;
  
  
  Acceptance tests
&lt;/h1&gt;

&lt;p&gt;The acceptance tests deploy resources to Azure to check whether the defined initiatives actually work: non-compliant resources cannot be deployed whereas compliant ones are allowed to be deployed.&lt;/p&gt;

&lt;p&gt;The following conventions were followed when testing the policy module:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Tests check that the initiative is working as expected, as opposed to testing individual policies. The reason is that this module only outputs initiatives, all the policies are linked from an initiative.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Only the behavior of custom policies is tested; built-in policies are expected to work.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tests are implemented using the &lt;a href="https://golang.org/pkg/testing/" rel="noopener noreferrer"&gt;Go testing framework&lt;/a&gt; together with the &lt;a href="https://terratest.gruntwork.io/docs/" rel="noopener noreferrer"&gt;Terratest module&lt;/a&gt;. This configuration allows calling the Terraform configuration from the Go tests.&lt;/p&gt;

&lt;p&gt;The lifecycle of the tests is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup: load the policy module to define policies and initiatives and assign initiatives in Azure (&lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/blob/main/tests/terraform/main.tf" rel="noopener noreferrer"&gt;&lt;code&gt;tests/terraform/main.tf&lt;/code&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Run: try to create compliant resources (for example, &lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/tree/main/tests/terraform/resource-location-allow" rel="noopener noreferrer"&gt;&lt;code&gt;tests/terraform/resource-location-allow&lt;/code&gt;&lt;/a&gt;) and non-compliant resources (for example, &lt;a href="https://github.com/beandrad/terraform-azurerm-policy-sample/tree/main/tests/terraform/resource-location-audit" rel="noopener noreferrer"&gt;&lt;code&gt;tests/terraform/resource-location-audit&lt;/code&gt;&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Assert: check whether the policy has been correctly applied using the returned error from the Terraform apply for &lt;code&gt;deny&lt;/code&gt; effect or the policy state for &lt;code&gt;audit&lt;/code&gt; effect.&lt;/li&gt;
&lt;li&gt;Teardown: delete test resources from Azure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running this kind of tests is slow, in particular, those checking effects other than &lt;code&gt;deny&lt;/code&gt;. There are two main components that cause this delay: the first one is policy definition and assignment, and the second one is policy evaluation (which, as stated above, is required to check the &lt;code&gt;audit&lt;/code&gt; effect).&lt;/p&gt;

&lt;p&gt;In order to speed up the tests, test cases are run in parallel using the &lt;a href="https://golang.org/pkg/testing/#T.Parallel" rel="noopener noreferrer"&gt;&lt;code&gt;Parallel() function&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, regarding the teardown, it is important to note that it is done in two different steps: one for the resources provisioned during the setup and the other for the resources deployed by each of the test cases. In the first case, the &lt;a href="https://godoc.org/testing#T.Cleanup" rel="noopener noreferrer"&gt;Cleanup function&lt;/a&gt; is used; defer wouldn't work since deferred functions are run before parallel subtests are executed. On the other hand, resources created by the test cases are destroyed in a deferred function.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;As stated in the beginning, the aim of this post is to provide a baseline example of an Azure policy module; however, it is important to point out that quite a few opinionated design decisions have been made and, therefore, this example shouldn't be taken as the only correct way of implementing an Azure policy module.&lt;/p&gt;

&lt;p&gt;Having said that, I hope this post helps those devs out there looking for some guidance on how to implement Terraform modules, define Azure custom policies and initiatives, and test those definitions.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>azure</category>
      <category>test</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Auto-start collection of Azure diagnostic telemetry</title>
      <dc:creator>Greg Oliver</dc:creator>
      <pubDate>Wed, 02 Dec 2020 13:20:43 +0000</pubDate>
      <link>https://dev.to/cse/auto-start-collection-of-azure-diagnostic-telemetry-468k</link>
      <guid>https://dev.to/cse/auto-start-collection-of-azure-diagnostic-telemetry-468k</guid>
      <description>&lt;p&gt;&lt;em&gt;This blog resulted from a customer development engagement. Want to read related blogs?  &lt;a href="https://dev.to/cse/secure-azure-as-code-5d9i"&gt;Secure Azure as Code&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Infrastructure and platform monitoring are the province of &lt;a href="https://docs.microsoft.com/en-us/azure/azure-monitor/"&gt;Azure Monitor&lt;/a&gt;. The documentation provides several ways to configure diagnostic profiles on your resources so that the telemetry flows, but doing it onesy-twosy is a tax. Using &lt;a href="https://docs.microsoft.com/en-us/azure/governance/policy/"&gt;Azure Policy&lt;/a&gt; together with an &lt;a href="https://github.com/Nepomuceno/terraform-azurerm-monitoring-policies"&gt;open source Terraform module&lt;/a&gt; allows this task to fade into the background - done and dusted.&lt;/p&gt;

&lt;h3&gt;
  
  
  Define policies and policy initiative in the management group
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="s2"&gt;"diagnostic_policies"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;source&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"github.com/Nepomuceno/terraform-azurerm-monitoring-policies.git?ref=main"&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"DiagnosticsInitiative"&lt;/span&gt;
  &lt;span class="nx"&gt;management_group_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;definition_management_group&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Terraform script in the root folder of the &lt;a href="(https://github.com/sebastus/icy-landscape)"&gt;github repo&lt;/a&gt; fully implements this step.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Assign policy initiative to your subscription
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_policy_assignment"&lt;/span&gt; &lt;span class="s2"&gt;"diagnostics_initiative"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                 &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"diagnostics-initiative-assignment"&lt;/span&gt;
  &lt;span class="nx"&gt;scope&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azurerm_subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;policy_definition_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azurerm_policy_set_definition&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DiagnosticsInitiative&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Policy Assignment created via terraform"&lt;/span&gt;
  &lt;span class="nx"&gt;display_name&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Unit test diagnostic Logs application"&lt;/span&gt;
  &lt;span class="nx"&gt;identity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"SystemAssigned"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"uksouth"&lt;/span&gt;

  &lt;span class="nx"&gt;metadata&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;METADATA&lt;/span&gt;&lt;span class="sh"&gt;
    {
    "category": "Logs"
    }
&lt;/span&gt;&lt;span class="no"&gt;METADATA
&lt;/span&gt;  &lt;span class="nx"&gt;parameters&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;PARAMETERS&lt;/span&gt;&lt;span class="sh"&gt;
{
  "workspaceId": {
    "value": "${azurerm_log_analytics_workspace.ws.id}"
  },
  "storageAccountName": {
    "value": "${azurerm_storage_account.storage.name}"
  }
}
&lt;/span&gt;&lt;span class="no"&gt;PARAMETERS
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Give the SystemAssigned identity defined above rights to remediate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_role_assignment"&lt;/span&gt; &lt;span class="s2"&gt;"contributor"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;scope&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azurerm_subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;role_definition_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"contributor"&lt;/span&gt;
  &lt;span class="nx"&gt;principal_id&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_policy_assignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;diagnostics_initiative&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;identity&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;principal_id&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scenario 01 in &lt;a href="https://github.com/sebastus/icy-landscape/tree/main/scenarios"&gt;the scenarios folder&lt;/a&gt; fully implements these steps. Test by using a subscription that already has resources in it that do not have diagnostic profile(s) defined, or create new resources after running the above. Scenarios 02 and 03 are provided for convenience. They are dependent on scenario 01, so run scenario 01 first, then 02 or 03, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Explanation and Background
&lt;/h3&gt;

&lt;p&gt;Azure Monitor diagnostic profiles tell the platform what information you want to collect and where to send it. "What information you want to collect" is different for each resource type and there is no "everything" button. And that's the rub - one must make decisions for each resource in the system architecture. Using the module makes it possible to encapsulate all of this into one easy step in the Terraform script.&lt;/p&gt;

&lt;p&gt;A project frequently equates to an Azure subscription, and there are usually multiple projects within an organization. Managing the resources in these projects is made more convenient through the use of &lt;a href="https://docs.microsoft.com/en-us/azure/governance/management-groups/"&gt;Management Group&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/azure/governance/policy/"&gt;Azure Policy&lt;/a&gt;. From &lt;a href="https://docs.microsoft.com/en-us/azure/governance/management-groups/overview"&gt;this page&lt;/a&gt;:  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Azure management groups provide a level of scope above subscriptions. You organize subscriptions into containers called "management groups" and apply your governance conditions to the management groups. All subscriptions within a management group automatically inherit the conditions applied to the management group. Management groups give you enterprise-grade management at a large scale no matter what type of subscriptions you might have. All subscriptions within a single management group must trust the same Azure Active Directory tenant.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Using the module, many Azure policies and a policy initiative are defined (usually) at the management group level. Because each project team monitors their own infrastructure and each diagnostic profile designates the destination of the telemetry, it's best to assign the policy initiative at the subscription level. This allows the telemetry collection point to be within that subscription. It is possible to create multiple diagnostic profiles per resource so that telemetry can be directed to a global management point if desired.&lt;/p&gt;

&lt;p&gt;Each policy defined by the module targets a resource type, such as network security group, virtual machine, network interface card, and so on. If a resource does not meet the requirements of the policy, a remediation task creates the diagnostic profile for the resource. When the module is assigned to the subscription (via terraform apply) the results are not instantaneous - the Azure policy engine may take up to 15 minutes to scan resources and run remediation tasks.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>monitor</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Terraform Bootstrap &amp; Backend State in Azure</title>
      <dc:creator>Ben Coleman</dc:creator>
      <pubDate>Tue, 01 Dec 2020 16:54:32 +0000</pubDate>
      <link>https://dev.to/cse/terraform-bootstrap-backend-state-in-azure-5b73</link>
      <guid>https://dev.to/cse/terraform-bootstrap-backend-state-in-azure-5b73</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;When starting a new project utilising Terraform to manage resources in Azure, there's usually a hurdle to overcome, where you need to bootstrap your environment with certain pre-reqs. The main one of those being a way hold shared state (what Terraform calls a backend)&lt;/p&gt;

&lt;p&gt;To this end I'd like to share a set of scripts &amp;amp; Terraform to help you though this initial bootstrap &amp;amp; setup process&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/benc-uk"&gt;
        benc-uk
      &lt;/a&gt; / &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap"&gt;
        terraform-mgmt-bootstrap
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Bootstrap core Azure state &amp;amp; resources using Terraform for use with Azure DevOps
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;The repo holds some reusable scripts and Terraform configuration to "bootstrap" a project in order to be able to start using Terraform with Azure. This paves the way for the set up of Azure DevOps Pipelines to deploy further resources. This aligns with the common "hub &amp;amp; spoke" style of Azure architecture. where one shared set of management resources are used to support the deployment and management of one or more spokes through automated CI/CD pipelines. &lt;/p&gt;

&lt;p&gt;In this case Azure DevOps is the CI/CD system we will be using &amp;amp; configuring&lt;/p&gt;

&lt;p&gt;These "spokes" could be separate subscriptions or simply multiple environments in different resource groups for hosting simultaneous instances of an app.&lt;/p&gt;

&lt;p&gt;Note. There is no dependency or relation to the &lt;a href="https://docs.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/hub-spoke-network-topology"&gt;hub &amp;amp; spoke network topology&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's four main parts setup up by this process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bootstrap of backend state in Azure Storage for all Terraform to use.&lt;/li&gt;
&lt;li&gt;Deployment (and redeployment) set of shared, management resources.&lt;/li&gt;
&lt;li&gt;Creation of service principals with role assignments in Azure AD.&lt;/li&gt;
&lt;li&gt;Initial configuration of Azure DevOps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the scripts in the repo are intended to be run manually and infrequently, and called from an administrators local machine or Azure Cloud Shell. &lt;em&gt;There is no automation or CI/CD, this is by design&lt;/em&gt; - the purpose of this is to provide the bedrock to allow further CI/CD to happen.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note. This article is not intended as an intro to using Azure and Terraform, so it assumes a fair degree of knowledge in this area.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Pre-reqs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Bash&lt;/li&gt;
&lt;li&gt;Terraform 0.13+&lt;/li&gt;
&lt;li&gt;Azure CLI&lt;/li&gt;
&lt;li&gt;Authenticated connection to Azure, using Azure CLI, logged into the subscription you wish to configure&lt;/li&gt;
&lt;li&gt;Azure DevOps organization and project&lt;/li&gt;
&lt;li&gt;An Azure DevOps PAT token (full scope) for the relevant Azure DevOps organization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;p&gt;Before running any of the scripts, the configuration and input variables need to be set. This is done in an &lt;code&gt;.env&lt;/code&gt; file, and this file is read and parsed by scripts&lt;/p&gt;

&lt;p&gt;Note. &lt;code&gt;.tfvars&lt;/code&gt; file is not used, this is intentional. The dotenv format is easier to parse, meaning we can use the values in bash scripts and for other purposes&lt;/p&gt;

&lt;p&gt;Copy the &lt;code&gt;.env.sample&lt;/code&gt; file to &lt;code&gt;.env&lt;/code&gt; and set values for all variables as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_state_storage&lt;/code&gt; - The name of the storage account to hold Terraform state.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_mgmt_res_group&lt;/code&gt; - The shared resource group for all hub resources, including the storage account.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_state_container&lt;/code&gt; - Name of the blob container to hold Terraform state (default: &lt;code&gt;tfstate&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_prefix&lt;/code&gt; - A prefix added to all resources, pick your project name or other prefix to give the resources unique names.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_region&lt;/code&gt; - Azure region to deploy all resources into.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_azdo_org_url&lt;/code&gt; - URL of Azure DevOps org to use, e.g. https&lt;span&gt;://dev.azure.com/foobar&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_azdo_project_name&lt;/code&gt; - Name of the Azure DevOps project in the above org.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TF_VAR_azdo_pat&lt;/code&gt; - &lt;a href="https://docs.microsoft.com/en-us/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&amp;amp;tabs=preview-page"&gt;Azure DevOps access token&lt;/a&gt; with rights to create variable groups and service connections.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Bootstrap of Backend State
&lt;/h1&gt;

&lt;p&gt;As a principal we want all our resources defined in Terraform, including the storage account using by Terraform to hold backend state. This results in a chicken and egg problem.&lt;/p&gt;

&lt;p&gt;To solve this a bootstrap script is used which creates the initial storage account and resource group using the Azure CLI. Then Terraform is initialized pointing at this storage account as a backend, and the storage account imported into state&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap/blob/main/bootstrap.sh"&gt;bootstrap.sh&lt;/a&gt; in the GitHub repo for details&lt;/p&gt;

&lt;p&gt;This script should never need running a second time even if the other management resources are modified&lt;/p&gt;

&lt;h1&gt;
  
  
  Management Resource Deployment
&lt;/h1&gt;

&lt;p&gt;The deployment of the rest of the shared management resources is done via Terraform, and the various .tf files in the root of the repo.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap/blob/main/deploy.sh"&gt;deploy.sh&lt;/a&gt; in the GitHub repo for details&lt;/p&gt;

&lt;p&gt;This Terraform creates &amp;amp; configures the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource Group (also in bootstrap).&lt;/li&gt;
&lt;li&gt;Storage Account for holding Terraform state (also in bootstrap).&lt;/li&gt;
&lt;li&gt;Azure Container Registry. Not used but intended for providing centralized access to containers.&lt;/li&gt;
&lt;li&gt;Azure Log Analytics. Not used but intended for log aggregation &lt;/li&gt;
&lt;li&gt;Key Vault* for holding credentials and secrets used by Azure DevOps Pipelines.&lt;/li&gt;
&lt;li&gt;Service Principal, with RBAC role assignment to access the KeyVault "Key Vault Reader (preview)".&lt;/li&gt;
&lt;li&gt;A second Service Principal (to be used for pipelines), with IAM role "Contributor" at the subscription level.&lt;/li&gt;
&lt;li&gt;KeyVault access policy for above Service Principal to allow it to get &amp;amp; list secrets.&lt;/li&gt;
&lt;li&gt;KeyVault access policy for the current user to be able to manage secrets.&lt;/li&gt;
&lt;li&gt;Populates KeyVault with secrets, holding the credential details for the pipeline service principal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may wish to modify the role assigned to the pipeline service principal &lt;/p&gt;

&lt;h1&gt;
  
  
  Azure DevOps
&lt;/h1&gt;

&lt;p&gt;The deployment Terraform also sets up some initial configuration in Azure DevOps namely service connection called &lt;code&gt;keyvault-access&lt;/code&gt; which will allow variable groups to be linked to the KeyVault.&lt;/p&gt;

&lt;p&gt;The creation of a Azure DevOps variable group linked to KeyVault can not be done via Terraform or the Azure CLI. A work-around using cURL and REST API has been used. This is some what brittle but it serves the purpose well enough.&lt;/p&gt;

&lt;p&gt;See &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap/blob/main/azdo-var-group.sh"&gt;azdo-var-group.sh&lt;/a&gt; in the GitHub repo for details&lt;/p&gt;

&lt;p&gt;Running this script will create a variable group called &lt;code&gt;shared-secrets&lt;/code&gt; in the Azure DevOps project and populate it with four variables&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pipeline-sp-clientid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pipeline-sp-secret&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azure-tenant-id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azure-sub-id&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These variables can be used in subsequent Azure DevOps pipelines.&lt;/p&gt;

&lt;h1&gt;
  
  
  Next Steps &amp;amp; Example Environment
&lt;/h1&gt;

&lt;p&gt;This repo is intended to lay the ground work for Azure DevOps pipelines to be set up to deploy further resources. The shared variable group is a key part of enabling this, but the configuration of those pipelines is something clearly project &amp;amp; environment specific, so is not covered further here.&lt;/p&gt;

&lt;p&gt;A working CD pipeline with demo Terraform is given in the &lt;code&gt;example/&lt;/code&gt; directory. This environment is nothing more than a resource group &amp;amp; a storage account for illustrative purposes. The focus is the pipeline file - &lt;code&gt;example/deploy.yaml&lt;/code&gt; this carries out the deployment as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Uses the above &lt;code&gt;shared-secrets&lt;/code&gt; variable group&lt;/li&gt;
&lt;li&gt;Runs using the service principal details held in Key Vault&lt;/li&gt;
&lt;li&gt;Keeps state in the management backend state storage account&lt;/li&gt;
&lt;li&gt;Carries out standard Terraform init / plan / apply&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refer to the &lt;a href="https://github.com/benc-uk/terraform-mgmt-bootstrap/blob/main/example/deploy.yaml"&gt;example/deploy.yaml&lt;/a&gt; file for further details&lt;/p&gt;

&lt;p&gt;If you are using a mono-repo, the whole of this repo can be dropped in as a sub-folder, in order to keep the Terraform separate from any Terraform you wish to use in your other pipelines.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>terraform</category>
      <category>devops</category>
    </item>
    <item>
      <title>Standardize resource names in Terraform scripts</title>
      <dc:creator>Greg Oliver</dc:creator>
      <pubDate>Tue, 01 Dec 2020 15:08:29 +0000</pubDate>
      <link>https://dev.to/cse/standardize-resource-names-in-terraform-scripts-1pl2</link>
      <guid>https://dev.to/cse/standardize-resource-names-in-terraform-scripts-1pl2</guid>
      <description>&lt;p&gt;&lt;em&gt;This blog resulted from a customer development engagement. Want to read related blogs?  &lt;a href="https://dev.to/cse/secure-azure-as-code-5d9i"&gt;Secure Azure as Code&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When starting a Terraform project for an Azure architecture, it's easy to come up with useful names for the resources in your architecture. They usually look like "my-resource-group', "my-public-ip", "my-vm", "mystorageaccount", and so on. When the architecture grows, or elements of it scale out, it becomes harder to design useful names that meet all requirements. This blog is about a tool that helps with this task.  &lt;/p&gt;

&lt;p&gt;If you agree with the above and just want a link to the tool, here it is: &lt;a href="https://github.com/aztfmod/terraform-provider-azurecaf"&gt;terraform-provider-azurecaf&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Usage samples are fully implemented in the &lt;a href="https://github.com/sebastus/icy-landscape/tree/main/scenarios"&gt;scenarios folder&lt;/a&gt; of the &lt;a href="https://github.com/sebastus/icy-landscape"&gt;github repo&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Everyone else, read on.  &lt;/p&gt;

&lt;h3&gt;
  
  
  Requirements that must be met
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;for each resource type, rules vary

&lt;ul&gt;
&lt;li&gt;length&lt;/li&gt;
&lt;li&gt;accepted characters&lt;/li&gt;
&lt;li&gt;accepted patterns (e.g. first character must be a lowercase alpha)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;It must be possible to override generated names in special cases&lt;/li&gt;
&lt;li&gt;It must be possible to generate globally unique names&lt;/li&gt;
&lt;li&gt;Generated names must behave like any other resource in tfstate

&lt;ul&gt;
&lt;li&gt;names persist across 'terraform apply' runs as long as name resource definition remains the same&lt;/li&gt;
&lt;li&gt;name resources can be destroyed, tainted, etc just like any other terraform resource&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Additional nice-to-have features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;a generated name should conform to a regular pattern that becomes familiar and instantly recognizable&lt;/li&gt;
&lt;li&gt;when there are many resources in list, it should be possible to instantly recognize resource types from the name&lt;/li&gt;
&lt;li&gt;clear and concise name generation code&lt;/li&gt;
&lt;li&gt;when an architecture grows or resources scale out horizontally, name generation follows naturally&lt;/li&gt;
&lt;li&gt;when testing permutations of resource properties, generating names is a very powerful enabling technique&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Solution to the problem
&lt;/h3&gt;

&lt;p&gt;The solution is a Terraform provider that generates resource names. Unsurprisingly, it meets all of the conditions above. Generated resource name configuration options include (in order of precedence):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;name - overrides other options&lt;/li&gt;
&lt;li&gt;slug - a few characters denoting the resource type&lt;/li&gt;
&lt;li&gt;random - randomly generated chars&lt;/li&gt;
&lt;li&gt;suffixes - an array of suffixes that are appended&lt;/li&gt;
&lt;li&gt;prefixes - an array of prefixes that are pre-pended&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All configuration options are defined in the &lt;a href="https://github.com/aztfmod/terraform-provider-azurecaf"&gt;provider repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The following examples are fully implemented in the &lt;a href="https://github.com/sebastus/icy-landscape/tree/main/scenarios"&gt;scenarios folder&lt;/a&gt; of the &lt;a href="https://github.com/sebastus/icy-landscape"&gt;github repo&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Generates and implements a resource group name similar to rg-xxxxxxxx (very simple example)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurecaf_name"&lt;/span&gt; &lt;span class="s2"&gt;"rg_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;resource_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt;

  &lt;span class="nx"&gt;random_length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt; &lt;span class="s2"&gt;"rg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurecaf_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rg_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"uksouth"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Generates and implements a log analytics workspace name (example of name override)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurecaf_name"&lt;/span&gt; &lt;span class="s2"&gt;"ws_name"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;resource_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_log_analytics_workspace"&lt;/span&gt;

  &lt;span class="nx"&gt;random_length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
  &lt;span class="nx"&gt;suffixes&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"local"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;substr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;azurerm_subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# desired outcome = log-&amp;lt;sub name&amp;gt;-xxxxxxxx-local&lt;/span&gt;
  &lt;span class="c1"&gt;# length = 3 + 1 + (44) + 1 + 8 + 1 + 5 = max of 63 characters for log analytics workspace name&lt;/span&gt;
  &lt;span class="c1"&gt;# 44 is the max # of chars to get from the subscription name in order to get everything else into the generated name&lt;/span&gt;
  &lt;span class="c1"&gt;# because the "name" parameter is an override, if more characters are used, other portions of the generated name will be truncated&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_log_analytics_workspace"&lt;/span&gt; &lt;span class="s2"&gt;"ws"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurecaf_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ws_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The resource name rules (such as the max length of 63 characters) for azurerm_log_analytics_workspace are in &lt;a href="https://github.com/aztfmod/terraform-provider-azurecaf/blob/3b5b52b487acf1c338257ced78fe587e2d315029/resourceDefinition.json#L1760"&gt;this file&lt;/a&gt;.  &lt;/p&gt;

&lt;h4&gt;
  
  
  Generates multiple singleton names with a single azurecaf_name resource
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurecaf_name"&lt;/span&gt; &lt;span class="s2"&gt;"names"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;resource_type&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt;
  &lt;span class="nx"&gt;resource_types&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"azurerm_lb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_public_ip"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;random_length&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_resource_group"&lt;/span&gt; &lt;span class="s2"&gt;"rg"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurecaf_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;
  &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"uksouth"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_public_ip"&lt;/span&gt; &lt;span class="s2"&gt;"pip"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurecaf_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"azurerm_public_ip"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_lb"&lt;/span&gt; &lt;span class="s2"&gt;"lb"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurecaf_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;names&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"azurerm_lb"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Generates a set of names per vm instance of a cluster of vms
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurecaf_name"&lt;/span&gt; &lt;span class="s2"&gt;"per_instance"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number_of_servers&lt;/span&gt;

  &lt;span class="nx"&gt;resource_type&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_windows_virtual_machine"&lt;/span&gt;
  &lt;span class="nx"&gt;resource_types&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"azurerm_network_interface"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;name&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"websvr"&lt;/span&gt;
  &lt;span class="nx"&gt;random_length&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_network_interface"&lt;/span&gt; &lt;span class="s2"&gt;"nic"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number_of_servers&lt;/span&gt;

  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurecaf_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;per_instance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"azurerm_network_interface"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_network_interface_backend_address_pool_association"&lt;/span&gt; &lt;span class="s2"&gt;"example"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number_of_servers&lt;/span&gt;

  &lt;span class="nx"&gt;network_interface_id&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurerm_network_interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"azurerm_windows_virtual_machine"&lt;/span&gt; &lt;span class="s2"&gt;"vm"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;number_of_servers&lt;/span&gt;

  &lt;span class="nx"&gt;name&lt;/span&gt;                &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;azurecaf_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;per_instance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;
  &lt;span class="nx"&gt;network_interface_ids&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;azurerm_network_interface&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nic&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>azure</category>
      <category>tooling</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Bypassing policies in Azure</title>
      <dc:creator>Isabel Andrade</dc:creator>
      <pubDate>Thu, 19 Nov 2020 09:13:24 +0000</pubDate>
      <link>https://dev.to/cse/bypassing-policies-in-azure-29fc</link>
      <guid>https://dev.to/cse/bypassing-policies-in-azure-29fc</guid>
      <description>&lt;p&gt;Azure policies allow your Azure infrastructure to stay compliant by auditing and enforcing rules over the resources those policies are evaluated against. &lt;/p&gt;

&lt;p&gt;In some instances, however, we need to be able to bypass a particular policy or initiative. One way of doing this is by using bypass tags.&lt;/p&gt;

&lt;p&gt;Bypass tags can be defined in custom policies so that if a particular tag is included in a resource, the policy is ignored. This approach has two main shortcomings:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It only applies to custom policies; if a built-in policy wants to be bypassed, a new custom policy that also includes the corresponding tag needs to be defined;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;auditing of bypass tags requires further configuration since it is not integrated into the Azure portal out of the box. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"if"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"allOf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"not"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"location"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"in"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[parameters('allowedLocations')]"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tags['bypassLocationPolicy']"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"exists"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"then"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deny"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;However, there’s a better way of bypassing policies: &lt;a href="https://docs.microsoft.com/en-us/azure/governance/policy/concepts/exemption-structure" rel="noopener noreferrer"&gt;Azure policy exemptions&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is a policy exemption?
&lt;/h1&gt;

&lt;p&gt;Policy exemptions allow bypassing policies in a particular scope so that the policies are not evaluated for the resources under this scope. &lt;/p&gt;

&lt;p&gt;As opposed to bypass tags, Azure automatically audits policy exemptions, so that they can be easily monitored as shown in the picture below.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4ylef5dsr3mu94ilwyqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F4ylef5dsr3mu94ilwyqs.png" alt="exemption_monitoring"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another advantage is that policy exemptions can be applied to any policy including build-in policies, without the need of defining additional policies.&lt;/p&gt;

&lt;p&gt;One of the issues with policy exemptions, as opposed to bypass tags, is that it is involved to exempt individual resources from policies with &lt;code&gt;deny&lt;/code&gt; effect. The reason for that is that in order to be able to apply a policy exemption, the exemption scope, the resource itself in this case, needs to exist. One way of achieving this result is by assigning the exemption to a broader scope, for example, a resource group, create the resource, then assign the exemption to the individual resource and remove it from the broader scope.&lt;/p&gt;

&lt;h1&gt;
  
  
  Limiting the scope of exemptions
&lt;/h1&gt;

&lt;p&gt;As mentioned above, policy exemptions are applied to a particular scope. This, in principle, would allow disabling exemptions for entire management groups or subscriptions, which may defeat the purpose of applying policies in the first place.  &lt;/p&gt;

&lt;p&gt;However, there’s one way we can limit the scope to which exemptions can be applied: through a custom policy! &lt;/p&gt;

&lt;p&gt;The idea of this custom policy would be to block the creation of policy exemptions with particular scopes. There’s one minor issue, however, the policy exemption scope doesn’t exist as an alias, and therefore, it cannot be used as a filter in the policy definition. The solution to this is to use the policy exemption ID, which happens to embed the scope. In our case, we wanted to block policy exemptions with scopes broader than the resource group level, so our policy definition looks as follows.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"if"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"allOf"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"equals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Microsoft.Authorization/policyExemptions"&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"notContains"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"resourceGroup"&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
        &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"then"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deny"&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;br&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Follow up&lt;br&gt;
&lt;/h1&gt;

&lt;p&gt;At the time of writing this post, policy exemptions are still a preview feature in Azure and therefore you may face some limitations when using them. Nevertheless, I invite you to try them out if you need to work in highly regulated environments (they have proven quite handy to us!). Please, find below some links that will help you get started!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/governance/policy/overview" rel="noopener noreferrer"&gt;Azure policies overview&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/governance/policy/concepts/exemption-structure" rel="noopener noreferrer"&gt;Azure policy exemption structure&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/governance/policy/tutorials/create-and-manage" rel="noopener noreferrer"&gt;Tutorial on how to create and manage policies in Azure&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>azure</category>
      <category>security</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Calling Azure APIs with the REST Extension for VS Code </title>
      <dc:creator>Ben Coleman</dc:creator>
      <pubDate>Wed, 18 Nov 2020 23:43:49 +0000</pubDate>
      <link>https://dev.to/cse/calling-azure-apis-with-rest-extension-for-vs-code-bhn</link>
      <guid>https://dev.to/cse/calling-azure-apis-with-rest-extension-for-vs-code-bhn</guid>
      <description>&lt;p&gt;The fantastic REST Client for VS Code is a popular and valuable tool when doing any work with a REST API, be it your own or a 3rd party. Using this extension you can define a set of HTTP calls in a &lt;code&gt;.http&lt;/code&gt; or &lt;code&gt;.rest&lt;/code&gt; file. The list of features it supports is impressive, you can use variables, chain calls together and build up a reference set of API calls which you can reuse and refer back to, or distribute with your code&lt;/p&gt;

&lt;p&gt;Get the extension here&lt;br&gt;
&lt;a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=humao.rest-client&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Huachao" rel="noopener noreferrer"&gt;
        Huachao
      &lt;/a&gt; / &lt;a href="https://github.com/Huachao/vscode-restclient" rel="noopener noreferrer"&gt;
        vscode-restclient
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      REST Client Extension for Visual Studio Code
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  Set up &amp;amp; Pre-reqs
&lt;/h1&gt;

&lt;p&gt;When calling any Azure API you clearly need to authenticate, to cut a VERY long story short, this means getting an access token.&lt;/p&gt;

&lt;p&gt;We'll use the common authentication scenario using a registered client, which is a &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/azuread-dev/v1-oauth2-client-creds-grant-flow#request-an-access-token" rel="noopener noreferrer"&gt;Azure service principal plus the 'non-interactive flow' to request a token&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The REST extension can help us get this token. Yay.&lt;/p&gt;

&lt;p&gt;First create a &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal" rel="noopener noreferrer"&gt;service principal&lt;/a&gt; and give it the &lt;a href="https://docs.microsoft.com/en-us/azure/role-based-access-control/role-assignments-portal" rel="noopener noreferrer"&gt;permissions to the Azure subscription&lt;/a&gt; you want to use.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file and place the service principal details into it, this lets us keep secrets out of source control (I mean, you have .env included in your &lt;code&gt;.gitignore&lt;/code&gt; of course)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;AZURE_SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"__YOUR_SUBSCRIPTION_ID__"&lt;/span&gt;
&lt;span class="nv"&gt;AZURE_TENANT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"__YOUR_TENANT_ID_ID__"&lt;/span&gt;
AZURE_CLIENT_ID&lt;span class="s2"&gt;"=__YOUR_CLIENT_ID__"&lt;/span&gt;
&lt;span class="nv"&gt;AZURE_CLIENT_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"__YOUR_CLIENT_SECRET__"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Requesting an Access Token
&lt;/h1&gt;

&lt;p&gt;In VS Code, create a new file with any name, but it should have &lt;code&gt;.http&lt;/code&gt; or &lt;code&gt;.rest&lt;/code&gt; as the file extension (like &lt;code&gt;azure-api.rest&lt;/code&gt;) this file extension is what activates the REST Extension for VS Code.&lt;/p&gt;

&lt;p&gt;Paste in the following contents&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;### Get access token to call Azure ARM API&lt;/span&gt;
&lt;span class="c1"&gt;# @name getToken &lt;/span&gt;
&lt;span class="s"&gt;POST https://login.microsoftonline.com/{{$dotenv %AZURE_TENANT_ID}}/oauth2/token&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/x-www-form-urlencoded&lt;/span&gt;

&lt;span class="s"&gt;grant_type=client_credentials&lt;/span&gt;
&lt;span class="nl"&gt;&amp;amp;resource&lt;/span&gt;&lt;span class="s"&gt;=https://management.azure.com/&lt;/span&gt;
&lt;span class="nl"&gt;&amp;amp;client_id&lt;/span&gt;&lt;span class="s"&gt;={{$dotenv %AZURE_CLIENT_ID}}&lt;/span&gt;
&lt;span class="nl"&gt;&amp;amp;client_secret&lt;/span&gt;&lt;span class="s"&gt;={{$dotenv %AZURE_CLIENT_SECRET}}&lt;/span&gt;

&lt;span class="c1"&gt;### Capture access token from getToken request&lt;/span&gt;
&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="s"&gt;authToken = {{getToken.response.body.access_token}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;{{$dotenv %FOO}}&lt;/code&gt; syntax is some of the magic in the REST extension to access variables from the &lt;code&gt;.env&lt;/code&gt; file&lt;/p&gt;

&lt;p&gt;A "Send Request" option should light up above the POST statement, click that to make the request and you should get a pane popup with the response containing the access token (and other details)&lt;/p&gt;

&lt;p&gt;It will store the access_token from the HTTP result into the &lt;code&gt;authToken&lt;/code&gt; variable, to be available to subsequent requests &lt;/p&gt;

&lt;h2&gt;
  
  
  Calling the Azure APIs
&lt;/h2&gt;

&lt;p&gt;Now you're set up to add more requests to the file and use the access token to call any Azure API&lt;/p&gt;

&lt;p&gt;For example to list all resource groups, paste the following after the code above. Note. The comment line starting with three hashes &lt;code&gt;###&lt;/code&gt; is important and what the REST extension uses to delimit requests. We plug the &lt;code&gt;authToken&lt;/code&gt; variable value into the Authorization header to authorise the request&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;### List all storage accounts for subscription&lt;/span&gt;
&lt;span class="s"&gt;GET https://management.azure.com/subscriptions/{{$dotenv %AZURE_SUBSCRIPTION_ID}}/providers/Microsoft.Storage/storageAccounts?api-version=2019-06-01&lt;/span&gt;
&lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer {{authToken}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One again, hit "Send Request" just above the GET and you should get a reply from Azure listing all your resource groups. Neat!&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;The REST Client for VS Code makes authentication to call Azure APIs a simple and reusable task. Then calling those APIs can be easily set up without ever needing to leave your IDE&lt;/p&gt;

</description>
      <category>azure</category>
      <category>rest</category>
      <category>vscode</category>
      <category>api</category>
    </item>
  </channel>
</rss>
