A Consistent Approach with Resource Group Name in the Terraform Module between AzureRM and AzAPI providers

A Consistent Approach with Resource Group Name in the Terraform Module between AzureRM and AzAPI providers

Introduction

When working with Azure and Terraform, many teams rely heavily on the AzureRM provider for creating and managing Azure resources. The AzureRM provider is feature-rich and allows for a broad range of Azure services to be managed through Infrastructure as Code (IaC). However, there are times when specific resources or features are not yet available through AzureRM. This is where the AzAPI provider comes into play.

The AzAPI provider is particularly useful for scenarios where a newly released Azure resource type or feature needs to be managed before it is fully supported in AzureRM. However, using both providers together can lead to challenges, especially around maintaining consistency in how input variables like resource group names are handled.

In this article, we'll explore a solution for maintaining consistency in Terraform modules by using resource group names as input variables, even when working with the AzAPI provider. We'll demonstrate how to dynamically derive the parent_id for AzAPI resources using the subscription ID, avoiding the need to hardcode values or change module structures.

Why Use AzAPI Alongside AzureRM?

The Terraform community predominantly uses the AzureRM provider because it supports a wide array of Azure services. It integrates seamlessly with Azure's authentication methods, supports state management, and is well-documented. However, when a feature is newly released or niche, it may not yet be implemented in AzureRM. This creates a need to use the AzAPI provider, which allows for direct interaction with the Azure REST API.

For example, if you need to create a new feature that is only available in preview (like a specific version of the API Management service), the AzAPI provider can be used. This provider allows you to define the resource directly using Azure's API schema.

The Problem: Consistency in Module Inputs

Most Terraform modules are designed to take resource group names as input variables. This approach is intuitive and allows the user to specify where resources should be created without needing to manage resource group IDs explicitly. This is the case in about 95% of modules.

However, the AzAPI provider often requires a parent_id, which is typically the full resource group ID, not just the name. While you could provide this ID directly, it deviates from the common practice of using resource group names and introduces inconsistency in how modules are used.

The Solution: Dynamically Deriving parent_id with azurerm_client_config

To maintain consistency, we can use the azurerm_client_config data source to retrieve the subscription ID dynamically. By doing this, we can construct the parent_id based on the subscription ID and resource group name, keeping the input variable as the resource group name.

Example: Using AzAPI to Create an API Management Service

Here's an example of how to use the AzAPI provider with a resource group name as an input, leveraging azurerm_client_config to derive the parent_id:

terraform {
  required_version = ">= 1.2"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = ">= 3.67"
    }
    azapi = {
      source  = "Azure/azapi"
      version = ">= 1.15.0"
    }
  }
}

# Retrieve the subscription ID dynamically

data "azurerm_client_config" "current" {}

# Define input variables for the module

variable "resource_group_name" {
  description = "The name of the resource group where the resource will be created."
  type            = string
}

variable "location" {
  description = "The Azure region where the resource will be created."
  type            = string
}

variable "name" {
  description = "The name of the API Management service."
  type            = string
}

# Use the azapi provider to create an API Management service 
# Only part related to parent_id

resource "azapi_resource" "apim" {
  type        = "Microsoft.ApiManagement/service@2023-03-01-preview"
  name      = var.name
  location  = var.location
  # Construct the parent_id using the subscription ID and resource group name
  parent_id = /subscriptions/${data.azurerm_client_config.current.subscription_id}/resourceGroups/${var.resource_group_name}"

..................        


Explanation

- `azurerm_client_config` Data Source: This retrieves the subscription ID of the currently authenticated user, allowing the module to use the subscription ID without hardcoding it.

- Input Variables: resource_group_name, location, and name are inputs to the module, keeping the structure consistent with other modules that use AzureRM alone.

- `parent_id` Construction: The parent_id is constructed dynamically by combining the subscription ID and the resource group name, matching the structure that the AzAPI resource expects.

Why This Approach?

1. Consistency with Existing Modules: By using resource group names as input, you maintain the same user experience across modules, regardless of whether they use AzureRM or AzAPI.

2. Avoid Hardcoding Subscription IDs: Using azurerm_client_config eliminates the need to manually provide or update subscription IDs, making the module more portable and easier to use.

3. Flexibility for New Features: This method allows you to quickly integrate new Azure features without waiting for AzureRM support, while still keeping your Terraform module structure familiar.

Conclusion

Integrating AzAPI with AzureRM can be a powerful way to leverage the latest Azure features while maintaining consistency in your Terraform modules. By using azurerm_client_config to dynamically derive the parent_id, you can keep your inputs simple and familiar, using resource group names as you would with purely AzureRMresources.

This approach allows your Terraform codebase to remain clean and user-friendly, even as you adopt new capabilities from Azure. It ensures that your modules can adapt to changes in Azure's offerings without sacrificing the consistency and simplicity that your team is accustomed to.

By following this method, you can ensure that your infrastructure code is prepared for the evolving landscape of Azure services, all while maintaining a seamless user experience for your team.


This article covers the context, the problem, and the solution, with a practical example and explanation. It should serve as a useful guide for anyone needing to bridge the gap between AzureRM and AzAPI in their Terraform workflows.

要查看或添加评论,请登录

Marek Kubovic的更多文章

社区洞察

其他会员也浏览了