Contents

Deploy Azure API Management and APIs with one command

Will it PaaS?

Challenge

Abstract
My hypothesis is, all app development will easily meet deadlines if we minimize the development time of the APIs starting from day one.

Doing so, the UI and UX work can start long before having the backend APIs and infrastructure set up. Thus, we will setup a full solution to achieve this by virtualizing the not-yet-done APIs with Mockoon, which is a free and graphical tool for designing and simulating real APIs (like payment APIs).

I think well-designed tools like Mockoon should be known by larger audience and be taken into use wide scale, which is why I chose to dockerize Mockoon (hence the name ‘dockoon’) December 2020. I am glad to see there has already been Anssi Syrjäsalo and happy to teach us how the cloud part is done as well.

Secondary, we introduce API management, API versioning and release pipelines in the API development from the beginning. By doing so, we neither start inventing those practices just days before going production, nor we lock ourselves up in backwards compatibility issues after app has gone live for customers.

Resolution

Note

This tutorial focuses on getting hands-on experience as fast as possible, without diving deeply into the technical details.

As an outcome, we will have a fully working solution (in an hour) which is intuitive to use even for those so far only familiar with Azure Portal.

We will create the following stack in your Azure subscription:

  • Container Instance for running APIs (we start with an example mock API)
  • Storage Account for API specs and a share to use as a container volume mount
  • Public API Management service incl. Portal, AppInsights and Log Analytics
  • Authenticated HTTPS API from OpenAPI spec, containerized API as the backend
  • TLS certificates for HTTPS with automated renewal to a key vault
Anssi Syrjäsalo
Azure resources. Key vault and DNS zone resource groups are created in prerequisites.

Prerequisites

If you have an ops background, basic Azure Portal and deployment knowledge is assumed. We will use Azure CLI to transpile Bicep files to ARM under the hood, so as humans, we do not write ARM templates that is effectively JSON.

We use sensible defaults, but knowing DNS, HTTPS and authentication basic for setting up the prerequisites won’t hurt. The sensible defaults are covered in chapters “API management basics” and “API development tips”.

If you are a developer, you will quickly feel comfortable writing Bicep if you want to modify the solution to your own purposes besides the parameters that are provided. In addition, having basic knowledge of OpenAPI specs will help.

Tip
If you do not have an Azure account yet, create a free account and get 200 USD of credits.

Domain name

You must own a domain which has been delegated to an existing public DNS zone in the same Azure subscription where this tutorial will be deployed.

Outcome
You have a public DNS Zone yourdomain.dev in Azure. Note the DNS zone name and the DNS zone resource group name as you will need it in further steps.
How is the DNS zone used?
In the next chapter, the deployment will create a DNS record (type A) for the Container Instances app. In addition, three CNAME records for API Gateway, Developer Portal and Management API are created and are configured as the default domains in API Management by deployment.

Certificate

To use Let’s Encrypt to get free TLS X.509 certificates for your domain(s), and in addition to have them renewed automatically every 90 days, deploy keyvault-acmebot to the Azure subscription, e.g. by using “Deploy to Azure” button in the instructions.

Deployment of acmebot creates a dedicated resource group, a consumption tier Function App and a key vault where the certificates are uploaded after created or renewed.

Proceed according to the steps in getting started and finally use /add-certificate endpoint (provides a web UI) to get a wildcard certificate *.yourdomain.dev.

Outcome
The certificate is found in the key vault (after adding certificate access policies in the key vault to yourself). Note the certificate name, the key vault name and the key vault resource group name as you need them below.
Tip
Once deployed, you can use the same solution for issuing certificates to any future domains and projects you will have beyond this tutorial.

Tools we will use

Clone the git repository:

git clone https://github.com/asyrjasalo/dockoon.git
cd dockoon/bicep

Azure CLI is assumed present to install or upgrade Bicep:

az bicep install
az bicep upgrade
Tip

If you do not have Bash available for your OS, you can clone this repo in Azure Cloud Shell and run the commands there.

Additionally, and if familiar with Azure DevOps, you can import azure-pipelines.yml in your project and run the pipeline.

Deploy to Azure

Copy prod.env.example to prod.env and configure the variables.

Why use a 42 year old config solution?
We prefer the simplest possible way of configuring tools, that is still environment variables as of 2021. They also work well in any CI/CD and are better in keeping secrets out of the git repo than for example azuredeploy.environment.parameters.json files.

Shortcut

To get everything up(dated) with one command according to the steps below:

./deploy prod.env ../apis.json ../openapi.json
Note
The DNS and key vault specific deployments (dns.bicep and kv.bicep) will be created in their own configured resource groups and thus visible there.

Steps

Export the variables:

set -a; source prod.env; set +a

Create a target resource group:

az group create \
    --name "$AZ_PREFIX-$AZ_ENVIRONMENT-$AZ_APP-rg" \
    --location "$AZ_LOCATION" \
    --subscription "$AZ_SUBSCRIPTION_ID" \
    --tags app="$AZ_APP" environment="$AZ_ENVIRONMENT" owner="$AZ_OWNER"

Create storage account for the API files:

az deployment group create \
    --resource-group "$AZ_PREFIX-$AZ_ENVIRONMENT-$AZ_APP-rg" \
    --subscription "$AZ_SUBSCRIPTION_ID" \
    --template-file sa.bicep \
    -p sa_name="${AZ_PREFIX//-/}${AZ_ENVIRONMENT//-/}${AZ_APP//-/}sa" \
    -p tags="{'app': '$AZ_APP', 'environment': '$AZ_ENVIRONMENT', 'owner': '$AZ_OWNER'}"

Upload apis.json to the storage account file share for the container:

az storage file upload \
    --account-name "${AZ_PREFIX//-/}${AZ_ENVIRONMENT//-/}${AZ_APP//-/}sa" \
    --share-name share \
    --source ../apis.json

Create deployment in the resource group:

az deployment group create \
    --resource-group "$AZ_PREFIX-$AZ_ENVIRONMENT-$AZ_APP-rg" \
    --subscription "$AZ_SUBSCRIPTION_ID" \
    --template-file main.bicep \
    -p prefix="$AZ_PREFIX" \
    -p environment="$AZ_ENVIRONMENT" \
    -p app="$AZ_APP" \
    -p owner="$AZ_OWNER" \
    -p dns_zone_name="$AZ_DNS_ZONE_NAME" \
    -p dns_zone_rg_name="$AZ_DNS_ZONE_RG_NAME" \
    -p key_vault_name="$AZ_KEY_VAULT_NAME" \
    -p key_vault_rg_name="$AZ_KEY_VAULT_RG_NAME" \
    -p key_vault_cert_name="$AZ_KEY_VAULT_CERT_NAME"
Note
Initial creation of API Management service might take half an hour.

Upload openapi.json to the storage account blob container for the APIM:

az storage blob upload \
    --account-name "${AZ_PREFIX//-/}${AZ_ENVIRONMENT//-/}${AZ_APP//-/}sa" \
    --container-name apis \
    --name openapi.json \
    --file ../openapi.json

Deploy (or update) API in APIM from the OpenAPI specification:

az deployment group create \
    --resource-group "$AZ_PREFIX-$AZ_ENVIRONMENT-$AZ_APP-rg" \
    --subscription "$AZ_SUBSCRIPTION_ID" \
    --template-file api.bicep \
    -p apim_name="$AZ_PREFIX-$AZ_ENVIRONMENT-$AZ_APP-apim" \
    -p app_name="$AZ_APP" \
    -p api_backend_url="http://$AZ_APP-$AZ_ENVIRONMENT.$AZ_DNS_ZONE_NAME:8080" \
    -p api_spec="https://${AZ_PREFIX//-/}${AZ_ENVIRONMENT//-/}${AZ_APP//-/}sa.blob.core.windows.net/apis/openapi.json"

After finished, get the product subscription key e.g. via Azure Portal and verify the API responds when called via the API Management Gateway URL:

curl https://api.${AZ_DNS_ZONE_NAME}/dockoon/v1/users \
    --header 'Ocp-Apim-Subscription-Key: {{subscription_key_for_app}}'
On success
List of users is responded as JSON with HTTP status 200 (OK).

API management basics

This chapter summarizes some good operational Azure API Management practices.

Portal

The developer portal (as well as management API) must be explicitly published in the API Management. To publish Developer Portal via Azure portal, browser to API Management -> Portal Overview -> Publish.

Registration

The API is created in the product app_name (which is also created). An API Management default group named ‘Developers’ is assigned to the product.

To get a subscription key for the API, sign up via your API Management developer portal. Portal signed up user is automatically placed in the group ‘Developers’, thus granting access (and a subscription key) to the product.

Logging

100% of requests are logged into the Log Analytics Workspace regardless if particular API has logging enabled or not. Similarly Application Insight metrics are stored in the workspace. You may want to adjust workspace retention_in_days as the default is 30 days (law.bicep).

API development tips

Deployment of api.bicep includes sensible defaults, such as APIs being accessible HTTPS only, but based on your purposes you may adjust parameters, most important of which are listed below.

Version

The API display name is taken from the API spec and the product name is taken from app_name. You can optionally configure parameters app_description and app_terms for the product, and api_description for the API.

By default, API version set named ‘v1’ is created and the version is carried as part of the URL. To deploy a new API version, set e.g. api_version=v2.

Revision

By default, revision 1 is set as current, which may not be desired in production. If you want to implement canary, create a new revision 2, set api_set_current=false and set revision 2 as current when suitable.

Subscription

If you want to require no authentication for the particular API deployed, add api_require_auth=false. Authentication is still required on the product level for the other APIs that are possibly assigned in the product.

If you want to require no approval from Administrators when new users subscribe to the product, add app_require_admin_approval=false.

Spec

OpenAPI (3.x), Swagger (2.x) and WSDL specification formats can be imported by API Management. If are deploying a SOAP API instead of REST, add api_type=soap and use api_format=wsdl-link with api_spec URL to the XML.

If you want to read api_spec content directly as a parameter, set api_format to openapi-json, swagger-json or wsdl. This may or may not work well, depending on your shell and the spec content.

Policy

API management policies can be set on service, product or API levels. By default, rate-limit policy is created on the API level by api.bicep.

You can set api_policy_xml to override the API level policy as XML content. To pass an URL to an XML file instead of the content, also set api_policy_format=rawxml-link.

What’s next?

Having tried several other free and paid alternatives, and also having written my own mocking tools, I think Mockoon is by far the most intuitive app for both designing API endpoints and virtualizing them unless they are done. You can install and use it for editing apis.json for your own purposes. Remember to export to apis.json from UI before running ./deploy again.

Updating openapi.json

Mockoon can also export openapi.json and I hope this functionality still gets improved, as e.g. Azure API Management is much stricter regarding the path parameter definitions (which is intented).

Due this, you may have to edit openapi.json manually before importing the Mockoon-exported spec in API Management.

If you want to host your own Docker containers in Azure Container Instances, which you likely want to try out next, you can check main.bicep for the parameters forwarded to aci.bicep. Include these parameters to the deployment commands and you are able to configure the container image, the command, cpu count, memory, etc. After changes, run ./deploy to update the services (now takes only a few minutes).

You may also want to see how to create the CI/CD pipeline in your own Azure DevOps project.

Which is left as an exercise. □

Good luck and rock on!

No APIs were harmed during production.
– Every Developer