← Back to list

APIOps with Azure API Management —  Infrastructure and Code Deployments

with Terraform and Azure Powershell in Github Actions

DevOpsWithYoge · 2024-05-08 14:17 · 18 claps · 6.0 min read
#azure-api-management #terraform #apiops #azure #azure-devops
Open on Medium ↗
Wiki topics: BIZ · Business Strategy ☁️ · DevOps & Cloud 🔓 · Open Source

APIOps with Azure API Management — Infrastructure and Code Deployments

with Terraform and Azure PowerShell in GitHub Actions

This blog explains the automation of Azure API management resource provisioning using terraform and code deployment using GitHub actions pipeline along with Azure PowerShell to deploy the policies dynamically with reusable and better maintainability pattern.

Contexts

  • APIM Keywords
  • Implementation Diagram for Automated Deployment
  • APIM Infrastructure deployment
  • APIM API Policies deployment
  • Realtime use cases
  • Conclusion

APIM Keywords

  • apim api — application programming interface’s created with inbound — outbound- backed and secured with integrated policies.
  • apim product — user created category for api’s to belong .
  • apim subscription — creating a subscription for product makes it easy to share the designated apim to external users with defined scope of api’s usage.
  • apim named values — helpful to retain the secret values which will be used by the apim api’s

Implementation Diagram for Automated deployment

Fig 1.0 Overall Automated Deployment Pattern for APIM

Fig 1.0 Overall Automated Deployment Pattern for APIM

I have ensured to create two repositories considering the one repository for Cloud Infrastructure deployment and other for Azure PaaS Code Deployments. if you have a large infrastructure in cloud and wants to segregate and maintain then its good to have two repos otherwise you can use single repository to deploy both infrastructure and policy updates.

I will explain the above deployment pattern in two categories .

  • Category 1: APIM Infrastructure Deployment
  • Category 2: APIM API policies Deployment

APIM Infrastructure Deployment

Skipping creation of resource group — virtual network — keyvault with terraform code.

💡 For Entra ID set up (backend-service) ensure to checkout this blog ➡️ https://medium.com/@devopswithyoge/streamlining-azure-integration-services-via-microsoft-entra-id-using-terraform-f41b64b02020

Note: For Azure APIM if you use internal or External virtual network connectivity then create public IP and a dedicated subnet for APIM alone.

you can generate OpenAPI Specifications from tools like Swagger and Postman .

Consider a separate repository to maintain the infrastructure as Code components and deploy the resources in cloud using it .

APIM Creation with Terraform

For APIM — enable RBAC to the storage accounts/servicebus/eventhubs or follow az ad group deployment pattern from the highlighted link.

Create a Open API specification for your API — I have used the sample Open api specification generated from postman

{
    "openapi":"3.0.1",
    "info": {
        "version" : "1",
        "title": "storage-get"
    },
    "paths" : {
        "/": {
            "get" : {
                "operationId": "get",
                "tags":["Storage Read"],
                "parameters": [],
                "responses":{
                    "200":{
                        "description": "Success Reponse"
                    },
                    "default" : {
                        "description": "Response Message",
                        "content" : {
                            "application/json" : {
                                "schema" : {
                                    "$ref": "#/components/schemas/response-message"
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    "components": {
        "schemas" : {
            "response-message" : {
                "type" : "object",
                "properties" : {
                    "correlationId" : {
                        "type": "string"
                    }
                }
            }
        }
    }
}
############################## Terraform Block ###################################
#Azure APIM Creation
resource "azurerm_api_management" "example" {
  name                = "example-apim"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  publisher_name      = "DevOpsWithYoge"
  publisher_email     = "user@devopswithyoge.io"

  sku_name = "Developer_1"
}
# Azure APIM API
resource "azurerm_api_management_api" "example" {
  name                = "storage-read"
  resource_group_name = azurerm_resource_group.example.name
  api_management_name = azurerm_api_management.example.name
  revision            = "1"
  display_name        = "Example API"
  path                = "example"
  protocols           = ["https"]

  import {
    content_format = "openapi+json"
    content_value  = file("../OpenAPISpecifications/storage-read.openapi.1.json")
  }
}

#Azure APIM Products
resource "azurerm_api_management_product" "example" {
  product_id            = "storage-fetch"
  api_management_name   = azurerm_api_management.example.name
  resource_group_name   = azurerm_resource_group.example.name
  display_name          = "Storage Fetch Services"
  subscription_required = true
  approval_required     = true
  published             = true
}

#Azure APIM Product API
resource "azurerm_api_management_product_api" "example" {
  api_name            = data.azurerm_api_management_api.example.name
  product_id          = data.azurerm_api_management_product.example.product_id
  api_management_name = data.azurerm_api_management.example.name
  resource_group_name = data.azurerm_api_management.example.resource_group_name
}

# Named values for APIM api (optional)
# resource "azurerm_api_management_named_value" "example" {
#     name                = "example-apimg"
#     resource_group_name = azurerm_resource_group.example.name
#     api_management_name = azurerm_api_management.example.name
#     display_name        = "ExampleProperty"
#     value               = "Example Value"
#   }

APIM API policies Deployment

💡Note: Ensure Policies are deploment from separate repository if you use other Azure PaaS resource , if you only using apim in azure then it can be coupled with the infrastructre pipelines and repo itself.

Policies for APIM api can be kept in the scope of Global — Product — API le

Policy in Folder: SampleAPI/blob/read-blob.xml.

<!-- Policy to Read Blob from storage account -->
<policies>
  <inbound>
      <base/>
      <set-variable name="x-ms-date" value="@(DateTime.UtcNow.ToString("R"))" />
      <authentication-managed-identity resource="https://storage.azure.com" output-token-variable-name="msi-access-token" ignore-error="false" />
      <set-header name="Authorization" exists-action="override">
         <value> @("Bearer "+ (string)context.Variables["ms-access-token"]) </value>
      </set-header>
      <set-header name="Content-Type" exists-action="override">
         <value>application/json </value>
      </set-header>
      <set-header name="x-ms-date" exists-action="override">
         <value>@((string)context.Variables["x-ms-date"])</value>
      </set-header>
      <set-header name="x-ms-version" exists-action="override">
         <value>2019-04-01</value>
      </set-header>
      <set-method>GET</set-method>
      <set-backend-service base-url="https://#{STORAGE_ACC_NAME}#.blob.core.windows.net/" />
      <rewrite-uri template="#{STORAGE_CONT_NAME}#/#{FILE_NAME}#" />
  </inbound>
  <backend>
     <base/>
  </backend>
  <outbound>
      <base/>
  </outbound>
  <on-error>
      <base/>
  </on-error>
</policies> 

YAML — To deploy APIM API Policies

Base Pipeline — in .github/workflows

name: Read-blob-api-policy 
on:
  push:
    branches:
      - master
    paths:
      - 'SampleAPI/blob/read-blob.xml'
  workflow_dispatch: # for enabling manual trigger
env:
  API_NAME: 'storage-read' #apim api name
  POLICY_PATH: 'SampleAPI/blob/read-blob'
  BLOB_CONTAINER: 'samplecontainer'
  ENVIRONMENT_NAME: 'dev'
  OPERATION_NAME: 'sampleGet'

jobs:
  deploy_dev:
    runs-on: 'ubuntu-latest'
    environment: Development
    steps:
      - name: Checkout action
        uses: actions/checkout@master
      - name: Update Environment Variables
        shell: pwsh
        run: |
          echo "BLOB_FILE_NAME= Sample/${{env.ENVIRONMENT_NAME}}joke.json" | Out-File FilePath $Env:GITHUB_ENV -Encoding utf 8 -Append 

      - name: apim_policy_stg
        id: apim_policy_stg
        uses: ./pipelines/apim_policy/deploy/stg
        with:
           ad_client: ${{secrets.AD_CLIENT_ID}}
           ad_client_secret: ${{secrets.AD_CLIENT_SECRET}}
           ad_tenant_id: ${{secrets.AD_TENANT_ID}}
           subscription_id: ${{var.SUBCRIPTION_ID}} #from Environment variables
           api_name: ${{env.API_NAME}}
           blob_container_name: ${{env.BLOB_CONTAINER}}
           blob_name: ${{env.BLOB_FILE_NAME}} #dynamically read from previous step
           policy_path: ${{env.POLICY_PATH}}
           environment_name: ${{env.ENVIRONMENT_NAME}}
           apim_operation_name: ${{env.APIM_OPERATION_NAME}}

Here in the specified location ./pipelines/apim_policy/deploy/stg — retain the reusable pipeline templates

name: APIM STORAGE POLICY
description: 'deploy APIM policy for storage account read data'
inputs:
   ad_client:
     description: 'client id'
     required: true
   ad_client_secret:
     description: 'client secret'
     required: true
   ad_tenant_id: 
     description: 'tenant id'
     required: true
   subscription_id: 
      description: 'subcription id'
      required: true
   api_name: 
     description: 'api name'
     required: true
   blob_container_name: 
     description: 'storage container name'
     required: true
   blob_name: 
     description: 'blob name'
     required: true
   policy_path:
     description: 'policy path'
     required: true
   environment_name:
     description: 'environment name'
     required: true
runs:
  using: "composite"
  steps:
    - uses: actions/checkout@v2
    - name: Update vars with env
      shell: pwsh
      run: |
         echo "RG_NAME=rg-${{inputs.environment_name}}-apim" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
         echo "APIM_NAME= apim-${{inputs.environment_name}}-int" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
         echo "AAD_APP_NAME=api-${{inputs.environment_name}}-backend-${{inputs.apim_name}}" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append
         echo "STORAGE_ACC_NAME=stg${{inputs.environment_name}}stack" | Out-File -FilePath $Env:GITHUB_ENV -Encoding utf-8 -Append

    - name: Install Az Module
      shell: pwsh
      run: Install-Module -Name Az.Accounts -Scope CurrentUser -Repository PSGallery -force

    - name: Azure Login
      uses: azure/login@v1
      with:
        client-id: ${{ inputs.ad_client }}
        tenant-id: ${{ inputs.ad_tenant_id }}
        subscription-id: ${{ inputs.subscription_id }} 
        enable-AzPSSession: true

    - name: Update APIM policy
      id: apim_policy
      uses: azure/powershell@v1
      azPSVersion: latest
      with:
        inlineScript: |
          $applicationID = (Get-AzADApplication -DisplayName "${{env.AAD_APP_NAME}}").AppId
          $PolicyPath = "${{inputs.policy_path}}"
          $apimContext = New-AzApiManagementContext -ResourceGroupName "${{env.RG_NAME}}" -ServiceName "${{env.APIM_NAME}}"
          $Policy = Get-Content -Path $PolicyPath

          #################### updating the static placeholders with dynamic values #################
          $Policy = $Policy.replace('#{BACKEND_APP_ID}#', $applicationID)
          $Policy = $Policy.replace('#{TENANT_ID}#', ${{inputs.ad_tenant_id}})
          $Policy = $Policy.replace('#{CLAIM_ROLE}#', ${{inputs.apim_name}}.${{inputs.apim_operation_name}})
          $Policy = $Policy.replace('#{STORAGE_ACC_NAME}#', ${{env.STORAGE_ACC_NAME}})
          $Policy = $Policy.replace('#{STORAGE_CONT_NAME}#', ${{inputs.blob_container_name}})
          $Policy = $Policy.replace('#{FILE_NAME}#', ${{inputs.blob_name}})

          Set-Content -Path $PolicyPath -Value $Policy
          Set-AzApiManagementPolicy -Context $apimContext -ApiId "${{inputs.apim_name}}" -OperationId "${{inputs.apim_operation_name}}" -PolicyFilePath -Format "application/vnd.ms-azure-apim.policy.raw+xml"

Using this APIM you can connect to other Azure resources like service bus , event-hubs, storage accounts , function app and logic apps etc.

GihubLink : apiops-repo

Real Time use cases:

Fig 1.1 Use case connectivity depection for APIM and Azure PaaS

Fig 1.1 Use case connectivity depection for APIM and Azure PaaS

  • You wanted to expose your function app url to the client , in that case you can add function app (https triggered) url as api backend and whenever the api is trigger it will inturn trigger the function app to process the data with business logic and sends the results to the client whether its success or failed.
  • Same applicable for logic apps
  • In some scenarios you want to send messages to service bus designated topic’s subscription in that case also you can use the api to have service bus subscriptions in backend and it will be helpful to communicate internally.

Conclusion

  • The APIM can also be connected to On Prem DB. Just that in this article I have focused in APIM and functionalities with Azure PaaS service.
  • Its capability is expandable. APIM makes the development of API easy and quick time to market .
  • Enabling Developer portal as its plus and minuses. Best practice is develop the APIM from code base and complete it. if its necessary a fast paced project then you can opt for developer portal.

I hope now you understood the complete automation of apim with respect to deployment and code aspect.

Give a 👏Clap if you enjoyed this content! 🤝 Don’t forget to hit that follow button for more exciting updates! Your support fuels my creativity! 🚀

References


메타데이터
post_id
5fdc66841da7
slug
apiops-with-azure-api-management-infrastructure-and-code-deployments-5fdc66841da7
url
https://medium.com/@devopswithyoge/apiops-with-azure-api-management-infrastructure-and-code-deployments-5fdc66841da7
canonical_url
https://medium.com/@devopswithyoge/apiops-with-azure-api-management-infrastructure-and-code-deployments-5fdc66841da7
author_url
https://medium.com/@devopswithyoge
status
ok
fetched_at
2026-07-23 21:46:44