How to manage Azure Api Management CA Certificates through ARM templates

Viewed 600

I'm trying to manage CA certificates in Azure APIM through ARM but everything I tried gave no positive result.

For visualization, this is what I'm talking about: CA Certificates in Azure Portal's APIM view

When I look at the schema Microsoft.ApiManagement/service, there's a section for certificates where I can set the storeName variable but without results.

For sanity, I tried to upload it though Powershell plus manually and both option worked but that CA Certificate got wiped from the APIM at each deployment of my ARM template even if I used the "Incremental" option.

First I tried to modify the APIM ARM template by adding that block to the "properties" section:

"certificates": [
{
  "encodedCertificate": "[parameters('RootCertificateBase64Content')]",
  "certificatePassword": "[parameters('RootCertificatePassword')]",
  "storeName": "Root"
}]

Here's my first test snippet for complete traceability:


{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "apimName": {
      "type": "string",
      "metadata": {
        "description": "Name of the apimanagement"
      }
    },
    "location": {
      "type": "string",
      "defaultValue": "[resourceGroup().location]",
      "metadata": {
        "description": "Location for all resources."
      }
    },
    "sku": {
      "type": "string",
      "allowedValues": [
        "Developer",
        "Standard",
        "Premium"
      ],
      "defaultValue": "Developer",
      "metadata": {
        "description": "The pricing tier of this API Management service"
      }
    },
    "skuCapacity": {
      "type": "string",
      "allowedValues": [
        "1",
        "2"
      ],
      "defaultValue": "1",
      "metadata": {
        "description": "The instance size of this API Management service."
      }
    },
    "subnetResourceId": {
      "type": "string",
      "metadata": {
        "description": ""
      }
    },
    "RootCertificateBase64Content": {
      "type": "string",
      "metadata": {
        "description": "The Root certificate content"
      }
    },
    "RootCertificatePassword": {
      "type": "string",
      "metadata": {
        "description": "The Root certificate password"
      }
    }
  },
  "variables": {
    "publisherEmail": "whatever@heyho.com",
    "publisherName": "Whatever Team",
    "notificationSenderEmail": "whatever@heygo.com"
  },
  "resources": [
    {
      "apiVersion": "2019-12-01",
      "name": "[parameters('apimName')]",
      "type": "Microsoft.ApiManagement/service",
      "location": "[parameters('location')]",
      "sku": {
        "name": "[parameters('sku')]",
        "capacity": "[parameters('skuCapacity')]"
      },
      "properties": {
        "notificationSenderEmail": "[variables('notificationSenderEmail')]",
        "publisherEmail": "[variables('publisherEmail')]",
        "publisherName": "[variables('publisherName')]",
        "virtualNetworkConfiguration": {
          "subnetResourceId": "[parameters('subnetResourceId')]"
        },
        "virtualNetworkType": "Internal",
        "certificates": [
        {
          "encodedCertificate": "[parameters('RootCertificateBase64Content')]",
          "certificatePassword": "[parameters('RootCertificatePassword')]",
          "storeName": "Root"
        }]
      },
      "identity": {
        "type": "SystemAssigned"
      }
    }
  ],
  "outputs": {
    "apiManagementPrivateHostIp": {
      "type": "string",
      "value": "[reference(concat(resourceId('Microsoft.ApiManagement/service', parameters('apimName')))).privateIPAddresses[0]]"
    }
  }
}

Second alternative I tried was to use the Microsoft.ApiManagement/service/certificates schema. There is no option there to specify the StoreName so I assumed it wasn't the right schema but I tried anyway. All attempts generated a certificate in the built-in Certificates store instead of the CA Certificates store.

Here's my second attempt's snippet:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "apimName": {
      "type": "string",
      "metadata": {
        "description": "The parent APIM name"
      }
    },
    "certificateName": {
      "type": "string",
      "metadata": {
        "description": "The certificate name"
      }
    },
    "CertificateBase64Content": {
      "type": "string",
      "metadata": {
        "description": "The content of the certificate"
      }
    },
    "CertificatePassword": {
      "type": "string",
      "metadata": {
        "description": "The certificate password"
      }
    }
  },
  "resources": [
    {
      "name": "[concat(parameters('apimName'), '/Root/', parameters('certificateName'))]",
      "type": "Microsoft.ApiManagement/service/certificates",
      "apiVersion": "2019-01-01",
      "properties": {
        "data": "[parameters('CertificateBase64Content')]",
        "password": "[parameters('CertificatePassword')]"
      }
    }
  ],
  "outputs": {}
}

While looking at terraform documentation, it seems that it's possible to manage these certificates through the base schema and I confirmed that through the terraform azurerm provider source code (Unfortunately I cannot use Terraform and I MUST use ARM in that scenario).

Any clues on how to manage CA certificates in Azure APIM through ARM?

1 Answers

I assume you want to update CA certificate authority sections of already existing APIM? If yes then just provide all required properties for Microsoft.ApiManagement/service but for name use already existing APIM name that you want to update and choose the same resource group.

Thanks to this, it will just update existing APIM with properties you provided, instead of creating new APIM. The required properties are name, type, apiVersion, location, sku, properties. For properties you need to provide publisherEmail and publisherName, and of course certificates - this is what you want to update after all. So the absolute minimum for update will look like this:

{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters":{
  "base64EncodedCertificate":{
     "defaultValue":"base64 encoded certificate",
     "type":"String"
  },
  "certificatePassword":{
     "defaultValue":"certificate password",
     "type":"String"
  }
},
"variables": {},
"resources": [
    {
        "name": "existing-apim-name",
        "type": "Microsoft.ApiManagement/service",
        "apiVersion": "2021-01-01-preview",
        "location": "West Europe",
        "sku": {
            "name": "Developer",
            "capacity": 1
        },
        "properties": {
            "publisherEmail": "publisher@gmail.com",
            "publisherName": "Publisher Name",
            "certificates": [
                {
                    "encodedCertificate": "[parameters('base64EncodedCertificate')]",
                    "certificatePassword": "[parameters('certificatePassword')]",
                    "storeName": "Root"
                }
            ]
        }
    }
]
}

Watch out. certificates array must contain all certificates that you want to have on this APIM. All existing CA certs that are not in this array will be deleted.

Related