LetsDevOps: Setup CI/CD for Azure API Management Service

Introduction


In this article we will implement the CI/CD for the Azure API Management Service.


Azure API Management is a reliable, secure and scalable way to publish, consume and manage API's.


DevOps Architecture



Technology Used


  • GitHub, GitHub Actions

  • Python, REST API, ARM template






APIM Component


As part of the CI/CD, Below list of the component can be deployed.

  1. APIs

  2. Backends

  3. NamedValues

  4. Operations

  5. Operations Policies

  6. APIs policies

This can be customizable through Python Script to deploy only required component as per your requirement.


Code Snippet of Python Script.

https://github.com/sumitraj0103/Letsdevops/blob/main/Deployment-Scripts/APIM-Sync/template-deploy-api-Management.py


# Change to True for Deploy else set False
deploy_apis=True
deploy_namedValues=False
deploy_backends=False
deploy_operations=True
deploy_policies=True
deploy_ops_policies=True

Component Deployment Sequence



Configuration Update


There might be some configuration that needs to be updated before Deploying to environment. For that We have created Python script which will update the ARM template with respect to environment Value specified in the properties File.


Python Script Details

Properties File Like




Setup Repo for CI/CD

As per the discussed method we can setup the CI/CD workflow. All the project related script and File is publicly available at.

https://github.com/sumitraj0103/Letsdevops


Now lets setup each Part one by One.


Repo Setup
  1. First we need to make sure the ARM template extracted from the Dev API Management Service and Imported to GitHub. Once you extract the ARM template there will be Two Files but we only required template.json File to be imported.




Properties Update

Next we need to see what are the Properties needs to be updated before we deploy to the Pre Prod and Prod. Since we extracted the template from Dev APIM all the configuration related to dev will be available in the ARM template. Hence to Deploy on other environment we need to update the ARM template and that will be achieved through Developed Python script.


In this case review the template and update the below files.



Example:


If you see the below example we are using the properties file where left value will be replaced by Right Value.

Deployment Script

You can fork the Deployment script and properties python script along with requirement.txt file and import to your Repo.


https://github.com/sumitraj0103/Letsdevops/tree/main/Deployment-Scripts




Workflow File

Since we are using the GitHub Actions for Demo you can get the Workflow file and Import to GitHub Account.


https://github.com/sumitraj0103/Letsdevops/blob/main/.github/workflows/apim-cicd.yml


name: APIM-CherryPick-TemplateDeploy

# Manual trigger with parameters
on:
  workflow_dispatch:
    inputs:
      #Name of your Source Cosmos DB
      ENVIRONMENT:
        description: 'Deployment Environment (npr/prp/prd)'
        required: true
        default: 'npr'
        
      ARMtemplate_Path:
        description: 'ARM template Json file to create apis/Collection. Path Relative tO GITHUB'
        required: true
        default: '/APIM/arm-template/'
            
      apis_list:
        description: 'List of APIs to Deploy--> , separated'
        required: true
        default: 'autouwrt-cust-dly,cardxlos-autouwrt-dpst-dly'

jobs:
  #############################################################
  # This is packaging up the files from Git to the Artifacts files
  #############################################################
  Build:
    runs-on: ubuntu-latest
    env:
      input_commitid: '${{ github.event.inputs.INPUT_COMMITID }}'

    # Checkout code
    steps:
    - name: Checkout repo
      uses: actions/checkout@v2

    # Publish Artifact: Publish: Deployment-Scripts
    - name: 'Publish Artifact: APIM SYNC' 
      uses: actions/upload-artifact@v2
      with:
        name: 'deployment-scripts'
        path: '${{ github.workspace }}/Deployment-Scripts/APIM-Sync/'
    
    - name: Install dependencies
      run: |
        cd "$GITHUB_WORKSPACE/Deployment-Scripts/Update-Properties/"
        python3 -m pip install --upgrade pip
        pip install -r requirements.txt
        
    # Optional: Add step to run tests here
    - name: Update Properties on Non-Production Environment
      if: ${{ github.event.inputs.ENVIRONMENT == 'npr' }}
      run: |
        cd "$GITHUB_WORKSPACE/APIM/arm-template/"
        python3 $GITHUB_WORKSPACE/Deployment-Scripts/Update-Properties/properties-update.py \
          '${{ github.workspace }}/APIM/npr-app-config.properties' \
          '${{ github.workspace }}/APIM/arm-template/'
    
    - name: Update Properties on Pre-Production Environment
      if: ${{ github.event.inputs.ENVIRONMENT == 'prp' }}
      run: |
        cd "$GITHUB_WORKSPACE/APIM/arm-template/"
        python3 $GITHUB_WORKSPACE/Deployment-Scripts/Update-Properties/properties-update.py \
          '${{ github.workspace }}/APIM/prp-app-config.properties' \
          '${{ github.workspace }}/APIM/arm-template/'
         
    - name: Update Properties on Production Environment
      if: ${{ github.event.inputs.ENVIRONMENT == 'prd' }}
      run: |
        cd "$GITHUB_WORKSPACE/APIM/arm-template/"
        python3 $GITHUB_WORKSPACE/Deployment-Scripts/Update-Properties/properties-update.py \
          '${{ github.workspace }}/APIM/prd-app-config.properties' \
          '${{ github.workspace }}/APIM/arm-template/'
          
    # Publish Artifact: Publish: Template JSON
    - name: 'Publish Artifact: Template JSON' 
      uses: actions/upload-artifact@v2
      with:
        name: 'template-file'
        path: '${{ github.workspace }}/${{ github.event.inputs.ARMtemplate_Path }}'
    
        
#############################################################
# Deploy to Dev
#############################################################
  Dev:
    if: ${{ github.event.inputs.Environment == 'npr' }}
    needs: Build
    runs-on: ubuntu-latest
    env:
       TargetAPIM_NAME: 'devops-apimtest-1'
       TargetAPIM_RG: 'devops-confluent-test' 
       keyVaultName: 'akv-sp'
 
        
    steps:
    # Login to Azure
    - name: Login via Az module
      uses: Azure/login@v1.4.5
      with:
        creds: | 
          ${{ secrets.SP_NPR }}
          
    # Download secret from KeyVault Secrets
    - name: Download publish profile from KeyVault Secrets
      uses: Azure/get-keyvault-secrets@v1
      with:
        keyvault: ${{ env.keyVaultName }}
        secrets: 'sp-npr-appid,sp-npr-secretkey,sp-npr-tenantid,sp-npr-subscriptionid'
      id: AzureSPCred
      
    # Download Artifact: deployment-scripts
    - name: 'Download Artifact: ARM-Templates' 
      uses: actions/download-artifact@v2
      with:
        name: 'deployment-scripts'
        path: ${{ github.workspace }}/Deployment-Scripts/APIM-Sync/

    # Download Artifact: Publish: Template JSON
    - name: 'Publish Artifact: Template JSON' 
      uses: actions/download-artifact@v2
      with:
        name: 'template-file'
        path: '${{ github.workspace }}/${{ github.event.inputs.ARMtemplate_Path }}'
        
    - name: Install dependencies
      run: |
        cd "$GITHUB_WORKSPACE/Deployment-Scripts/APIM-Sync/"
        python3 -m pip install --upgrade pip
        pip install -r requirements.txt
        
    - name: Deploy Template
      run: |
       chmod +x $GITHUB_WORKSPACE/Deployment-Scripts/APIM-Sync/template-deploy-api-Management.py
       python3 $GITHUB_WORKSPACE/Deployment-Scripts/APIM-Sync/template-deploy-api-Management.py
      env:
        ARMtemplate_Path: '${{ github.workspace }}/${{ github.event.inputs.ARMtemplate_Path }}'
        TargetAPIM_NAME: ${{ env.TargetAPIM_NAME }}
        TargetAPIM_RG: ${{ env.TargetAPIM_RG }}
        CLIENT_SECRET: ${{ steps.AzureSPCred.outputs.sp-npr-secretkey }}
        CLIENT_ID: ${{ steps.AzureSPCred.outputs.sp-npr-appid }}
        TENANT_ID: ${{ steps.AzureSPCred.outputs.sp-npr-tenantid }}
        SUBSCRIPTION_ID: ${{ steps.AzureSPCred.outputs.sp-npr-subscriptionid }}
        apis_list: ${{ github.event.inputs.apis_list }}

Configure GitHub Actions


Azure Service Principle

For all the authentication we are using the Service Principle so if you want to use the same please create SP and set the Permission to access to API Management service and Key Vault


KeyVault

In the workflow we are using the Key Vault to fetch the below required details. Make sure the Key Vault access policies setup to access by Service Principle

  • sp-npr-appid

  • sp-npr-secretkey

  • sp-npr-tenantid

  • sp-npr-subscriptionid


    - name: Download publish profile from KeyVault Secrets
      uses: Azure/get-keyvault-secrets@v1
      with:
        keyvault: ${{ env.keyVaultName }}
        secrets: 'sp-npr-appid,sp-npr-secretkey,sp-npr-tenantid,sp-npr-subscriptionid'
      id: AzureSPCred

Workflow File


Workflow Input Details can be updated.

  • ENVIRONMENT

  • ARMtemplate_Path

  • apis_list


  workflow_dispatch:
    inputs:
      #Name of your Source Cosmos DB
      ENVIRONMENT:
        description: 'Deployment Environment (npr/prp/prd)'
        required: true
        default: 'npr'
        
      ARMtemplate_Path:
        description: 'ARM template Json file to create apis/Collection. Path Relative tO GITHUB'
        required: true
        default: '/APIM/arm-template/'
            
      apis_list:
        description: 'List of APIs to Deploy--> , separated OR all for all the Object'
        required: true
        default: 'all'

Env Setting update as per the Environment

  • TargetAPIM_NAME --> Name of the APIM service

  • TargetAPIM_RG --> APIM Service Resource Group

  • keyVaultName --> KeyVault where SP credential info setup.


  Dev:
    if: ${{ github.event.inputs.Environment == 'npr' }}
    needs: Build
    runs-on: ubuntu-latest
    env:
       TargetAPIM_NAME: 'devops-apimtest-1'
       TargetAPIM_RG: 'devops-confluent-test' 
       keyVaultName: 'akv-sp'

Create Service Principle secret in GitHub Actions Secret for the Connectivity to Azure.


Secret Name: SP_NPR [Service Principle Non Prod]

value:

{
    "clientId": "Update me:  Client ID ",
    "clientSecret": "Update me: Client Secret",
    "subscriptionId": "Update me: Subscription ID",
    "tenantId": "Update me: Tenant ID",
    "activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
    "resourceManagerEndpointUrl": " https://management.azure.com/",
    "activeDirectoryGraphResourceId": " https://graph.windows.net/",
    "sqlManagementEndpointUrl": " https://management.core.windows.net:8443/",
    "galleryEndpointUrl": " https://gallery.azure.com/",
    "managementEndpointUrl": " https://management.core.windows.net/"
}


    steps:
    # Login to Azure
    - name: Login via Az module
      uses: Azure/login@v1.4.5
      with:
        creds: | 
          ${{ secrets.SP_NPR }}

Run GitHub Actions


Actions --> APIM-CherryPick-TemplateDeploy --> Run workflow.