{"id":7493,"date":"2026-10-13T08:30:05","date_gmt":"2026-10-13T08:30:05","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=7493"},"modified":"2026-10-13T08:31:35","modified_gmt":"2026-10-13T08:31:35","slug":"how-to-do-looping-iterations-in-terraform","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/how-to-do-looping-iterations-in-terraform\/","title":{"rendered":"Terraform Loops and Iteration: Complete Guide to count, for_each, for Expressions, and Dynamic Blocks"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Terraform Loops and Iteration \u2014 Summary Table<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>#<\/th><th>Option \/ Method<\/th><th>Purpose<\/th><th>Input<\/th><th>Common use case<\/th><th>Creates resources?<\/th><\/tr><tr><td>1<\/td><td><code>count<\/code><\/td><td>Repeats a resource or module a specified number of times<\/td><td>Number<\/td><td>Create 3 EC2 instances or Azure VMs<\/td><td>Yes, when used on a resource\/module<\/td><\/tr><tr><td>2<\/td><td><code>for_each<\/code><\/td><td>Repeats resources or modules using named keys<\/td><td>Map or set of strings<\/td><td>Create VMs for <code>dev<\/code>, <code>test<\/code>, and <code>prod<\/code><\/td><td>Yes, when used on a resource\/module<\/td><\/tr><tr><td>3<\/td><td><code>for<\/code> expression \u2014 list<\/td><td>Transforms elements into a new list<\/td><td>List, tuple, or set<\/td><td>Convert environment names to uppercase<\/td><td>No<\/td><\/tr><tr><td>4<\/td><td><code>for<\/code> expression \u2014 map<\/td><td>Transforms elements into a map\/object<\/td><td>Collection<\/td><td>Build a map of application names and settings<\/td><td>No<\/td><\/tr><tr><td>5<\/td><td><code>for<\/code> expression with <code>if<\/code><\/td><td>Filters elements based on a condition<\/td><td>Collection<\/td><td>Select only enabled applications<\/td><td>No, but the result can drive resource creation<\/td><\/tr><tr><td>6<\/td><td>Nested <code>for<\/code> expressions<\/td><td>Iterates over nested collections<\/td><td>Nested lists, maps, or objects<\/td><td>Generate application\/environment combinations<\/td><td>No, but the result can drive resource creation<\/td><\/tr><tr><td>7<\/td><td><code>dynamic<\/code> block<\/td><td>Generates repeated nested configuration blocks<\/td><td>Collection via <code>for_each<\/code><\/td><td>Generate AWS security group ingress rules<\/td><td>No new top-level resources<\/td><\/tr><tr><td>8<\/td><td><code>flatten()<\/code> with iteration<\/td><td>Converts nested lists into a single list<\/td><td>Nested lists<\/td><td>Flatten application\/environment combinations<\/td><td>No<\/td><\/tr><tr><td>9<\/td><td><code>setproduct()<\/code> with iteration<\/td><td>Generates combinations from collections<\/td><td>Two or more collections<\/td><td>Create resources for every app\/environment combination<\/td><td>No, but the result can drive resource creation<\/td><\/tr><tr><td>10<\/td><td><code>toset()<\/code> with <code>for_each<\/code><\/td><td>Converts a list to a set of unique strings<\/td><td>List<\/td><td>Create one resource per unique application name<\/td><td>Yes, through <code>for_each<\/code><\/td><\/tr><tr><td>11<\/td><td><code>keys()<\/code> \/ <code>values()<\/code><\/td><td>Extracts map keys or values<\/td><td>Map<\/td><td>Prepare data for iteration or outputs<\/td><td>No<\/td><\/tr><tr><td>12<\/td><td>Module <code>count<\/code><\/td><td>Repeats module instances numerically<\/td><td>Number<\/td><td>Optionally deploy a module<\/td><td>Yes, creates module instances<\/td><\/tr><tr><td>13<\/td><td>Module <code>for_each<\/code><\/td><td>Repeats module instances by key<\/td><td>Map or set of strings<\/td><td>Deploy a module for each application<\/td><td>Yes, creates module instances<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Complete Guide to&nbsp;<code>count<\/code>,&nbsp;<code>for_each<\/code>,&nbsp;<code>for<\/code>&nbsp;Expressions, and Dynamic Blocks<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Audience:<\/strong>&nbsp;Beginners through advanced DevOps \/ cloud engineers<br><strong>Cloud examples:<\/strong>&nbsp;AWS EC2 and Azure Linux Virtual Machines<br><strong>Terraform version:<\/strong>&nbsp;Terraform 1.3+ recommended<br><strong>Approach:<\/strong>&nbsp;Each hands-on cloud lab is a standalone&nbsp;<code>main.tf<\/code>, with run steps, expected outcomes, and cleanup.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Cost and security:<\/strong>&nbsp;Cloud labs create billable resources. Review plans before applying and destroy resources when finished. SSH rules should be limited to your own public IPv4 address using CIDR notation such as&nbsp;<code>203.0.113.10\/32<\/code>. Do not open SSH to&nbsp;<code>0.0.0.0\/0<\/code>&nbsp;in production. Never put cloud credentials or private keys in Terraform files.<\/p>\n<\/blockquote>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Contents<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Learning goals<\/li>\n\n\n\n<li>Before you start<\/li>\n\n\n\n<li>The five main iteration patterns<\/li>\n\n\n\n<li>Lab 1 &#8212;\u00a0<code>count<\/code>: create multiple instances<\/li>\n\n\n\n<li>Lab 2 &#8212;\u00a0<code>for_each<\/code>: create named instances<\/li>\n\n\n\n<li>Lab 3 &#8212;\u00a0<code>for<\/code>\u00a0expressions: transform collections<\/li>\n\n\n\n<li>Lab 4 &#8212; Filtering with\u00a0<code>for ... if<\/code><\/li>\n\n\n\n<li>Lab 5 &#8212;\u00a0<code>dynamic<\/code>\u00a0blocks<\/li>\n\n\n\n<li>Lab 6 &#8212; Nested iteration and\u00a0<code>flatten<\/code><\/li>\n\n\n\n<li>Lab 7 &#8212;\u00a0<code>setproduct<\/code>\u00a0for combinations<\/li>\n\n\n\n<li>Lab 8 &#8212; Iterating over objects and maps<\/li>\n\n\n\n<li>Lab 9 &#8212; Conditional iteration<\/li>\n\n\n\n<li>Lab 10 &#8212; Iterating over modules<\/li>\n\n\n\n<li><code>count<\/code>\u00a0vs\u00a0<code>for_each<\/code><\/li>\n\n\n\n<li>Common errors and troubleshooting<\/li>\n\n\n\n<li>Best practices<\/li>\n\n\n\n<li>Quick reference<\/li>\n\n\n\n<li>Practice exercises<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">1. Learning goals<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After this guide, you should be able to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Repeat resources with\u00a0<code>count<\/code>\u00a0or\u00a0<code>for_each<\/code>.<\/li>\n\n\n\n<li>Transform a list, map, or object with a\u00a0<code>for<\/code>\u00a0expression.<\/li>\n\n\n\n<li>Filter collections with an\u00a0<code>if<\/code>\u00a0clause.<\/li>\n\n\n\n<li>Generate repeated nested blocks with\u00a0<code>dynamic<\/code>.<\/li>\n\n\n\n<li>Flatten nested collections and generate combinations.<\/li>\n\n\n\n<li>Repeat modules with\u00a0<code>count<\/code>\u00a0or\u00a0<code>for_each<\/code>.<\/li>\n\n\n\n<li>Understand resource addresses, plan-time requirements, and common iteration errors.<\/li>\n\n\n\n<li>Run and clean up practical AWS and Azure labs.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">2. Before you start<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Install Terraform and the relevant CLI.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">AWS<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Configure credentials using an AWS profile, environment variables, or an IAM role. Confirm the identity:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform version\naws sts <span class=\"hljs-keyword\">get<\/span>-caller-identity\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">You need permissions to create and delete EC2 instances and security groups. Use a valid Ubuntu AMI ID from the same AWS region as the provider.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Azure<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Sign in and select the right subscription:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml\">terraform version\naz login\naz account show --output table\naz account set --subscription \"<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SUBSCRIPTION_ID_OR_NAME<\/span>&gt;<\/span>\"\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">You need permissions to create and delete resource groups, networking, public IPs, and Linux VMs. Regional quota, policy, and VM-size availability can prevent creation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">General workflow<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For each lab, use a separate empty directory and save that lab&#8217;s code as&nbsp;<code>main.tf<\/code>.<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">terraform init\nterraform fmt\nterraform validate\nterraform plan\nterraform apply\nterraform output\nterraform destroy\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Terraform prompts before applying or destroying unless you pass an automatic approval flag. For learning, review the plan and type the confirmation yourself.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Azure SSH key:<\/strong>&nbsp;Most Azure labs expect the contents of a public key, for example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">cat ~<span class=\"hljs-regexp\">\/.ssh\/i<\/span>d_ed25519.pub\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">If no key exists, create one with&nbsp;<code>ssh-keygen -t ed25519<\/code>. Pass the&nbsp;<strong>public<\/strong>&nbsp;key to Terraform, never the private key.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3. The five main iteration patterns<\/h2>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Pattern Main purpose Typical use<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><code>count<\/code>&nbsp;Create a numeric number Three identical test of resource\/module instances, or one instances optional instance<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>for_each<\/code>&nbsp;Create instances from a One VM per named map or set of strings application<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>for<\/code>&nbsp;expression Transform a collection Convert names to into another collection uppercase or build a map<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>for ... if<\/code>&nbsp;Filter a collection Keep only enabled applications<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><code>dynamic<\/code>&nbsp;block Generate repeated AWS security-group nested blocks inside ingress rules one resource<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Supporting tools include&nbsp;<code>flatten()<\/code>,&nbsp;<code>toset()<\/code>,&nbsp;<code>keys()<\/code>,&nbsp;<code>values()<\/code>,&nbsp;<code>zipmap()<\/code>, and&nbsp;<code>setproduct()<\/code>. These are functions that help prepare collections for iteration.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4. Lab 1 &#8212;&nbsp;<code>count<\/code>: create multiple instances<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">How&nbsp;<code>count<\/code>&nbsp;works<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>count<\/code>&nbsp;accepts a non-negative integer. Terraform creates that many instances, and each instance has a numeric index:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>count.index<\/code>\u00a0starts at\u00a0<code>0<\/code>.<\/li>\n\n\n\n<li>With\u00a0<code>count = 3<\/code>, the addresses are\u00a0<code>resource.example[0]<\/code>,\u00a0<code>[1]<\/code>, and\u00a0<code>[2]<\/code>.<\/li>\n\n\n\n<li><code>resource.example[*].id<\/code>\u00a0collects IDs from all counted instances.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Use&nbsp;<code>count<\/code>&nbsp;when instances are interchangeable or when a resource should exist only zero or one times. If removing an item from a list shifts indexes, Terraform can plan unexpected replacements.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4A. AWS &#8212; create three EC2 instances<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Save as&nbsp;<code>main.tf<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    aws = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/aws\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 5.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"aws\"<\/span> {\n  region = <span class=\"hljs-keyword\">var<\/span>.aws_region\n}\n\nvariable <span class=\"hljs-string\">\"aws_region\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"ap-northeast-1\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"instance_count\"<\/span> {\n  type    = number\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-number\">3<\/span>\n\n  validation {\n    condition     = <span class=\"hljs-keyword\">var<\/span>.instance_count &gt;= <span class=\"hljs-number\">0<\/span> &amp;&amp; <span class=\"hljs-keyword\">var<\/span>.instance_count &lt;= <span class=\"hljs-number\">5<\/span>\n    error_message = <span class=\"hljs-string\">\"instance_count must be between 0 and 5 for this lab.\"<\/span>\n  }\n}\n\nvariable <span class=\"hljs-string\">\"ami_id\"<\/span> {\n  type        = string\n  description = <span class=\"hljs-string\">\"Valid Ubuntu AMI ID in the selected AWS region.\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type        = string\n  description = <span class=\"hljs-string\">\"Your public IPv4 address in CIDR notation, e.g. 203.0.113.10\/32.\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"tf-count-lab-\"<\/span>\n  description = <span class=\"hljs-string\">\"SSH restricted to the student's public IP\"<\/span>\n\n  ingress {\n    description = <span class=\"hljs-string\">\"SSH from student IP only\"<\/span>\n    from_port   = <span class=\"hljs-number\">22<\/span>\n    to_port     = <span class=\"hljs-number\">22<\/span>\n    protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-keyword\">var<\/span>.ssh_cidr]\n  }\n\n  egress {\n    from_port   = <span class=\"hljs-number\">0<\/span>\n    to_port     = <span class=\"hljs-number\">0<\/span>\n    protocol    = <span class=\"hljs-string\">\"-1\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"0.0.0.0\/0\"<\/span>]\n  }\n\n  tags = {\n    Name = <span class=\"hljs-string\">\"tf-count-lab-sg\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"web\"<\/span> {\n  count                  = <span class=\"hljs-keyword\">var<\/span>.instance_count\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name  = <span class=\"hljs-string\">\"count-web-${count.index + 1}\"<\/span>\n    Index = tostring(count.index)\n  }\n}\n\noutput <span class=\"hljs-string\">\"instance_ids\"<\/span> {\n  value = aws_instance.web&#91;*].id\n}\n\noutput <span class=\"hljs-string\">\"instance_public_ips\"<\/span> {\n  value = aws_instance.web&#91;*].public_ip\n}\n\noutput <span class=\"hljs-string\">\"created_count\"<\/span> {\n  value = length(aws_instance.web)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform init\nterraform fmt\nterraform validate\nterraform plan \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_UBUNTU_AMI\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform apply \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_UBUNTU_AMI\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform output\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">To test zero instances, use&nbsp;<code>-var=\"instance_count=0\"<\/code>&nbsp;with&nbsp;<code>plan<\/code>&nbsp;and then&nbsp;<code>apply<\/code>. The security group remains because it is not counted. Destroy the lab when finished, using the same required variables.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected:<\/strong>&nbsp;The default creates three EC2 instances. Output lists their IDs and public IPs. AMI IDs are regional; get a current Ubuntu AMI for the configured region before applying.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4B. Azure &#8212; create three Linux VMs<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This example includes a resource group, VNet, subnet, public IPs, NSG, NICs, NSG association, and Linux VMs.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    azurerm = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/azurerm\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 4.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"azurerm\"<\/span> {\n  features {}\n  resource_provider_registrations = <span class=\"hljs-string\">\"none\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"location\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"Japan East\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"vm_count\"<\/span> {\n  type    = number\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-number\">3<\/span>\n\n  validation {\n    condition     = <span class=\"hljs-keyword\">var<\/span>.vm_count &gt;= <span class=\"hljs-number\">0<\/span> &amp;&amp; <span class=\"hljs-keyword\">var<\/span>.vm_count &lt;= <span class=\"hljs-number\">5<\/span>\n    error_message = <span class=\"hljs-string\">\"vm_count must be between 0 and 5 for this lab.\"<\/span>\n  }\n}\n\nvariable <span class=\"hljs-string\">\"admin_username\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"azureuser\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_public_key\"<\/span> {\n  type        = string\n  description = <span class=\"hljs-string\">\"Contents of your SSH public key.\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type        = string\n  description = <span class=\"hljs-string\">\"Your public IPv4 address in CIDR notation, e.g. 203.0.113.10\/32.\"<\/span>\n}\n\nlocals {\n  prefix = <span class=\"hljs-string\">\"tfcount\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"${local.prefix}-rg\"<\/span>\n  location = <span class=\"hljs-keyword\">var<\/span>.location\n}\n\nresource <span class=\"hljs-string\">\"azurerm_virtual_network\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.100.0.0\/16\"<\/span>]\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n}\n\nresource <span class=\"hljs-string\">\"azurerm_subnet\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                 = <span class=\"hljs-string\">\"default\"<\/span>\n  resource_group_name  = azurerm_resource_group.lab.name\n  virtual_network_name = azurerm_virtual_network.lab.name\n  address_prefixes     = &#91;<span class=\"hljs-string\">\"10.100.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-nsg\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  security_rule {\n    name                       = <span class=\"hljs-string\">\"AllowSSHFromStudent\"<\/span>\n    priority                   = <span class=\"hljs-number\">100<\/span>\n    direction                  = <span class=\"hljs-string\">\"Inbound\"<\/span>\n    access                     = <span class=\"hljs-string\">\"Allow\"<\/span>\n    protocol                   = <span class=\"hljs-string\">\"Tcp\"<\/span>\n    source_port_range          = <span class=\"hljs-string\">\"*\"<\/span>\n    destination_port_range     = <span class=\"hljs-string\">\"22\"<\/span>\n    source_address_prefix      = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n    destination_address_prefix = <span class=\"hljs-string\">\"*\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"vm\"<\/span> {\n  count               = <span class=\"hljs-keyword\">var<\/span>.vm_count\n  name                = <span class=\"hljs-string\">\"${local.prefix}-pip-${count.index + 1}\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  allocation_method   = <span class=\"hljs-string\">\"Static\"<\/span>\n  sku                 = <span class=\"hljs-string\">\"Standard\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface\"<\/span> <span class=\"hljs-string\">\"vm\"<\/span> {\n  count               = <span class=\"hljs-keyword\">var<\/span>.vm_count\n  name                = <span class=\"hljs-string\">\"${local.prefix}-nic-${count.index + 1}\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  ip_configuration {\n    name                          = <span class=\"hljs-string\">\"internal\"<\/span>\n    subnet_id                     = azurerm_subnet.lab.id\n    private_ip_address_allocation = <span class=\"hljs-string\">\"Dynamic\"<\/span>\n    public_ip_address_id          = azurerm_public_ip.vm&#91;count.index].id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"vm\"<\/span> {\n  count                     = <span class=\"hljs-keyword\">var<\/span>.vm_count\n  network_interface_id      = azurerm_network_interface.vm&#91;count.index].id\n  network_security_group_id = azurerm_network_security_group.lab.id\n}\n\nresource <span class=\"hljs-string\">\"azurerm_linux_virtual_machine\"<\/span> <span class=\"hljs-string\">\"vm\"<\/span> {\n  count               = <span class=\"hljs-keyword\">var<\/span>.vm_count\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vm-${count.index + 1}\"<\/span>\n  computer_name       = <span class=\"hljs-string\">\"${local.prefix}-${count.index + 1}\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;\n    azurerm_network_interface.vm&#91;count.index].id\n  ]\n  disable_password_authentication = <span class=\"hljs-literal\">true<\/span>\n\n  admin_ssh_key {\n    username   = <span class=\"hljs-keyword\">var<\/span>.admin_username\n    public_key = <span class=\"hljs-keyword\">var<\/span>.ssh_public_key\n  }\n\n  os_disk {\n    caching              = <span class=\"hljs-string\">\"ReadWrite\"<\/span>\n    storage_account_type = <span class=\"hljs-string\">\"Standard_LRS\"<\/span>\n  }\n\n  source_image_reference {\n    publisher = <span class=\"hljs-string\">\"Canonical\"<\/span>\n    offer     = <span class=\"hljs-string\">\"0001-com-ubuntu-server-jammy\"<\/span>\n    sku       = <span class=\"hljs-string\">\"22_04-lts-gen2\"<\/span>\n    version   = <span class=\"hljs-string\">\"latest\"<\/span>\n  }\n\n  tags = {\n    Lab   = <span class=\"hljs-string\">\"count\"<\/span>\n    Index = tostring(count.index)\n  }\n}\n\noutput <span class=\"hljs-string\">\"vm_ids\"<\/span> {\n  value = azurerm_linux_virtual_machine.vm&#91;*].id\n}\n\noutput <span class=\"hljs-string\">\"public_ips\"<\/span> {\n  value = azurerm_public_ip.vm&#91;*].ip_address\n}\n\noutput <span class=\"hljs-string\">\"created_count\"<\/span> {\n  value = length(azurerm_linux_virtual_machine.vm)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform init\nterraform fmt\nterraform validate\nterraform plan \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_public_key=$(cat ~\/.ssh\/id_ed25519.pub)\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform apply \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_public_key=$(cat ~\/.ssh\/id_ed25519.pub)\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform output\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Try&nbsp;<code>-var=\"vm_count=0\"<\/code>&nbsp;to see the VMs, NICs, and public IPs removed while the shared network remains. Use&nbsp;<code>terraform destroy<\/code>&nbsp;when finished. Verify VM size availability and quota for your subscription and region.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5. Lab 2 &#8212;&nbsp;<code>for_each<\/code>: create named instances<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">How&nbsp;<code>for_each<\/code>&nbsp;works<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>for_each<\/code>&nbsp;accepts a map or a set of strings. Terraform creates one instance for every key:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Map:\u00a0<code>each.key<\/code>\u00a0is the map key;\u00a0<code>each.value<\/code>\u00a0is the associated value.<\/li>\n\n\n\n<li>Set of strings:\u00a0<code>each.key<\/code>\u00a0and\u00a0<code>each.value<\/code>\u00a0are the current string.<\/li>\n\n\n\n<li>Addresses use stable keys, for example\u00a0<code>aws_instance.app[\"frontend\"]<\/code>.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">This is usually the better choice when each resource has a meaningful identity, such as an application, environment, or subnet.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5A. AWS &#8212; create one EC2 instance per application<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    aws = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/aws\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 5.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"aws\"<\/span> {\n  region = <span class=\"hljs-keyword\">var<\/span>.aws_region\n}\n\nvariable <span class=\"hljs-string\">\"aws_region\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"ap-northeast-1\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ami_id\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"applications\"<\/span> {\n  type = map(object({\n    instance_type = string\n    environment   = string\n  }))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = { instance_type = <span class=\"hljs-string\">\"t3.micro\"<\/span>, environment = <span class=\"hljs-string\">\"dev\"<\/span> }\n    backend  = { instance_type = <span class=\"hljs-string\">\"t3.micro\"<\/span>, environment = <span class=\"hljs-string\">\"test\"<\/span> }\n    worker   = { instance_type = <span class=\"hljs-string\">\"t3.micro\"<\/span>, environment = <span class=\"hljs-string\">\"dev\"<\/span> }\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"tf-foreach-lab-\"<\/span>\n\n  ingress {\n    from_port   = <span class=\"hljs-number\">22<\/span>\n    to_port     = <span class=\"hljs-number\">22<\/span>\n    protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-keyword\">var<\/span>.ssh_cidr]\n  }\n\n  egress {\n    from_port   = <span class=\"hljs-number\">0<\/span>\n    to_port     = <span class=\"hljs-number\">0<\/span>\n    protocol    = <span class=\"hljs-string\">\"-1\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"0.0.0.0\/0\"<\/span>]\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each               = <span class=\"hljs-keyword\">var<\/span>.applications\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = each.value.instance_type\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name        = <span class=\"hljs-string\">\"app-${each.key}\"<\/span>\n    Application = each.key\n    Environment = each.value.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"instance_ids_by_application\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, instance <span class=\"hljs-keyword\">in<\/span> aws_instance.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> instance.id }\n}\n\noutput <span class=\"hljs-string\">\"public_ips_by_application\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, instance <span class=\"hljs-keyword\">in<\/span> aws_instance.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> instance.public_ip }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform init\nterraform fmt\nterraform validate\nterraform plan \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_UBUNTU_AMI\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform apply \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_UBUNTU_AMI\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform output\nterraform destroy \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_UBUNTU_AMI\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected:<\/strong>&nbsp;Three EC2 instances with keys&nbsp;<code>frontend<\/code>,&nbsp;<code>backend<\/code>, and&nbsp;<code>worker<\/code>. The output maps application names to IDs and IPs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5B. Azure &#8212; create one Linux VM per application<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    azurerm = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/azurerm\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 4.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"azurerm\"<\/span> {\n  features {}\n  resource_provider_registrations = <span class=\"hljs-string\">\"none\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"location\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"Japan East\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"admin_username\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"azureuser\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_public_key\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"applications\"<\/span> {\n  type = map(object({\n    vm_size     = string\n    environment = string\n  }))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = { vm_size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>, environment = <span class=\"hljs-string\">\"dev\"<\/span> }\n    backend  = { vm_size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>, environment = <span class=\"hljs-string\">\"test\"<\/span> }\n    worker   = { vm_size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>, environment = <span class=\"hljs-string\">\"dev\"<\/span> }\n  }\n}\n\nlocals {\n  prefix = <span class=\"hljs-string\">\"tfforeach\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"${local.prefix}-rg\"<\/span>\n  location = <span class=\"hljs-keyword\">var<\/span>.location\n}\n\nresource <span class=\"hljs-string\">\"azurerm_virtual_network\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.110.0.0\/16\"<\/span>]\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n}\n\nresource <span class=\"hljs-string\">\"azurerm_subnet\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                 = <span class=\"hljs-string\">\"default\"<\/span>\n  resource_group_name  = azurerm_resource_group.lab.name\n  virtual_network_name = azurerm_virtual_network.lab.name\n  address_prefixes     = &#91;<span class=\"hljs-string\">\"10.110.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-nsg\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  security_rule {\n    name                       = <span class=\"hljs-string\">\"AllowSSHFromStudent\"<\/span>\n    priority                   = <span class=\"hljs-number\">100<\/span>\n    direction                  = <span class=\"hljs-string\">\"Inbound\"<\/span>\n    access                     = <span class=\"hljs-string\">\"Allow\"<\/span>\n    protocol                   = <span class=\"hljs-string\">\"Tcp\"<\/span>\n    source_port_range          = <span class=\"hljs-string\">\"*\"<\/span>\n    destination_port_range     = <span class=\"hljs-string\">\"22\"<\/span>\n    source_address_prefix      = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n    destination_address_prefix = <span class=\"hljs-string\">\"*\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = <span class=\"hljs-keyword\">var<\/span>.applications\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-pip\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  allocation_method   = <span class=\"hljs-string\">\"Static\"<\/span>\n  sku                 = <span class=\"hljs-string\">\"Standard\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = <span class=\"hljs-keyword\">var<\/span>.applications\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-nic\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  ip_configuration {\n    name                          = <span class=\"hljs-string\">\"internal\"<\/span>\n    subnet_id                     = azurerm_subnet.lab.id\n    private_ip_address_allocation = <span class=\"hljs-string\">\"Dynamic\"<\/span>\n    public_ip_address_id          = azurerm_public_ip.app&#91;each.key].id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each                  = <span class=\"hljs-keyword\">var<\/span>.applications\n  network_interface_id      = azurerm_network_interface.app&#91;each.key].id\n  network_security_group_id = azurerm_network_security_group.lab.id\n}\n\nresource <span class=\"hljs-string\">\"azurerm_linux_virtual_machine\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = <span class=\"hljs-keyword\">var<\/span>.applications\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-vm\"<\/span>\n  computer_name       = <span class=\"hljs-string\">\"${local.prefix}-${each.key}\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = each.value.vm_size\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;\n    azurerm_network_interface.app&#91;each.key].id\n  ]\n  disable_password_authentication = <span class=\"hljs-literal\">true<\/span>\n\n  admin_ssh_key {\n    username   = <span class=\"hljs-keyword\">var<\/span>.admin_username\n    public_key = <span class=\"hljs-keyword\">var<\/span>.ssh_public_key\n  }\n\n  os_disk {\n    caching              = <span class=\"hljs-string\">\"ReadWrite\"<\/span>\n    storage_account_type = <span class=\"hljs-string\">\"Standard_LRS\"<\/span>\n  }\n\n  source_image_reference {\n    publisher = <span class=\"hljs-string\">\"Canonical\"<\/span>\n    offer     = <span class=\"hljs-string\">\"0001-com-ubuntu-server-jammy\"<\/span>\n    sku       = <span class=\"hljs-string\">\"22_04-lts-gen2\"<\/span>\n    version   = <span class=\"hljs-string\">\"latest\"<\/span>\n  }\n\n  tags = {\n    Application = each.key\n    Environment = each.value.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"vm_ids_by_application\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, vm <span class=\"hljs-keyword\">in<\/span> azurerm_linux_virtual_machine.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> vm.id }\n}\n\noutput <span class=\"hljs-string\">\"public_ips_by_application\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, pip <span class=\"hljs-keyword\">in<\/span> azurerm_public_ip.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> pip.ip_address }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform init\nterraform fmt\nterraform validate\nterraform plan \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_public_key=$(cat ~\/.ssh\/id_ed25519.pub)\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform apply \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_public_key=$(cat ~\/.ssh\/id_ed25519.pub)\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform output\nterraform destroy \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_public_key=$(cat ~\/.ssh\/id_ed25519.pub)\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><strong>Expected:<\/strong>&nbsp;Three VMs, each with its own public IP, NIC, and stable key. Azure resource names have restrictions; keep names short and use supported characters.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">6. Lab 3 &#8212;&nbsp;<code>for<\/code>&nbsp;expressions: transform collections<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">How&nbsp;<code>for<\/code>&nbsp;expressions work<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<code>for<\/code>&nbsp;expression reads items from a collection and builds a new list\/tuple or map\/object.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">List result:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">&#91;for name in var.names : upper(name)]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Map result:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">{ <span class=\"hljs-keyword\">for<\/span> name <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-keyword\">var<\/span>.names : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> upper(name) }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<code>for<\/code>&nbsp;expression itself does not create cloud resources. It creates data that can be used by resources, outputs, or locals.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6A. AWS &#8212; build a map of instance metadata<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This is a complete EC2 example that uses a&nbsp;<code>for<\/code>&nbsp;expression to prepare names and output the resources as a map.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    aws = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/aws\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 5.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"aws\"<\/span> {\n  region = <span class=\"hljs-keyword\">var<\/span>.aws_region\n}\n\nvariable <span class=\"hljs-string\">\"aws_region\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"ap-northeast-1\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ami_id\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"names\"<\/span> {\n  type    = list(string)\n  <span class=\"hljs-keyword\">default<\/span> = &#91;<span class=\"hljs-string\">\"frontend\"<\/span>, <span class=\"hljs-string\">\"backend\"<\/span>, <span class=\"hljs-string\">\"worker\"<\/span>]\n}\n\nlocals {\n  normalized_names = &#91;<span class=\"hljs-keyword\">for<\/span> name <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-keyword\">var<\/span>.names : lower(trimspace(name))]\n  name_to_tag      = { <span class=\"hljs-keyword\">for<\/span> name <span class=\"hljs-keyword\">in<\/span> local.normalized_names : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> upper(name) }\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"tf-for-lab-\"<\/span>\n\n  ingress {\n    from_port   = <span class=\"hljs-number\">22<\/span>\n    to_port     = <span class=\"hljs-number\">22<\/span>\n    protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-keyword\">var<\/span>.ssh_cidr]\n  }\n\n  egress {\n    from_port   = <span class=\"hljs-number\">0<\/span>\n    to_port     = <span class=\"hljs-number\">0<\/span>\n    protocol    = <span class=\"hljs-string\">\"-1\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"0.0.0.0\/0\"<\/span>]\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each               = toset(local.normalized_names)\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name          = <span class=\"hljs-string\">\"for-${each.key}\"<\/span>\n    NormalizedTag = local.name_to_tag&#91;each.key]\n  }\n}\n\noutput <span class=\"hljs-string\">\"normalized_names\"<\/span> {\n  value = local.normalized_names\n}\n\noutput <span class=\"hljs-string\">\"uppercase_map\"<\/span> {\n  value = local.name_to_tag\n}\n\noutput <span class=\"hljs-string\">\"instance_ids\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, instance <span class=\"hljs-keyword\">in<\/span> aws_instance.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> instance.id }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with the standard AWS workflow and supply&nbsp;<code>ami_id<\/code>&nbsp;and&nbsp;<code>ssh_cidr<\/code>. Change the&nbsp;<code>names<\/code>&nbsp;list to experiment. Since this lab uses a set for&nbsp;<code>for_each<\/code>, duplicate names collapse to one key. Keep names unique to avoid confusing results.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6B. Azure &#8212; transform names and create VMs from the resulting collection<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    azurerm = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/azurerm\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 4.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"azurerm\"<\/span> {\n  features {}\n  resource_provider_registrations = <span class=\"hljs-string\">\"none\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"location\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"Japan East\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"admin_username\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"azureuser\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_public_key\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"names\"<\/span> {\n  type    = list(string)\n  <span class=\"hljs-keyword\">default<\/span> = &#91;<span class=\"hljs-string\">\"frontend\"<\/span>, <span class=\"hljs-string\">\"backend\"<\/span>, <span class=\"hljs-string\">\"worker\"<\/span>]\n}\n\nlocals {\n  normalized_names = &#91;<span class=\"hljs-keyword\">for<\/span> name <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-keyword\">var<\/span>.names : lower(trimspace(name))]\n  name_to_tag      = { <span class=\"hljs-keyword\">for<\/span> name <span class=\"hljs-keyword\">in<\/span> local.normalized_names : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> upper(name) }\n  prefix           = <span class=\"hljs-string\">\"tffor\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"${local.prefix}-rg\"<\/span>\n  location = <span class=\"hljs-keyword\">var<\/span>.location\n}\n\nresource <span class=\"hljs-string\">\"azurerm_virtual_network\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.120.0.0\/16\"<\/span>]\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n}\n\nresource <span class=\"hljs-string\">\"azurerm_subnet\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                 = <span class=\"hljs-string\">\"default\"<\/span>\n  resource_group_name  = azurerm_resource_group.lab.name\n  virtual_network_name = azurerm_virtual_network.lab.name\n  address_prefixes     = &#91;<span class=\"hljs-string\">\"10.120.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-nsg\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  security_rule {\n    name                       = <span class=\"hljs-string\">\"AllowSSHFromStudent\"<\/span>\n    priority                   = <span class=\"hljs-number\">100<\/span>\n    direction                  = <span class=\"hljs-string\">\"Inbound\"<\/span>\n    access                     = <span class=\"hljs-string\">\"Allow\"<\/span>\n    protocol                   = <span class=\"hljs-string\">\"Tcp\"<\/span>\n    source_port_range          = <span class=\"hljs-string\">\"*\"<\/span>\n    destination_port_range     = <span class=\"hljs-string\">\"22\"<\/span>\n    source_address_prefix      = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n    destination_address_prefix = <span class=\"hljs-string\">\"*\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = toset(local.normalized_names)\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-pip\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  allocation_method   = <span class=\"hljs-string\">\"Static\"<\/span>\n  sku                 = <span class=\"hljs-string\">\"Standard\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = toset(local.normalized_names)\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-nic\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  ip_configuration {\n    name                          = <span class=\"hljs-string\">\"internal\"<\/span>\n    subnet_id                     = azurerm_subnet.lab.id\n    private_ip_address_allocation = <span class=\"hljs-string\">\"Dynamic\"<\/span>\n    public_ip_address_id          = azurerm_public_ip.app&#91;each.key].id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each                  = toset(local.normalized_names)\n  network_interface_id      = azurerm_network_interface.app&#91;each.key].id\n  network_security_group_id = azurerm_network_security_group.lab.id\n}\n\nresource <span class=\"hljs-string\">\"azurerm_linux_virtual_machine\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = toset(local.normalized_names)\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-vm\"<\/span>\n  computer_name       = <span class=\"hljs-string\">\"${local.prefix}-${each.key}\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;\n    azurerm_network_interface.app&#91;each.key].id\n  ]\n  disable_password_authentication = <span class=\"hljs-literal\">true<\/span>\n\n  admin_ssh_key {\n    username   = <span class=\"hljs-keyword\">var<\/span>.admin_username\n    public_key = <span class=\"hljs-keyword\">var<\/span>.ssh_public_key\n  }\n\n  os_disk {\n    caching              = <span class=\"hljs-string\">\"ReadWrite\"<\/span>\n    storage_account_type = <span class=\"hljs-string\">\"Standard_LRS\"<\/span>\n  }\n\n  source_image_reference {\n    publisher = <span class=\"hljs-string\">\"Canonical\"<\/span>\n    offer     = <span class=\"hljs-string\">\"0001-com-ubuntu-server-jammy\"<\/span>\n    sku       = <span class=\"hljs-string\">\"22_04-lts-gen2\"<\/span>\n    version   = <span class=\"hljs-string\">\"latest\"<\/span>\n  }\n\n  tags = {\n    Application   = each.key\n    NormalizedTag = local.name_to_tag&#91;each.key]\n  }\n}\n\noutput <span class=\"hljs-string\">\"normalized_names\"<\/span> {\n  value = local.normalized_names\n}\n\noutput <span class=\"hljs-string\">\"uppercase_map\"<\/span> {\n  value = local.name_to_tag\n}\n\noutput <span class=\"hljs-string\">\"public_ips\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, pip <span class=\"hljs-keyword\">in<\/span> azurerm_public_ip.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> pip.ip_address }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with the standard Azure workflow and SSH inputs. The&nbsp;<code>for<\/code>&nbsp;expressions prepare the normalized list and map;&nbsp;<code>for_each<\/code>&nbsp;then creates one VM per unique normalized name.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">7. Lab 4 &#8212; Filtering with&nbsp;<code>for ... if<\/code><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The&nbsp;<code>if<\/code>&nbsp;at the end of a&nbsp;<code>for<\/code>&nbsp;expression filters elements. Only items for which the condition is true appear in the resulting collection.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">locals {\n  enabled_apps = {\n    <span class=\"hljs-keyword\">for<\/span> name, app <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-keyword\">var<\/span>.applications : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> app\n    <span class=\"hljs-keyword\">if<\/span> app.enabled\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">7A. AWS &#8212; create instances only for enabled applications<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    aws = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/aws\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 5.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"aws\"<\/span> {\n  region = <span class=\"hljs-keyword\">var<\/span>.aws_region\n}\n\nvariable <span class=\"hljs-string\">\"aws_region\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"ap-northeast-1\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ami_id\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"applications\"<\/span> {\n  type = map(object({\n    enabled      = bool\n    instance_type = string\n  }))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = { enabled = <span class=\"hljs-literal\">true<\/span>,  instance_type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\n    backend  = { enabled = <span class=\"hljs-literal\">true<\/span>,  instance_type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\n    sandbox  = { enabled = <span class=\"hljs-literal\">false<\/span>, instance_type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\n  }\n}\n\nlocals {\n  enabled_apps = {\n    <span class=\"hljs-keyword\">for<\/span> name, app <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-keyword\">var<\/span>.applications : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> app\n    <span class=\"hljs-keyword\">if<\/span> app.enabled\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"tf-filter-lab-\"<\/span>\n\n  ingress {\n    from_port   = <span class=\"hljs-number\">22<\/span>\n    to_port     = <span class=\"hljs-number\">22<\/span>\n    protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-keyword\">var<\/span>.ssh_cidr]\n  }\n\n  egress {\n    from_port   = <span class=\"hljs-number\">0<\/span>\n    to_port     = <span class=\"hljs-number\">0<\/span>\n    protocol    = <span class=\"hljs-string\">\"-1\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"0.0.0.0\/0\"<\/span>]\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each               = local.enabled_apps\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = each.value.instance_type\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name        = <span class=\"hljs-string\">\"filter-${each.key}\"<\/span>\n    Application = each.key\n  }\n}\n\noutput <span class=\"hljs-string\">\"enabled_app_names\"<\/span> {\n  value = keys(local.enabled_apps)\n}\n\noutput <span class=\"hljs-string\">\"instance_ids\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, instance <span class=\"hljs-keyword\">in<\/span> aws_instance.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> instance.id }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with the standard AWS workflow. The default creates&nbsp;<code>frontend<\/code>&nbsp;and&nbsp;<code>backend<\/code>;&nbsp;<code>sandbox<\/code>&nbsp;is filtered out. To enable it, change&nbsp;<code>enabled = false<\/code>&nbsp;to&nbsp;<code>true<\/code>&nbsp;in the variable default or provide a complete replacement map in a&nbsp;<code>terraform.tfvars<\/code>&nbsp;file.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7B. Azure &#8212; create VMs only for enabled applications<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    azurerm = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/azurerm\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 4.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"azurerm\"<\/span> {\n  features {}\n  resource_provider_registrations = <span class=\"hljs-string\">\"none\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"location\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"Japan East\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"admin_username\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"azureuser\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_public_key\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"applications\"<\/span> {\n  type = map(object({\n    enabled = bool\n    vm_size = string\n  }))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = { enabled = <span class=\"hljs-literal\">true<\/span>,  vm_size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span> }\n    backend  = { enabled = <span class=\"hljs-literal\">true<\/span>,  vm_size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span> }\n    sandbox  = { enabled = <span class=\"hljs-literal\">false<\/span>, vm_size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span> }\n  }\n}\n\nlocals {\n  prefix = <span class=\"hljs-string\">\"tffilter\"<\/span>\n  enabled_apps = {\n    <span class=\"hljs-keyword\">for<\/span> name, app <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-keyword\">var<\/span>.applications : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> app\n    <span class=\"hljs-keyword\">if<\/span> app.enabled\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"${local.prefix}-rg\"<\/span>\n  location = <span class=\"hljs-keyword\">var<\/span>.location\n}\n\nresource <span class=\"hljs-string\">\"azurerm_virtual_network\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.130.0.0\/16\"<\/span>]\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n}\n\nresource <span class=\"hljs-string\">\"azurerm_subnet\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                 = <span class=\"hljs-string\">\"default\"<\/span>\n  resource_group_name  = azurerm_resource_group.lab.name\n  virtual_network_name = azurerm_virtual_network.lab.name\n  address_prefixes     = &#91;<span class=\"hljs-string\">\"10.130.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-nsg\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  security_rule {\n    name                       = <span class=\"hljs-string\">\"AllowSSHFromStudent\"<\/span>\n    priority                   = <span class=\"hljs-number\">100<\/span>\n    direction                  = <span class=\"hljs-string\">\"Inbound\"<\/span>\n    access                     = <span class=\"hljs-string\">\"Allow\"<\/span>\n    protocol                   = <span class=\"hljs-string\">\"Tcp\"<\/span>\n    source_port_range          = <span class=\"hljs-string\">\"*\"<\/span>\n    destination_port_range     = <span class=\"hljs-string\">\"22\"<\/span>\n    source_address_prefix      = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n    destination_address_prefix = <span class=\"hljs-string\">\"*\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = local.enabled_apps\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-pip\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  allocation_method   = <span class=\"hljs-string\">\"Static\"<\/span>\n  sku                 = <span class=\"hljs-string\">\"Standard\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = local.enabled_apps\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-nic\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  ip_configuration {\n    name                          = <span class=\"hljs-string\">\"internal\"<\/span>\n    subnet_id                     = azurerm_subnet.lab.id\n    private_ip_address_allocation = <span class=\"hljs-string\">\"Dynamic\"<\/span>\n    public_ip_address_id          = azurerm_public_ip.app&#91;each.key].id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each                  = local.enabled_apps\n  network_interface_id      = azurerm_network_interface.app&#91;each.key].id\n  network_security_group_id = azurerm_network_security_group.lab.id\n}\n\nresource <span class=\"hljs-string\">\"azurerm_linux_virtual_machine\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each            = local.enabled_apps\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-vm\"<\/span>\n  computer_name       = <span class=\"hljs-string\">\"${local.prefix}-${each.key}\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = each.value.vm_size\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;azurerm_network_interface.app&#91;each.key].id]\n  disable_password_authentication = <span class=\"hljs-literal\">true<\/span>\n\n  admin_ssh_key {\n    username   = <span class=\"hljs-keyword\">var<\/span>.admin_username\n    public_key = <span class=\"hljs-keyword\">var<\/span>.ssh_public_key\n  }\n\n  os_disk {\n    caching              = <span class=\"hljs-string\">\"ReadWrite\"<\/span>\n    storage_account_type = <span class=\"hljs-string\">\"Standard_LRS\"<\/span>\n  }\n\n  source_image_reference {\n    publisher = <span class=\"hljs-string\">\"Canonical\"<\/span>\n    offer     = <span class=\"hljs-string\">\"0001-com-ubuntu-server-jammy\"<\/span>\n    sku       = <span class=\"hljs-string\">\"22_04-lts-gen2\"<\/span>\n    version   = <span class=\"hljs-string\">\"latest\"<\/span>\n  }\n\n  tags = {\n    Application = each.key\n  }\n}\n\noutput <span class=\"hljs-string\">\"enabled_app_names\"<\/span> {\n  value = keys(local.enabled_apps)\n}\n\noutput <span class=\"hljs-string\">\"public_ips\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, pip <span class=\"hljs-keyword\">in<\/span> azurerm_public_ip.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> pip.ip_address }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with the Azure workflow and SSH inputs. By default, only&nbsp;<code>frontend<\/code>&nbsp;and&nbsp;<code>backend<\/code>&nbsp;are created. Enabling&nbsp;<code>sandbox<\/code>&nbsp;creates its public IP, NIC, and VM.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">8. Lab 5 &#8212;&nbsp;<code>dynamic<\/code>&nbsp;blocks<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<code>dynamic<\/code>&nbsp;block generates nested blocks within a resource. It is not the same as&nbsp;<code>for_each<\/code>&nbsp;on a resource: &#8211;&nbsp;<code>for_each<\/code>&nbsp;on a resource creates multiple top-level resources. &#8211;&nbsp;<code>dynamic<\/code>&nbsp;creates multiple nested blocks inside one resource.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8A. AWS &#8212; dynamic security group ingress rules<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This example creates one security group and generates one ingress block per rule. SSH is restricted to your CIDR. HTTP is an example rule restricted to a private network range.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    aws = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/aws\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 5.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"aws\"<\/span> {\n  region = <span class=\"hljs-keyword\">var<\/span>.aws_region\n}\n\nvariable <span class=\"hljs-string\">\"aws_region\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"ap-northeast-1\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"enable_http_rule\"<\/span> {\n  type    = bool\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-literal\">true<\/span>\n}\n\nlocals {\n  fixed_rules = &#91;\n    {\n      name = <span class=\"hljs-string\">\"ssh\"<\/span>\n      port = <span class=\"hljs-number\">22<\/span>\n      cidr = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n    }\n  ]\n\n  optional_rules = <span class=\"hljs-keyword\">var<\/span>.enable_http_rule ? &#91;\n    {\n      name = <span class=\"hljs-string\">\"http-private\"<\/span>\n      port = <span class=\"hljs-number\">80<\/span>\n      cidr = <span class=\"hljs-string\">\"10.0.0.0\/8\"<\/span>\n    }\n  ] : &#91;]\n\n  ingress_rules = concat(local.fixed_rules, local.optional_rules)\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"tf-dynamic-lab-\"<\/span>\n  description = <span class=\"hljs-string\">\"Dynamic ingress rule demonstration\"<\/span>\n\n  dynamic <span class=\"hljs-string\">\"ingress\"<\/span> {\n    for_each = local.ingress_rules\n    iterator = rule\n\n    content {\n      description = rule.value.name\n      from_port   = rule.value.port\n      to_port     = rule.value.port\n      protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n      cidr_blocks = &#91;rule.value.cidr]\n    }\n  }\n\n  egress {\n    from_port   = <span class=\"hljs-number\">0<\/span>\n    to_port     = <span class=\"hljs-number\">0<\/span>\n    protocol    = <span class=\"hljs-string\">\"-1\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"0.0.0.0\/0\"<\/span>]\n  }\n\n  tags = {\n    Name = <span class=\"hljs-string\">\"tf-dynamic-lab-sg\"<\/span>\n  }\n}\n\noutput <span class=\"hljs-string\">\"configured_rules\"<\/span> {\n  value = local.ingress_rules\n}\n\noutput <span class=\"hljs-string\">\"security_group_id\"<\/span> {\n  value = aws_security_group.lab.id\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform init\nterraform fmt\nterraform validate\nterraform plan -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform apply -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\nterraform output\nterraform plan -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span> -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"enable_http_rule=false\"<\/span>\nterraform destroy -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">This lab creates a security group only, so it does not create an EC2 instance. The HTTP rule is limited to&nbsp;<code>10.0.0.0\/8<\/code>&nbsp;as an example and will not necessarily be reachable from your laptop.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8B. Azure &#8212; iterate NSG rules with&nbsp;<code>for_each<\/code><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Azure NSG rules are normally represented as separate&nbsp;<code>azurerm_network_security_rule<\/code>&nbsp;resources, so use&nbsp;<code>for_each<\/code>&nbsp;instead of a&nbsp;<code>dynamic<\/code>&nbsp;block for this provider pattern.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    azurerm = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/azurerm\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 4.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"azurerm\"<\/span> {\n  features {}\n  resource_provider_registrations = <span class=\"hljs-string\">\"none\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"location\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"Japan East\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"enable_http_rule\"<\/span> {\n  type    = bool\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-literal\">true<\/span>\n}\n\nlocals {\n  rules = merge(\n    {\n      ssh = {\n        priority = <span class=\"hljs-number\">100<\/span>\n        port     = <span class=\"hljs-string\">\"22\"<\/span>\n        source   = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n      }\n    },\n    <span class=\"hljs-keyword\">var<\/span>.enable_http_rule ? {\n      http = {\n        priority = <span class=\"hljs-number\">110<\/span>\n        port     = <span class=\"hljs-string\">\"80\"<\/span>\n        source   = <span class=\"hljs-string\">\"10.0.0.0\/8\"<\/span>\n      }\n    } : {}\n  )\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"tfdynamic-rg\"<\/span>\n  location = <span class=\"hljs-keyword\">var<\/span>.location\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfdynamic-nsg\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_rule\"<\/span> <span class=\"hljs-string\">\"rule\"<\/span> {\n  for_each                    = local.rules\n  name                        = <span class=\"hljs-string\">\"Allow-${each.key}\"<\/span>\n  priority                    = each.value.priority\n  direction                   = <span class=\"hljs-string\">\"Inbound\"<\/span>\n  access                      = <span class=\"hljs-string\">\"Allow\"<\/span>\n  protocol                    = <span class=\"hljs-string\">\"Tcp\"<\/span>\n  source_port_range           = <span class=\"hljs-string\">\"*\"<\/span>\n  destination_port_range      = each.value.port\n  source_address_prefix       = each.value.source\n  destination_address_prefix  = <span class=\"hljs-string\">\"*\"<\/span>\n  resource_group_name         = azurerm_resource_group.lab.name\n  network_security_group_name = azurerm_network_security_group.lab.name\n}\n\noutput <span class=\"hljs-string\">\"created_rule_names\"<\/span> {\n  value = keys(azurerm_network_security_rule.rule)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run&nbsp;<code>terraform init<\/code>,&nbsp;<code>terraform validate<\/code>, and&nbsp;<code>terraform plan -var=\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/code>. Set&nbsp;<code>-var=\"enable_http_rule=false\"<\/code>&nbsp;to omit the HTTP rule. Destroy the lab when finished. This lab focuses on iteration and NSG rules; the next labs demonstrate complete VM networking.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">9. Lab 6 &#8212; Nested iteration and&nbsp;<code>flatten<\/code><\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">When input data is nested, a&nbsp;<code>for<\/code>&nbsp;expression can create a nested list and&nbsp;<code>flatten()<\/code>&nbsp;can turn it into one list. The flattened list can then be converted to a map for&nbsp;<code>for_each<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Example input:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">variable <span class=\"hljs-string\">\"applications\"<\/span> {\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = &#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>]\n    backend  = &#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>]\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Desired combinations:&nbsp;<code>frontend-dev<\/code>,&nbsp;<code>frontend-test<\/code>,&nbsp;<code>backend-dev<\/code>,&nbsp;<code>backend-prod<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9A. AWS &#8212; one EC2 instance for each application\/environment pair<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    aws = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/aws\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 5.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"aws\"<\/span> {\n  region = <span class=\"hljs-keyword\">var<\/span>.aws_region\n}\n\nvariable <span class=\"hljs-string\">\"aws_region\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"ap-northeast-1\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ami_id\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"applications\"<\/span> {\n  type = map(<span class=\"hljs-keyword\">list<\/span>(string))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = &#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>]\n    backend  = &#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>]\n  }\n}\n\nlocals {\n  pairs_nested = &#91;\n    <span class=\"hljs-keyword\">for<\/span> app_name, environments in <span class=\"hljs-keyword\">var<\/span>.applications : &#91;\n      <span class=\"hljs-keyword\">for<\/span> environment in environments : {\n        key         = <span class=\"hljs-string\">\"${app_name}-${environment}\"<\/span>\n        app         = app_name\n        environment = environment\n      }\n    ]\n  ]\n\n  pairs = flatten(local.pairs_nested)\n  instances = {\n    <span class=\"hljs-keyword\">for<\/span> item in local.pairs : item.key =&gt; item\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"tf-flatten-lab-\"<\/span>\n\n  ingress {\n    from_port   = <span class=\"hljs-number\">22<\/span>\n    to_port     = <span class=\"hljs-number\">22<\/span>\n    protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-keyword\">var<\/span>.ssh_cidr]\n  }\n\n  egress {\n    from_port   = <span class=\"hljs-number\">0<\/span>\n    to_port     = <span class=\"hljs-number\">0<\/span>\n    protocol    = <span class=\"hljs-string\">\"-1\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"0.0.0.0\/0\"<\/span>]\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each               = local.instances\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name        = each.key\n    Application = each.value.app\n    Environment = each.value.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"instance_keys\"<\/span> {\n  value = keys(aws_instance.pair)\n}\n\noutput <span class=\"hljs-string\">\"instance_ids\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> key, instance in aws_instance.pair : key =&gt; instance.id }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with the usual AWS commands and inputs. Expect four instances. The&nbsp;<code>instances<\/code>&nbsp;map provides stable, descriptive keys.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9B. Azure &#8212; one Linux VM for each application\/environment pair<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    azurerm = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/azurerm\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 4.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"azurerm\"<\/span> {\n  features {}\n  resource_provider_registrations = <span class=\"hljs-string\">\"none\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"location\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"Japan East\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"admin_username\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"azureuser\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_public_key\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"applications\"<\/span> {\n  type = map(<span class=\"hljs-keyword\">list<\/span>(string))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = &#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>]\n    backend  = &#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>]\n  }\n}\n\nlocals {\n  prefix = <span class=\"hljs-string\">\"tfflatten\"<\/span>\n  pairs_nested = &#91;\n    <span class=\"hljs-keyword\">for<\/span> app_name, environments in <span class=\"hljs-keyword\">var<\/span>.applications : &#91;\n      <span class=\"hljs-keyword\">for<\/span> environment in environments : {\n        key         = <span class=\"hljs-string\">\"${app_name}-${environment}\"<\/span>\n        app         = app_name\n        environment = environment\n      }\n    ]\n  ]\n  pairs = flatten(local.pairs_nested)\n  instances = {\n    <span class=\"hljs-keyword\">for<\/span> item in local.pairs : item.key =&gt; item\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"${local.prefix}-rg\"<\/span>\n  location = <span class=\"hljs-keyword\">var<\/span>.location\n}\n\nresource <span class=\"hljs-string\">\"azurerm_virtual_network\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.140.0.0\/16\"<\/span>]\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n}\n\nresource <span class=\"hljs-string\">\"azurerm_subnet\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                 = <span class=\"hljs-string\">\"default\"<\/span>\n  resource_group_name  = azurerm_resource_group.lab.name\n  virtual_network_name = azurerm_virtual_network.lab.name\n  address_prefixes     = &#91;<span class=\"hljs-string\">\"10.140.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-nsg\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  security_rule {\n    name                       = <span class=\"hljs-string\">\"AllowSSHFromStudent\"<\/span>\n    priority                   = <span class=\"hljs-number\">100<\/span>\n    direction                  = <span class=\"hljs-string\">\"Inbound\"<\/span>\n    access                     = <span class=\"hljs-string\">\"Allow\"<\/span>\n    protocol                   = <span class=\"hljs-string\">\"Tcp\"<\/span>\n    source_port_range          = <span class=\"hljs-string\">\"*\"<\/span>\n    destination_port_range     = <span class=\"hljs-string\">\"22\"<\/span>\n    source_address_prefix      = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n    destination_address_prefix = <span class=\"hljs-string\">\"*\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each            = local.instances\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-pip\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  allocation_method   = <span class=\"hljs-string\">\"Static\"<\/span>\n  sku                 = <span class=\"hljs-string\">\"Standard\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each            = local.instances\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-nic\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n\n  ip_configuration {\n    name                          = <span class=\"hljs-string\">\"internal\"<\/span>\n    subnet_id                     = azurerm_subnet.lab.id\n    private_ip_address_allocation = <span class=\"hljs-string\">\"Dynamic\"<\/span>\n    public_ip_address_id          = azurerm_public_ip.pair&#91;each.key].id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each                  = local.instances\n  network_interface_id      = azurerm_network_interface.pair&#91;each.key].id\n  network_security_group_id = azurerm_network_security_group.lab.id\n}\n\nresource <span class=\"hljs-string\">\"azurerm_linux_virtual_machine\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each            = local.instances\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-vm\"<\/span>\n  computer_name       = <span class=\"hljs-string\">\"${local.prefix}-${each.key}\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;azurerm_network_interface.pair&#91;each.key].id]\n  disable_password_authentication = <span class=\"hljs-keyword\">true<\/span>\n\n  admin_ssh_key {\n    username   = <span class=\"hljs-keyword\">var<\/span>.admin_username\n    public_key = <span class=\"hljs-keyword\">var<\/span>.ssh_public_key\n  }\n\n  os_disk {\n    caching              = <span class=\"hljs-string\">\"ReadWrite\"<\/span>\n    storage_account_type = <span class=\"hljs-string\">\"Standard_LRS\"<\/span>\n  }\n\n  source_image_reference {\n    publisher = <span class=\"hljs-string\">\"Canonical\"<\/span>\n    offer     = <span class=\"hljs-string\">\"0001-com-ubuntu-server-jammy\"<\/span>\n    sku       = <span class=\"hljs-string\">\"22_04-lts-gen2\"<\/span>\n    version   = <span class=\"hljs-string\">\"latest\"<\/span>\n  }\n\n  tags = {\n    Application = each.value.app\n    Environment = each.value.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"instance_keys\"<\/span> {\n  value = keys(azurerm_linux_virtual_machine.pair)\n}\n\noutput <span class=\"hljs-string\">\"public_ips\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> key, pip in azurerm_public_ip.pair : key =&gt; pip.ip_address }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with the Azure workflow and SSH inputs. Expect four VMs. If you change the nested lists, inspect the plan carefully: removed keys cause the corresponding VMs and network resources to be destroyed.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">10. Lab 7 &#8212;&nbsp;<code>setproduct<\/code>&nbsp;for combinations<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><code>setproduct()<\/code>&nbsp;returns combinations from two or more collections. It is useful for combinations such as each application across each environment. Only use it when all combinations are truly desired.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7A. AWS &#8212; create EC2 instances across app and environment combinations<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    aws = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/aws\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 5.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"aws\"<\/span> {\n  region = <span class=\"hljs-keyword\">var<\/span>.aws_region\n}\n\nvariable <span class=\"hljs-string\">\"aws_region\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"ap-northeast-1\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ami_id\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"applications\"<\/span> {\n  type    = set(string)\n  <span class=\"hljs-keyword\">default<\/span> = &#91;<span class=\"hljs-string\">\"frontend\"<\/span>, <span class=\"hljs-string\">\"backend\"<\/span>]\n}\n\nvariable <span class=\"hljs-string\">\"environments\"<\/span> {\n  type    = set(string)\n  <span class=\"hljs-keyword\">default<\/span> = &#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>]\n}\n\nlocals {\n  combinations = &#91;\n    <span class=\"hljs-keyword\">for<\/span> pair in setproduct(<span class=\"hljs-keyword\">var<\/span>.applications, <span class=\"hljs-keyword\">var<\/span>.environments) : {\n      app         = pair&#91;<span class=\"hljs-number\">0<\/span>]\n      environment = pair&#91;<span class=\"hljs-number\">1<\/span>]\n      key         = <span class=\"hljs-string\">\"${pair&#91;0]}-${pair&#91;1]}\"<\/span>\n    }\n  ]\n\n  instances = { <span class=\"hljs-keyword\">for<\/span> item in local.combinations : item.key =&gt; item }\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"tf-product-lab-\"<\/span>\n\n  ingress {\n    from_port   = <span class=\"hljs-number\">22<\/span>\n    to_port     = <span class=\"hljs-number\">22<\/span>\n    protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-keyword\">var<\/span>.ssh_cidr]\n  }\n\n  egress {\n    from_port   = <span class=\"hljs-number\">0<\/span>\n    to_port     = <span class=\"hljs-number\">0<\/span>\n    protocol    = <span class=\"hljs-string\">\"-1\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"0.0.0.0\/0\"<\/span>]\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each               = local.instances\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name        = each.key\n    Application = each.value.app\n    Environment = each.value.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"combination_keys\"<\/span> {\n  value = keys(aws_instance.pair)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with AWS inputs. The defaults create four EC2 instances: frontend-dev, frontend-test, backend-dev, and backend-test.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7B. Azure &#8212; create Linux VMs across app and environment combinations<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    azurerm = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/azurerm\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 4.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"azurerm\"<\/span> {\n  features {}\n  resource_provider_registrations = <span class=\"hljs-string\">\"none\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"location\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"Japan East\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"admin_username\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"azureuser\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_public_key\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"applications\"<\/span> {\n  type    = set(string)\n  <span class=\"hljs-keyword\">default<\/span> = &#91;<span class=\"hljs-string\">\"frontend\"<\/span>, <span class=\"hljs-string\">\"backend\"<\/span>]\n}\n\nvariable <span class=\"hljs-string\">\"environments\"<\/span> {\n  type    = set(string)\n  <span class=\"hljs-keyword\">default<\/span> = &#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>]\n}\n\nlocals {\n  prefix = <span class=\"hljs-string\">\"tfproduct\"<\/span>\n  combinations = &#91;\n    <span class=\"hljs-keyword\">for<\/span> pair in setproduct(<span class=\"hljs-keyword\">var<\/span>.applications, <span class=\"hljs-keyword\">var<\/span>.environments) : {\n      app         = pair&#91;<span class=\"hljs-number\">0<\/span>]\n      environment = pair&#91;<span class=\"hljs-number\">1<\/span>]\n      key         = <span class=\"hljs-string\">\"${pair&#91;0]}-${pair&#91;1]}\"<\/span>\n    }\n  ]\n  instances = { <span class=\"hljs-keyword\">for<\/span> item in local.combinations : item.key =&gt; item }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"${local.prefix}-rg\"<\/span>\n  location = <span class=\"hljs-keyword\">var<\/span>.location\n}\n\nresource <span class=\"hljs-string\">\"azurerm_virtual_network\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.150.0.0\/16\"<\/span>]\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n}\n\nresource <span class=\"hljs-string\">\"azurerm_subnet\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                 = <span class=\"hljs-string\">\"default\"<\/span>\n  resource_group_name  = azurerm_resource_group.lab.name\n  virtual_network_name = azurerm_virtual_network.lab.name\n  address_prefixes     = &#91;<span class=\"hljs-string\">\"10.150.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-nsg\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  security_rule {\n    name                       = <span class=\"hljs-string\">\"AllowSSHFromStudent\"<\/span>\n    priority                   = <span class=\"hljs-number\">100<\/span>\n    direction                  = <span class=\"hljs-string\">\"Inbound\"<\/span>\n    access                     = <span class=\"hljs-string\">\"Allow\"<\/span>\n    protocol                   = <span class=\"hljs-string\">\"Tcp\"<\/span>\n    source_port_range          = <span class=\"hljs-string\">\"*\"<\/span>\n    destination_port_range     = <span class=\"hljs-string\">\"22\"<\/span>\n    source_address_prefix      = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n    destination_address_prefix = <span class=\"hljs-string\">\"*\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each            = local.instances\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-pip\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  allocation_method   = <span class=\"hljs-string\">\"Static\"<\/span>\n  sku                 = <span class=\"hljs-string\">\"Standard\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each            = local.instances\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-nic\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  ip_configuration {\n    name                          = <span class=\"hljs-string\">\"internal\"<\/span>\n    subnet_id                     = azurerm_subnet.lab.id\n    private_ip_address_allocation = <span class=\"hljs-string\">\"Dynamic\"<\/span>\n    public_ip_address_id          = azurerm_public_ip.pair&#91;each.key].id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each                  = local.instances\n  network_interface_id      = azurerm_network_interface.pair&#91;each.key].id\n  network_security_group_id = azurerm_network_security_group.lab.id\n}\n\nresource <span class=\"hljs-string\">\"azurerm_linux_virtual_machine\"<\/span> <span class=\"hljs-string\">\"pair\"<\/span> {\n  for_each            = local.instances\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-vm\"<\/span>\n  computer_name       = <span class=\"hljs-string\">\"${local.prefix}-${each.key}\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;azurerm_network_interface.pair&#91;each.key].id]\n  disable_password_authentication = <span class=\"hljs-keyword\">true<\/span>\n\n  admin_ssh_key {\n    username   = <span class=\"hljs-keyword\">var<\/span>.admin_username\n    public_key = <span class=\"hljs-keyword\">var<\/span>.ssh_public_key\n  }\n\n  os_disk {\n    caching              = <span class=\"hljs-string\">\"ReadWrite\"<\/span>\n    storage_account_type = <span class=\"hljs-string\">\"Standard_LRS\"<\/span>\n  }\n\n  source_image_reference {\n    publisher = <span class=\"hljs-string\">\"Canonical\"<\/span>\n    offer     = <span class=\"hljs-string\">\"0001-com-ubuntu-server-jammy\"<\/span>\n    sku       = <span class=\"hljs-string\">\"22_04-lts-gen2\"<\/span>\n    version   = <span class=\"hljs-string\">\"latest\"<\/span>\n  }\n\n  tags = {\n    Application = each.value.app\n    Environment = each.value.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"combination_keys\"<\/span> {\n  value = keys(azurerm_linux_virtual_machine.pair)\n}\n\noutput <span class=\"hljs-string\">\"public_ips\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> key, pip in azurerm_public_ip.pair : key =&gt; pip.ip_address }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with Azure inputs. Expect four VMs. Before scaling this pattern up, calculate the number of combinations: the total is the product of the collection sizes.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">11. Lab 8 &#8212; Iterating over objects and maps<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A map of objects lets each resource have its own settings. For example, each VM may have a name, size, and environment tag.&nbsp;<code>each.value<\/code>&nbsp;accesses that object&#8217;s attributes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8A. AWS &#8212; per-instance configuration<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    aws = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/aws\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 5.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"aws\"<\/span> {\n  region = <span class=\"hljs-keyword\">var<\/span>.aws_region\n}\n\nvariable <span class=\"hljs-string\">\"aws_region\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"ap-northeast-1\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ami_id\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"servers\"<\/span> {\n  type = map(object({\n    instance_type = string\n    owner         = string\n    environment   = string\n  }))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    api = {\n      instance_type = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n      owner         = <span class=\"hljs-string\">\"platform\"<\/span>\n      environment   = <span class=\"hljs-string\">\"dev\"<\/span>\n    }\n    batch = {\n      instance_type = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n      owner         = <span class=\"hljs-string\">\"data\"<\/span>\n      environment   = <span class=\"hljs-string\">\"test\"<\/span>\n    }\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"tf-object-lab-\"<\/span>\n\n  ingress {\n    from_port   = <span class=\"hljs-number\">22<\/span>\n    to_port     = <span class=\"hljs-number\">22<\/span>\n    protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-keyword\">var<\/span>.ssh_cidr]\n  }\n\n  egress {\n    from_port   = <span class=\"hljs-number\">0<\/span>\n    to_port     = <span class=\"hljs-number\">0<\/span>\n    protocol    = <span class=\"hljs-string\">\"-1\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"0.0.0.0\/0\"<\/span>]\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"server\"<\/span> {\n  for_each               = <span class=\"hljs-keyword\">var<\/span>.servers\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = each.value.instance_type\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name        = each.key\n    Owner       = each.value.owner\n    Environment = each.value.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"server_configuration\"<\/span> {\n  value = {\n    <span class=\"hljs-keyword\">for<\/span> name, instance <span class=\"hljs-keyword\">in<\/span> aws_instance.server :\n    <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> {\n      id        = instance.id\n      public_ip = instance.public_ip\n    }\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with AWS inputs. Inspect the tags in the EC2 console and&nbsp;<code>terraform output<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8B. Azure &#8212; per-VM configuration<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n  required_providers {\n    azurerm = {\n      source  = <span class=\"hljs-string\">\"hashicorp\/azurerm\"<\/span>\n      version = <span class=\"hljs-string\">\"~&gt; 4.0\"<\/span>\n    }\n  }\n}\n\nprovider <span class=\"hljs-string\">\"azurerm\"<\/span> {\n  features {}\n  resource_provider_registrations = <span class=\"hljs-string\">\"none\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"location\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"Japan East\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"admin_username\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"azureuser\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"ssh_public_key\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nvariable <span class=\"hljs-string\">\"servers\"<\/span> {\n  type = map(object({\n    vm_size     = string\n    owner       = string\n    environment = string\n  }))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    api = {\n      vm_size     = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n      owner       = <span class=\"hljs-string\">\"platform\"<\/span>\n      environment = <span class=\"hljs-string\">\"dev\"<\/span>\n    }\n    batch = {\n      vm_size     = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n      owner       = <span class=\"hljs-string\">\"data\"<\/span>\n      environment = <span class=\"hljs-string\">\"test\"<\/span>\n    }\n  }\n}\n\nlocals {\n  prefix = <span class=\"hljs-string\">\"tfobject\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"${local.prefix}-rg\"<\/span>\n  location = <span class=\"hljs-keyword\">var<\/span>.location\n}\n\nresource <span class=\"hljs-string\">\"azurerm_virtual_network\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.160.0.0\/16\"<\/span>]\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n}\n\nresource <span class=\"hljs-string\">\"azurerm_subnet\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                 = <span class=\"hljs-string\">\"default\"<\/span>\n  resource_group_name  = azurerm_resource_group.lab.name\n  virtual_network_name = azurerm_virtual_network.lab.name\n  address_prefixes     = &#91;<span class=\"hljs-string\">\"10.160.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-nsg\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  security_rule {\n    name                       = <span class=\"hljs-string\">\"AllowSSHFromStudent\"<\/span>\n    priority                   = <span class=\"hljs-number\">100<\/span>\n    direction                  = <span class=\"hljs-string\">\"Inbound\"<\/span>\n    access                     = <span class=\"hljs-string\">\"Allow\"<\/span>\n    protocol                   = <span class=\"hljs-string\">\"Tcp\"<\/span>\n    source_port_range          = <span class=\"hljs-string\">\"*\"<\/span>\n    destination_port_range     = <span class=\"hljs-string\">\"22\"<\/span>\n    source_address_prefix      = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr\n    destination_address_prefix = <span class=\"hljs-string\">\"*\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"server\"<\/span> {\n  for_each            = <span class=\"hljs-keyword\">var<\/span>.servers\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-pip\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  allocation_method   = <span class=\"hljs-string\">\"Static\"<\/span>\n  sku                 = <span class=\"hljs-string\">\"Standard\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface\"<\/span> <span class=\"hljs-string\">\"server\"<\/span> {\n  for_each            = <span class=\"hljs-keyword\">var<\/span>.servers\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-nic\"<\/span>\n  location            = azurerm_resource_group.lab.location\n  resource_group_name = azurerm_resource_group.lab.name\n  ip_configuration {\n    name                          = <span class=\"hljs-string\">\"internal\"<\/span>\n    subnet_id                     = azurerm_subnet.lab.id\n    private_ip_address_allocation = <span class=\"hljs-string\">\"Dynamic\"<\/span>\n    public_ip_address_id          = azurerm_public_ip.server&#91;each.key].id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"server\"<\/span> {\n  for_each                  = <span class=\"hljs-keyword\">var<\/span>.servers\n  network_interface_id      = azurerm_network_interface.server&#91;each.key].id\n  network_security_group_id = azurerm_network_security_group.lab.id\n}\n\nresource <span class=\"hljs-string\">\"azurerm_linux_virtual_machine\"<\/span> <span class=\"hljs-string\">\"server\"<\/span> {\n  for_each            = <span class=\"hljs-keyword\">var<\/span>.servers\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-vm\"<\/span>\n  computer_name       = <span class=\"hljs-string\">\"${local.prefix}-${each.key}\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = each.value.vm_size\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;azurerm_network_interface.server&#91;each.key].id]\n  disable_password_authentication = <span class=\"hljs-literal\">true<\/span>\n\n  admin_ssh_key {\n    username   = <span class=\"hljs-keyword\">var<\/span>.admin_username\n    public_key = <span class=\"hljs-keyword\">var<\/span>.ssh_public_key\n  }\n\n  os_disk {\n    caching              = <span class=\"hljs-string\">\"ReadWrite\"<\/span>\n    storage_account_type = <span class=\"hljs-string\">\"Standard_LRS\"<\/span>\n  }\n\n  source_image_reference {\n    publisher = <span class=\"hljs-string\">\"Canonical\"<\/span>\n    offer     = <span class=\"hljs-string\">\"0001-com-ubuntu-server-jammy\"<\/span>\n    sku       = <span class=\"hljs-string\">\"22_04-lts-gen2\"<\/span>\n    version   = <span class=\"hljs-string\">\"latest\"<\/span>\n  }\n\n  tags = {\n    Owner       = each.value.owner\n    Environment = each.value.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"server_configuration\"<\/span> {\n  value = {\n    <span class=\"hljs-keyword\">for<\/span> name, vm <span class=\"hljs-keyword\">in<\/span> azurerm_linux_virtual_machine.server :\n    <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> {\n      id        = vm.id\n      public_ip = azurerm_public_ip.server&#91;name].ip_address\n    }\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run with Azure SSH inputs. Each object drives the size and tags for the corresponding VM.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">12. Lab 9 &#8212; Conditional iteration<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Iteration and conditional logic can be combined. For example, use a map of services and include only those with&nbsp;<code>enabled = true<\/code>. This is useful for optional environments, apps, and infrastructure components.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9A. AWS &#8212; enabled instances and per-app types<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use the AWS filtering example from Lab 4 as the complete lab. Its key logic is:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">locals {\n  enabled_apps = {\n    <span class=\"hljs-keyword\">for<\/span> name, app in <span class=\"hljs-keyword\">var<\/span>.applications : name =&gt; app\n    <span class=\"hljs-keyword\">if<\/span> app.enabled\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each      = local.enabled_apps\n  ami           = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type = each.value.instance_type\n  <span class=\"hljs-comment\"># Include the security group and tags from Lab 4.<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The full standalone AWS configuration is in&nbsp;<strong>Lab 4A<\/strong>. Copy that entire example into its own directory to run it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9B. Azure &#8212; enabled VMs and related network resources<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use the Azure filtering example from Lab 4 as the complete lab. Its key logic is:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">locals {\n  enabled_apps = {\n    <span class=\"hljs-keyword\">for<\/span> name, app in <span class=\"hljs-keyword\">var<\/span>.applications : name =&gt; app\n    <span class=\"hljs-keyword\">if<\/span> app.enabled\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_linux_virtual_machine\"<\/span> <span class=\"hljs-string\">\"app\"<\/span> {\n  for_each = local.enabled_apps\n  <span class=\"hljs-comment\"># The full VM, NIC, public IP, and NSG configuration is in Lab 4B.<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">The full standalone Azure configuration is in&nbsp;<strong>Lab 4B<\/strong>. Copy that entire example into its own directory. The public IPs, NICs, associations, and VMs all use the same filtered map, so their keys stay aligned.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">13. Lab 10 &#8212; Iterating over modules<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform modules can use&nbsp;<code>count<\/code>&nbsp;or&nbsp;<code>for_each<\/code>, just like resources. This lab uses a local module so you can experiment without cloud costs. The same pattern can be applied to a module that provisions EC2 or Azure VMs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create this directory structure:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">module<\/span>-iteration-lab\/\n\u251c\u2500\u2500 main.tf\n\u2514\u2500\u2500 modules\/\n    \u2514\u2500\u2500 label\/\n        \u2514\u2500\u2500 main.tf\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Root&nbsp;<code>main.tf<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">terraform {\n  required_version = <span class=\"hljs-string\">\"&gt;= 1.3.0\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"labels\"<\/span> {\n  type    = set(string)\n  <span class=\"hljs-keyword\">default<\/span> = &#91;<span class=\"hljs-string\">\"frontend\"<\/span>, <span class=\"hljs-string\">\"backend\"<\/span>, <span class=\"hljs-string\">\"worker\"<\/span>]\n}\n\nmodule <span class=\"hljs-string\">\"label\"<\/span> {\n  source   = <span class=\"hljs-string\">\".\/modules\/label\"<\/span>\n  for_each = <span class=\"hljs-keyword\">var<\/span>.labels\n\n  label = each.key\n}\n\noutput <span class=\"hljs-string\">\"uppercase_labels\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, module_instance in module.label : name =&gt; module_instance.value }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\"><code>modules\/label\/main.tf<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">variable <span class=\"hljs-string\">\"label\"<\/span> {\n  type = string\n}\n\noutput <span class=\"hljs-string\">\"value\"<\/span> {\n  value = upper(<span class=\"hljs-keyword\">var<\/span>.label)\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">terraform init\nterraform fmt\nterraform validate\nterraform plan\nterraform apply\nterraform output\nterraform destroy\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Expected output is a map like:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">{\n  <span class=\"hljs-string\">\"backend\"<\/span>  = <span class=\"hljs-string\">\"BACKEND\"<\/span>\n  <span class=\"hljs-string\">\"frontend\"<\/span> = <span class=\"hljs-string\">\"FRONTEND\"<\/span>\n  <span class=\"hljs-string\">\"worker\"<\/span>   = <span class=\"hljs-string\">\"WORKER\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">No cloud resources are created in this lab.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">14.&nbsp;<code>count<\/code>&nbsp;vs&nbsp;<code>for_each<\/code><\/h2>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Question&nbsp;<code>count<\/code>&nbsp;<code>for_each<\/code><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Input type Integer Map or set of strings<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Resource address&nbsp;<code>[0]<\/code>,&nbsp;<code>[1]<\/code>, etc.&nbsp;<code>[\"key\"]<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Best use Numeric quantity or Named, independently on\/off managed resources<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Stable identity Index-based Key-based<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Typical risk Index changes can shift Changing a key changes identities the address<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Example addresses<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-35\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"># <span class=\"hljs-selector-tag\">count<\/span>\n<span class=\"hljs-selector-tag\">aws_instance<\/span><span class=\"hljs-selector-class\">.web<\/span><span class=\"hljs-selector-attr\">&#91;0]<\/span>\n\n# <span class=\"hljs-selector-tag\">for_each<\/span>\n<span class=\"hljs-selector-tag\">aws_instance<\/span><span class=\"hljs-selector-class\">.app<\/span><span class=\"hljs-selector-attr\">&#91;<span class=\"hljs-string\">\"frontend\"<\/span>]<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-35\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Prefer&nbsp;<code>for_each<\/code>&nbsp;when resources have meaningful names or different configuration. Prefer&nbsp;<code>count<\/code>&nbsp;for a simple number of interchangeable resources or a basic conditional resource.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">15. Common errors and troubleshooting<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Invalid&nbsp;<code>for_each<\/code>&nbsp;argument<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Cause:<\/strong>&nbsp;The value is not a map or set of strings, or Terraform cannot know the keys during planning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Use a map\/set and keys known before apply. A common pattern is to use known application names as keys and put computed IDs in values.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Invalid&nbsp;<code>count<\/code>&nbsp;argument<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Cause:<\/strong>&nbsp;Terraform cannot determine the number of instances during planning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Base&nbsp;<code>count<\/code>&nbsp;on known variables or configuration. Avoid using a resource attribute that is unknown until apply.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Invalid index when count is zero<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Cause:<\/strong>&nbsp;Code references&nbsp;<code>resource.example[0]<\/code>&nbsp;even though&nbsp;<code>count = 0<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Guard the reference with a conditional expression or use a splat expression such as&nbsp;<code>resource.example[*].id<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Duplicate keys in a&nbsp;<code>for<\/code>&nbsp;expression<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Cause:<\/strong>&nbsp;A map comprehension produces the same key more than once.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Make keys unique or use grouping mode (<code>...<\/code>) if grouping values under each key is intended.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Unexpected replacement when changing count<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Cause:<\/strong>&nbsp;Counted resources are indexed numerically. Removing or reordering list elements can change which object belongs to an index.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Use&nbsp;<code>for_each<\/code>&nbsp;with stable names for independently meaningful resources.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Azure VM size or quota error<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Cause:<\/strong>&nbsp;The size is not available in the region, restricted by policy, or exceeds subscription quota.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Verify regional availability, subscription quota, and policy. Terraform iteration cannot increase quota.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">AWS AMI not found<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Cause:<\/strong>&nbsp;AMI IDs are regional or stale.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Find a current Ubuntu AMI in the provider&#8217;s configured region.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">SSH does not work<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Check the source CIDR, public IP, routing, NSG\/security group, and private key. Supply the SSH&nbsp;<strong>public<\/strong>&nbsp;key to Azure. Do not expose SSH globally to solve a connectivity issue.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">16. Best practices<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Use\u00a0<code>for_each<\/code>\u00a0for named infrastructure that should retain stable identities.<\/li>\n\n\n\n<li>Use\u00a0<code>count<\/code>\u00a0for simple quantities and on\/off resources.<\/li>\n\n\n\n<li>Keep\u00a0<code>for<\/code>\u00a0expressions readable; use intermediate\u00a0<code>locals<\/code>\u00a0for complex transformations.<\/li>\n\n\n\n<li>Filter a collection before passing it to\u00a0<code>for_each<\/code>.<\/li>\n\n\n\n<li>Use the same key map for related resources such as public IPs, NICs, and VMs.<\/li>\n\n\n\n<li>Use\u00a0<code>dynamic<\/code>\u00a0only for nested blocks; it is not a replacement for resource\u00a0<code>for_each<\/code>.<\/li>\n\n\n\n<li>Check the plan after changing keys or counts because instances may be destroyed or replaced.<\/li>\n\n\n\n<li>Keep resource names unique and within cloud-provider naming restrictions.<\/li>\n\n\n\n<li>Pin provider major versions and review upgrades.<\/li>\n\n\n\n<li>Use least-privilege networking and keep secrets out of Terraform files.<\/li>\n\n\n\n<li>Keep each lab in its own directory or isolated state.<\/li>\n\n\n\n<li>Destroy lab infrastructure when finished.<\/li>\n<\/ol>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">17. Quick reference<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Task Syntax<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Repeat a resource N times&nbsp;<code>count = var.n<\/code>&nbsp;Access count index&nbsp;<code>count.index<\/code>&nbsp;Collect count outputs&nbsp;<code>resource.example[*].id<\/code>&nbsp;Repeat for each map\/set item&nbsp;<code>for_each = var.items<\/code>&nbsp;Access current key\/value&nbsp;<code>each.key<\/code>,&nbsp;<code>each.value<\/code>&nbsp;Transform a list&nbsp;<code>[for x in var.items : expression]<\/code>&nbsp;Build a map&nbsp;<code>{ for x in var.items : x.key =&gt; x.value }<\/code>&nbsp;Filter a collection&nbsp;<code>[for x in var.items : x if condition]<\/code>&nbsp;Filter a map&nbsp;<code>{ for k, v in var.map : k =&gt; v if condition }<\/code>&nbsp;Flatten nested lists&nbsp;<code>flatten(local.nested)<\/code>&nbsp;Convert list to set&nbsp;<code>toset(var.list)<\/code>&nbsp;Extract map keys&nbsp;<code>keys(var.map)<\/code>&nbsp;Extract map values&nbsp;<code>values(var.map)<\/code>&nbsp;Generate combinations&nbsp;<code>setproduct(var.a, var.b)<\/code>&nbsp;Generate nested blocks&nbsp;<code>dynamic \"block_name\" { for_each = ... }<\/code>&nbsp;Repeat module instances&nbsp;<code>module \"x\" { for_each = ... }<\/code><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">18. Practice exercises<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Exercise 1 &#8212; Count<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create two EC2 instances or Azure Linux VMs using&nbsp;<code>count<\/code>. Output all IDs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hint:<\/strong>&nbsp;<code>count = 2<\/code>; use a splat expression in the output.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Exercise 2 &#8212; for_each<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create resources for&nbsp;<code>frontend<\/code>,&nbsp;<code>backend<\/code>, and&nbsp;<code>worker<\/code>, each with a different tag.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hint:<\/strong>&nbsp;Use a map and&nbsp;<code>each.key<\/code>&nbsp;\/&nbsp;<code>each.value<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Exercise 3 &#8212; Filtering<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Given an object map containing&nbsp;<code>enabled = true\/false<\/code>, create only enabled resources.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hint:<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-36\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">locals {\n  enabled_items = {\n    <span class=\"hljs-keyword\">for<\/span> name, item <span class=\"hljs-keyword\">in<\/span> <span class=\"hljs-keyword\">var<\/span>.items : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> item\n    <span class=\"hljs-keyword\">if<\/span> item.enabled\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-36\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Exercise 4 &#8212; Transform a list<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Convert&nbsp;<code>[\"dev\", \"test\", \"prod\"]<\/code>&nbsp;to uppercase.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Answer:<\/strong><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-37\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">&#91;for environment in var.environments : upper(environment)]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-37\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h3 class=\"wp-block-heading\">Exercise 5 &#8212; Flatten<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Given a map of applications to environments, create one resource per app\/environment pair.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hint:<\/strong>&nbsp;Build a nested list with nested&nbsp;<code>for<\/code>&nbsp;expressions, call&nbsp;<code>flatten()<\/code>, and then convert the result to a map keyed by a unique string.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Exercise 6 &#8212; Dynamic blocks<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Generate multiple AWS security group ingress rules from a list of objects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hint:<\/strong>&nbsp;Define a list of rule objects and use&nbsp;<code>dynamic \"ingress\"<\/code>&nbsp;with&nbsp;<code>for_each<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Exercise 7 &#8212; Module iteration<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Call a local module once per item in a set of strings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Hint:<\/strong>&nbsp;<code>module \"example\" { for_each = var.items ... }<\/code>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Final checklist<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ ] I can explain the difference between\u00a0<code>count<\/code>\u00a0and\u00a0<code>for_each<\/code>.<\/li>\n\n\n\n<li>[ ] I can use\u00a0<code>for<\/code>\u00a0expressions to transform a collection.<\/li>\n\n\n\n<li>[ ] I can filter a map or list with\u00a0<code>if<\/code>.<\/li>\n\n\n\n<li>[ ] I understand when\u00a0<code>dynamic<\/code>\u00a0blocks are appropriate.<\/li>\n\n\n\n<li>[ ] I can flatten nested lists and generate combinations.<\/li>\n\n\n\n<li>[ ] I can read resource addresses in a Terraform plan.<\/li>\n\n\n\n<li>[ ] I checked all plans before applying.<\/li>\n\n\n\n<li>[ ] I destroyed all temporary cloud resources.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Key idea:<\/strong>&nbsp;<code>count<\/code>&nbsp;and&nbsp;<code>for_each<\/code>&nbsp;repeat resource or module instances;&nbsp;<code>for<\/code>&nbsp;expressions transform collections;&nbsp;<code>dynamic<\/code>&nbsp;blocks repeat nested configuration. Choose the construct that matches the job.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Terraform Loops and Iteration \u2014 Summary Table # Option \/ Method Purpose Input Common use case Creates resources? 1 count Repeats a resource or module a specified&#8230; <\/p>\n","protected":false},"author":1,"featured_media":7795,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[5129],"tags":[5449,5497,5496,5130],"class_list":["post-7493","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-terraform","tag-devopsschool","tag-iterations","tag-looping","tag-terraform"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/7493","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=7493"}],"version-history":[{"count":10,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/7493\/revisions"}],"predecessor-version":[{"id":79119,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/7493\/revisions\/79119"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media\/7795"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=7493"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=7493"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=7493"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}