<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: suvankit</title>
    <description>The latest articles on DEV Community by suvankit (@suvankit).</description>
    <link>https://dev.to/suvankit</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F492688%2Fafff4274-ebfa-44e5-b577-ee284ffc1f65.PNG</url>
      <title>DEV Community: suvankit</title>
      <link>https://dev.to/suvankit</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/suvankit"/>
    <language>en</language>
    <item>
      <title>Azure MFA Enforcement and Service Principal Migration</title>
      <dc:creator>suvankit</dc:creator>
      <pubDate>Sat, 18 Oct 2025 14:36:23 +0000</pubDate>
      <link>https://dev.to/suvankit/azure-mfa-enforcement-and-service-principal-migration-5caa</link>
      <guid>https://dev.to/suvankit/azure-mfa-enforcement-and-service-principal-migration-5caa</guid>
      <description>&lt;p&gt;Microsoft has announced that by October 1, 2025 all Azure sign-ins (including CLI, PowerShell, REST, and IaC tools) will require MFA for user accounts. This means existing automation scripts that use user credentials will break, since MFA cannot be completed non-interactively. To address this, Azure recommends switching any “service accounts” to workload identities – namely service principals or managed identities – which do not require MFA and support non-interactive login.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Impact on automation&lt;/strong&gt;: Any script doing az login with a user/password will fail with an “Interactive authentication needed” error once MFA enforcement begins. For example, ROPC flows or unattended logins become incompatible with MFA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Use Service Principals (or Managed Identities) for automation instead, as these are intended for apps/scripts and aren’t affected by the MFA mandate.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By moving to service principals, our automation can continue running unattended without MFA prompts. Below we explain what service principals are (in plain terms), how they differ from managed identities, and what roles we can assign to them (both Azure RBAC and EA/billing roles). We also give sample Terraform and Azure CLI snippets for creating SPNs and assigning roles.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is an Azure Service Principal (Layman’s Terms)
&lt;/h2&gt;

&lt;p&gt;An Azure service principal is essentially a “robot identity” in our Azure AD tenant. Instead of creating a real user for automation, we create an application registration which in turn creates a service principal object. This service principal has its own client ID (app ID) and credential (client secret or certificate) which our scripts can use to authenticate. In simple terms, it’s like giving our script its own login account.&lt;/p&gt;

&lt;p&gt;According to Microsoft, a service principal is “An application whose tokens can be used to authenticate and grant access to specific Azure resources”. In practice, using a service principal lets us avoid “fake user” accounts (legacy service accounts) and instead use a dedicated non-human identity for automation. Its permissions are controlled by Azure RBAC roles, so we can tightly restrict exactly what resources it can access. Common use-cases include Terraform deployments, CI/CD pipelines (e.g. Azure DevOps service connections), or any third-party tool that needs Azure tokens.&lt;/p&gt;

&lt;p&gt;In contrast, managed identities are a special type of service principal automatically created and managed by Azure for a specific resource (like a VM or App Service). The key differences are: managed identities are tied to one or more Azure resources and Azure maintains the credentials (we never see the secret). This makes managed identities very secure but only useful when our code runs on an Azure resource. A general service principal (unlike a managed identity) is not bound to any resource and is managed by us – giving more flexibility (multi-tenant use, cross-subscription) at the cost of having to securely manage its secret. In summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Service Principal&lt;/strong&gt; – a standalone Azure AD identity (with client ID/secret) for automation. &lt;em&gt;Flexible&lt;/em&gt;: can access many resources or subscriptions, but we must create and store its credentials.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Managed Identity&lt;/strong&gt; – an automatically managed service principal tied to a specific Azure resource. &lt;em&gt;Less flexible&lt;/em&gt;: only usable from that resource, but more secure since Azure handles the credentials.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Authenticating with a Service Principal
&lt;/h2&gt;

&lt;p&gt;Once we have a service principal, our automation can log in with it instead of a user. For example, with the Azure CLI we would use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az login --service-principal -u &amp;lt;APP_ID&amp;gt; -p &amp;lt;CLIENT_SECRET&amp;gt; --tenant &amp;lt;TENANT_ID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command signs you in as the service principal non-interactively. The output (as shown below) includes the &lt;code&gt;appId&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt; (the secret), and &lt;code&gt;tenant&lt;/code&gt; we will need to store securely:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hwrhbkyehr631z99k1n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9hwrhbkyehr631z99k1n.png" alt=" " width="800" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After logging in, we can run az commands just like a user. Our SPN’s actions are governed by its assigned roles (below), and it will not be prompted for MFA.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure RBAC Roles for Service Principals
&lt;/h2&gt;

&lt;p&gt;A service principal can be assigned Azure RBAC roles at any scope (management group, subscription, resource group, or resource) to grant it permissions to Azure resources. The built-in RBAC roles work the same for SPNs as for users. Common roles include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Owner&lt;/strong&gt; – Full access to manage all resources and assign roles (highest privilege).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contributor&lt;/strong&gt; – Manage all resources (create/update/delete), but cannot assign RBAC roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reader&lt;/strong&gt; – View-only access to all resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Access Administrator&lt;/strong&gt; – Can manage user and service principal access (role assignments), but not resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can also assign service principals any specialized built-in roles (e.g. Key Vault Contributor, Storage Account Contributor, Azure Functions Contributor, etc.) depending on the tasks they need to perform. The principle of least privilege applies: give the SP only the roles it needs. For example, an SPN that only deploys resources might be a Contributor on a resource group; an SPN that only needs to read metrics could be a Reader.&lt;/p&gt;

&lt;p&gt;Terraform can create these assignments. For example, after creating an SPN, we can assign roles like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data "azuread_service_principal" "example" {
  application_id = azuread_application.example.application_id
}

resource "azurerm_role_assignment" "assign_contributor" {
  scope                = azurerm_resource_group.example.id
  role_definition_name = "Contributor"
  principal_id         = data.azuread_service_principal.example.object_id
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This snippet looks up the SPN by its &lt;code&gt;application_id&lt;/code&gt; and assigns it the Contributor role on a resource group. The same pattern works for any built-in or custom role (using its name or ID). We can also iterate (for_each) over a list of role names if the SP needs multiple roles in the same scope.&lt;/p&gt;

&lt;h2&gt;
  
  
  Azure EA/Billing Roles for Service Principals
&lt;/h2&gt;

&lt;p&gt;For organizations on an Enterprise Agreement (EA), Azure defines special &lt;em&gt;billing&lt;/em&gt; and &lt;em&gt;administrative&lt;/em&gt; roles that govern costs, subscriptions, and billing data across the enrollment hierarchy. These roles differ from RBAC roles: they control EA-level resources (like enrollments, departments, accounts) rather than Azure resource groups. Notably, EA roles (such as &lt;em&gt;Enrollment Reader&lt;/em&gt;, &lt;em&gt;Department Reader&lt;/em&gt;, &lt;em&gt;Subscription Creator&lt;/em&gt;, &lt;em&gt;EA Purchaser&lt;/em&gt;) can be assigned to service principals via APIs for automating billing tasks. These roles are not visible in the Azure portal and must be assigned programmatically.&lt;br&gt;
Key EA roles we can grant to a service principal include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EnrollmentReader&lt;/strong&gt; – View usage and charges across the entire enrollment (all accounts and subscriptions) and see remaining commitment balance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DepartmentReader&lt;/strong&gt; – View usage and charges within a specific department scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SubscriptionCreator&lt;/strong&gt; – Create new subscriptions under an enrollment account. (This maps to the EA Administrator’s permission to add subscriptions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EA Purchaser&lt;/strong&gt; – Purchase reservation orders and view all enrollment usage (inherits EnrollmentReader and DepartmentReader rights).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PartnerAdmin Reader&lt;/strong&gt; – (For EA partners) View data for all enrollments under the partner organization.
Each EA role has a fixed role-definition ID that we use when assigning it. Unlike RBAC roles, an SP can only hold one EA role at a time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use cases&lt;/strong&gt;: For example, an automation that needs to create Azure subscriptions on demand would use the &lt;code&gt;SubscriptionCreator&lt;/code&gt; EA role. A reporting service that pulls cost details could use &lt;code&gt;EnrollmentReader&lt;/code&gt;. These roles ensure the SP can manage billing entities without being a full EA admin.&lt;/p&gt;

&lt;p&gt;Because EA roles aren’t yet supported in Terraform, we assign them with Azure REST APIs or Azure CLI. For example, using Azure CLI’s &lt;code&gt;az rest&lt;/code&gt; command we can PUT a billing role assignment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Assign SubscriptionCreator role to SP on an EA enrollment account
az rest --method put \
  --uri "https://management.azure.com/providers/Microsoft.Billing/enrollmentAccounts/{enrollmentId}/billingRoleAssignments/{guid}?api-version=2020-05-01" \
  --body '{
    "properties": {
      "principalId": "&amp;lt;SERVICE_PRINCIPAL_OBJECT_ID&amp;gt;",
      "roleDefinitionId": "a0bcee42-bf30-4d1b-926a-48d21664ef71",  # ID for SubscriptionCreator:contentReference[oaicite:42]{index=42}
      "scope": "/providers/Microsoft.Billing/enrollmentAccounts/{enrollmentId}"
    }
}'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would replace &lt;code&gt;{enrollmentId}&lt;/code&gt; with our EA enrollment’s ID, use the SPN’s object ID, and the role-definition ID from the table above. Similarly, &lt;code&gt;EnrollmentReader&lt;/code&gt; is ID &lt;code&gt;24f8edb6-1668-4659-b5e2-40bb5f3a7d7e&lt;/code&gt;, etc. (The Azure CLI also provides billing-specific commands under &lt;code&gt;az billing&lt;/code&gt;, but the REST approach is more direct for EA roles).&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Service Principal with Terraform
&lt;/h2&gt;

&lt;p&gt;As a concrete example, here’s how we might provision a service principal using Terraform. We typically use the &lt;code&gt;azuread&lt;/code&gt; provider to create an Azure AD application and SPN, and optionally a client secret:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;terraform {
  required_providers {
    azuread = { source = "hashicorp/azuread" }
  }
}

# 1. Create the Azure AD application (registration)
resource "azuread_application" "app" {
  display_name = "example-service-principal"
}

# 2. Create the service principal linked to that application
resource "azuread_service_principal" "sp" {
  application_id = azuread_application.app.application_id
}

# 3. Create a client secret for the SP (rotating monthly, for example)
resource "time_rotating" "month" {
  rotation_days = 30
}

resource "azuread_service_principal_password" "password" {
  service_principal_id = azuread_service_principal.sp.object_id
  rotate_when_changed  = { rotation = time_rotating.month.id }
}

# Output the credentials (client_id and client_secret)
output "client_id" {
  value = azuread_application.app.application_id
}
output "client_secret" {
  value     = azuread_service_principal_password.password.value
  sensitive = true
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we run this, Terraform will create an AAD App and a corresponding SPN, and then generate a client secret. The outputs &lt;code&gt;client_id&lt;/code&gt; and &lt;code&gt;client_secret&lt;/code&gt; can be used by our scripts to authenticate. (Always keep the secret safe, e.g. store it in Azure Key Vault rather than plaintext).&lt;/p&gt;

&lt;p&gt;Once the SPN exists, we can use the Azure CLI or Terraform (as above) to assign roles to it. For example, to give this SPN &lt;em&gt;Contributor&lt;/em&gt; rights on a subscription or resource group, use an &lt;code&gt;azurerm_role_assignment&lt;/code&gt; as shown earlier.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;With Azure’s new MFA mandate, any automation using user accounts will break. The fix is to use service principals (or managed identities) for non-interactive authentication. A service principal is like a “service account” for our code: it has its own Azure AD identity and credentials. Managed identities are similar but tied to a specific Azure resource. We then control what the SPN can do by assigning &lt;strong&gt;Azure&lt;/strong&gt; &lt;strong&gt;RBAC&lt;/strong&gt; roles (e.g. Contributor, Owner) at the resource level, and if we’re on an Enterprise Agreement, by assigning &lt;strong&gt;EA billing&lt;/strong&gt; roles (e.g. SubscriptionCreator, EnrollmentReader) at the enrollment level.&lt;/p&gt;

&lt;p&gt;In practice, we would create the SPN (via Terraform, CLI, or portal), assign it the minimum necessary roles, and update our automation scripts to log in with the SPN’s credentials (e.g. &lt;code&gt;az login --service-principal …&lt;/code&gt;). This approach maintains secure automated workflows while complying with the new MFA requirements.&lt;/p&gt;

&lt;p&gt;Sources:&lt;br&gt;
Microsoft documentation-&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/entra/identity/authentication/concept-mandatory-multifactor-authentication#:~:text=" rel="noopener noreferrer"&gt;Mandatory MFA&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/cli/azure/authenticate-azure-cli-mfa?view=azure-cli-latest#:~:text=Action%20is%20required%20if%20you%27re,interactive%20automation%20use%20cases" rel="noopener noreferrer"&gt;Impact of MFA on automation&lt;/a&gt;&lt;br&gt;
&lt;a href="https://devblogs.microsoft.com/devops/demystifying-service-principals-managed-identities/#:~:text=Most%20relevant%20to%20Service%20Principal%2C,is%20using%20Azure%20Active%20Directory%E2%80%A6%E2%80%9D" rel="noopener noreferrer"&gt;Service principals&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#:~:text=Built,36a593fc5850" rel="noopener noreferrer"&gt;Built in RBAC roles&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/assign-roles-azure-service-principals#:~:text=Role%20Actions%20allowed%20Role%20definition,charges%20across%20all%20accounts%20and" rel="noopener noreferrer"&gt;EA Roles assignment&lt;/a&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>automation</category>
      <category>devops</category>
      <category>security</category>
    </item>
    <item>
      <title>Smart Subnet Allocation: Optimizing Your AWS Infrastructure with Terraform</title>
      <dc:creator>suvankit</dc:creator>
      <pubDate>Sat, 13 Jul 2024 19:17:04 +0000</pubDate>
      <link>https://dev.to/suvankit/smart-subnet-allocation-optimizing-your-aws-infrastructure-with-terraform-5c90</link>
      <guid>https://dev.to/suvankit/smart-subnet-allocation-optimizing-your-aws-infrastructure-with-terraform-5c90</guid>
      <description>&lt;p&gt;Picture this: You're orchestrating a complex AWS infrastructure, juggling multiple subnets and a fleet of instances that seem to multiply overnight. Suddenly, you're faced with a puzzle - how do you efficiently allocate these instances across your subnets without turning your VPC into a digital traffic jam 😵?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8zf7j80meo681lkfolo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8zf7j80meo681lkfolo.gif" alt=" " width="220" height="274"&gt;&lt;/a&gt;&lt;br&gt;
 Ahh total mess!! Let's understand the problem statement clearly.&lt;/p&gt;

&lt;p&gt;Imagine you're the conductor of a grand cloud orchestra. You've got a VPC with more than two subnets, and you're tasked with deploying a variety of servers, including those sneaky auto-scaling groups that grow and shrink on a whim. The question that keeps you up at night: "How can I ensure each instance finds its perfect subnet home, automatically 🤔?"&lt;/p&gt;

&lt;p&gt;Sure, AWS offers auto-allocation of IP addresses within a CIDR block, but when you're dealing with a complex VPC architecture, you need something smarter. Something that can look at the big picture and make decisions that keep your network balanced and efficient.&lt;/p&gt;

&lt;p&gt;Ta-daa, here enters The Smart Subnet Allocator 🤓.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazvzmqrehb9utfte9e3n.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fazvzmqrehb9utfte9e3n.gif" alt=" " width="220" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After much head-scratching and coffee-fueled brainstorming, I stumbled upon an elegant solution. Here's the secret sauce:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Subnet Reconnaissance&lt;/strong&gt;: First, we scout out all available subnets in our target VPC. It's like taking inventory of all possible homes for our instances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IP Usage Analytics&lt;/strong&gt;: We then put on our detective hats and calculate how many IPs are being used in each subnet. This gives us a clear picture of which neighborhoods are bustling and which are quiet.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The Great Subnet Sort&lt;/strong&gt;: Armed with this information, we sort our subnets from least crowded to most crowded. It's like arranging your closet from emptiest shelf to fullest.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Round-Robin Magic&lt;/strong&gt;: Finally, we assign our instances to subnets in a round-robin fashion, starting with the least crowded subnet. It's like dealing cards, ensuring everyone gets a fair shot at the best spots.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach ensures that we're always placing new instances in the subnets with the most room to breathe, automatically balancing our network load and making the most efficient use of our VPC real estate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6s1hc081ty67m615nsno.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6s1hc081ty67m615nsno.png" alt=" " width="800" height="910"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By implementing this logic in Terraform, we can automate this entire process, making our infrastructure not just code, but smart code. It's like having a tiny, efficient robot organizing your cloud resources for optimal performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F875g21h8mdp17h4hw92x.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F875g21h8mdp17h4hw92x.gif" alt=" " width="220" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll next dive into the Terraform code that makes this happen. We'll show you how to implement this smart subnet allocation strategy, turning your VPC from a chaotic city into a well-planned metropolis of cloud resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="k"&gt;terraform&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;required_providers&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;aws&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;version&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 2.7.0"&lt;/span&gt;
      &lt;span class="nx"&gt;source&lt;/span&gt;  &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"hashicorp/aws"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We first configured Terraform and required providers. For our use case we took AWS as the cloud provider&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Fetch VPC details&lt;/span&gt;
&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_vpc"&lt;/span&gt; &lt;span class="s2"&gt;"vpc"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_name&lt;/span&gt;
    &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_values&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"available"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Get all subnet IDs inside the VPC&lt;/span&gt;
&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet_ids"&lt;/span&gt; &lt;span class="s2"&gt;"subnets"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;vpc_id&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"my-vpc"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Fetch details for all available subnets&lt;/span&gt;
&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&lt;/span&gt; &lt;span class="s2"&gt;"available_subnets"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_subnet_ids&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt;       &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Get instance allocation details for each subnet&lt;/span&gt;
&lt;span class="k"&gt;data&lt;/span&gt; &lt;span class="s2"&gt;"aws_instances"&lt;/span&gt; &lt;span class="s2"&gt;"instances_in_subnets"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;for_each&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;available_subnets&lt;/span&gt;
  &lt;span class="nx"&gt;filter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"subnet-id"&lt;/span&gt;
    &lt;span class="nx"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the next, we defined our data section in order to get the subnet details from our VPC.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="nx"&gt;locals&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;# Calculate available IP count for each subnet&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_counts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;available_subnets&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt; 
      &lt;span class="nx"&gt;tonumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cidr_block&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="nx"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;aws_instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances_in_subnets&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Sort subnets based on available IP count (ascending order)&lt;/span&gt;
  &lt;span class="nx"&gt;sorted_subnet_counts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nx"&gt;for&lt;/span&gt; &lt;span class="nx"&gt;subnet_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="nx"&gt;in&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subnet_counts&lt;/span&gt; &lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;subnet_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;subnet_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="c1"&gt;# Reverse the sorted list to get descending order&lt;/span&gt;
  &lt;span class="nx"&gt;sorted_subnet_counts_desc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sorted_subnet_counts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code snippet encapsulates the core logic of our solution:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;em&gt;subnet_counts&lt;/em&gt; map calculates the number of available IPs in each 
 subnet, addressing points 1 and 2 of our solution.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;sorted_subnet_counts&lt;/em&gt; transforms this information into a sorted list, 
 implementing point 3.&lt;/li&gt;
&lt;li&gt;Finally, &lt;em&gt;sorted_subnet_counts_desc&lt;/em&gt; reverses the list, preparing us 
 for the round-robin allocation described in point 4.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that we have our sorted list of subnets, let's look at how we can use it to deploy multiple instances with smart subnet allocation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight terraform"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Considering simplest approach to deploy multiple instances &lt;/span&gt;
&lt;span class="k"&gt;variable&lt;/span&gt; &lt;span class="s2"&gt;"instance_count"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;type&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;
  &lt;span class="nx"&gt;default&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# Create EC2 instances with dynamic subnet allocation&lt;/span&gt;
&lt;span class="k"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt; &lt;span class="s2"&gt;"instance"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;count&lt;/span&gt;         &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instance_count&lt;/span&gt;
  &lt;span class="nx"&gt;instance_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"t2.micro"&lt;/span&gt;
  &lt;span class="nx"&gt;subnet_id&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sorted_subnet_counts_desc&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sorted_subnet_counts_desc&lt;/span&gt;&lt;span class="p"&gt;)].&lt;/span&gt;&lt;span class="nx"&gt;subnet_id&lt;/span&gt;

  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"instance-&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;# Other configuration...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code demonstrates the practical application of our subnet allocation strategy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We define a variable &lt;em&gt;instance_count&lt;/em&gt; to specify how many instances we 
 want to deploy.&lt;/li&gt;
&lt;li&gt;The aws_instance resource uses Terraform's count parameter to create 
 multiple instances.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;subnet_id&lt;/em&gt; assignment is where the magic happens. We use the 
 modulo operator (%) to cycle through our sorted subnet list in a 
 round-robin fashion, implementing the fourth point of our solution.&lt;/li&gt;
&lt;li&gt;Each instance is tagged with a unique name for easy identification.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach ensures that our instances are evenly distributed across the available subnets, starting with those that have the most available IPs. It's a simple yet effective way to maintain balance in your VPC as you scale your infrastructure.&lt;/p&gt;

&lt;p&gt;Let's not forget, in the world of cloud infrastructure, a little automation goes a long way 😋.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxsr1fgvlh5e0abfd5sg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzxsr1fgvlh5e0abfd5sg.gif" alt=" " width="220" height="271"&gt;&lt;/a&gt;&lt;br&gt;
 Happy terraforming 🤗!&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>aws</category>
      <category>devops</category>
      <category>cloud</category>
    </item>
  </channel>
</rss>
