Search code examples
xmlazureterraformterraform-provider-azureapim

How to add policies for different APIs as per api requirement


I am writing a terraform code where I am writing xml as well. I have two APIs and different policy requirements. I am trying to achieve it as below code but it doesn't help. Does anyone know how to add policies according to the APIs requirement?

<choose>
     ########## API ONE ###########
     <when condition="@(context.Request.Headers.GetValueOrDefault("ApiKey") == "Default")">
         <rate-limit-by-key calls="10" renewal-period="60" counter-key="@(context.Request.IpAddress)" />
     </when>
     ########## API TWO ###########
     <when condition="@(context.Subscription.Name.Contains("API_name") and context.Request.Headers.GetValueOrDefault("ApiKey") == "Default")">
          <rate-limit-by-key calls="2000" renewal-period="60" counter-key="@(context.Request.Headers.GetValueOrDefault("Authorization","").AsJwt()?.Subject)" />
      </when>
      <otherwise>
           <rate-limit-by-key calls="10000" renewal-period="60" counter-key="@(context.Subscription.Id)" />
      </otherwise>

Solution

  • Resource azurerm_api_management_api_policy manages an API Management API Policy.

    You can:

    • Use a single template file for all policies
    • Use separate templates, one per policy

    Using separate policy files for each API

    Advantages:

    • Simplicity: Each template file is simpler and easier to understand, as it only contains the configuration for one policy.
    • Isolation: Changes or errors in one template file don't affect the others.

    Disadvantages:

    • Increased management: More files to manage and keep track of.
    • Potential redundancy: If there are common elements in the policies, they will be duplicated in each template file.

    Example - consider the following folder structure:

    policies/
      foo-policy.xml
      bar.policy.xml
    

    And then create azurerm_api_management_api_policy resources for each policy.

    Example:

    resource "azurerm_api_management_api_policy" "foo" {
      api_name            = "foo-api"
      api_management_name = var.api_management_name
      resource_group_name = var.resource_group_name
    
      xml_content = file("${path.module}/policies/foo-policy.xml")
    }
    
    resource "azurerm_api_management_api_policy" "bar" {
      api_name            = "bar-api"
      api_management_name = var.api_management_name
      resource_group_name = var.resource_group_name
    
      xml_content = file("${path.module}/policies/bar-policy.xml")
    }
    

    Using one template file for the policies

    As an alternative, you can have one single template for the API policies and use templatefile to generate the desired content.

    Advantages:

    • Centralization: All policy configurations are in one place, making it easier to manage and understand the overall policy structure.
    • Reduced redundancy: If there are common elements in the policies, they can be defined once in the template, reducing duplication.
    • Dynamic generation: The policy can be dynamically generated based on variables, allowing for more flexible and programmable configuration.

    Disadvantages:

    • Complexity: The template file can become complex and hard to read if there are many conditions or a lot of nested logic.
    • Risk of errors: A mistake in the template or in the variable values can affect all policies, not just one.

    Example - file policies/policy-template.tpl

    <choose>
      %{ if api_version == "one" ~}
      <when condition='@(context.Request.Headers.GetValueOrDefault("ApiKey") == "Default")'>
        <rate-limit-by-key calls="10" renewal-period="60" counter-key='@(context.Request.IpAddress)' />
      </when>
      %{ endif ~}
      %{ if api_version == "two" ~}
      <when condition='@(context.Subscription.Name.Contains("API_name") and context.Request.Headers.GetValueOrDefault("ApiKey") == "Default")'>
        <rate-limit-by-key calls="2000" renewal-period="60" counter-key='@(context.Request.Headers.GetValueOrDefault("Authorization","").AsJwt()?.Subject)' />
      </when>
      <otherwise>
          <rate-limit-by-key calls="10000" renewal-period="60" counter-key="@(context.Subscription.Id)" />
      </otherwise>
      %{ endif ~}
    </choose>
    

    Terraform code:

    resource "azurerm_api_management_api_policy" "one" {
      api_name            = "one-api"
      api_management_name = var.api_management_name
      resource_group_name = var.resource_group_name
    
      xml_content = templatefile("${path.module}/policies/policy-template.tpl", {
        api_version = "one"
      })
    }
    
    resource "azurerm_api_management_api_policy" "two" {
      api_name            = "two-api"
      api_management_name = var.api_management_name
      resource_group_name = var.resource_group_name
    
      xml_content = templatefile("${path.module}/policies/policy-template.tpl", {
        api_version = "two"
      })
    }