Apply a custom domain to Azure API Management

⏱️3 min read
Share:

Azure API Management is a fast way to create a consistent, modern API gateway for existing back-end services [^1]. This article describes how to apply a custom domain to API Management. In addition, we will explain how to enable SSL with your own certificate. All resources are deployed with ARM Template [^3] or Azure CLI, so that you could construct CI/CD pipelines with them.

1. Deploy Key Vault

First, deploy Key Vault to hold the certificates.

json
1{
2 "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
3 "contentVersion": "1.0.0.0",
4 "parameters": {
5 "keyVaultName": {
6 "type": "string",
7 "metadata": {
8 "description": "Key Vault Name"
9 }
10 },
11 "apiMgmtName": {
12 "type": "string",
13 "metadata": {
14 "description": "API Management Name"
15 }
16 },
17 "commanderObjectId": {
18 "type": "securestring",
19 "metadata": {
20 "description": "Object id of azure cli command executor."
21 }
22 }
23 },
24 "variables": {},
25 "resources": [
26 {
27 "name": "[parameters('apiMgmtName')]",
28 "type": "Microsoft.ApiManagement/service",
29 "apiVersion": "2019-01-01",
30 "properties": {
31 "notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com",
32 "hostnameConfigurations": [],
33 "publisherEmail": "ch241.sample@example.com",
34 "publisherName": "mark241"
35 },
36 "sku": {
37 "name": "Developer"
38 },
39 "identity": {
40 "type": "SystemAssigned"
41 },
42 "location": "[resourceGroup().location]"
43 },
44 {
45 "name": "[parameters('keyVaultName')]",
46 "type": "Microsoft.KeyVault/vaults",
47 "apiVersion": "2018-02-14",
48 "location": "[resourceGroup().location]",
49 "dependsOn": [
50 "[resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName'))]"
51 ],
52 "properties": {
53 "tenantId": "[subscription().tenantId]",
54 "sku": {
55 "family": "A",
56 "name": "standard"
57 },
58 "accessPolicies": [
59 {
60 "tenantId": "[subscription().tenantId]",
61 "objectId": "[reference(resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName')), '2019-01-01', 'Full').identity.principalId]",
62 "permissions": {
63 "keys": [],
64 "secrets": ["get"],
65 "certificates": ["get"],
66 "storage": []
67 }
68 },
69 {
70 "tenantId": "[subscription().tenantId]",
71 "objectId": "[parameters('commanderObjectId')]",
72 "permissions": {
73 "keys": [],
74 "secrets": [],
75 "certificates": ["import"],
76 "storage": []
77 }
78 }
79 ],
80 "enabledForDeployment": false,
81 "enabledForDiskEncryption": false,
82 "enabledForTemplateDeployment": false
83 },
84 "resources": []
85 }
86 ]
87}

The Template above contains Key Vault and API Management resources. First, let's take a look at API Management.

json
1{
2 "name": "[parameters('apiMgmtName')]",
3 "type": "Microsoft.ApiManagement/service",
4 "apiVersion": "2019-01-01",
5 "properties": {
6 "notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com",
7 "hostnameConfigurations": [],
8 "publisherEmail": "ch241.sample@example.com",
9 "publisherName": "mark241"
10 },
11 "sku": {
12 "name": "Developer"
13 },
14 "identity": {
15 "type": "SystemAssigned"
16 },
17 "location": "[resourceGroup().location]"
18}

Here's a brief explanation of why we created API Management first. In the Key Vault deployment described below, you grant API Management read access to Key Vault. This is for API Management to get the certificate stored in Key Vault. API Management and its Managed Id must exist before this authorization can be granted. For more information about Managed Id, please refer to the official document [^4]. It is an ID for identifying API Management, and authority management is performed using this ID.

json
1"identity": {
2 "type": "SystemAssigned"
3 }

In the template above part, the Managed Id for API Management has been generated. See the official documentation [^2] for other details.

Next, let's look at Key Vault resources.

json
1{
2 "name": "[parameters('keyVaultName')]",
3 "type": "Microsoft.KeyVault/vaults",
4 "apiVersion": "2018-02-14",
5 "location": "[resourceGroup().location]",
6 "dependsOn": [
7 "[resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName'))]"
8 ],
9 "properties": {
10 "tenantId": "[subscription().tenantId]",
11 "sku": {
12 "family": "A",
13 "name": "standard"
14 },
15 "accessPolicies": [
16 {
17 "tenantId": "[subscription().tenantId]",
18 "objectId": "[reference(resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName')), '2019-01-01', 'Full').identity.principalId]",
19 "permissions": {
20 "keys": [],
21 "secrets": ["get"],
22 "certificates": ["get"],
23 "storage": []
24 }
25 },
26 {
27 "tenantId": "[subscription().tenantId]",
28 "objectId": "[parameters('commanderObjectId')]",
29 "permissions": {
30 "keys": [],
31 "secrets": [],
32 "certificates": ["import"],
33 "storage": []
34 }
35 }
36 ],
37 "enabledForDeployment": false,
38 "enabledForDiskEncryption": false,
39 "enabledForTemplateDeployment": false
40 },
41 "resources": []
42}

The key point of Key Vault resources is to manage access rights with accessPolicy. You will see two targets listed in the accessPolicy.

json
1{
2 "tenantId": "[subscription().tenantId]",
3 "objectId": "[reference(resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName')), '2019-01-01', 'Full').identity.principalId]",
4 "permissions": {
5 "keys": [],
6 "secrets": ["get"],
7 "certificates": ["get"],
8 "storage": []
9 }
10}

The first is to grant API management get permission to obtain a certificate.

json
1"objectId": "[reference(resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName')), '2019-01-01', 'Full').identity.principalId]"

With the above description, specify the Managed Id of API Management and grant the authority. Grant get to secrets and certificates.

json
1"permissions": {
2 "keys": [],
3 "secrets": ["get"],
4 "certificates": ["get"],
5 "storage": []
6 }

The second is permission to import the certificate into Key Vault.

json
1{
2 "tenantId": "[subscription().tenantId]",
3 "objectId": "[parameters('commanderObjectId')]",
4 "permissions": {
5 "keys": [],
6 "secrets": [],
7 "certificates": ["import"],
8 "storage": []
9 }
10}

In this article we will use the Azure CLI to import the certificate into Key Vault. Therefore, you need to grant import permission to the Azure CLI executor (service principal or user). Specify the target service principal or user object ID in commanderObjectId, and grant import authority to certificates.

2. Import the certificate into Key Vault

Next, import the certificate into Key Vault. Here, let's use Azure CLI commands.

powershell
1az keyvault certificate import --file $certFile --name $secretName --vault-name $keyVaultName --password $certPass
  • --file: Certificate file path. .pfx format.
  • --name: Key Vault secret resource name to store the certificate.
  • --vault-name: The name of the Key Vault that stores the certificate.
  • --password: Certificate password

Here, if you specify the Key Vault you created earlier, the certificate will be imported. Execute the above command with the authority of the executor who has given the import authority.

3. Deploy a custom domain for API Management

Finally, redeploy API Management.

json
1{
2 "$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
3 "contentVersion": "1.0.0.0",
4 "parameters": {
5 "apiMgmtName": {
6 "type": "string",
7 "metadata": {
8 "description": "Service name of API Management"
9 }
10 },
11 "hostName": {
12 "type": "string",
13 "metadata": {
14 "description": "Host name of API Management"
15 }
16 },
17 "keyVaultName": {
18 "type": "string",
19 "metadata": {
20 "description": "Key Vault name"
21 }
22 },
23 "secretName": {
24 "type": "string",
25 "metadata": {
26 "description": "Secret name"
27 }
28 }
29 },
30 "variables": {
31 "keyVaultResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretName'))]"
32 },
33 "resources": [
34 {
35 "name": "[parameters('apiMgmtName')]",
36 "type": "Microsoft.ApiManagement/service",
37 "apiVersion": "2019-01-01",
38 "properties": {
39 "notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com",
40 "hostnameConfigurations": [
41 {
42 "type": "Proxy",
43 "hostName": "[parameters('hostName')]",
44 "keyVaultId": "[reference(variables('keyVaultResourceId'), '2018-02-14').secretUriWithVersion]"
45 }
46 ],
47 "publisherEmail": "ch241.sample@example.com",
48 "publisherName": "mark241"
49 },
50 "sku": {
51 "name": "Developer"
52 },
53 "identity": {
54 "type": "SystemAssigned"
55 },
56 "location": "[resourceGroup().location]"
57 }
58 ]
59}

This seems similar to what we deployed earlier, except for the hostnameConfigurations part. It was an empty array because we did not apply a custom domain earlier, but this time it contains the settings of the custom domain.

  • type: The type of service to apply custom domain. There are four types: Proxy, Portal, Scm, and Management.
  • hostName: custom domain FQDN
  • keyVaultId: Key Vault uri from which API Management get the certificate

Let's specify Proxy for type. This is the type when applying a custom domain to API Gateway ({api management name}.azure-api.net). keyVaultId can be obtained by the property secretUtiWithVersion as described above.

Overall Script

Finally, here is a script that deploys all the above templates. Please change them appropriately according to your CI / CD environment.

powershell
1Param(
2 [parameter(mandatory = $true)][String]$resourceGroup,
3 [parameter(mandatory = $true)][String]$keyVaultName,
4 [parameter(mandatory = $true)][String]$apiMgmtName,
5 [parameter(mandatory = $true)][String]$objectId,
6 [parameter(mandatory = $true)][String]$certFile,
7 [parameter(mandatory = $true)][String]$certPass,
8 [parameter(mandatory = $true)][String]$secretName,
9 [parameter(mandatory = $true)][String]$hostName
10)
11
12# 1. Deploy Key Vault
13try{
14 az group deployment create --resource-group $resourceGroup --template-file ./keyvault.json --parameters keyVaultName=$keyVaultName apiMgmtName=$apiMgmtName commanderObjectId=$objectId
15}
16catch {
17 $message = $_.Exception.message
18 Write-Error "Failed to deploy key vault: ${message}"
19}
20
21# 2. Import a certificate
22try{
23 az keyvault certificate import --file $certFile --name $secretName --vault-name $keyVaultName --password $certPass
24}
25catch {
26 $message = $_.Exception.message
27 Write-Error "Failed to import certificate: ${message}"
28}
29
30# 3. Deploy API Management
31try {
32 az group deployment create --resource-group $resourceGroup --template-file ./apimgmt.json --parameters apiMgmtName=$apiMgmtName hostName=$hostName keyVaultName=$keyVaultName secretName=$secretName
33}
34catch {
35 $message = $_.Exception.message
36 Write-Error "Failed to deploy api management: ${message}"
37}

Summary

This article described how to apply an API Management custom domain using ARM Template.

  1. Deploy Key Vault
  2. Import certificates to Key Vault
  3. Apply custom domain to API Management

We've successfully applied a custom domain using the steps above.

[^1]: API Management documentation [^2]: Microsoft. ApiManagement service template reference [^3]: Azure Resource Manager documentation [^4]: Azure AD-managed identities for Azure resources documentation

Share:

Related Articles

Connect backend to Azure API Management
Software

Connect backend to Azure API Management

Learn how to add APIs to API Management using ARM Template. Use operations, policy and backend resources to connect to your backend.

mark241
Describe Azure resources as ARM Template
Software

Describe Azure resources as ARM Template

ARM Template is a json file that defines Azure resources. Learn how to create ARM Templates efficiently for deploying new resources.

mark241
Android application CI/CD with Flutter
Software

Android application CI/CD with Flutter

Learn how to build CI/CD pipeline for Android apps using Flutter. Based on GitHub Actions, not using fastlane.

mark241