{"id":12956,"date":"2026-10-13T08:33:31","date_gmt":"2026-10-13T08:33:31","guid":{"rendered":"https:\/\/www.devopsschool.com\/blog\/?p=12956"},"modified":"2026-10-13T08:33:33","modified_gmt":"2026-10-13T08:33:33","slug":"terraform-conditioning-example-program","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/terraform-conditioning-example-program\/","title":{"rendered":"Terraform Conditional Expressions and Logic: Complete Guide with Examples"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Terraform Conditional Expressions and Logic \u2014 Summary Table<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><tbody><tr><th>#<\/th><th>Concept<\/th><th>Purpose<\/th><th>Example<\/th><th>Creates Resources?<\/th><\/tr><tr><td>1<\/td><td>Ternary operator<\/td><td>Choose between two values<\/td><td><code>var.env == \"prod\" ? \"t3.large\" : \"t3.micro\"<\/code><\/td><td>No<\/td><\/tr><tr><td>2<\/td><td>Equality operators<\/td><td>Check equality or inequality<\/td><td><code>var.env == \"prod\"<\/code><\/td><td>No<\/td><\/tr><tr><td>3<\/td><td>Comparison operators<\/td><td>Compare values<\/td><td><code>var.count &gt; 2<\/code><\/td><td>No<\/td><\/tr><tr><td>4<\/td><td>Logical AND (<code>&amp;&amp;<\/code>)<\/td><td>All conditions must be true<\/td><td><code>var.env == \"prod\" &amp;&amp; var.monitoring<\/code><\/td><td>No<\/td><\/tr><tr><td>5<\/td><td>Logical OR (<code>\\|\\|<\/code>)<\/td><td>At least one condition must be true<\/td><td><code>var.env == \"prod\" \\|\\| var.env == \"stage\"<\/code><\/td><td>No<\/td><\/tr><tr><td>6<\/td><td>Logical NOT (<code>!<\/code>)<\/td><td>Reverse a Boolean value<\/td><td><code>!var.enable_public_ip<\/code><\/td><td>No<\/td><\/tr><tr><td>7<\/td><td>Parentheses<\/td><td>Group complex conditions<\/td><td><code>(var.env == \"prod\" \\|\\| var.env == \"stage\") &amp;&amp; var.enabled<\/code><\/td><td>No<\/td><\/tr><tr><td>8<\/td><td>Conditional <code>count<\/code><\/td><td>Create zero or one resource<\/td><td><code>count = var.enabled ? 1 : 0<\/code><\/td><td>Yes<\/td><\/tr><tr><td>9<\/td><td>Conditional <code>for_each<\/code><\/td><td>Create selected named resources<\/td><td><code>for_each = var.enabled ? var.instances : {}<\/code><\/td><td>Yes<\/td><\/tr><tr><td>10<\/td><td>Conditional <code>locals<\/code><\/td><td>Select configuration by environment<\/td><td><code>instance_type = var.env == \"prod\" ? \"t3.large\" : \"t3.micro\"<\/code><\/td><td>No<\/td><\/tr><tr><td>11<\/td><td>Filter with <code>for<\/code><\/td><td>Select collection elements that meet a condition<\/td><td><code>{ for k, v in var.rules : k =&gt; v if v.enabled }<\/code><\/td><td>No, but can feed <code>for_each<\/code><\/td><\/tr><tr><td>12<\/td><td><code>lookup()<\/code><\/td><td>Retrieve a map value with a default<\/td><td><code>lookup(var.sizes, var.env, \"t3.micro\")<\/code><\/td><td>No<\/td><\/tr><tr><td>13<\/td><td><code>try()<\/code><\/td><td>Fall back when an expression errors<\/td><td><code>try(var.settings.instance_type, \"t3.micro\")<\/code><\/td><td>No<\/td><\/tr><tr><td>14<\/td><td><code>can()<\/code><\/td><td>Check whether an expression evaluates without error<\/td><td><code>can(var.settings.port)<\/code><\/td><td>No<\/td><\/tr><tr><td>15<\/td><td><code>coalesce()<\/code><\/td><td>Return the first non-null, non-empty string<\/td><td><code>coalesce(var.name, \"default-name\")<\/code><\/td><td>No<\/td><\/tr><tr><td>16<\/td><td>Variable validation<\/td><td>Reject invalid input<\/td><td><code>validation { ... }<\/code><\/td><td>No<\/td><\/tr><tr><td>17<\/td><td>Preconditions<\/td><td>Enforce requirements before an operation<\/td><td><code>precondition { ... }<\/code><\/td><td>No<\/td><\/tr><tr><td>18<\/td><td>Postconditions<\/td><td>Verify a resource or data-source result<\/td><td><code>postcondition { ... }<\/code><\/td><td>No<\/td><\/tr><tr><td>19<\/td><td>Conditional <code>dynamic<\/code> block<\/td><td>Include nested configuration conditionally<\/td><td><code>for_each = var.enabled ? [1] : []<\/code><\/td><td>No standalone resource<\/td><\/tr><tr><td>20<\/td><td>Conditional module<\/td><td>Deploy a module only when needed<\/td><td><code>count = var.create_network ? 1 : 0<\/code><\/td><td>Yes, module instances<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Complete Master Guide with AWS and Azure Labs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Audience:<\/strong>&nbsp;Beginners to advanced DevOps \/ Cloud engineers<br><strong>Terraform:<\/strong>&nbsp;Terraform 1.5+ recommended (some examples use features available in Terraform 1.2+)<br><strong>Clouds:<\/strong>&nbsp;AWS EC2 and Azure Linux Virtual Machines<br><strong>Format:<\/strong>&nbsp;Self-contained labs, explanations, run commands, expected outcomes, troubleshooting, and cleanup<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Table of Contents<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#1-learning-objectives\">Learning objectives<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#2-before-you-begin\">Before you begin<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#3-conditional-logic-the-basic-idea\">Conditional logic: the basic idea<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#4-lab-1--ternary-conditional-expression\">Lab 1 &#8212; Ternary conditional expression<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#5-lab-2--logical-operators-and-compound-conditions\">Lab 2 &#8212; Logical operators and compound conditions<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#6-lab-3--conditional-resource-creation-with-count\">Lab 3 &#8212; Conditional resource creation with count<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#7-lab-4--for_each-with-conditional-filtering\">Lab 4 &#8212; for_each with conditional filtering<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#8-lab-5--conditional-configuration-using-locals\">Lab 5 &#8212; Conditional configuration using locals<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#9-lab-6--dynamic-blocks-and-optional-nested-rules\">Lab 6 &#8212; Dynamic blocks and optional nested rules<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#10-lab-7--input-variable-validation\">Lab 7 &#8212; Input variable validation<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#11-lab-8--preconditions-and-postconditions\">Lab 8 &#8212; Preconditions and postconditions<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#12-lab-9--try-can-lookup-and-coalesce\">Lab 9 &#8212; try(), can(), lookup(), and coalesce()<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#13-lab-10--conditional-module-instances\">Lab 10 &#8212; Conditional module instances<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#14-important-patterns-and-gotchas\">Important patterns and gotchas<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#15-troubleshooting\">Troubleshooting<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#16-best-practices\">Best practices<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#17-quick-reference\">Quick reference<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#18-exercises-and-answers\">Exercises and answers<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/file+.vscode-resource.vscode-cdn.net\/Users\/rajesh\/Downloads\/terraform_conditional_expressions_master_guide.md#19-glossary\">Glossary<\/a><\/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 objectives<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">After completing this guide, you should be able to:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Choose a value using Terraform&#8217;s conditional (<code>condition ? true_value : false_value<\/code>) expression.<\/li>\n\n\n\n<li>Combine conditions using\u00a0<code>&amp;&amp;<\/code>,\u00a0<code>||<\/code>,\u00a0<code>!<\/code>, and comparison operators.<\/li>\n\n\n\n<li>Create zero, one, or many resources using\u00a0<code>count<\/code>\u00a0and\u00a0<code>for_each<\/code>.<\/li>\n\n\n\n<li>Filter collections using\u00a0<code>for<\/code>\u00a0expressions and\u00a0<code>if<\/code>.<\/li>\n\n\n\n<li>Generate nested configuration using\u00a0<code>dynamic<\/code>\u00a0blocks.<\/li>\n\n\n\n<li>Validate input values and enforce assumptions with preconditions and postconditions.<\/li>\n\n\n\n<li>Handle optional values and expression errors with\u00a0<code>try<\/code>,\u00a0<code>can<\/code>,\u00a0<code>lookup<\/code>, and\u00a0<code>coalesce<\/code>.<\/li>\n\n\n\n<li>Test a configuration with\u00a0<code>terraform plan<\/code>,\u00a0<code>apply<\/code>,\u00a0<code>output<\/code>, and\u00a0<code>destroy<\/code>.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">2. Before you begin<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Install and authenticate<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You need Terraform and credentials for the cloud you are testing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>AWS<\/strong>&nbsp;&#8211; Install the AWS CLI and Terraform. &#8211; Configure credentials, for example with&nbsp;<code>aws configure<\/code>, an AWS profile, or an IAM role. &#8211; The identity needs permission to create and delete EC2 instances and security groups. Depending on the lab, it may also need permissions for VPC-related resources. &#8211; Choose a region where your account can create the requested instance type.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Azure<\/strong>&nbsp;&#8211; Install Azure CLI and Terraform. &#8211; Sign in with&nbsp;<code>az login<\/code>. &#8211; Select the correct subscription:&nbsp;<code>az account set --subscription \"&lt;SUBSCRIPTION_ID_OR_NAME&gt;\"<\/code>. &#8211; Your identity needs permission to create and delete resource groups and networking\/compute resources. Subscription policy and regional quotas can affect VM creation.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check tools:<\/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\naz account show --output table\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<h3 class=\"wp-block-heading\">A safe lab workflow<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">For each lab: 1. Create a new, empty directory. 2. Save the complete example as&nbsp;<code>main.tf<\/code>. 3. Run&nbsp;<code>terraform init<\/code>. 4. Run&nbsp;<code>terraform fmt<\/code>. 5. Run&nbsp;<code>terraform validate<\/code>. 6. Review&nbsp;<code>terraform plan<\/code>. 7. Run&nbsp;<code>terraform apply<\/code>&nbsp;and confirm when ready. 8. Inspect the outputs and cloud console. 9. Run&nbsp;<code>terraform destroy<\/code>&nbsp;when finished.<\/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 warning:<\/strong>&nbsp;Applying cloud labs can incur charges. Destroy resources after testing. Some examples create public IP addresses or permit SSH only from an address you specify. Do not use&nbsp;<code>0.0.0.0\/0<\/code>&nbsp;for SSH in production. Never commit cloud credentials or private keys to source control.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">How the examples are organized<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Each cloud example below is intended to be a complete&nbsp;<code>main.tf<\/code>&nbsp;for that scenario. AWS examples create EC2 infrastructure. Azure VM examples include a resource group, virtual network, subnet, network interface, public IP, network security group, and Linux VM. For simplicity, examples use common Ubuntu image identifiers; image availability and cloud policies can vary by region and subscription.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3. Conditional logic: the basic idea<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform configuration is declarative. You describe the desired infrastructure, and Terraform determines the actions needed to reach that state. Terraform does not use ordinary procedural&nbsp;<code>if { ... } else { ... }<\/code>&nbsp;statements around resource blocks. Instead, conditions are expressed through values, collection filtering, meta-arguments, and validation constructs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The conditional expression<\/h3>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">condition ? value_if_true : value_if_false\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Example:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">variable <span class=\"hljs-string\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"dev\"<\/span>\n}\n\nlocals {\n  instance_type = <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"prod\"<\/span> ? <span class=\"hljs-string\">\"t3.medium\"<\/span> : <span class=\"hljs-string\">\"t3.micro\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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&nbsp;<code>environment<\/code>&nbsp;is&nbsp;<code>\"prod\"<\/code>,&nbsp;<code>instance_type<\/code>&nbsp;is&nbsp;<code>\"t3.medium\"<\/code>. Otherwise, it is&nbsp;<code>\"t3.micro\"<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Logical and comparison operators<\/h3>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Operator Meaning Example<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\"><code>==<\/code>&nbsp;Equal&nbsp;<code>var.environment == \"prod\"<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>!=<\/code>&nbsp;Not equal&nbsp;<code>var.environment != \"dev\"<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>&gt;<\/code>&nbsp;\/&nbsp;<code>&lt;<\/code>&nbsp;Greater \/ less than&nbsp;<code>var.instance_count &gt; 1<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>&gt;=<\/code>&nbsp;\/&nbsp;<code>&lt;=<\/code>&nbsp;Greater\/less than or&nbsp;<code>var.port &gt;= 1024<\/code>&nbsp;equal<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>&amp;&amp;<\/code>&nbsp;AND: both sides must be&nbsp;<code>var.enabled &amp;&amp; var.environment == \"prod\"<\/code>&nbsp;true<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code>||<\/code>&nbsp;OR: either side may be&nbsp;<code>var.environment == \"dev\" || var.environment == \"test\"<\/code>&nbsp;true<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><code>!<\/code>&nbsp;NOT: reverse a Boolean&nbsp;<code>!var.disabled<\/code><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Use parentheses for readability when combining multiple conditions.<\/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; Ternary conditional expression<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Goal<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Choose a smaller compute size for non-production and a larger size for production. This lab demonstrates a condition selecting a value; it does not conditionally omit the resource.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4A. AWS &#8212; choose EC2 instance type<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create&nbsp;<code>main.tf<\/code>:<\/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\">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\">\"environment\"<\/span> {\n  type        = string\n  description = <span class=\"hljs-string\">\"Set to dev or prod.\"<\/span>\n  <span class=\"hljs-keyword\">default<\/span>     = <span class=\"hljs-string\">\"dev\"<\/span>\n\n  validation {\n    condition     = contains(&#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n    error_message = <span class=\"hljs-string\">\"environment must be dev or prod.\"<\/span>\n  }\n}\n\nvariable <span class=\"hljs-string\">\"ami_id\"<\/span> {\n  type        = string\n  description = <span class=\"hljs-string\">\"A 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, for example 203.0.113.10\/32.\"<\/span>\n}\n\nlocals {\n  instance_type = <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"prod\"<\/span> ? <span class=\"hljs-string\">\"t3.small\"<\/span> : <span class=\"hljs-string\">\"t3.micro\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"web\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"conditional-lab-\"<\/span>\n  description = <span class=\"hljs-string\">\"SSH for a temporary Terraform conditional-expression lab\"<\/span>\n\n  ingress {\n    description = <span class=\"hljs-string\">\"SSH from the student's address 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\">\"conditional-lab-sg\"<\/span>\n  }\n}\n\nresource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"example\"<\/span> {\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = local.instance_type\n  vpc_security_group_ids = &#91;aws_security_group.web.id]\n\n  tags = {\n    Name        = <span class=\"hljs-string\">\"conditional-${var.environment}\"<\/span>\n    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"selected_instance_type\"<\/span> {\n  value = local.instance_type\n}\n\noutput <span class=\"hljs-string\">\"instance_id\"<\/span> {\n  value = aws_instance.example.id\n}\n\noutput <span class=\"hljs-string\">\"public_ip\"<\/span> {\n  value = aws_instance.example.public_ip\n}\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\">Run it (replace the placeholders with values valid for your account and region):<\/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 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-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\"><strong>Observe:<\/strong>&nbsp;With the default&nbsp;<code>environment = \"dev\"<\/code>, output&nbsp;<code>selected_instance_type<\/code>&nbsp;is&nbsp;<code>t3.micro<\/code>. To test production, add&nbsp;<code>-var=\"environment=prod\"<\/code>&nbsp;to both&nbsp;<code>plan<\/code>&nbsp;and&nbsp;<code>apply<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>AMI tip:<\/strong>&nbsp;AMI IDs are regional. Find a current Ubuntu AMI in the selected region using the AWS console or Canonical&#8217;s published images. Do not copy an AMI ID from a different region.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">4B. Azure &#8212; choose Linux VM size<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create&nbsp;<code>main.tf<\/code>:<\/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 {\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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"dev\"<\/span>\n\n  validation {\n    condition     = contains(&#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n    error_message = <span class=\"hljs-string\">\"environment must be dev or prod.\"<\/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, not the private 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, for example 203.0.113.10\/32.\"<\/span>\n}\n\nlocals {\n  vm_size = <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"prod\"<\/span> ? <span class=\"hljs-string\">\"Standard_B2s\"<\/span> : <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n  prefix  = <span class=\"hljs-string\">\"tfcond-${var.environment}\"<\/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.20.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.20.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-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_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\">\"AllowSSHFromMyIP\"<\/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_network_interface\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-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.lab.id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  network_interface_id      = azurerm_network_interface.lab.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\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vm\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = local.vm_size\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;\n    azurerm_network_interface.lab.id\n  ]\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    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"selected_vm_size\"<\/span> {\n  value = local.vm_size\n}\n\noutput <span class=\"hljs-string\">\"public_ip\"<\/span> {\n  value = azurerm_public_ip.lab.ip_address\n}\n\noutput <span class=\"hljs-string\">\"ssh_command\"<\/span> {\n  value = <span class=\"hljs-string\">\"ssh ${var.admin_username}@${azurerm_public_ip.lab.ip_address}\"<\/span>\n}\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\">Run:<\/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 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-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\">If you use a different public key file, substitute its path. If&nbsp;<code>~\/.ssh\/id_ed25519.pub<\/code>&nbsp;does not exist, create a key pair with&nbsp;<code>ssh-keygen -t ed25519<\/code>. Check that the selected VM size is available and permitted in the subscription and region.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Observe:<\/strong>&nbsp;The default selects&nbsp;<code>Standard_B1s<\/code>;&nbsp;<code>-var=\"environment=prod\"<\/code>&nbsp;selects&nbsp;<code>Standard_B2s<\/code>. These are example sizes, not a guarantee of regional availability or quota.<\/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; Logical operators and compound conditions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Goal<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use more than one input to decide a value. This is useful when production settings should be selected only when the environment is production&nbsp;<strong>and<\/strong>&nbsp;a feature is enabled.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5A. AWS &#8212; conditionally choose instance type<\/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-7\" 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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"prod\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"high_performance_enabled\"<\/span> {\n  type    = bool\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-literal\">true<\/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\nlocals {\n  use_large_instance = <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"prod\"<\/span> &amp;&amp; <span class=\"hljs-keyword\">var<\/span>.high_performance_enabled\n  instance_type      = local.use_large_instance ? <span class=\"hljs-string\">\"t3.small\"<\/span> : <span class=\"hljs-string\">\"t3.micro\"<\/span>\n  environment_class  = <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"dev\"<\/span> || <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"test\"<\/span> ? <span class=\"hljs-string\">\"nonproduction\"<\/span> : <span class=\"hljs-string\">\"production-like\"<\/span>\n  feature_disabled   = !<span class=\"hljs-keyword\">var<\/span>.high_performance_enabled\n}\n\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"logic-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\">\"lab\"<\/span> {\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = local.instance_type\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name               = <span class=\"hljs-string\">\"logic-lab\"<\/span>\n    EnvironmentClass   = local.environment_class\n    HighPerformanceOff = tostring(local.feature_disabled)\n  }\n}\n\noutput <span class=\"hljs-string\">\"use_large_instance\"<\/span> {\n  value = local.use_large_instance\n}\n\noutput <span class=\"hljs-string\">\"instance_type\"<\/span> {\n  value = local.instance_type\n}\n\noutput <span class=\"hljs-string\">\"environment_class\"<\/span> {\n  value = local.environment_class\n}\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\">Run with the same&nbsp;<code>terraform init<\/code>,&nbsp;<code>validate<\/code>,&nbsp;<code>plan<\/code>,&nbsp;<code>apply<\/code>,&nbsp;<code>output<\/code>, and&nbsp;<code>destroy<\/code>&nbsp;workflow used in Lab 1. Supply&nbsp;<code>ami_id<\/code>&nbsp;and&nbsp;<code>ssh_cidr<\/code>&nbsp;as variables. Try:<\/p>\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 plan \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_AMI\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ssh_cidr=YOUR_PUBLIC_IP\/32\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"environment=prod\"<\/span> \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"high_performance_enabled=true\"<\/span>\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\">Then change&nbsp;<code>high_performance_enabled=false<\/code>&nbsp;and inspect the plan. The selected instance type changes from&nbsp;<code>t3.small<\/code>&nbsp;to&nbsp;<code>t3.micro<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">5B. Azure &#8212; logical operators choose VM size<\/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-9\" 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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"prod\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"high_performance_enabled\"<\/span> {\n  type    = bool\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-literal\">true<\/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\nlocals {\n  use_large_vm       = <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"prod\"<\/span> &amp;&amp; <span class=\"hljs-keyword\">var<\/span>.high_performance_enabled\n  vm_size            = local.use_large_vm ? <span class=\"hljs-string\">\"Standard_B2s\"<\/span> : <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n  environment_class  = <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"dev\"<\/span> || <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"test\"<\/span> ? <span class=\"hljs-string\">\"nonproduction\"<\/span> : <span class=\"hljs-string\">\"production-like\"<\/span>\n  prefix             = <span class=\"hljs-string\">\"tflogic\"<\/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.30.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.30.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-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_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\">\"AllowSSHFromMyIP\"<\/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_network_interface\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-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.lab.id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  network_interface_id      = azurerm_network_interface.lab.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\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vm\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = local.vm_size\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;\n    azurerm_network_interface.lab.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    EnvironmentClass = local.environment_class\n  }\n}\n\noutput <span class=\"hljs-string\">\"use_large_vm\"<\/span> {\n  value = local.use_large_vm\n}\n\noutput <span class=\"hljs-string\">\"vm_size\"<\/span> {\n  value = local.vm_size\n}\n\noutput <span class=\"hljs-string\">\"environment_class\"<\/span> {\n  value = local.environment_class\n}\n\noutput <span class=\"hljs-string\">\"public_ip\"<\/span> {\n  value = azurerm_public_ip.lab.ip_address\n}\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\">Run the standard workflow and provide:<\/p>\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\">-<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-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\">Test these combinations: &#8211;&nbsp;<code>environment=prod<\/code>,&nbsp;<code>high_performance_enabled=true<\/code>&nbsp;\u2192 larger VM. &#8211;&nbsp;<code>environment=prod<\/code>,&nbsp;<code>high_performance_enabled=false<\/code>&nbsp;\u2192 smaller VM. &#8211;&nbsp;<code>environment=dev<\/code>,&nbsp;<code>high_performance_enabled=true<\/code>&nbsp;\u2192 smaller VM.<\/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; Conditional resource creation with count<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use&nbsp;<code>count = condition ? 1 : 0<\/code>&nbsp;when a resource should exist only when a condition is true. When the condition is false, Terraform plans zero instances of that resource.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Important:<\/strong>&nbsp;Resources using&nbsp;<code>count<\/code>&nbsp;are addressed with numeric indexes, such as&nbsp;<code>aws_instance.optional[0]<\/code>. Changing&nbsp;<code>count<\/code>&nbsp;from one to zero destroys that instance when you apply the change.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6A. AWS &#8212; optional EC2 instance<\/h3>\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 {\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\">\"create_instance\"<\/span> {\n  type    = bool\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-literal\">true<\/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\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"count-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\">\"optional\"<\/span> {\n  count                  = <span class=\"hljs-keyword\">var<\/span>.create_instance ? <span class=\"hljs-number\">1<\/span> : <span class=\"hljs-number\">0<\/span>\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\">\"optional-ec2\"<\/span>\n  }\n}\n\noutput <span class=\"hljs-string\">\"instance_ids\"<\/span> {\n  value = aws_instance.optional&#91;*].id\n}\n\noutput <span class=\"hljs-string\">\"instance_count\"<\/span> {\n  value = length(aws_instance.optional)\n}\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\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform init\nterraform validate\nterraform plan -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_AMI\"<\/span> -<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\">\"ami_id=ami-REPLACE_WITH_VALID_AMI\"<\/span> -<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-12\"><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 turn off the instance:<\/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\">terraform plan -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"create_instance=false\"<\/span> -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_AMI\"<\/span> -<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-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\">If the state currently contains the instance, applying this plan destroys it. Finish with&nbsp;<code>terraform destroy<\/code>, using the same required variable values.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">6B. Azure &#8212; optional Linux VM<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This example conditionally creates the VM. The network foundation remains present while&nbsp;<code>create_vm = false<\/code>, which makes the effect easy to observe.<\/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    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\">\"create_vm\"<\/span> {\n  type    = bool\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-literal\">true<\/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\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.40.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.40.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  count               = <span class=\"hljs-keyword\">var<\/span>.create_vm ? <span class=\"hljs-number\">1<\/span> : <span class=\"hljs-number\">0<\/span>\n  name                = <span class=\"hljs-string\">\"${local.prefix}-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_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\">\"AllowSSHFromMyIP\"<\/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_network_interface\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  count               = <span class=\"hljs-keyword\">var<\/span>.create_vm ? <span class=\"hljs-number\">1<\/span> : <span class=\"hljs-number\">0<\/span>\n  name                = <span class=\"hljs-string\">\"${local.prefix}-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.lab&#91;<span class=\"hljs-number\">0<\/span>].id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  count                     = <span class=\"hljs-keyword\">var<\/span>.create_vm ? <span class=\"hljs-number\">1<\/span> : <span class=\"hljs-number\">0<\/span>\n  network_interface_id      = azurerm_network_interface.lab&#91;<span class=\"hljs-number\">0<\/span>].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\">\"lab\"<\/span> {\n  count               = <span class=\"hljs-keyword\">var<\/span>.create_vm ? <span class=\"hljs-number\">1<\/span> : <span class=\"hljs-number\">0<\/span>\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vm\"<\/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.lab&#91;<span class=\"hljs-number\">0<\/span>].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\noutput <span class=\"hljs-string\">\"vm_count\"<\/span> {\n  value = length(azurerm_linux_virtual_machine.lab)\n}\n\noutput <span class=\"hljs-string\">\"public_ip\"<\/span> {\n  value = <span class=\"hljs-keyword\">var<\/span>.create_vm ? azurerm_public_ip.lab&#91;<span class=\"hljs-number\">0<\/span>].ip_address : <span class=\"hljs-literal\">null<\/span>\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:<\/p>\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 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-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\">To test no VM:<\/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\">terraform plan \\\n  -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"create_vm=false\"<\/span> \\\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-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<p class=\"wp-block-paragraph\">The VM, NIC, and public IP are removed if you apply that change. The resource group, VNet, subnet, and NSG remain until destroyed. Destroy the lab when finished.<\/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; for_each with conditional filtering<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use&nbsp;<code>for_each<\/code>&nbsp;when each instance has a stable key. A filtered map can include only items that meet a condition. Unlike&nbsp;<code>count<\/code>,&nbsp;<code>for_each<\/code>&nbsp;instances are addressed by keys rather than numeric positions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7A. AWS &#8212; create EC2 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    type    = string\n  }))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = { enabled = <span class=\"hljs-literal\">true<\/span>,  type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\n    backend  = { enabled = <span class=\"hljs-literal\">true<\/span>,  type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\n    sandbox  = { enabled = <span class=\"hljs-literal\">false<\/span>, type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\n  }\n}\n\nlocals {\n  enabled_applications = {\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\">\"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               = local.enabled_applications\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = each.value.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  }\n}\n\noutput <span class=\"hljs-string\">\"created_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\noutput <span class=\"hljs-string\">\"created_application_names\"<\/span> {\n  value = keys(aws_instance.app)\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 using the standard workflow and supply&nbsp;<code>ami_id<\/code>&nbsp;and&nbsp;<code>ssh_cidr<\/code>. The defaults create&nbsp;<code>frontend<\/code>&nbsp;and&nbsp;<code>backend<\/code>, but not&nbsp;<code>sandbox<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To enable&nbsp;<code>sandbox<\/code>, pass a complete replacement map through a&nbsp;<code>.tfvars<\/code>&nbsp;file or change the default. For example, create&nbsp;<code>terraform.tfvars<\/code>:<\/p>\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\">applications = {\n  frontend = { enabled = <span class=\"hljs-literal\">true<\/span>,  type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\n  backend  = { enabled = <span class=\"hljs-literal\">true<\/span>,  type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\n  sandbox  = { enabled = <span class=\"hljs-literal\">true<\/span>,  type = <span class=\"hljs-string\">\"t3.micro\"<\/span> }\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\">Then run&nbsp;<code>terraform plan<\/code>&nbsp;and&nbsp;<code>terraform apply<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7B. Azure &#8212; create Linux VMs only for enabled applications<\/h3>\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    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    size    = string\n  }))\n  <span class=\"hljs-keyword\">default<\/span> = {\n    frontend = { enabled = <span class=\"hljs-literal\">true<\/span>,  size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span> }\n    backend  = { enabled = <span class=\"hljs-literal\">true<\/span>,  size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span> }\n    sandbox  = { enabled = <span class=\"hljs-literal\">false<\/span>, size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span> }\n  }\n}\n\nlocals {\n  prefix = <span class=\"hljs-string\">\"tfforeach\"<\/span>\n  enabled_applications = {\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.50.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.50.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\">\"AllowSSHFromMyIP\"<\/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_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            = local.enabled_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                  = local.enabled_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            = local.enabled_applications\n  name                = <span class=\"hljs-string\">\"${local.prefix}-${each.key}-vm\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = each.value.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  }\n}\n\noutput <span class=\"hljs-string\">\"created_vm_names\"<\/span> {\n  value = keys(azurerm_linux_virtual_machine.app)\n}\n\noutput <span class=\"hljs-string\">\"public_ips\"<\/span> {\n  value = { <span class=\"hljs-keyword\">for<\/span> name, ip <span class=\"hljs-keyword\">in<\/span> azurerm_public_ip.app : <span class=\"hljs-function\"><span class=\"hljs-params\">name<\/span> =&gt;<\/span> ip.ip_address }\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 \\\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-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\">The default creates two VMs. Enabling or disabling an application changes only that keyed instance and its related networking resources.<\/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; Conditional configuration using locals<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">A&nbsp;<code>local<\/code>&nbsp;value can centralize decisions that are reused across resources. This makes configuration easier to read and reduces repeated expressions.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8A. AWS &#8212; environment-based sizing and tags<\/h3>\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    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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"dev\"<\/span>\n  validation {\n    condition     = contains(&#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n    error_message = <span class=\"hljs-string\">\"Use dev, test, or prod.\"<\/span>\n  }\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\nlocals {\n  settings = {\n    dev  = { type = <span class=\"hljs-string\">\"t3.micro\"<\/span>, monitoring = <span class=\"hljs-literal\">false<\/span> }\n    test = { type = <span class=\"hljs-string\">\"t3.micro\"<\/span>, monitoring = <span class=\"hljs-literal\">false<\/span> }\n    prod = { type = <span class=\"hljs-string\">\"t3.small\"<\/span>, monitoring = <span class=\"hljs-literal\">true<\/span> }\n  }\n\n  selected = local.settings&#91;<span class=\"hljs-keyword\">var<\/span>.environment]\n  name     = <span class=\"hljs-string\">\"app-${var.environment}\"<\/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\">\"locals-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\">\"lab\"<\/span> {\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = local.selected.type\n  monitoring             = local.selected.monitoring\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n\n  tags = {\n    Name        = local.name\n    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"selected_settings\"<\/span> {\n  value = local.selected\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 with&nbsp;<code>environment=dev<\/code>, then&nbsp;<code>environment=prod<\/code>. Observe the instance type and monitoring setting in&nbsp;<code>terraform plan<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8B. Azure &#8212; environment-based VM size and tags<\/h3>\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\">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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"dev\"<\/span>\n  validation {\n    condition     = contains(&#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n    error_message = <span class=\"hljs-string\">\"Use dev, test, or prod.\"<\/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}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nlocals {\n  settings = {\n    dev  = { size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>, monitoring = <span class=\"hljs-string\">\"basic\"<\/span> }\n    test = { size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>, monitoring = <span class=\"hljs-string\">\"basic\"<\/span> }\n    prod = { size = <span class=\"hljs-string\">\"Standard_B2s\"<\/span>, monitoring = <span class=\"hljs-string\">\"enhanced\"<\/span> }\n  }\n  selected = local.settings&#91;<span class=\"hljs-keyword\">var<\/span>.environment]\n  prefix   = <span class=\"hljs-string\">\"tflocals-${var.environment}\"<\/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  tags = {\n    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n    Monitoring  = local.selected.monitoring\n  }\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.60.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.60.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-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_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\">\"AllowSSHFromMyIP\"<\/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_network_interface\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-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.lab.id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  network_interface_id      = azurerm_network_interface.lab.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\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"${local.prefix}-vm\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = local.selected.size\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;azurerm_network_interface.lab.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    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n    Monitoring  = local.selected.monitoring\n  }\n}\n\noutput <span class=\"hljs-string\">\"selected_settings\"<\/span> {\n  value = local.selected\n}\n\noutput <span class=\"hljs-string\">\"public_ip\"<\/span> {\n  value = azurerm_public_ip.lab.ip_address\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\">Run using the Azure workflow from Lab 1, with the SSH public key and CIDR variables. Compare the plan for&nbsp;<code>environment=dev<\/code>&nbsp;and&nbsp;<code>environment=prod<\/code>.<\/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; Dynamic blocks and optional nested rules<\/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 inside a resource. It is useful for a variable number of ingress rules or similar nested provider configuration. It does not create multiple top-level resources.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9A. AWS &#8212; dynamic ingress rules<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" 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\"<\/span> {\n  type    = bool\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-literal\">true<\/span>\n}\n\nlocals {\n  base_rules = &#91;\n    { name = <span class=\"hljs-string\">\"ssh\"<\/span>,  port = <span class=\"hljs-number\">22<\/span>,  cidr = <span class=\"hljs-keyword\">var<\/span>.ssh_cidr },\n  ]\n  http_rules = <span class=\"hljs-keyword\">var<\/span>.enable_http ? &#91;\n    { name = <span class=\"hljs-string\">\"http\"<\/span>, port = <span class=\"hljs-number\">80<\/span>, cidr = <span class=\"hljs-string\">\"10.0.0.0\/8\"<\/span> }\n  ] : &#91;]\n  ingress_rules = concat(local.base_rules, local.http_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\">\"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    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\">\"dynamic-lab-sg\"<\/span>\n  }\n}\n\noutput <span class=\"hljs-string\">\"configured_ingress_rules\"<\/span> {\n  value = local.ingress_rules\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\">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<\/code>. Set&nbsp;<code>-var=\"enable_http=false\"<\/code>&nbsp;to see the HTTP rule disappear from the plan. This lab creates only a security group, so it does not need an EC2 instance.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9B. Azure &#8212; optional SSH and HTTP security rules<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Azure NSG rules are separate resources, so use&nbsp;<code>for_each<\/code>&nbsp;rather than a&nbsp;<code>dynamic<\/code>&nbsp;nested block.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" 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\"<\/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 ? {\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-24\"><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 plan<\/code>, then repeat with&nbsp;<code>-var=\"enable_http=false\"<\/code>. This example intentionally shows the Azure-native pattern: separate NSG rules are managed with&nbsp;<code>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\">10. Lab 7 &#8212; Input variable validation<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Variable validation checks user-provided values and stops planning with a helpful message when the value is invalid. Validation is suitable for allowed environment names, port ranges, naming rules, and other input constraints.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7A. AWS &#8212; validate environment and port<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" 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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"dev\"<\/span>\n\n  validation {\n    condition     = contains(&#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n    error_message = <span class=\"hljs-string\">\"environment must be dev, test, or prod.\"<\/span>\n  }\n}\n\nvariable <span class=\"hljs-string\">\"application_port\"<\/span> {\n  type    = number\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-number\">8080<\/span>\n\n  validation {\n    condition     = <span class=\"hljs-keyword\">var<\/span>.application_port &gt;= <span class=\"hljs-number\">1<\/span> &amp;&amp; <span class=\"hljs-keyword\">var<\/span>.application_port &lt;= <span class=\"hljs-number\">65535<\/span>\n    error_message = <span class=\"hljs-string\">\"application_port must be between 1 and 65535.\"<\/span>\n  }\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\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"validation-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  ingress {\n    from_port   = <span class=\"hljs-keyword\">var<\/span>.application_port\n    to_port     = <span class=\"hljs-keyword\">var<\/span>.application_port\n    protocol    = <span class=\"hljs-string\">\"tcp\"<\/span>\n    cidr_blocks = &#91;<span class=\"hljs-string\">\"10.0.0.0\/8\"<\/span>]\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\">\"lab\"<\/span> {\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  tags = {\n    Name        = <span class=\"hljs-string\">\"validation-${var.environment}\"<\/span>\n    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"application_port\"<\/span> {\n  value = <span class=\"hljs-keyword\">var<\/span>.application_port\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\">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\">Test valid input, then invalid input:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform init\nterraform validate\nterraform plan -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_AMI\"<\/span> -<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\">\"environment=prod\"<\/span> -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"application_port=8080\"<\/span>\nterraform plan -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"ami_id=ami-REPLACE_WITH_VALID_AMI\"<\/span> -<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\">\"application_port=70000\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><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 second plan should fail variable validation before infrastructure is created.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">7B. Azure &#8212; validate environment and SSH port concept<\/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    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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"dev\"<\/span>\n  validation {\n    condition     = contains(&#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n    error_message = <span class=\"hljs-string\">\"environment must be dev, test, or prod.\"<\/span>\n  }\n}\n\nvariable <span class=\"hljs-string\">\"ssh_port\"<\/span> {\n  type    = number\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-number\">22<\/span>\n  validation {\n    condition     = <span class=\"hljs-keyword\">var<\/span>.ssh_port &gt;= <span class=\"hljs-number\">1<\/span> &amp;&amp; <span class=\"hljs-keyword\">var<\/span>.ssh_port &lt;= <span class=\"hljs-number\">65535<\/span>\n    error_message = <span class=\"hljs-string\">\"ssh_port must be between 1 and 65535.\"<\/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}\n\nvariable <span class=\"hljs-string\">\"ssh_cidr\"<\/span> {\n  type = string\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"tfvalidation-${var.environment}-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\">\"tfvalidation-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.70.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.70.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfvalidation-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_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfvalidation-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\">\"AllowSSH\"<\/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     = tostring(<span class=\"hljs-keyword\">var<\/span>.ssh_port)\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_network_interface\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfvalidation-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.lab.id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  network_interface_id      = azurerm_network_interface.lab.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\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfvalidation-vm\"<\/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.lab.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    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"environment\"<\/span> {\n  value = <span class=\"hljs-keyword\">var<\/span>.environment\n}\n\noutput <span class=\"hljs-string\">\"public_ip\"<\/span> {\n  value = azurerm_public_ip.lab.ip_address\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&nbsp;<code>ssh_public_key<\/code>&nbsp;and&nbsp;<code>ssh_cidr<\/code>. Try&nbsp;<code>-var=\"ssh_port=70000\"<\/code>; validation should reject it. The example permits a custom SSH port to demonstrate numeric validation; the VM&#8217;s SSH daemon itself remains configured on port 22 unless separately changed, so keep&nbsp;<code>ssh_port=22<\/code>&nbsp;for actual SSH access.<\/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; Preconditions and postconditions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Precondition:<\/strong>\u00a0verifies an assumption before Terraform proceeds with the relevant operation.<\/li>\n\n\n\n<li><strong>Postcondition:<\/strong>\u00a0verifies a property of a resource after Terraform reads or creates it.<\/li>\n\n\n\n<li><strong>Check block:<\/strong>\u00a0performs an assertion and reports a warning if it fails; it is not a substitute for blocking validation.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">These constructs are useful for expressing requirements close to the resource or output they protect.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8A. AWS &#8212; enforce a production tag with a precondition<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" 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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"prod\"<\/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\nresource <span class=\"hljs-string\">\"aws_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name_prefix = <span class=\"hljs-string\">\"condition-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\">\"lab\"<\/span> {\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\">\"precondition-lab\"<\/span>\n    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n  }\n\n  lifecycle {\n    precondition {\n      condition     = contains(&#91;<span class=\"hljs-string\">\"test\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n      error_message = <span class=\"hljs-string\">\"This lab permits only test or prod environments.\"<\/span>\n    }\n\n    postcondition {\n      condition     = <span class=\"hljs-keyword\">self<\/span>.instance_type == <span class=\"hljs-string\">\"t3.micro\"<\/span>\n      error_message = <span class=\"hljs-string\">\"The instance type must remain t3.micro for this lab.\"<\/span>\n    }\n  }\n}\n\noutput <span class=\"hljs-string\">\"instance_id\"<\/span> {\n  value = aws_instance.lab.id\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\">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&nbsp;<code>environment=prod<\/code>&nbsp;and then try&nbsp;<code>environment=dev<\/code>. The latter should fail the precondition. This example&#8217;s postcondition checks the configured instance type; it demonstrates the syntax rather than a cloud health check.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">8B. Azure &#8212; precondition on VM configuration<\/h3>\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\">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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"prod\"<\/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\nlocals {\n  vm_size = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"tfcondition-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\">\"tfcondition-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.80.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.80.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfcondition-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_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfcondition-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\">\"AllowSSH\"<\/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_network_interface\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfcondition-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.lab.id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  network_interface_id      = azurerm_network_interface.lab.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\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tfcondition-vm\"<\/span>\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = local.vm_size\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;azurerm_network_interface.lab.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  lifecycle {\n    precondition {\n      condition     = contains(&#91;<span class=\"hljs-string\">\"test\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n      error_message = <span class=\"hljs-string\">\"This lab permits only test or prod environments.\"<\/span>\n    }\n\n    postcondition {\n      condition     = <span class=\"hljs-keyword\">self<\/span>.size == local.vm_size\n      error_message = <span class=\"hljs-string\">\"The VM size does not match the selected configuration.\"<\/span>\n    }\n  }\n\n  tags = {\n    Environment = <span class=\"hljs-keyword\">var<\/span>.environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"vm_id\"<\/span> {\n  value = azurerm_linux_virtual_machine.lab.id\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\">Run with&nbsp;<code>environment=prod<\/code>, then try&nbsp;<code>environment=dev<\/code>&nbsp;and inspect the validation failure. Use the same Azure key\/CIDR inputs and cleanup procedure as earlier Azure labs.<\/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; try(), can(), lookup(), and coalesce()<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">These functions are often used alongside conditions, but they are not all conditional expressions.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>try(a, b)<\/code>\u00a0returns the first expression that does not produce an error.<\/li>\n\n\n\n<li><code>can(expression)<\/code>\u00a0returns\u00a0<code>true<\/code>\u00a0if the expression can be evaluated without an error.<\/li>\n\n\n\n<li><code>lookup(map, key, default)<\/code>\u00a0returns a map value or a fallback.<\/li>\n\n\n\n<li><code>coalesce(a, b, ...)<\/code>\u00a0returns the first non-null, non-empty-string value.<\/li>\n\n\n\n<li><code>contains(list, value)<\/code>\u00a0tests membership.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Do not use these functions to hide errors that should be fixed directly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9A. AWS &#8212; safe defaults and conditional configuration<\/h3>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" 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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"dev\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"custom_instance_type\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"\"<\/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\nlocals {\n  instance_types = {\n    dev  = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n    test = <span class=\"hljs-string\">\"t3.micro\"<\/span>\n    prod = <span class=\"hljs-string\">\"t3.small\"<\/span>\n  }\n\n  default_type = lookup(local.instance_types, <span class=\"hljs-keyword\">var<\/span>.environment, <span class=\"hljs-string\">\"t3.micro\"<\/span>)\n  chosen_type  = coalesce(<span class=\"hljs-keyword\">var<\/span>.custom_instance_type, local.default_type)\n  environment_is_known = contains(keys(local.instance_types), <span class=\"hljs-keyword\">var<\/span>.environment)\n  parsed_number_is_valid = can(tonumber(<span class=\"hljs-string\">\"123\"<\/span>))\n  safe_environment = <span class=\"hljs-keyword\">try<\/span>(trimspace(<span class=\"hljs-keyword\">var<\/span>.environment), <span class=\"hljs-string\">\"dev\"<\/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\">\"functions-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\">\"lab\"<\/span> {\n  ami                    = <span class=\"hljs-keyword\">var<\/span>.ami_id\n  instance_type          = local.chosen_type\n  vpc_security_group_ids = &#91;aws_security_group.lab.id]\n  tags = {\n    Name        = <span class=\"hljs-string\">\"functions-lab\"<\/span>\n    Environment = local.safe_environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"selected_instance_type\"<\/span> {\n  value = local.chosen_type\n}\n\noutput <span class=\"hljs-string\">\"environment_is_known\"<\/span> {\n  value = local.environment_is_known\n}\n\noutput <span class=\"hljs-string\">\"parsed_number_is_valid\"<\/span> {\n  value = local.parsed_number_is_valid\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\">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 usual AWS commands and required inputs. Try&nbsp;<code>-var=\"environment=prod\"<\/code>&nbsp;and then&nbsp;<code>-var=\"custom_instance_type=t3.small\"<\/code>. The explicit custom value takes precedence. The example uses&nbsp;<code>can()<\/code>&nbsp;and&nbsp;<code>try()<\/code>&nbsp;to illustrate safe expression evaluation; they do not verify that an instance type is available in your account or region.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">9B. Azure &#8212; lookup and coalesce for VM size and name<\/h3>\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\">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\">\"environment\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"dev\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"custom_vm_size\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"\"<\/span>\n}\n\nvariable <span class=\"hljs-string\">\"custom_name\"<\/span> {\n  type    = string\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-string\">\"\"<\/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\nlocals {\n  vm_sizes = {\n    dev  = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n    test = <span class=\"hljs-string\">\"Standard_B1s\"<\/span>\n    prod = <span class=\"hljs-string\">\"Standard_B2s\"<\/span>\n  }\n  default_size = lookup(local.vm_sizes, <span class=\"hljs-keyword\">var<\/span>.environment, <span class=\"hljs-string\">\"Standard_B1s\"<\/span>)\n  vm_size      = coalesce(<span class=\"hljs-keyword\">var<\/span>.custom_vm_size, local.default_size)\n  vm_name      = coalesce(<span class=\"hljs-keyword\">var<\/span>.custom_name, <span class=\"hljs-string\">\"tf-functions-${var.environment}-vm\"<\/span>)\n  environment_is_known = contains(keys(local.vm_sizes), <span class=\"hljs-keyword\">var<\/span>.environment)\n  number_parse_works   = can(tonumber(<span class=\"hljs-string\">\"123\"<\/span>))\n  safe_environment     = <span class=\"hljs-keyword\">try<\/span>(trimspace(<span class=\"hljs-keyword\">var<\/span>.environment), <span class=\"hljs-string\">\"dev\"<\/span>)\n}\n\nresource <span class=\"hljs-string\">\"azurerm_resource_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name     = <span class=\"hljs-string\">\"tffunctions-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\">\"tffunctions-vnet\"<\/span>\n  address_space       = &#91;<span class=\"hljs-string\">\"10.90.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.90.1.0\/24\"<\/span>]\n}\n\nresource <span class=\"hljs-string\">\"azurerm_public_ip\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tffunctions-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_security_group\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tffunctions-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\">\"AllowSSH\"<\/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_network_interface\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  name                = <span class=\"hljs-string\">\"tffunctions-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.lab.id\n  }\n}\n\nresource <span class=\"hljs-string\">\"azurerm_network_interface_security_group_association\"<\/span> <span class=\"hljs-string\">\"lab\"<\/span> {\n  network_interface_id      = azurerm_network_interface.lab.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\">\"lab\"<\/span> {\n  name                = local.vm_name\n  resource_group_name = azurerm_resource_group.lab.name\n  location            = azurerm_resource_group.lab.location\n  size                = local.vm_size\n  admin_username      = <span class=\"hljs-keyword\">var<\/span>.admin_username\n  network_interface_ids = &#91;azurerm_network_interface.lab.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    Environment = local.safe_environment\n  }\n}\n\noutput <span class=\"hljs-string\">\"selected_vm_size\"<\/span> {\n  value = local.vm_size\n}\n\noutput <span class=\"hljs-string\">\"vm_name\"<\/span> {\n  value = local.vm_name\n}\n\noutput <span class=\"hljs-string\">\"environment_is_known\"<\/span> {\n  value = local.environment_is_known\n}\n\noutput <span class=\"hljs-string\">\"number_parse_works\"<\/span> {\n  value = local.number_parse_works\n}\n\noutput <span class=\"hljs-string\">\"public_ip\"<\/span> {\n  value = azurerm_public_ip.lab.ip_address\n}\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\">Run with the standard Azure workflow. Try&nbsp;<code>-var=\"environment=prod\"<\/code>&nbsp;and&nbsp;<code>-var=\"custom_vm_size=Standard_B1s\"<\/code>.&nbsp;<code>coalesce<\/code>&nbsp;chooses the non-empty custom value when supplied. Confirm the chosen size is available before applying.<\/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; Conditional module instances<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Concept<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Modules can use&nbsp;<code>count<\/code>&nbsp;or&nbsp;<code>for_each<\/code>, just like resources. When using&nbsp;<code>count<\/code>, outputs from the module become a list of module instances. A module using&nbsp;<code>for_each<\/code>&nbsp;is addressed by its keys.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This lab is deliberately a small local module example so it can be tested without creating cloud resources. It demonstrates Terraform language behavior; cloud-specific modules can use the same pattern.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create this directory layout:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">conditional-<span class=\"hljs-built_in\">module<\/span>-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-32\"><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-33\" 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}\n\nvariable <span class=\"hljs-string\">\"create_label\"<\/span> {\n  type    = bool\n  <span class=\"hljs-keyword\">default<\/span> = <span class=\"hljs-literal\">true<\/span>\n}\n\n<span class=\"hljs-built_in\">module<\/span> <span class=\"hljs-string\">\"label\"<\/span> {\n  source = <span class=\"hljs-string\">\".\/modules\/label\"<\/span>\n  count  = <span class=\"hljs-keyword\">var<\/span>.create_label ? <span class=\"hljs-number\">1<\/span> : <span class=\"hljs-number\">0<\/span>\n\n  label = <span class=\"hljs-string\">\"demo\"<\/span>\n}\n\noutput <span class=\"hljs-string\">\"label_value\"<\/span> {\n  value = <span class=\"hljs-keyword\">var<\/span>.create_label ? <span class=\"hljs-built_in\">module<\/span>.label&#91;<span class=\"hljs-number\">0<\/span>].value : <span class=\"hljs-literal\">null<\/span>\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\"><code>modules\/label\/main.tf<\/code>:<\/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\">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-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\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-35\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">terraform init\nterraform validate\nterraform plan\nterraform apply\nterraform output\nterraform plan -<span class=\"hljs-keyword\">var<\/span>=<span class=\"hljs-string\">\"create_label=false\"<\/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\">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 demonstrates conditional module instantiation. No cloud infrastructure is created.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">14. Important patterns and gotchas<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\"><code>count<\/code>&nbsp;versus&nbsp;<code>for_each<\/code><\/h3>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Feature&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 Non-negative integer Map or set of strings<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Address Numeric index, Key, e.g.&nbsp;<code>[0]<\/code>&nbsp;e.g.&nbsp;<code>[\"frontend\"]<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Best for Fixed number or simple Named resources with on\/off stable identity<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Main risk Removing an element Renaming a key changes from a list can shift the resource address indexes<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Conditional expressions must have compatible result types<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Good:<\/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\"><span class=\"hljs-keyword\">var<\/span>.enabled ? <span class=\"hljs-string\">\"enabled\"<\/span> : <span class=\"hljs-string\">\"disabled\"<\/span>\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<p class=\"wp-block-paragraph\">Potentially problematic if the branches have incompatible types:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-37\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">var<\/span>.enabled ? <span class=\"hljs-number\">1<\/span> : <span class=\"hljs-string\">\"no\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-37\"><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\">Keep both branches the same type where possible.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do not use&nbsp;<code>count<\/code>&nbsp;to make a resource depend on an unknown result<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Terraform must know&nbsp;<code>count<\/code>&nbsp;and&nbsp;<code>for_each<\/code>&nbsp;instance keys during planning. If the condition depends on an attribute that is unknown until apply, Terraform may not be able to determine the instance count. Base instance selection on known input variables or known configuration whenever possible.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Resource references change when&nbsp;<code>count<\/code>&nbsp;or&nbsp;<code>for_each<\/code>&nbsp;is used<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Without&nbsp;<code>count<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">aws_instance<\/span><span class=\"hljs-selector-class\">.web<\/span><span class=\"hljs-selector-class\">.id<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><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\">With&nbsp;<code>count<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-39\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">aws_instance<\/span><span class=\"hljs-selector-class\">.web<\/span><span class=\"hljs-selector-attr\">&#91;0]<\/span><span class=\"hljs-selector-class\">.id<\/span>\n<span class=\"hljs-selector-tag\">aws_instance<\/span><span class=\"hljs-selector-class\">.web<\/span><span class=\"hljs-selector-attr\">&#91;*]<\/span><span class=\"hljs-selector-class\">.id<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-39\"><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\">With&nbsp;<code>for_each<\/code>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-40\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-tag\">aws_instance<\/span><span class=\"hljs-selector-class\">.web<\/span><span class=\"hljs-selector-attr\">&#91;<span class=\"hljs-string\">\"frontend\"<\/span>]<\/span><span class=\"hljs-selector-class\">.id<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-40\"><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<h3 class=\"wp-block-heading\"><code>null<\/code>&nbsp;is not the same as&nbsp;<code>false<\/code><\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>false<\/code>\u00a0is a Boolean value.<\/li>\n\n\n\n<li><code>null<\/code>\u00a0means absence of a value and can omit an optional argument.<\/li>\n\n\n\n<li>An empty string (<code>\"\"<\/code>) is still a string.<\/li>\n\n\n\n<li>An empty list (<code>[]<\/code>) is a collection with zero elements.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\"><code>dynamic<\/code>&nbsp;is for nested blocks<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use&nbsp;<code>for_each<\/code>&nbsp;on a resource or module to repeat top-level instances. Use&nbsp;<code>dynamic<\/code>&nbsp;when you need repeated nested blocks within one resource.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Azure NSG rules and AWS security group rules differ<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The AWS provider supports inline&nbsp;<code>ingress<\/code>\/<code>egress<\/code>&nbsp;blocks, including&nbsp;<code>dynamic<\/code>&nbsp;blocks in supported resource schemas. Azure NSG rules are commonly represented as separate&nbsp;<code>azurerm_network_security_rule<\/code>&nbsp;resources, making&nbsp;<code>for_each<\/code>&nbsp;the natural pattern.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><code>try()<\/code>&nbsp;and&nbsp;<code>can()<\/code>&nbsp;are not generic exception handling<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Use them for expressions that might be absent or invalid, especially when normalizing external or loosely structured data. Do not wrap every expression in&nbsp;<code>try()<\/code>&nbsp;to conceal configuration mistakes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Precondition, postcondition, and check are different<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Preconditions and postconditions can block an operation when their assertions fail.<\/li>\n\n\n\n<li><code>check<\/code>\u00a0blocks are designed for ongoing checks and generally report warnings rather than blocking the operation.<\/li>\n\n\n\n<li>Variable validation is usually the clearest choice for invalid user inputs.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">15. Troubleshooting<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Error: Invalid for_each argument<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Common cause:<\/strong>&nbsp;The keys or set members cannot be determined until apply, or the value is not a map\/set of strings.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Use stable keys known during planning. For maps of objects, keep the keys independent of computed cloud resource IDs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Error: Invalid count argument<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Common cause:<\/strong>&nbsp;Terraform cannot determine the count during planning.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Use a Boolean input variable or another value known before apply.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Error: Invalid index<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Common cause:<\/strong>&nbsp;Referencing&nbsp;<code>resource.example[0]<\/code>&nbsp;when&nbsp;<code>count = 0<\/code>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Guard the reference with a condition, or use a splat expression such as&nbsp;<code>resource.example[*].id<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Azure VM size or quota errors<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Common cause:<\/strong>&nbsp;The selected VM size is unavailable in the region, restricted by policy, or exceeds quota.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Check Azure regional availability, subscription quota, and policy. Choose a size permitted by the subscription; changing a Terraform condition cannot grant 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>Common cause:<\/strong>&nbsp;AMI IDs are regional, stale, or incorrect.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Fix:<\/strong>&nbsp;Look up a valid image in the configured AWS region and pass its ID to&nbsp;<code>ami_id<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">SSH connection fails<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Check: &#8211;&nbsp;<code>ssh_cidr<\/code>&nbsp;matches your current public IPv4 address in CIDR notation (often&nbsp;<code>\/32<\/code>). &#8211; You supplied the&nbsp;<strong>public<\/strong>&nbsp;key, not the private key, to Azure. &#8211; The matching private key is available locally. &#8211; The cloud resource has finished provisioning. &#8211; The selected region, route, security rules, and OS image are correct. &#8211; For Azure, if you changed the NSG destination port, the Linux SSH daemon must also be configured for that port.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Provider version or registration issues<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Run:<\/p>\n\n\n<pre class=\"wp-block-code\"><span><code class=\"hljs\">terraform init -upgrade\nterraform providers\nterraform validate\n<\/code><\/span><\/pre>\n\n\n<p class=\"wp-block-paragraph\">Review provider constraints and your organization&#8217;s Azure provider-registration policy. Do not run&nbsp;<code>init -upgrade<\/code>&nbsp;blindly in production without reviewing the provider version changes.<\/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>Prefer\u00a0<code>for_each<\/code>\u00a0for named resources where stable keys matter.<\/li>\n\n\n\n<li>Use\u00a0<code>count<\/code>\u00a0for simple on\/off resources or truly interchangeable instances.<\/li>\n\n\n\n<li>Put complex decisions in\u00a0<code>locals<\/code>\u00a0and give them descriptive names.<\/li>\n\n\n\n<li>Validate inputs early with variable\u00a0<code>validation<\/code>\u00a0blocks.<\/li>\n\n\n\n<li>Use preconditions and postconditions for assumptions tied to resources.<\/li>\n\n\n\n<li>Keep environment settings in a map\/object instead of deeply nested ternaries.<\/li>\n\n\n\n<li>Keep security rules restrictive. Never expose SSH publicly just to simplify a lab.<\/li>\n\n\n\n<li>Pin provider major versions and review upgrades.<\/li>\n\n\n\n<li>Inspect\u00a0<code>terraform plan<\/code>\u00a0before every apply.<\/li>\n\n\n\n<li>Use separate directories or isolated state for each hands-on lab.<\/li>\n\n\n\n<li>Destroy temporary lab resources to avoid ongoing costs.<\/li>\n\n\n\n<li>Avoid changing\u00a0<code>for_each<\/code>\u00a0keys or\u00a0<code>count<\/code>\u00a0list order in existing production state without understanding the resulting resource address changes.<\/li>\n\n\n\n<li>Keep secrets out of\u00a0<code>.tf<\/code>\u00a0files and source control.<\/li>\n\n\n\n<li>Test conditions by changing one input at a time and comparing plans.<\/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<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Need Recommended technique<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">Choose one value or another&nbsp;<code>condition ? a : b<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Combine Boolean requirements&nbsp;<code>&amp;&amp;<\/code>,&nbsp;<code>||<\/code>,&nbsp;<code>!<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create a resource only when enabled&nbsp;<code>count = var.enabled ? 1 : 0<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Create named resources from a&nbsp;<code>for_each<\/code>&nbsp;map\/set<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Filter a list or map&nbsp;<code>for ... if ...<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Transform a collection&nbsp;<code>for<\/code>&nbsp;expression<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Repeat nested provider blocks&nbsp;<code>dynamic<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Reject invalid input Variable&nbsp;<code>validation<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Enforce an assumption before\/after&nbsp;<code>precondition<\/code>&nbsp;\/&nbsp;<code>postcondition<\/code>&nbsp;a resource operation<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Report an ongoing assertion warning&nbsp;<code>check<\/code>&nbsp;block<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Safely attempt an expression&nbsp;<code>try()<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Test if an expression evaluates&nbsp;<code>can()<\/code>&nbsp;without error<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Get a map value with a fallback&nbsp;<code>lookup()<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Choose first non-null\/non-empty&nbsp;<code>coalesce()<\/code>&nbsp;string<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check whether a collection contains&nbsp;<code>contains()<\/code>&nbsp;a value<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Provide optional argument absence&nbsp;<code>null<\/code><\/h2>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">18. Exercises and answers<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Exercise 1<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Choose&nbsp;<code>t3.small<\/code>&nbsp;only if&nbsp;<code>environment<\/code>&nbsp;is&nbsp;<code>prod<\/code>; otherwise choose&nbsp;<code>t3.micro<\/code>.<\/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-41\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">locals {\n  instance_type = <span class=\"hljs-keyword\">var<\/span>.environment == <span class=\"hljs-string\">\"prod\"<\/span> ? <span class=\"hljs-string\">\"t3.small\"<\/span> : <span class=\"hljs-string\">\"t3.micro\"<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-41\"><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 2<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Create an EC2 instance only if&nbsp;<code>create_instance<\/code>&nbsp;is true.<\/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-42\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">resource <span class=\"hljs-string\">\"aws_instance\"<\/span> <span class=\"hljs-string\">\"optional\"<\/span> {\n  count = <span class=\"hljs-keyword\">var<\/span>.create_instance ? <span class=\"hljs-number\">1<\/span> : <span class=\"hljs-number\">0<\/span>\n  <span class=\"hljs-comment\"># Include the required AMI, instance type, and other settings.<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-42\"><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<h3 class=\"wp-block-heading\">Exercise 3<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Filter a map of applications to keep only enabled applications.<\/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-43\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">locals {\n  enabled_applications = {\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-43\"><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<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Allow only&nbsp;<code>dev<\/code>,&nbsp;<code>test<\/code>, or&nbsp;<code>prod<\/code>.<\/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-44\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">variable <span class=\"hljs-string\">\"environment\"<\/span> {\n  type = string\n\n  validation {\n    condition     = contains(&#91;<span class=\"hljs-string\">\"dev\"<\/span>, <span class=\"hljs-string\">\"test\"<\/span>, <span class=\"hljs-string\">\"prod\"<\/span>], <span class=\"hljs-keyword\">var<\/span>.environment)\n    error_message = <span class=\"hljs-string\">\"Use dev, test, or prod.\"<\/span>\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-44\"><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 5<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">What is the difference between&nbsp;<code>dynamic<\/code>&nbsp;and&nbsp;<code>for_each<\/code>?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Answer:<\/strong>&nbsp;<code>for_each<\/code>&nbsp;repeats resource or module instances. A&nbsp;<code>dynamic<\/code>&nbsp;block generates repeated nested blocks inside a resource.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Exercise 6<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Why might Terraform reject a&nbsp;<code>count<\/code>&nbsp;expression?<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Answer:<\/strong>&nbsp;Terraform must know how many instances to plan. If the count depends on a value that is unknown until apply, Terraform may not be able to calculate it.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">19. Glossary<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Conditional expression:<\/strong>\u00a0Selects a value based on a Boolean condition.<\/li>\n\n\n\n<li><strong>Boolean:<\/strong>\u00a0A value that is either\u00a0<code>true<\/code>\u00a0or\u00a0<code>false<\/code>.<\/li>\n\n\n\n<li><strong>Meta-argument:<\/strong>\u00a0A special argument such as\u00a0<code>count<\/code>,\u00a0<code>for_each<\/code>, or\u00a0<code>depends_on<\/code>\u00a0that changes Terraform&#8217;s resource\/module behavior.<\/li>\n\n\n\n<li><strong>Collection:<\/strong>\u00a0A list, tuple, set, map, or object.<\/li>\n\n\n\n<li><strong>Iteration:<\/strong>\u00a0Processing or creating configuration for multiple elements.<\/li>\n\n\n\n<li><strong>Filtering:<\/strong>\u00a0Selecting only collection elements that meet a condition.<\/li>\n\n\n\n<li><strong>Dynamic block:<\/strong>\u00a0A construct that generates nested blocks from a collection.<\/li>\n\n\n\n<li><strong>Precondition:<\/strong>\u00a0An assertion that must hold before a relevant operation can proceed.<\/li>\n\n\n\n<li><strong>Postcondition:<\/strong>\u00a0An assertion evaluated after a resource operation\/read.<\/li>\n\n\n\n<li><strong>Plan:<\/strong>\u00a0Terraform&#8217;s preview of proposed infrastructure changes.<\/li>\n\n\n\n<li><strong>State:<\/strong>\u00a0Terraform&#8217;s record of managed infrastructure objects.<\/li>\n<\/ul>\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<p class=\"wp-block-paragraph\">Before finishing a lab, verify:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>[ ]\u00a0<code>terraform fmt<\/code>\u00a0completed.<\/li>\n\n\n\n<li>[ ]\u00a0<code>terraform validate<\/code>\u00a0passed.<\/li>\n\n\n\n<li>[ ] The plan matches the condition you intended to test.<\/li>\n\n\n\n<li>[ ] Outputs show the expected value or number of instances.<\/li>\n\n\n\n<li>[ ] You inspected the cloud console or CLI where appropriate.<\/li>\n\n\n\n<li>[ ] You ran\u00a0<code>terraform destroy<\/code>\u00a0for temporary infrastructure.<\/li>\n\n\n\n<li>[ ] You checked that no lab resources remain.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Remember:<\/strong>&nbsp;Terraform conditions decide values and desired configuration. Terraform then compares that configuration with state and real infrastructure to calculate a plan. Always review the plan before applying it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Terraform Conditional Expressions and Logic \u2014 Summary Table # Concept Purpose Example Creates Resources? 1 Ternary operator Choose between two values var.env == &#8220;prod&#8221; ? &#8220;t3.large&#8221; :&#8230; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_joinchat":[],"footnotes":""},"categories":[5129],"tags":[],"class_list":["post-12956","post","type-post","status-publish","format-standard","hentry","category-terraform"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/12956","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=12956"}],"version-history":[{"count":11,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/12956\/revisions"}],"predecessor-version":[{"id":79121,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/12956\/revisions\/79121"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=12956"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=12956"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=12956"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}