Terraform Basics – Week 4: Securing Your Azure VM’s with NSGs and Dynamic Blocks

Table of Contents

1. Recap of Week 3

2. This Week’s Architecture

3. What Is a Network Security Group (NSG)?

4. Real world challenge with Network Security Groups in Terraform

5. Using Dynamic Blocks to solve for the challenge

6. Deployin…


This content originally appeared on DEV Community and was authored by Ozan Guner

Table of Contents

1. Recap of Week 3

2. This Week's Architecture

3. What Is a Network Security Group (NSG)?

4. Real world challenge with Network Security Groups in Terraform

5. Using Dynamic Blocks to solve for the challenge

6. Deploying to Azure

7. Wrap-Up

1. Recap of Week 3

In Week 3, we focused on improving the structure of our Terraform configuration by introducing variable files. We moved our input values into a dedicated tfvars file and saw how Terraform automatically loads those values during plan and apply. This helped us clean up the main configuration, reduce repetition, and make the deployment easier to adjust without touching the core logic.

We also talked about why this approach matters in real-world projects, especially when working with multiple environments or collaborating with others. With a cleaner and more flexible setup in place, we can now start enhancing our deployment. You can find the full content for Week 3 here.

This week, we’ll take the next step by adding a Network Security Group and introducing dynamic blocks to define security rules in a more scalable way.

2. This Week's architecture

Arcihtecture Diagram

You can find this week's terraform files here.

3. What Is a Network Security Group (NSG)?

A Network Security Group (aka NSG) is the resource in Azure that lets you control which types of traffic can reach your VM. Instead of leaving your VM open to the internet, an NSG allows you to define rules that specify what should be allowed in or out. For example, you might allow SSH or RDP from your own IP while blocking everything else. If you have worked with Access Control Lists or Firewall Security Rules / Policies before in a network, it's the Azure equivalent of those concepts.

You can attach an NSG to a subnet or directly to the VM’s network interface (more on that later). Either way, it gives you a straightforward way to lock down access without changing anything inside the VM itself. In this week’s example, we’ll use an NSG to protect the VM we created earlier and make sure only the traffic we expect can reach it.

4. Real world challenge with Network Security Groups in Terraform

Defining an NSG with one or two rules is straightforward. You add a few security_rule blocks to your Terraform file, run apply, and everything works. The challenge starts when you need to open multiple ports, support different source networks, or define separate rules for SSH, RDP, HTTP, HTTPS, and more.

At that point, your configuration quickly turns into a long list of almost identical blocks. The only parts that change are the name, the port, and sometimes the source address or priority. It still works, but the file becomes harder to read and maintain. Adding a new rule means copying an existing block and editing several fields. Updating a port or changing the allowed network means searching through the file and hoping nothing gets missed.

This becomes even more problematic when you support multiple environments or need to adjust rules frequently. The repetition adds noise, increases the chance of mistakes, and makes the code harder to follow. To illustrate this, let's start with a simple example.

Below is a standard NSG with a single inbound rule:

You can also refer to Terraform documentation here.

The structure is simple: define a name, reference the resource group, and include your security_rule blocks underneath.

But the moment you start adding more rules, the file grows quickly. Here is a version with only three rules:

Even with just three, it’s already harder to scan and understand. Now imagine maintaining this when there are dozens or even hundreds of rules. This is a real challenge in production environments.

5. Using Dynamic Blocks to solve for the challenge

This is where dynamic blocks come in. Dynamic blocks allow you to generate repeated parts of a resource based on a list or map. In most NSGs, only a few elements actually change per rule: the name, the port, and the allowed network. Everything else stays the same. Instead of writing multiple security_rule blocks by hand, you can loop through the “dynamic” parts and let Terraform create the rules for you.

To do that, we start by defining a variable that holds the ports we want to allow. This goes in variables.tf:

nsg-allowed-ports

Then we set our values in terraform.tfvars:

Now we’re ready to create nsg.tf and define our NSG resource. The resource itself is straightforward:

Below that, we add the dynamic block. The syntax always follows the same pattern: dynamic "block_name".

Let’s break down the main parts:

for_each: This tells Terraform to loop through every element in the list we created earlier. In this example, for_each = var.nsg_allowed_ports means we will generate one security rule for each port.

Inside the loop, we refer to the current element using security_rule.value

name: Each security rule needs a unique name. To generate one, we combine a prefix (allow-port-) with the current port number following the syntax shown on the screenshot. This produces values like allow-port-22, allow-port-443, and so on.

priority: Each rule must have a unique priority. Here, we calculate the priority based on the index of the port in the list.As you may already know, the first element in the list has an index of 0 and the last element in the list has an index of n-1, n being the number of elements in the list. The first element gets a priority of 100(100+ 100*0), the second gets 200(100+ 100*1), the third gets 300 (100+ 100*2), and so on. This keeps the priorities predictable and avoids collisions.

destination_port_range:This is simply the port we’re allowing, so we use security_rule.value.

With one dynamic block, we replaced several repetitive security rule definitions. This makes the code easier to read, easier to update, and easier to scale as your requirements grow. That’s the real benefit of dynamic blocks—they help keep your Terraform configuration clean and maintainable as your infrastructure becomes more complex.

So now that we have our proper network security group configuration file in place, we still need to associate it with the NIC of our virtual machine.

Security group associations are defined as a separate resource in Terraform. You don't necessarily have to add it under the nsg.tf file, you can also add it under virtual-machine.tf file, but I'd like to add my associations it under nsg.tf file to see all resources that are associated with that specific NSG under the same file.

6. Deploying to Azure

  1. As always - we start with terraform init :

  1. Next we use terraform plan command. I'd like to highlight a few things on the plan output:

You can see that our dynamic block is working as we expected, it created 3 rules with the expected values on names, priority and the destination port range attributes.

Also, our NSG association for the VM is in the plan :

  1. Now that everything looks good - we go ahead and issue the terraform apply command.

Apply successfully completed and our resources are created. Let's take a look at NSG and how it looks on the Azure side :

Looks exactly like expected, 3 rules created on top of the default rules with expected values.

  1. Finally, don't forget to issue terraform destroy command so you don't generate unnecessary costs.

7. Wrap-Up

And that's a wrap for this week! We focused on strengthening our deployment by introducing a Network Security Group and attaching it to our VM. We also looked at a common challenge that comes up when NSGs start to grow and the number of rules increases. With dynamic block, we reduced repetition, made updates easier, and kept our Terraform files readable as our environment expands.

Next week, we’ll continue building on this foundation by exploring output values and data types, which will help us expose useful information from our resources and make our configuration more reusable.


This content originally appeared on DEV Community and was authored by Ozan Guner


Print Share Comment Cite Upload Translate Updates
APA

Ozan Guner | Sciencx (2025-11-17T03:26:30+00:00) Terraform Basics – Week 4: Securing Your Azure VM’s with NSGs and Dynamic Blocks. Retrieved from https://www.scien.cx/2025/11/17/terraform-basics-week-4-securing-your-azure-vms-with-nsgs-and-dynamic-blocks/

MLA
" » Terraform Basics – Week 4: Securing Your Azure VM’s with NSGs and Dynamic Blocks." Ozan Guner | Sciencx - Monday November 17, 2025, https://www.scien.cx/2025/11/17/terraform-basics-week-4-securing-your-azure-vms-with-nsgs-and-dynamic-blocks/
HARVARD
Ozan Guner | Sciencx Monday November 17, 2025 » Terraform Basics – Week 4: Securing Your Azure VM’s with NSGs and Dynamic Blocks., viewed ,<https://www.scien.cx/2025/11/17/terraform-basics-week-4-securing-your-azure-vms-with-nsgs-and-dynamic-blocks/>
VANCOUVER
Ozan Guner | Sciencx - » Terraform Basics – Week 4: Securing Your Azure VM’s with NSGs and Dynamic Blocks. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/11/17/terraform-basics-week-4-securing-your-azure-vms-with-nsgs-and-dynamic-blocks/
CHICAGO
" » Terraform Basics – Week 4: Securing Your Azure VM’s with NSGs and Dynamic Blocks." Ozan Guner | Sciencx - Accessed . https://www.scien.cx/2025/11/17/terraform-basics-week-4-securing-your-azure-vms-with-nsgs-and-dynamic-blocks/
IEEE
" » Terraform Basics – Week 4: Securing Your Azure VM’s with NSGs and Dynamic Blocks." Ozan Guner | Sciencx [Online]. Available: https://www.scien.cx/2025/11/17/terraform-basics-week-4-securing-your-azure-vms-with-nsgs-and-dynamic-blocks/. [Accessed: ]
rf:citation
» Terraform Basics – Week 4: Securing Your Azure VM’s with NSGs and Dynamic Blocks | Ozan Guner | Sciencx | https://www.scien.cx/2025/11/17/terraform-basics-week-4-securing-your-azure-vms-with-nsgs-and-dynamic-blocks/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.