{"id":27830,"date":"2025-01-10T13:28:37","date_gmt":"2025-01-10T13:28:37","guid":{"rendered":"https:\/\/cloud-cod.com\/?p=27830"},"modified":"2025-01-12T13:41:40","modified_gmt":"2025-01-12T13:41:40","slug":"azure-pipeline-self-hosted-agents-and-azure-storage-for-terraform-state","status":"publish","type":"post","link":"https:\/\/cloud-cod.com\/index.php\/2025\/01\/10\/azure-pipeline-self-hosted-agents-and-azure-storage-for-terraform-state\/","title":{"rendered":"Azure Pipeline Self-hosted Agents and Azure Storage for Terraform State"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"27830\" class=\"elementor elementor-27830\" data-elementor-post-type=\"post\">\n\t\t\t\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-4a2d979 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"4a2d979\" data-element_type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-25dbc44\" data-id=\"25dbc44\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1bd860f elementor-widget elementor-widget-image\" data-id=\"1bd860f\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.17.0 - 01-11-2023 *\/\n.elementor-widget-image{text-align:center}.elementor-widget-image a{display:inline-block}.elementor-widget-image a img[src$=\".svg\"]{width:48px}.elementor-widget-image img{vertical-align:middle;display:inline-block}<\/style>\t\t\t\t\t\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"549\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-768x549.png\" class=\"attachment-medium_large size-medium_large wp-image-27946\" alt=\"Azure Pipeline Self Hosted Agent\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-768x549.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-300x214.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-1024x732.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-1536x1098.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20.png 2013w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d609886 elementor-toc--minimized-on-tablet elementor-widget elementor-widget-table-of-contents\" data-id=\"d609886\" data-element_type=\"widget\" data-settings=\"{&quot;exclude_headings_by_selector&quot;:[],&quot;marker_view&quot;:&quot;bullets&quot;,&quot;headings_by_tags&quot;:[&quot;h2&quot;,&quot;h3&quot;,&quot;h4&quot;,&quot;h5&quot;,&quot;h6&quot;],&quot;icon&quot;:{&quot;value&quot;:&quot;fas fa-circle&quot;,&quot;library&quot;:&quot;fa-solid&quot;},&quot;minimize_box&quot;:&quot;yes&quot;,&quot;minimized_on&quot;:&quot;tablet&quot;,&quot;hierarchical_view&quot;:&quot;yes&quot;,&quot;min_height&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_tablet&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]},&quot;min_height_mobile&quot;:{&quot;unit&quot;:&quot;px&quot;,&quot;size&quot;:&quot;&quot;,&quot;sizes&quot;:[]}}\" data-widget_type=\"table-of-contents.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor-pro - v3.17.0 - 01-11-2023 *\/\n.elementor-widget-table-of-contents .elementor-toc__header-title{color:var(--header-color)}.elementor-widget-table-of-contents.elementor-toc--collapsed .elementor-toc__toggle-button--collapse,.elementor-widget-table-of-contents:not(.elementor-toc--collapsed) .elementor-toc__toggle-button--expand{display:none}.elementor-widget-table-of-contents .elementor-widget-container{min-height:var(--box-min-height);border:var(--box-border-width,1px) solid var(--box-border-color,#9da5ae);border-radius:var(--box-border-radius,3px);background-color:var(--box-background-color);transition:min-height .4s;overflow:hidden}.elementor-toc__header{display:flex;align-items:center;justify-content:space-between;padding:var(--box-padding,20px);background-color:var(--header-background-color);border-bottom:var(--separator-width,1px) solid var(--box-border-color,#9da5ae)}.elementor-toc__header-title{font-size:18px;margin:0;color:var(--header-color)}.elementor-toc__toggle-button{cursor:pointer;display:inline-flex}.elementor-toc__toggle-button i{color:var(--toggle-button-color)}.elementor-toc__toggle-button svg{height:1em;width:1em;fill:var(--toggle-button-color)}.elementor-toc__spinner-container{text-align:center}.elementor-toc__spinner{font-size:2em}.elementor-toc__spinner.e-font-icon-svg{height:1em;width:1em}.elementor-toc__body{padding:var(--box-padding,20px);max-height:var(--toc-body-max-height);overflow-y:auto}.elementor-toc__body::-webkit-scrollbar{width:7px}.elementor-toc__body::-webkit-scrollbar-thumb{background-color:#babfc5;border-radius:10px}.elementor-toc__list-wrapper{list-style:none;padding:0}.elementor-toc__list-item{margin-bottom:.5em}.elementor-toc__list-item.elementor-item-active{font-weight:700}.elementor-toc__list-item .elementor-toc__list-wrapper{margin-top:.5em;margin-left:var(--nested-list-indent,1em)}.elementor-toc__list-item-text:hover{color:var(--item-text-hover-color);-webkit-text-decoration:var(--item-text-hover-decoration);text-decoration:var(--item-text-hover-decoration)}.elementor-toc__list-item-text.elementor-item-active{color:var(--item-text-active-color);-webkit-text-decoration:var(--item-text-active-decoration);text-decoration:var(--item-text-active-decoration)}.elementor-toc__list-item-text-wrapper{display:flex;align-items:center}.elementor-toc__list-item-text-wrapper:before,.elementor-toc__list-item-text-wrapper i{margin-right:8px;color:var(--marker-color)}.elementor-toc__list-item-text-wrapper svg{margin-right:8px;fill:var(--marker-color);height:var(--marker-size,.5em);width:var(--marker-size,.5em)}.elementor-toc__list-item-text-wrapper i{font-size:var(--marker-size,.5em)}.elementor-toc__list-item-text-wrapper:before{font-size:var(--marker-size,1em)}.elementor-toc--content-ellipsis .elementor-toc__list-item-text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.elementor-toc__list-items--collapsible>.elementor-toc__list-wrapper>.elementor-toc__list-item>.elementor-toc__list-wrapper{display:none}.elementor-toc__heading-anchor{position:absolute}.elementor-toc__body .elementor-toc__list-item-text{color:var(--item-text-color);-webkit-text-decoration:var(--item-text-decoration);text-decoration:var(--item-text-decoration)}.elementor-toc__body .elementor-toc__list-item-text:hover{color:var(--item-text-hover-color);-webkit-text-decoration:var(--item-text-hover-decoration);text-decoration:var(--item-text-hover-decoration)}.elementor-toc__body .elementor-toc__list-item-text.elementor-item-active{color:var(--item-text-active-color);-webkit-text-decoration:var(--item-text-active-decoration);text-decoration:var(--item-text-active-decoration)}ol.elementor-toc__list-wrapper{counter-reset:item}ol.elementor-toc__list-wrapper .elementor-toc__list-item{counter-increment:item}ol.elementor-toc__list-wrapper .elementor-toc__list-item-text-wrapper:before{content:counters(item,\".\") \". \"}<\/style>\t\t<div class=\"elementor-toc__header\">\n\t\t\t<h5 class=\"elementor-toc__header-title\">\n\t\t\t\tSITEMAP\t\t\t<\/h5>\n\t\t\t\t\t\t\t<div class=\"elementor-toc__toggle-button elementor-toc__toggle-button--expand\" role=\"button\" tabindex=\"0\" aria-controls=\"elementor-toc__d609886\" aria-expanded=\"true\" aria-label=\"Open table of contents\"><i aria-hidden=\"true\" class=\"fas fa-chevron-down\"><\/i><\/div>\n\t\t\t\t<div class=\"elementor-toc__toggle-button elementor-toc__toggle-button--collapse\" role=\"button\" tabindex=\"0\" aria-controls=\"elementor-toc__d609886\" aria-expanded=\"true\" aria-label=\"Close table of contents\"><i aria-hidden=\"true\" class=\"fas fa-chevron-up\"><\/i><\/div>\n\t\t\t\t\t<\/div>\n\t\t<div id=\"elementor-toc__d609886\" class=\"elementor-toc__body\">\n\t\t\t<div class=\"elementor-toc__spinner-container\">\n\t\t\t\t<i class=\"elementor-toc__spinner eicon-animation-spin eicon-loading\" aria-hidden=\"true\"><\/i>\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4a2ede1 elementor-widget elementor-widget-heading\" data-id=\"4a2ede1\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.17.0 - 01-11-2023 *\/\n.elementor-heading-title{padding:0;margin:0;line-height:1}.elementor-widget-heading .elementor-heading-title[class*=elementor-size-]>a{color:inherit;font-size:inherit;line-height:inherit}.elementor-widget-heading .elementor-heading-title.elementor-size-small{font-size:15px}.elementor-widget-heading .elementor-heading-title.elementor-size-medium{font-size:19px}.elementor-widget-heading .elementor-heading-title.elementor-size-large{font-size:29px}.elementor-widget-heading .elementor-heading-title.elementor-size-xl{font-size:39px}.elementor-widget-heading .elementor-heading-title.elementor-size-xxl{font-size:59px}<\/style><h2 class=\"elementor-heading-title elementor-size-default\">Introduction<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4765094 elementor-widget elementor-widget-text-editor\" data-id=\"4765094\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<style>\/*! elementor - v3.17.0 - 01-11-2023 *\/\n.elementor-widget-text-editor.elementor-drop-cap-view-stacked .elementor-drop-cap{background-color:#69727d;color:#fff}.elementor-widget-text-editor.elementor-drop-cap-view-framed .elementor-drop-cap{color:#69727d;border:3px solid;background-color:transparent}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap{margin-top:8px}.elementor-widget-text-editor:not(.elementor-drop-cap-view-default) .elementor-drop-cap-letter{width:1em;height:1em}.elementor-widget-text-editor .elementor-drop-cap{float:left;text-align:center;line-height:1;font-size:50px}.elementor-widget-text-editor .elementor-drop-cap-letter{display:inline-block}<\/style>\t\t\t\t<p>The previous article (\u00a0<a href=\"https:\/\/cloud-cod.com\/index.php\/2025\/01\/03\/azure-devops-pipeline-for-deploying-aviatrix-controller-and-copilot\/\">https:\/\/cloud-cod.com\/index.php\/2025\/01\/03\/azure-devops-pipeline-for-deploying-aviatrix-controller-and-copilot\/<\/a> ) showed how to create the Azure DevOps Pipeline for your Terraform code, which stores the Terraform tfsate file(s) in the Azure Storage Blob Container. The Pipeline we deployed used <strong>Microsoft-hosted Agents<\/strong>. The solution works quite nicely, but we saw that a different Agent with a different Public IP executed each Pipeline Stage.<\/p><p>Of course, we wanted to harden the access to the Azure Storage as much as possible. Therefore, we used the <strong>Azure Storage Firewall Rules<\/strong>. Using the Microsoft-hosted Agent forced us to update the Firewalls Rules with the Agent&#8217;s Public IP each time the Stage was triggered and remove the Agent&#8217;s Public IP at the end of each Stage. This led to additional steps in our Tasks. Because of Azure API lag\/delay, we also had to add extra &#8220;sleep&#8221; time. The result was that the execution of the Pipeline took more time than it should have. Additionally, sometimes the Azure API is sluggish, which could cause the Pipeline to fail. Of course, you could increase the &#8220;sleep&#8221; time to solve it, but it will add even more delay. It is not the perfect solution, isn&#8217;t it?..<\/p><p>This blog article shows one way of solving the issues described above. This time, we will leverage the <strong>Self-hosted Agent<\/strong> (a VM executing the Pipeline) created inside our VNET. What is important is that we will also establish a <strong>Private Endpoint<\/strong> to connect to the Azure Storage privately (traffic will not flow through the Internet). Thanks to that, the Azure Storage Firewall could be set to block ALL public access. Great advantage from the security standpoint!<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d58ad6b elementor-widget elementor-widget-image\" data-id=\"d58ad6b\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/diagram_pipeline_agent_private_endpoint_terraform.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Pipeline Agent Private Endpoint Terraform\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc5MzksInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvZGlhZ3JhbV9waXBlbGluZV9hZ2VudF9wcml2YXRlX2VuZHBvaW50X3RlcnJhZm9ybS5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"518\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/diagram_pipeline_agent_private_endpoint_terraform-768x518.png\" class=\"attachment-medium_large size-medium_large wp-image-27939\" alt=\"Azure Pipeline Agent Private Endpoint Terraform\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/diagram_pipeline_agent_private_endpoint_terraform-768x518.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/diagram_pipeline_agent_private_endpoint_terraform-300x202.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/diagram_pipeline_agent_private_endpoint_terraform-1024x690.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/diagram_pipeline_agent_private_endpoint_terraform.png 1224w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c5c112d elementor-widget elementor-widget-heading\" data-id=\"c5c112d\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Azure Storage for Terraform tfstate file(s)<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8972826 elementor-widget elementor-widget-text-editor\" data-id=\"8972826\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>We will use the same Storage Account created in the previous blog article. If you do not have it, please create it:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ac39b18 elementor-widget elementor-widget-code-highlight\" data-id=\"ac39b18\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp># Create a Storage Account Container for Azure DevOpS Pipeline TF backend\r\nresource \"azurerm_resource_group\" \"avx-mgmt-tf-storage-rg\" {\r\n  name     = \"avx-mgmt-storage-rg\"\r\n  location = \"westeurope\"\r\n}\r\n\r\nresource \"azurerm_storage_account\" \"avx-mgmt-tf-storage-account\" {\r\n  name                     = \"avxmgmttfstorageaccount\"  # name can only consist of lowercase letters and numbers, and must be between 3 and 24 characters long\r\n  resource_group_name      = azurerm_resource_group.avx-mgmt-tf-storage-rg.name\r\n  location                 = \"westeurope\"\r\n  account_tier             = \"Standard\"\r\n  account_replication_type = \"LRS\"  # LRS - Locally Redundant Storage is ok for Test\/Non-Prod Storage Account\r\n  \r\n  network_rules {\r\n     default_action             = \"Deny\"\r\n     ip_rules = [\"<your-public-ip>\"]\r\n   }\r\n\r\n  # allow_nested_items_to_be_public = false\r\n  # public_network_access_enabled   = false\r\n}\r\n\r\n# Storage Account Container used to keep the Terraform tfstate for the code from my previous article\r\nresource \"azurerm_storage_container\" \"avx-mgmt-tf-storage-container\" {\r\n  name                 = \"avx-mgmt-tf-storage-container\"\r\n  storage_account_id   = azurerm_storage_account.avx-mgmt-tf-storage-account.id\r\n}\r\n\r\n# Storage Account Container to be used by the code presented in this article\r\nresource \"azurerm_storage_container\" \"avxiatrix-env-tf-storage-container\" {\r\n  name                 = \"avxiatrix-env-tf-storage-container\"\r\n  storage_account_id   = azurerm_storage_account.avx-mgmt-tf-storage-account.id\r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0a3d92d elementor-widget elementor-widget-image\" data-id=\"0a3d92d\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_firewall_rules.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Storage Firewall Rules\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4NDAsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfc3RvcmFnZV9maXJld2FsbF9ydWxlcy5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"677\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_firewall_rules-768x677.png\" class=\"attachment-medium_large size-medium_large wp-image-27840\" alt=\"Azure Storage Firewall Rules\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_firewall_rules-768x677.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_firewall_rules-300x264.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_firewall_rules-1024x903.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_firewall_rules-1536x1354.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_firewall_rules.png 1899w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fa77e48 elementor-widget elementor-widget-text-editor\" data-id=\"fa77e48\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>As you can see above, I am still using the Firewall Rules to allow my Public IP and to ensure that the pipeline I showed in my previous blog article still works (because it is using the Microsoft-hosted Agents). If you would like to block Public Access completely, please remove the &#8220;network_rules&#8221; section from your Terraform code and use the following two arguments instead:<\/p><ul><li>allow_nested_items_to_be_public = false<\/li><li>public_network_access_enabled = false<\/li><\/ul><p>You will see the Public Access is Disabled:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-7255527 elementor-widget elementor-widget-image\" data-id=\"7255527\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_access_disabled.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Storage Firewall - Access disabled\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4MzYsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfc3RvcmFnZV9hY2Nlc3NfZGlzYWJsZWQucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"389\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_access_disabled-768x389.png\" class=\"attachment-medium_large size-medium_large wp-image-27836\" alt=\"Azure Storage Firewall - Access disabled\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_access_disabled-768x389.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_access_disabled-300x152.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_access_disabled-1024x518.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_access_disabled-1536x778.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_access_disabled.png 1825w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a435460 elementor-widget elementor-widget-text-editor\" data-id=\"a435460\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The container (&#8220;avxiatrix-env-tf-storage-container&#8221;) is there:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d01b9fc elementor-widget elementor-widget-image\" data-id=\"d01b9fc\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_container.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Storage Container\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4NDQsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfc3RvcmFnZV9jb250YWluZXIucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"457\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_container-768x457.png\" class=\"attachment-medium_large size-medium_large wp-image-27844\" alt=\"Azure Storage Container\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_container-768x457.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_container-300x178.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_container-1024x609.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_container-1536x913.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_storage_container.png 1573w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fbbb0d0 elementor-widget elementor-widget-heading\" data-id=\"fbbb0d0\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Azure DevOps Project and Repo<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ffad8a5 elementor-widget elementor-widget-text-editor\" data-id=\"ffad8a5\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>I will create a separate Project within my Organization in Azure DevOps.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ea36d81 elementor-widget elementor-widget-code-highlight\" data-id=\"ea36d81\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp># Create a Project in your Organization\r\n# You must have a Personal Access Token\r\nresource \"azuredevops_project\" \"aviatrix-infra-tf\" {\r\n  name               = \"Aviatrix-Infra-TF\"\r\n  description        = \"Project that contains Aviatrix Gateways\"\r\n  visibility         = \"private\"\r\n  version_control    = \"Git\"\r\n  work_item_template = \"Basic\"\r\n\r\n  features = {\r\n    \"testplans\"    = \"disabled\"\r\n    \"artifacts\"    = \"disabled\"\r\n    \"boards\"       = \"disabled\"\r\n    \"repositories\" = \"enabled\"\r\n    \"pipelines\"    = \"enabled\"\r\n  }\r\n}\r\n\r\n# Repository that contains code for Aviatrix Controller and Copilot\r\nresource \"azuredevops_git_repository\" \"aviatrix-infra-tf-gitrepo\" {\r\n  project_id = azuredevops_project.aviatrix-infra-tf.id\r\n  name       = \"Aviatrix-Infra-Git-Repo\"\r\n  initialization {\r\n    init_type = \"Clean\"\r\n  }\r\n  lifecycle {\r\n    ignore_changes = [\r\n      initialization,\r\n    ]\r\n  }\r\n}\r\n\r\nresource \"azuredevops_build_definition\" \"aviatrix-infra-tf-pipeline-deploy\" {\r\n  project_id = azuredevops_project.aviatrix-infra-tf.id\r\n  name       = \"avx-env-pipeline-deploy\"\r\n\r\n  ci_trigger {\r\n    use_yaml = true\r\n  }\r\n\r\n  repository {\r\n    repo_type   = \"TfsGit\"\r\n    repo_id     = azuredevops_git_repository.aviatrix-infra-tf-gitrepo.id\r\n    branch_name = azuredevops_git_repository.aviatrix-infra-tf-gitrepo.default_branch\r\n    yml_path    = \"azure-pipelines.yml\"\r\n  }\r\n\r\n}\r\n\r\nresource \"azuredevops_build_definition\" \"aviatrix-infra-tf-pipeline-destroy\" {\r\n  project_id = azuredevops_project.aviatrix-infra-tf.id\r\n  name       = \"avx-env-pipeline-destroy\"\r\n\r\n  ci_trigger {\r\n    use_yaml = true\r\n  }\r\n\r\n  repository {\r\n    repo_type   = \"TfsGit\"\r\n    repo_id     = azuredevops_git_repository.aviatrix-infra-tf-gitrepo.id\r\n    branch_name = azuredevops_git_repository.aviatrix-infra-tf-gitrepo.default_branch\r\n    yml_path    = \"azure-pipelines-destroy.yml\"\r\n  }\r\n}\r\n\r\n# Authorizaton required. Otherwise not able to access Azure Storage\r\nresource \"azuredevops_serviceendpoint_azurerm\" \"avx-ado-svcendpoint-azurerm-02\" {\r\n  project_id                             = azuredevops_project.aviatrix-infra-tf.id\r\n  service_endpoint_name                  = \"AzureRM Service Endpoint for Aviatrix Gateways deployment\"\r\n  service_endpoint_authentication_scheme = \"ServicePrincipal\"\r\n  azurerm_spn_tenantid                   = \"<Your-Tenant-ID>\"\r\n  azurerm_subscription_id                = \"<Your-Subscription-ID>\"\r\n  azurerm_subscription_name              = \"<Your-Subscription-Name>\"\r\n}\r\n\r\nresource \"azuredevops_resource_authorization\" \"avx-ado-resource-auth-02\" {\r\n  project_id  = azuredevops_project.aviatrix-infra-tf.id\r\n  resource_id = azuredevops_serviceendpoint_azurerm.avx-ado-svcendpoint-azurerm-02.id\r\n  authorized  = true\r\n}\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-16e8ad4 elementor-widget elementor-widget-text-editor\" data-id=\"16e8ad4\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The Service Principal we used for the Service Endpoint has a Contributor role at the Azure Subscription level:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-715fa9e elementor-widget elementor-widget-image\" data-id=\"715fa9e\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_subscription_iam.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Subscription IAM\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4NDUsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfc3Vic2NyaXB0aW9uX2lhbS5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"354\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_subscription_iam-768x354.png\" class=\"attachment-medium_large size-medium_large wp-image-27845\" alt=\"Azure Subscription IAM\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_subscription_iam-768x354.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_subscription_iam-300x138.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_subscription_iam-1024x473.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_subscription_iam-1536x709.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_subscription_iam-2048x945.png 2048w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-752405f elementor-widget elementor-widget-heading\" data-id=\"752405f\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Network Resources for Azure Agent VM<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0894e1b elementor-widget elementor-widget-text-editor\" data-id=\"0894e1b\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Let&#8217;s create the following network resources (e.g., VNET, Subnet, Route Table, NSG, NIC, SG). The Agent will be deployed inside the VNET.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f3c8825 elementor-widget elementor-widget-code-highlight\" data-id=\"f3c8825\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>## Create Azure Resource Group\r\nresource \"azurerm_resource_group\" \"az-devops-rg\" {\r\n  name     = var.az-devops-rg\r\n  location = var.az-devops-region\r\n}\r\n\r\n## Create VNET and Subnet for Azure Agent\r\nresource \"azurerm_virtual_network\" \"az-devops-vnet\" {\r\n  name                = var.az-devops-vnet-name\r\n  location            = azurerm_resource_group.az-devops-rg.location\r\n  resource_group_name = azurerm_resource_group.az-devops-rg.name\r\n  address_space       = var.az-devops-vnet-address-space\r\n}\r\n\r\nresource \"azurerm_subnet\" \"az-devops-vnet-subnet\" {\r\n  name                 = var.az-devops-subnet-name\r\n  resource_group_name  = azurerm_resource_group.az-devops-rg.name\r\n  virtual_network_name = azurerm_virtual_network.az-devops-vnet.name\r\n  address_prefixes     = var.az-devops-subnet-address-space\r\n}\r\n\r\nresource \"azurerm_route_table\" \"az-devops-subnet-rt-public\" {\r\n  name                = \"avx-devops-subnet-rt-public\"\r\n  location            = azurerm_resource_group.az-devops-rg.location\r\n  resource_group_name = azurerm_resource_group.az-devops-rg.name\r\n\r\n  route {\r\n    name           = \"default\"\r\n    address_prefix = \"0.0.0.0\/0\"\r\n    next_hop_type  = \"Internet\"\r\n  }\r\n}\r\n\r\nresource \"azurerm_subnet_route_table_association\" \"az-devops-subnet-rt-association\" {\r\n  subnet_id      = azurerm_subnet.az-devops-vnet-subnet.id\r\n  route_table_id = azurerm_route_table.az-devops-subnet-rt-public.id\r\n}\r\n\r\n# NSG for Azure Agent VM instance\r\nresource \"azurerm_network_security_group\" \"az-devops-agent-nsg\" {\r\n  name                = var.az-devops-agent-nsg\r\n  location            = azurerm_resource_group.az-devops-rg.location\r\n  resource_group_name = azurerm_resource_group.az-devops-rg.name\r\n\r\n  security_rule {\r\n    name                   = \"https\"\r\n    priority               = 100\r\n    direction              = \"Inbound\"\r\n    access                 = \"Allow\"\r\n    protocol               = \"Tcp\"\r\n    source_port_range      = \"*\"\r\n    destination_port_range = \"22\"\r\n    source_address_prefixes    = var.az-admin-public-ips\r\n    destination_address_prefix = \"*\"\r\n    description                = \"https-access-to-controller\"\r\n  }\r\n\r\n  # lifecycle {\r\n  #   ignore_changes = [security_rule]\r\n  # }\r\n}\r\n\r\nresource \"azurerm_public_ip\" \"az-devops-agent-public-ip\" {\r\n  name                = var.az-devops-agent-pip-name\r\n  location            = azurerm_resource_group.az-devops-rg.location\r\n  resource_group_name = azurerm_resource_group.az-devops-rg.name\r\n  allocation_method       = \"Static\"\r\n  idle_timeout_in_minutes = 30\r\n  domain_name_label       = \"azpipeline\"\r\n  sku                     = \"Basic\"\r\n}\r\n\r\n# Azure Agent VM NIC\r\nresource \"azurerm_network_interface\" \"az-devops-agent-iface-01\" {\r\n  name                = var.az-devops-agent-nic-name\r\n  location            = azurerm_resource_group.az-devops-rg.location\r\n  resource_group_name = azurerm_resource_group.az-devops-rg.name\r\n\r\n  ip_configuration {\r\n    name                          = var.az-devops-agent-nic-ipconf-name\r\n    subnet_id                     = azurerm_subnet.az-devops-vnet-subnet.id\r\n    private_ip_address_allocation = \"Static\"\r\n    private_ip_address            = var.az-devops-agent-prv-ip\r\n    public_ip_address_id          = azurerm_public_ip.az-devops-agent-public-ip.id\r\n  }\r\n}\r\n\r\nresource \"azurerm_network_interface_security_group_association\" \"az-devops-agent-nsg-association\" {\r\n  network_interface_id      = azurerm_network_interface.az-devops-agent-iface-01.id\r\n  network_security_group_id = azurerm_network_security_group.az-devops-agent-nsg.id\r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a06fbc6 elementor-widget elementor-widget-heading\" data-id=\"a06fbc6\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Agent Pool and Pipeline Authorizations<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8f82bd7 elementor-widget elementor-widget-text-editor\" data-id=\"8f82bd7\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Let&#8217;s create the Agent Pool and authorize our Project to use it.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d678697 elementor-widget elementor-widget-code-highlight\" data-id=\"d678697\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp># Agent Pool\r\nresource \"azuredevops_agent_pool\" \"ado-agent-pool-01\" {\r\n  name           = \"ado-agent-pool-01\"\r\n  auto_provision = false\r\n  auto_update    = false\r\n}\r\n\r\n# Authorization for the Pipeline\r\nresource \"azuredevops_agent_queue\" \"ado-agent-queue-02\" {\r\n  project_id    = azuredevops_project.aviatrix-infra-tf.id\r\n  agent_pool_id = azuredevops_agent_pool.ado-agent-pool-01.id\r\n}\r\n\r\nresource \"azuredevops_pipeline_authorization\" \"ado-pipeline-authorization-02\" {\r\n  project_id  = azuredevops_project.aviatrix-infra-tf.id\r\n  resource_id = azuredevops_agent_queue.ado-agent-queue-02.id\r\n  type        = \"queue\"\r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-3a13166 elementor-widget elementor-widget-image\" data-id=\"3a13166\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool-1.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Pipeline Agent Pool\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4NjYsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYWdlbnRfcG9vbC0xLnBuZyJ9\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"829\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool-1-768x829.png\" class=\"attachment-medium_large size-medium_large wp-image-27866\" alt=\"Azure Pipeline Agent Pool\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool-1-768x829.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool-1-278x300.png 278w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool-1-948x1024.png 948w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool-1.png 1092w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-5793d5e elementor-widget elementor-widget-text-editor\" data-id=\"5793d5e\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The authorization is there (as you can see, I have authorized two Projects):<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b42d39a elementor-widget elementor-widget-image\" data-id=\"b42d39a\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool_security.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Agent Pool Security\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4NjUsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYWdlbnRfcG9vbF9zZWN1cml0eS5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"612\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool_security-768x612.png\" class=\"attachment-medium_large size-medium_large wp-image-27865\" alt=\"Agent Pool Security\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool_security-768x612.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool_security-300x239.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool_security-1024x816.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool_security-1536x1224.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/agent_pool_security.png 1559w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-4575693 elementor-widget elementor-widget-heading\" data-id=\"4575693\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Azure Private Endpoint for Storage<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-29c5649 elementor-widget elementor-widget-text-editor\" data-id=\"29c5649\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The following code creates the Azure Private Endpoint (to access the Azure Storage) and a few DNS-related resources. Why DNS? These DNS resources are required to resolve the Azure service&#8217;s private endpoint name to its private IP address. Without it, DNS resolution will return a public IP when you access the storage account using its public DNS name (&lt;storage-account-name&gt;.blob.core.windows.net). This can result in the connection attempting to go through the public internet, defeating a private endpoint&#8217;s purpose.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-836cfa3 elementor-widget elementor-widget-code-highlight\" data-id=\"836cfa3\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp># Azure Private Endpoint\r\nresource \"azurerm_private_endpoint\" \"az-private-endpoint-storage\" {\r\n  name                = \"az-private-endpoint-storage\"\r\n  location            = azurerm_resource_group.az-devops-rg.location\r\n  resource_group_name = azurerm_resource_group.az-devops-rg.name\r\n  subnet_id           = azurerm_subnet.az-devops-vnet-subnet.id\r\n\r\n  private_service_connection {\r\n    name                           = \"storage-blob-connection\"\r\n    private_connection_resource_id = azurerm_storage_account.avx-mgmt-tf-storage-account.id\r\n    subresource_names              = [\"blob\"]\r\n    is_manual_connection           = false\r\n  }\r\n}\r\n\r\n# DNS Configuration\r\n# Private DNS Zone for Blob Storage\r\nresource \"azurerm_private_dns_zone\" \"dns-zone\" {\r\n  name                = \"privatelink.blob.core.windows.net\"\r\n  resource_group_name = azurerm_resource_group.az-devops-rg.name\r\n}\r\n\r\n# Link DNS Zone to VNET\r\nresource \"azurerm_private_dns_zone_virtual_network_link\" \"vnet-dns-link\" {\r\n  name                  = \"vnet-dns-link\"\r\n  resource_group_name   = azurerm_resource_group.az-devops-rg.name\r\n  private_dns_zone_name = azurerm_private_dns_zone.dns-zone.name\r\n  virtual_network_id    = azurerm_virtual_network.az-devops-vnet.id\r\n}\r\n\r\n# A Record for the Private Endpoint\r\nresource \"azurerm_private_dns_a_record\" \"stroage-a-record\" {\r\n  name                = azurerm_storage_account.avx-mgmt-tf-storage-account.name\r\n  zone_name           = azurerm_private_dns_zone.dns-zone.name\r\n  resource_group_name = azurerm_resource_group.az-devops-rg.name\r\n  ttl                 = 300\r\n  records             = [azurerm_private_endpoint.az-private-endpoint-storage.private_service_connection[0].private_ip_address]\r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-76fcdb1 elementor-widget elementor-widget-image\" data-id=\"76fcdb1\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_endpoint.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Private Endpoint\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4ODUsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfcHJpdmF0ZV9lbmRwb2ludC5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"667\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_endpoint-768x667.png\" class=\"attachment-medium_large size-medium_large wp-image-27885\" alt=\"Azure Private Endpoint\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_endpoint-768x667.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_endpoint-300x261.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_endpoint-1024x890.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_endpoint.png 1367w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-da88d9f elementor-widget elementor-widget-image\" data-id=\"da88d9f\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_zone.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Private DNS Zone\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4NzMsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfcHJpdmF0ZV9kbnNfem9uZS5wbmcifQ%3D%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"213\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_zone-768x213.png\" class=\"attachment-medium_large size-medium_large wp-image-27873\" alt=\"Azure Private DNS Zone\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_zone-768x213.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_zone-300x83.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_zone-1024x284.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_zone-1536x426.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_zone-2048x568.png 2048w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-384339a elementor-widget elementor-widget-image\" data-id=\"384339a\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_a_record.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Private DNS Zone - A Record\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4NzQsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfcHJpdmF0ZV9kbnNfYV9yZWNvcmQucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"214\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_a_record-768x214.png\" class=\"attachment-medium_large size-medium_large wp-image-27874\" alt=\"Azure Private DNS Zone - A Record\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_a_record-768x214.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_a_record-300x84.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_a_record-1024x286.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_a_record-1536x429.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_private_dns_a_record-2048x572.png 2048w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f6ba6eb elementor-widget elementor-widget-heading\" data-id=\"f6ba6eb\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Azure Self-Hosted Agent<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-89315e4 elementor-widget elementor-widget-text-editor\" data-id=\"89315e4\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The code for the VM creation. Please note that using Key Vault to store the admin password is recommended. In this case, your Service Principal will also require the IAM Role for Key Vault.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-621a3e7 elementor-widget elementor-widget-code-highlight\" data-id=\"621a3e7\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>resource \"azurerm_linux_virtual_machine\" \"az-devops-agent-vm\" {\r\n  admin_username                  = var.az-devops-agent-admin-name\r\n  admin_password                  = \"<your-admin-password>\" # you could use Key Vault to store it\r\n  name                            = var.az-devops-agent-vm-name\r\n  disable_password_authentication = false\r\n  location                        = azurerm_resource_group.az-devops-rg.location\r\n  network_interface_ids           = [azurerm_network_interface.az-devops-agent-iface-01.id]\r\n  resource_group_name             = azurerm_resource_group.az-devops-rg.name\r\n  size                            = var.az-devops-agent-vm-size\r\n\r\n  user_data = base64encode(templatefile(\"userdata.tftpl\", {}))\r\n\r\n  os_disk {\r\n    name                 = var.az-devops-agent-os-disk-name\r\n    caching              = \"ReadWrite\"\r\n    storage_account_type = \"Standard_LRS\"\r\n    disk_size_gb         = \"128\"\r\n  }\r\n\r\n  source_image_reference {\r\n    publisher = \"Canonical\"\r\n    offer     = \"0001-com-ubuntu-server-jammy\"\r\n    sku       = \"22_04-lts\"\r\n    version   = \"latest\"\r\n  }\r\n\r\n  tags = {\r\n    Environment        = \"DevOps-Pipeline-Agent\"\r\n  }\r\n\r\n  lifecycle {\r\n    ignore_changes = [\r\n      admin_password\r\n    ]\r\n  }\r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-ae6e0b5 elementor-widget elementor-widget-text-editor\" data-id=\"ae6e0b5\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>You could use userdata file to install the required components (Terraform, Agent, AZ CLI) or just SSH to the VM and execute the commands by yourself.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0ece607 elementor-widget elementor-widget-text-editor\" data-id=\"0ece607\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The Azure self-hosted Agents require Git (2.9.0 or higher) to be installed (all the requirements: <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/devops\/pipelines\/agents\/linux-agent?view=azure-devops\">https:\/\/learn.microsoft.com\/en-us\/azure\/devops\/pipelines\/agents\/linux-agent?view=azure-devops<\/a>). If you deploy the Azure VM, you will get Git already installed:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-1cfa490 elementor-widget elementor-widget-image\" data-id=\"1cfa490\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/git.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Git\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4OTIsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvZ2l0LnBuZyJ9\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"80\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/git-768x80.png\" class=\"attachment-medium_large size-medium_large wp-image-27892\" alt=\"Git\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/git-768x80.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/git-300x31.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/git.png 939w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-411c62b elementor-widget elementor-widget-text-editor\" data-id=\"411c62b\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Terraform installation (\u00a0<a href=\"https:\/\/developer.hashicorp.com\/terraform\/tutorials\/aws-get-started\/install-cli\">https:\/\/developer.hashicorp.com\/terraform\/tutorials\/aws-get-started\/install-cli<\/a> ):<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c3012fb elementor-widget elementor-widget-code-highlight\" data-id=\"c3012fb\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>#! \/usr\/bin\/env bash\r\nsudo apt-get update && sudo apt-get install -y gnupg software-properties-common\r\nwget -O- https:\/\/apt.releases.hashicorp.com\/gpg | \\\r\ngpg --dearmor | \\\r\nsudo tee \/usr\/share\/keyrings\/hashicorp-archive-keyring.gpg > \/dev\/null\r\ngpg --no-default-keyring \\\r\n--keyring \/usr\/share\/keyrings\/hashicorp-archive-keyring.gpg \\\r\n--fingerprint\r\necho \"deb [signed-by=\/usr\/share\/keyrings\/hashicorp-archive-keyring.gpg] \\\r\nhttps:\/\/apt.releases.hashicorp.com $(lsb_release -cs) main\" | \\\r\nsudo tee \/etc\/apt\/sources.list.d\/hashicorp.list\r\nsudo apt update -y\r\nsudo apt-get install terraform<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e79ca23 elementor-widget elementor-widget-text-editor\" data-id=\"e79ca23\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Azure Pipeline Self-hosted Agent installation (\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/cli\/azure\/install-azure-cli-linux?pivots=apt\">https:\/\/learn.microsoft.com\/en-us\/cli\/azure\/install-azure-cli-linux?pivots=apt<\/a> ):<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-58392a1 elementor-widget elementor-widget-code-highlight\" data-id=\"58392a1\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>wget https:\/\/vstsagentpackage.azureedge.net\/agent\/3.248.0\/vsts-agent-linux-x64-3.248.0.tar.gz\r\nmkdir myagent && cd myagent\r\ntar zxvf ~\/vsts-agent-linux-x64-3.248.0.tar.gz\r\n.\/config.sh --url https:\/\/dev.azure.com\/<your-org> --auth pat --token <personal-access-token> --pool <your-agent-pool> --agent <your-Agent-name>\r\nsudo .\/svc.sh install\r\nsudo .\/svc.sh start\r\nsudo .\/svc.sh status<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-38b161e elementor-widget elementor-widget-text-editor\" data-id=\"38b161e\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>AZ CLI installation (\u00a0<a href=\"https:\/\/learn.microsoft.com\/en-us\/cli\/azure\/install-azure-cli-linux?pivots=apt\">https:\/\/learn.microsoft.com\/en-us\/cli\/azure\/install-azure-cli-linux?pivots=apt<\/a> ):<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-11ea0df elementor-widget elementor-widget-code-highlight\" data-id=\"11ea0df\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>curl -sL https:\/\/aka.ms\/InstallAzureCLIDeb | sudo bash\r\naz login<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-db635c7 elementor-widget elementor-widget-text-editor\" data-id=\"db635c7\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Verification:<\/p><ul><li>DNS, Azure Storage Account is reachable via private IP 10.100.0.4<\/li><\/ul>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8a2ce60 elementor-widget elementor-widget-image\" data-id=\"8a2ce60\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_dns_private_dig.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Private DNS DIG command\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4NzgsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfZG5zX3ByaXZhdGVfZGlnLnBuZyJ9\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"301\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_dns_private_dig-768x301.png\" class=\"attachment-medium_large size-medium_large wp-image-27878\" alt=\"Azure Private DNS DIG command\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_dns_private_dig-768x301.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_dns_private_dig-300x118.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_dns_private_dig-1024x402.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_dns_private_dig-1536x602.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_dns_private_dig.png 1673w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-a40ab87 elementor-widget elementor-widget-text-editor\" data-id=\"a40ab87\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul><li>Terraform<\/li><\/ul>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b4a1118 elementor-widget elementor-widget-image\" data-id=\"b4a1118\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/terraform.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Terraform\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4OTMsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvdGVycmFmb3JtLnBuZyJ9\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"105\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/terraform-768x105.png\" class=\"attachment-medium_large size-medium_large wp-image-27893\" alt=\"Terraform\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/terraform-768x105.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/terraform-300x41.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/terraform.png 887w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-889afd0 elementor-widget elementor-widget-text-editor\" data-id=\"889afd0\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<ul><li>AZ CLI<\/li><\/ul>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c917083 elementor-widget elementor-widget-image\" data-id=\"c917083\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/az_cli_version.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"AZ CLI\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc4OTQsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXpfY2xpX3ZlcnNpb24ucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"218\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/az_cli_version-768x218.png\" class=\"attachment-medium_large size-medium_large wp-image-27894\" alt=\"AZ CLI\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/az_cli_version-768x218.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/az_cli_version-300x85.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/az_cli_version.png 802w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f5c3421 elementor-widget elementor-widget-heading\" data-id=\"f5c3421\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Remaining Terraform Code<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-30478d8 elementor-widget elementor-widget-text-editor\" data-id=\"30478d8\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The remaining Terraform code is presented below.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-845d4cc elementor-widget elementor-widget-text-editor\" data-id=\"845d4cc\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The <strong>providers.tf<\/strong> file:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e33ab9d elementor-widget elementor-widget-code-highlight\" data-id=\"e33ab9d\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>provider \"azurerm\" {\r\n  features {}\r\n}\r\n\r\nprovider \"azuredevops\" {\r\n  org_service_url = var.ado_org_service_url\r\n}\r\n\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2dabe77 elementor-widget elementor-widget-text-editor\" data-id=\"2dabe77\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The <strong>variables.tf<\/strong> file:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-642397e elementor-widget elementor-widget-code-highlight\" data-id=\"642397e\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>variable \"ado_org_service_url\" {\r\n  type        = string\r\n  description = \"Organization Service URL\"  \r\n  default     = \"https:\/\/dev.azure.com\/<your-org>\/\"\r\n}\r\n\r\n# DevOps Part - for Self-hosted DevOps Pipeline Agent\r\nvariable \"az-devops-rg\" {\r\n  type        = string\r\n  description = \"The name of the Resource Group used by DevOps Pipeline Agent\"\r\n}\r\n\r\nvariable \"az-devops-region\" {\r\n  type        = string\r\n  description = \"The Region to be used\"\r\n}\r\n\r\nvariable \"az-devops-vnet-name\" {\r\n  type        = string\r\n  description = \"The name of the DevOps Pipeline Agent components VNET\"\r\n}\r\n\r\nvariable \"az-devops-vnet-address-space\" {\r\n  type        = list(string)\r\n  description = \"The Address Space assigned to the DevOps Pipeline VNET\"\r\n}\r\n\r\nvariable \"az-devops-subnet-name\" {\r\n  type        = string\r\n  description = \"The name of the DevOps Pipeline Subnet\"\r\n}\r\n\r\nvariable \"az-devops-subnet-address-space\" {\r\n  type        = list(string)\r\n  description = \"The Address Space assigned to the DevOps Pipeline Subnet\" \r\n}\r\n\r\n# Azure DevOps Agent\r\nvariable \"az-devops-agent-nsg\" {\r\n  type        = string\r\n  description = \"The name of the DevOps Pipeline Agent VM NSG\"  \r\n}\r\n\r\nvariable \"az-admin-public-ips\" {\r\n  type        = list(string)\r\n  description = \"The list of Public IPs that need access to the Agent VM\" \r\n}\r\n\r\nvariable \"az-devops-agent-pip-name\" {\r\n  type        = string\r\n  description = \"The name of the Public IP used by the DevOps Pipeline Agent\"\r\n}\r\n\r\nvariable \"az-devops-agent-nic-name\" {\r\n  type        = string\r\n  description = \"The name of the Network interface used by the DevOps Pipeline Agent\"     \r\n}\r\n\r\nvariable \"az-devops-agent-nic-ipconf-name\" {\r\n  type        = string\r\n  description = \"The name of the IP Config assigned to the DevOps Pipeline Agent NIC\"   \r\n}\r\n\r\nvariable \"az-devops-agent-prv-ip\" {\r\n  type        = string\r\n  description = \"The Private IP address to be assigned to the DevOps Pipeline Agent VM NIC\"   \r\n}\r\n\r\nvariable \"az-devops-agent-vm-name\" {\r\n  type        = string\r\n  description = \"The name of the DevOps Pipeline Agent VM instance\"     \r\n}\r\n\r\nvariable \"az-devops-agent-vm-size\" {\r\n  type        = string\r\n  description = \"The family size of the DevOps Pipeline Agent VM instance\"    \r\n}\r\n\r\nvariable \"az-devops-agent-os-disk-name\" {\r\n  type        = string\r\n  description = \"The name of the DevOps Pipeline Agent OS disk\"  \r\n}\r\n\r\nvariable \"az-devops-agent-admin-name\" {\r\n  type        = string\r\n  description = \"The name of the Admin Account for the DevOps Pipeline Agent\"     \r\n}\r\n\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-91568f3 elementor-widget elementor-widget-text-editor\" data-id=\"91568f3\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The <strong>versions.tf<\/strong> file with Terraform backend:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-0ec812f elementor-widget elementor-widget-code-highlight\" data-id=\"0ec812f\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>terraform { \r\n  required_providers {\r\n    azuredevops = {\r\n      source  = \"microsoft\/azuredevops\"\r\n      version = \">=0.1.0\"\r\n    }\r\n\r\n    azurerm = {\r\n      source  = \"hashicorp\/azurerm\"\r\n      version = \">= 2.39\"\r\n    }\r\n  }\r\n\r\n# Backend for TF STATE FILE\r\n  cloud { \r\n    organization = \"<your-org>\" \r\n\r\n    workspaces { \r\n      name = \"<workspace-name>\" \r\n    } \r\n  } \r\n}<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-210ad5c elementor-widget elementor-widget-text-editor\" data-id=\"210ad5c\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Example of the <strong>terraform.auto.tfvars<\/strong> file:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-024ac20 elementor-widget elementor-widget-code-highlight\" data-id=\"024ac20\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp># DevOps Pipeline\r\naz-devops-rg                   = \"az-devops-rg\"\r\naz-devops-region               = \"West Europe\"\r\naz-devops-vnet-name            = \"az-devops-vnet-01\"\r\naz-devops-vnet-address-space   = [\"10.100.0.0\/24\"]\r\naz-devops-subnet-name          = \"az-devops-vnet-subnet-01\"\r\naz-devops-subnet-address-space = [\"10.100.0.0\/25\"]\r\n\r\n# DevOps Agent\r\naz-devops-agent-nsg             = \"az-devops-agent-nsg\"\r\naz-devops-agent-pip-name        = \"az-devops-agent-public-ip\" \r\naz-devops-agent-nic-name        = \"az-devops-agent-nic-01\"\r\naz-devops-agent-nic-ipconf-name = \"az-devops-agent-nic-ipconf-01\"\r\naz-devops-agent-prv-ip          = \"10.100.0.10\"\r\naz-devops-agent-admin-name      = \"avxadmin\"\r\naz-devops-agent-vm-name         = \"az-devops-agent-vm\"\r\naz-devops-agent-vm-size         = \"Standard_D4s_v5\"\r\naz-devops-agent-os-disk-name    = \"az-devops-agent-os-disk\"<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-f28faf2 elementor-widget elementor-widget-heading\" data-id=\"f28faf2\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Pipeline Test<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-8328f65 elementor-widget elementor-widget-text-editor\" data-id=\"8328f65\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Let&#8217;s check whether the Pipeline runs successfully. I will execute the <strong>terraform init<\/strong> and the <strong>terraform plan<\/strong> commands to confirm that they finish without errors.<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d9040b7 elementor-widget elementor-widget-image\" data-id=\"d9040b7\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_repo2.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure DevOps Repo\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc5MzcsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfcGlwZWxpbmVfcmVwbzIucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"398\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_repo2-768x398.png\" class=\"attachment-medium_large size-medium_large wp-image-27937\" alt=\"Azure DevOps Repo\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_repo2-768x398.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_repo2-300x155.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_repo2-1024x531.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_repo2-1536x796.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_repo2-2048x1061.png 2048w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2d3f51f elementor-widget elementor-widget-text-editor\" data-id=\"2d3f51f\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>Just to let you know, <strong>terraform init<\/strong> does not require additional configuraiton. Still, for <strong>terraform plan<\/strong> you have to successfully authenticate to the provider you want to use (AzureRM in my case). There are a few ways to pass the<strong> Client ID<\/strong>, <strong>Client Secret<\/strong>, <strong>Tenant ID<\/strong>, and <strong>Subscription ID<\/strong> to Terraform. For the sake of simplicity I will show how to use the <strong>Pipeline Variables<\/strong>.<\/p><p>I will create four Pipeline Variables and marked them as Secret:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e90c2f6 elementor-widget elementor-widget-image\" data-id=\"e90c2f6\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/pipeline_variables_azurerm.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Pipeline Variables\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc5MzAsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvcGlwZWxpbmVfdmFyaWFibGVzX2F6dXJlcm0ucG5nIn0%3D\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"300\" height=\"223\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/pipeline_variables_azurerm-300x223.png\" class=\"attachment-medium size-medium wp-image-27930\" alt=\"Azure Pipeline Variables\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/pipeline_variables_azurerm-300x223.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/pipeline_variables_azurerm.png 735w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-e0bfa4c elementor-widget elementor-widget-code-highlight\" data-id=\"e0bfa4c\" data-element_type=\"widget\" data-widget_type=\"code-highlight.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div class=\"prismjs-default copy-to-clipboard \">\n\t\t\t<pre data-line=\"\" class=\"highlight-height language-javascript line-numbers\">\n\t\t\t\t<code readonly=\"true\" class=\"language-javascript\">\n\t\t\t\t\t<xmp>trigger: none\r\n\r\npool: ado-agent-pool-01\r\n\r\nsteps:\r\n- script: |\r\n    echo \"Using self-hosted Agent\"\r\n    export ARM_CLIENT_ID=$(ARM_CLIENT_ID)\r\n    export ARM_CLIENT_SECRET=$(ARM_CLIENT_SECRET)\r\n    export ARM_TENANT_ID=$(ARM_TENANT_ID)\r\n    export ARM_SUBSCRIPTION_ID=$(ARM_SUBSCRIPTION_ID)\r\n    \r\n    terraform init\r\n    terraform plan\r\n  displayName: 'Terraform Init and Plan'\r\n  env:\r\n    ARM_CLIENT_ID: $(ARM_CLIENT_ID)\r\n    ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)\r\n    ARM_TENANT_ID: $(ARM_TENANT_ID)\r\n    ARM_SUBSCRIPTION_ID: $(ARM_SUBSCRIPTION_ID)\r\n<\/xmp>\n\t\t\t\t<\/code>\n\t\t\t<\/pre>\n\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-afcd8fb elementor-widget elementor-widget-text-editor\" data-id=\"afcd8fb\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>The result:<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d726b7c elementor-widget elementor-widget-image\" data-id=\"d726b7c\" data-element_type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<a href=\"http:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_result.png\" data-elementor-open-lightbox=\"yes\" data-elementor-lightbox-title=\"Azure Pipeline Result\" data-e-action-hash=\"#elementor-action%3Aaction%3Dlightbox%26settings%3DeyJpZCI6Mjc5MzgsInVybCI6Imh0dHBzOlwvXC9jbG91ZC1jb2QuY29tXC93cC1jb250ZW50XC91cGxvYWRzXC8yMDI1XC8wMVwvYXp1cmVfcGlwZWxpbmVfcmVzdWx0LnBuZyJ9\">\n\t\t\t\t\t\t\t<img loading=\"lazy\" decoding=\"async\" width=\"768\" height=\"362\" src=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_result-768x362.png\" class=\"attachment-medium_large size-medium_large wp-image-27938\" alt=\"Azure Pipeline Result\" srcset=\"https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_result-768x362.png 768w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_result-300x141.png 300w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_result-1024x483.png 1024w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_result-1536x724.png 1536w, https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/azure_pipeline_result-2048x966.png 2048w\" sizes=\"auto, (max-width: 768px) 100vw, 768px\" \/>\t\t\t\t\t\t\t\t<\/a>\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d323e1c elementor-widget elementor-widget-heading\" data-id=\"d323e1c\" data-element_type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">Summary<\/h2>\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2c6a09e elementor-widget elementor-widget-text-editor\" data-id=\"2c6a09e\" data-element_type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t<p>I hope this article has been informative and helpful, providing valuable insights on the Azure Pipeline Self-Hosted Agents topic and the integration with the Azure Storage Blob Containers, and Terraform. Thank you for taking the time to read, and I look forward to sharing more with you in the future!<\/p>\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>The articles show how to create the Azure Pipeline Self-Hosted Agent (Ubuntu) and integrate a Private Endpoint with an Azure Storage Container.<\/p>\n","protected":false},"author":2,"featured_media":27946,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[18,29,30,17],"tags":[],"class_list":["post-27830","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-devops","category-pipeline","category-terraform"],"uagb_featured_image_src":{"full":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20.png",2013,1439,false],"thumbnail":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-150x150.png",150,150,true],"medium":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-300x214.png",300,214,true],"medium_large":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-768x549.png",768,549,true],"large":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-1024x732.png",800,572,true],"1536x1536":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-1536x1098.png",1536,1098,true],"2048x2048":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20.png",2013,1439,false],"onepress-blog-small":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-300x150.png",300,150,true],"onepress-small":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-480x300.png",480,300,true],"onepress-medium":["https:\/\/cloud-cod.com\/wp-content\/uploads\/2025\/01\/blog20-640x400.png",640,400,true]},"uagb_author_info":{"display_name":"Jakub","author_link":"https:\/\/cloud-cod.com\/index.php\/author\/jakub\/"},"uagb_comment_info":425,"uagb_excerpt":"The articles show how to create the Azure Pipeline Self-Hosted Agent (Ubuntu) and integrate a Private Endpoint with an Azure Storage Container.","_links":{"self":[{"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/posts\/27830","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/comments?post=27830"}],"version-history":[{"count":101,"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/posts\/27830\/revisions"}],"predecessor-version":[{"id":27953,"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/posts\/27830\/revisions\/27953"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/media\/27946"}],"wp:attachment":[{"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/media?parent=27830"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/categories?post=27830"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloud-cod.com\/index.php\/wp-json\/wp\/v2\/tags?post=27830"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}