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.
First, deploy Key Vault to hold the certificates.
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"keyVaultName": {
"type": "string",
"metadata": {
"description": "Key Vault Name"
}
},
"apiMgmtName": {
"type": "string",
"metadata": {
"description": "API Management Name"
}
},
"commanderObjectId": {
"type": "securestring",
"metadata": {
"description": "Object id of azure cli command executor."
}
}
},
"variables": {},
"resources": [
{
"name": "[parameters('apiMgmtName')]",
"type": "Microsoft.ApiManagement/service",
"apiVersion": "2019-01-01",
"properties": {
"notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com",
"hostnameConfigurations": [],
"publisherEmail": "ch241.sample@example.com",
"publisherName": "mark241"
},
"sku": {
"name": "Developer"
},
"identity": {
"type": "SystemAssigned"
},
"location": "[resourceGroup().location]"
},
{
"name": "[parameters('keyVaultName')]",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName'))]"
],
"properties": {
"tenantId": "[subscription().tenantId]",
"sku": {
"family": "A",
"name": "standard"
},
"accessPolicies": [
{
"tenantId": "[subscription().tenantId]",
"objectId": "[reference(resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName')), '2019-01-01', 'Full').identity.principalId]",
"permissions": {
"keys": [],
"secrets": ["get"],
"certificates": ["get"],
"storage": []
}
},
{
"tenantId": "[subscription().tenantId]",
"objectId": "[parameters('commanderObjectId')]",
"permissions": {
"keys": [],
"secrets": [],
"certificates": ["import"],
"storage": []
}
}
],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": false
},
"resources": []
}
]
}
The Template above contains Key Vault
and API Management
resources.
First, let's take a look at API Management
.
{
"name": "[parameters('apiMgmtName')]",
"type": "Microsoft.ApiManagement/service",
"apiVersion": "2019-01-01",
"properties": {
"notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com",
"hostnameConfigurations": [],
"publisherEmail": "ch241.sample@example.com",
"publisherName": "mark241"
},
"sku": {
"name": "Developer"
},
"identity": {
"type": "SystemAssigned"
},
"location": "[resourceGroup().location]"
}
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.
"identity": {
"type": "SystemAssigned"
}
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.
{
"name": "[parameters('keyVaultName')]",
"type": "Microsoft.KeyVault/vaults",
"apiVersion": "2018-02-14",
"location": "[resourceGroup().location]",
"dependsOn": [
"[resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName'))]"
],
"properties": {
"tenantId": "[subscription().tenantId]",
"sku": {
"family": "A",
"name": "standard"
},
"accessPolicies": [
{
"tenantId": "[subscription().tenantId]",
"objectId": "[reference(resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName')), '2019-01-01', 'Full').identity.principalId]",
"permissions": {
"keys": [],
"secrets": ["get"],
"certificates": ["get"],
"storage": []
}
},
{
"tenantId": "[subscription().tenantId]",
"objectId": "[parameters('commanderObjectId')]",
"permissions": {
"keys": [],
"secrets": [],
"certificates": ["import"],
"storage": []
}
}
],
"enabledForDeployment": false,
"enabledForDiskEncryption": false,
"enabledForTemplateDeployment": false
},
"resources": []
}
The key point of Key Vault
resources is to manage access rights with accessPolicy
.
You will see two targets listed in the accessPolicy
.
{
"tenantId": "[subscription().tenantId]",
"objectId": "[reference(resourceId('Microsoft.ApiManagement/service', parameters('apiMgmtName')), '2019-01-01', 'Full').identity.principalId]",
"permissions": {
"keys": [],
"secrets": ["get"],
"certificates": ["get"],
"storage": []
}
}
The first is to grant API management
get permission to obtain a certificate.
"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
.
"permissions": {
"keys": [],
"secrets": ["get"],
"certificates": ["get"],
"storage": []
}
The second is permission to import the certificate into Key Vault
.
{
"tenantId": "[subscription().tenantId]",
"objectId": "[parameters('commanderObjectId')]",
"permissions": {
"keys": [],
"secrets": [],
"certificates": ["import"],
"storage": []
}
}
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
.
Key Vault
Next, import the certificate into Key Vault
.
Here, let's use Azure CLI
commands.
az 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 passwordHere, 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.
API Management
Finally, redeploy API Management
.
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"apiMgmtName": {
"type": "string",
"metadata": {
"description": "Service name of API Management"
}
},
"hostName": {
"type": "string",
"metadata": {
"description": "Host name of API Management"
}
},
"keyVaultName": {
"type": "string",
"metadata": {
"description": "Key Vault name"
}
},
"secretName": {
"type": "string",
"metadata": {
"description": "Secret name"
}
}
},
"variables": {
"keyVaultResourceId": "[resourceId(resourceGroup().name, 'Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('secretName'))]"
},
"resources": [
{
"name": "[parameters('apiMgmtName')]",
"type": "Microsoft.ApiManagement/service",
"apiVersion": "2019-01-01",
"properties": {
"notificationSenderEmail": "apimgmt-noreply@mail.windowsazure.com",
"hostnameConfigurations": [
{
"type": "Proxy",
"hostName": "[parameters('hostName')]",
"keyVaultId": "[reference(variables('keyVaultResourceId'), '2018-02-14').secretUriWithVersion]"
}
],
"publisherEmail": "ch241.sample@example.com",
"publisherName": "mark241"
},
"sku": {
"name": "Developer"
},
"identity": {
"type": "SystemAssigned"
},
"location": "[resourceGroup().location]"
}
]
}
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 FQDNkeyVaultId
: Key Vault
uri from which API Management
get the certificateLet'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.
Finally, here is a script that deploys all the above templates. Please change them appropriately according to your CI / CD environment.
Param(
[parameter(mandatory = $true)][String]$resourceGroup,
[parameter(mandatory = $true)][String]$keyVaultName,
[parameter(mandatory = $true)][String]$apiMgmtName,
[parameter(mandatory = $true)][String]$objectId,
[parameter(mandatory = $true)][String]$certFile,
[parameter(mandatory = $true)][String]$certPass,
[parameter(mandatory = $true)][String]$secretName,
[parameter(mandatory = $true)][String]$hostName
)
# 1. Deploy Key Vault
try{
az group deployment create --resource-group $resourceGroup --template-file ./keyvault.json --parameters keyVaultName=$keyVaultName apiMgmtName=$apiMgmtName commanderObjectId=$objectId
}
catch {
$message = $_.Exception.message
Write-Error "Failed to deploy key vault: ${message}"
}
# 2. Import a certificate
try{
az keyvault certificate import --file $certFile --name $secretName --vault-name $keyVaultName --password $certPass
}
catch {
$message = $_.Exception.message
Write-Error "Failed to import certificate: ${message}"
}
# 3. Deploy API Management
try {
az group deployment create --resource-group $resourceGroup --template-file ./apimgmt.json --parameters apiMgmtName=$apiMgmtName hostName=$hostName keyVaultName=$keyVaultName secretName=$secretName
}
catch {
$message = $_.Exception.message
Write-Error "Failed to deploy api management: ${message}"
}
This article described how to apply an API Management
custom domain using ARM Template
.
Key Vault
Key Vault
API Management
We've successfully applied a custom domain using the steps above.