{"id":1296,"date":"2026-05-07T23:18:16","date_gmt":"2026-05-07T23:18:16","guid":{"rendered":"https:\/\/zulfikar.co.uk\/blog\/?p=1296"},"modified":"2026-05-11T00:21:06","modified_gmt":"2026-05-11T00:21:06","slug":"vibe-code-your-landing-zone","status":"publish","type":"post","link":"https:\/\/zulfikar.co.uk\/blog\/vibe-code-your-landing-zone\/","title":{"rendered":"Vibe Code your Landing Zone!"},"content":{"rendered":"\n<p>What if I told you there&#8217;s an even easier way to deploy your Landing Zone (LZ)<\/p>\n\n\n\n<p>If like me your preferred IaC language is Terraform you&#8217;ll be used to hand crafting the scripts &amp; modules to deploy your LZ elements as per the required design. It&#8217;s an intensive effort even for a moderately sized deployment.<\/p>\n\n\n\n<p>Now there&#8217;s an easier way. You can simply describe what you need (your design), using well written &amp; accurate prompts and GitHub CoPilot (GHCP) will build out your terraform code\/modules to match this design:<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to get started prompting Landing Zones?<\/h2>\n\n\n\n<p>Fire up VS Code<\/p>\n\n\n\n<p>We&#8217;re going to assume you already have:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Github repo setup for your LZ<\/li>\n\n\n\n<li>VS Code is logged into the same Github account your new LZ is in<\/li>\n\n\n\n<li>VS Code configured with required extensions (HashiCorp Terraform, Microsoft Terraform, Azure Resources)<\/li>\n<\/ul>\n\n\n\n<p>GHCP is now integrated with VS Code &#8211; update your version of VS Code if possible otherwise install the GHCP extensions<\/p>\n\n\n\n<p>Witin VS Code use Ctrl + Alt + I to launch the GHCP prompting window, it should look like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-prompting-window.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"302\" height=\"196\" src=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-prompting-window.jpg\" alt=\"\" class=\"wp-image-1297\" srcset=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-prompting-window.jpg 302w, https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-prompting-window-300x195.jpg 300w\" sizes=\"auto, (max-width: 302px) 100vw, 302px\" \/><\/a><\/figure>\n\n\n\n<p>Locally within VS Code make sure you have a folder structure setup for your LZ<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>My_Landing_Zone\n-----------modules\/\n           -------management\n           -------connectivity\n           -------identity\n           -------subscriptions\n-----------environments\/\n-----------------------dev\/\n-----------.github\/\n-----------------------copilot-instructions.md\/\n-----------main.tf\n-----------variables.tf\n-----------outputs.tf\n-----------terraform.tfvars<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Let&#8217;s Prompt<\/h2>\n\n\n\n<p>Ok, with everything ready here&#8217;s the initial prompt:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-promp1-scaffold.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"496\" height=\"320\" src=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-promp1-scaffold.jpg\" alt=\"\" class=\"wp-image-1304\" srcset=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-promp1-scaffold.jpg 496w, https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-promp1-scaffold-300x194.jpg 300w\" sizes=\"auto, (max-width: 496px) 100vw, 496px\" \/><\/a><\/figure>\n\n\n\n<p>GHCP does it&#8217;s thing:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-promp1-scaffold-response.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"498\" height=\"461\" src=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-promp1-scaffold-response.jpg\" alt=\"\" class=\"wp-image-1305\" srcset=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-promp1-scaffold-response.jpg 498w, https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vs-code-github-copilot-promp1-scaffold-response-300x278.jpg 300w\" sizes=\"auto, (max-width: 498px) 100vw, 498px\" \/><\/a><\/figure>\n\n\n\n<p>This creates your initial LZ configuration, we&#8217;ve still got to deploy to Azure<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">But wait, what if I use Claude Code?<\/h2>\n\n\n\n<p>Ha! Microsoft would have you believe that only GHCP is capable of this, but vibe coding has been around a while and this is something better achieved in a paid subscription to the AI tool of choice &#8211; in my case it&#8217;s Claude. Let&#8217;s go:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>I&#8217;m building a greenfield Azure Landing Zone for Azure tenant xpressnet.co.uk using Terraform as the IaC tool.<\/p>\n\n\n\n<p><strong>Context<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>This is the connectivity module only (modules\/connectivity\/)<\/li>\n\n\n\n<li>azurerm provider version ~>3.0<\/li>\n\n\n\n<li>All resources deploy to UK South (uksouth) unless stated<\/li>\n\n\n\n<li>Module will be called from a root main.tf \u2014 write it as a self-contained module<\/li>\n\n\n\n<li>Follow Microsoft ALZ hub\/spoke best practices<\/li>\n<\/ul>\n\n\n\n<p><strong>Hub VNet<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Address space: 10.0.0.0\/16<\/li>\n\n\n\n<li>Subnets required (use variables for all CIDR ranges, no hardcoded values):\n<ul class=\"wp-block-list\">\n<li>GatewaySubnet (suggest 10.0.0.0\/27 as default variable value)<\/li>\n\n\n\n<li>AzureFirewallSubnet (suggest 10.0.1.0\/26 as default variable value)<\/li>\n\n\n\n<li>AzureFirewallManagementSubnet (suggest 10.0.1.64\/26 as default variable value)<\/li>\n\n\n\n<li>ManagementSubnet (suggest 10.0.2.0\/24 as default variable value)<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<p><strong>Spoke VNets<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create a variable that accepts a map of spoke definitions (name, address space, resource group)<\/li>\n\n\n\n<li>Each spoke should peer bidirectionally to the hub<\/li>\n\n\n\n<li>Allow traffic forwarding and gateway transit on peering<\/li>\n<\/ul>\n\n\n\n<p><strong>NSGs<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create an NSG for the ManagementSubnet<\/li>\n\n\n\n<li>Deny all inbound by default, allow RDP\/SSH only from ManagementSubnet CIDR<\/li>\n\n\n\n<li>Associate NSGs to appropriate subnets<\/li>\n\n\n\n<li>Do NOT attach NSGs to GatewaySubnet or AzureFirewallSubnet (Azure does not permit this)<\/li>\n<\/ul>\n\n\n\n<p><strong>Route Tables<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Create a route table for ManagementSubnet<\/li>\n\n\n\n<li>Default route (0.0.0.0\/0) pointing to AzureFirewall private IP (accept this as a variable \u2014 firewall may not exist yet)<\/li>\n\n\n\n<li>Associate route table to ManagementSubnet only<\/li>\n<\/ul>\n\n\n\n<p><strong>Tagging<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>All resources must accept a var.tags map and apply it<\/li>\n\n\n\n<li>Suggested default tags: environment, owner, created_date<\/li>\n<\/ul>\n\n\n\n<p><strong>File Structure Required<\/strong><\/p>\n\n\n\n<p>modules\/connectivity\/ ??? main.tf \u2014 all resources ??? variables.tf \u2014 all input variables with descriptions and defaults where sensible ??? outputs.tf \u2014 output hub VNet ID, hub VNet name, all subnet IDs, spoke VNet IDs ??? README.md \u2014 brief description of module inputs and outputs<\/p>\n\n\n\n<p><strong>Constraints<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>No hardcoded values anywhere in resources \u2014 everything via variables<\/li>\n\n\n\n<li>Use terraform resource naming convention: lowercase, hyphens not underscores<\/li>\n\n\n\n<li>Add lifecycle ignore_changes on tags where appropriate<\/li>\n\n\n\n<li>Do not create an Azure Firewall resource itself \u2014 just reserve the subnet and accept firewall private IP as a variable for routing purposes<\/li>\n<\/ul>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Et Voila, my Terraform<\/h2>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/my-connectivity-lz-outputs.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"698\" height=\"248\" src=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/my-connectivity-lz-outputs.jpg\" alt=\"\" class=\"wp-image-1307\" srcset=\"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/my-connectivity-lz-outputs.jpg 698w, https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/my-connectivity-lz-outputs-300x107.jpg 300w\" sizes=\"auto, (max-width: 698px) 100vw, 698px\" \/><\/a><\/figure>\n\n\n\n<p>Beautiful isn&#8217;t it? Now keep going, the Subscription Vending one will be the most fun<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A Recommendation from experience<\/h2>\n\n\n\n<p>Before running <code>terraform apply<\/code> on anything, always run:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>terraform plan -out=tfplan<\/code><\/pre>\n\n\n\n<p>And review the plan output carefully. Copilot\/Claude-generated Terraform is generally solid but will occasionally get resource naming, SKUs, or dependency ordering slightly wrong so the plan output makes these visible before anything is deployed.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What if I told you there&#8217;s an even easier way to deploy your Landing Zone (LZ) If like me your preferred IaC language is Terraform you&#8217;ll be used to hand crafting the scripts &amp; modules to deploy your LZ elements as per the required design. It&#8217;s an intensive effort even for a moderately sized deployment. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1299,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[445,10],"tags":[274,702,695,696,693,700,698,703,694,699,697,701],"class_list":["post-1296","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-azure","category-tfn","tag-azure","tag-firewall","tag-github","tag-github-copilot","tag-landing-zones","tag-modules","tag-prompting","tag-subnet","tag-subscription-vending","tag-terraform","tag-vibe-code","tag-vnet"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/zulfikar.co.uk\/blog\/wp-content\/uploads\/2026\/05\/vibe-code-landing-zones-featured-image.png","jetpack_shortlink":"https:\/\/wp.me\/p502c8-kU","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1296","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/comments?post=1296"}],"version-history":[{"count":5,"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1296\/revisions"}],"predecessor-version":[{"id":1309,"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/posts\/1296\/revisions\/1309"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/media\/1299"}],"wp:attachment":[{"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/media?parent=1296"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/categories?post=1296"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/zulfikar.co.uk\/blog\/wp-json\/wp\/v2\/tags?post=1296"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}