<?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: Greg Oliver</title>
    <description>The latest articles on DEV Community by Greg Oliver (@sebastus).</description>
    <link>https://dev.to/sebastus</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%2Fuser%2Fprofile_image%2F516723%2F48bf1967-cbcc-49d8-93d8-8162c464c939.png</url>
      <title>DEV Community: Greg Oliver</title>
      <link>https://dev.to/sebastus</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sebastus"/>
    <language>en</language>
    <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>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>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>
  </channel>
</rss>
