This post was originally published here

This is the second post in my series around setting up CI/CD for Azure API Management using Azure Resource Manager templates. In the previous post we created our API Management instance, and have set up our build and release pipelines. In this post we will add custom products, users and groups to our API Management instance, which will be used to set up our policies and access to our APIs.

API Management products, users and groups

The posts in this series are the following, this list will be updated as the posts are being published.

For this post, we will be adding a new user to the API Management instance we created in the previous blog post in this series. This user will represent a client developer from the Contoso company, who will be using the APIs which we will define later on. In this scenario, Contoso consumes our APIs in their own processes. The user will be placed into a group, which represents the Contoso company. In a real life scenario, this group would contain users for all the developers and services of this particular client. And finally we will create a product for the Contoso company as well, and link the group to the product. The product is where we will be setting up policies and quotas, so we can limit the usage our services.

As explained in the first post in this series, we will be using different repositories for the various parts of our API Management setup. In that post, we already showed how we can set up a repository and clone this to our local machine. For this post, we will be creating a new repository, in which we will create the ARM template for our products, users and groups. Create the API Management products, users and groups repository and clone it to you machine.

Create new repository

Create new repository

API Management products, users and groups repository

API Management products, users and groups repository

Now we will start by creating the ARM template for adding a user for Contoso, who will be consuming our APIs. In your cloned repository, create a new file and name it products-users-groups.json, and add the following ARM template contents to the file.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "APIManagementInstanceName": {
          "type": "string",
          "defaultValue": "MyAPIManagementInstance"
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "Microsoft.ApiManagement/service/users",
            "name": "[concat(parameters('APIManagementInstanceName'), '/john-smith-contoso-com')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {
                "firstName": "John",
                "lastName": "Smith",
                "email": "john.smith@contoso.com",
                "state": "active",
                "note": "Developer working for Contoso, one of the consumers of our APIs",
                "confirmation": "invite"
            },
            "dependsOn": []
        }
    ]
}

What we do here, is creating a new user (John Smith), and add it to our API Management instance. We have the name of the instance as a parameter, so we could override this from our deployment pipeline. As you will notice, we don’t set anything in our dependsOn, as the API Management instance has been created from another template. Also note the “confirmation”: “invite” line, which makes sure that the user will receive an email on the specified address to finish his registration by setting his own password.

Next we will expand our ARM template to also create the group, so let’s update the ARM template to the following.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "APIManagementInstanceName": {
          "type": "string",
          "defaultValue": "MyAPIManagementInstance"
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "Microsoft.ApiManagement/service/users",
            "name": "[concat(parameters('APIManagementInstanceName'), '/john-smith-contoso-com')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {
                "firstName": "John",
                "lastName": "Smith",
                "email": "john.smith@contoso.com",
                "state": "active",
                "note": "Developer working for Contoso, one of the consumers of our APIs",
                "confirmation": "invite"
            },
            "dependsOn": []
        },
        {
            "type": "Microsoft.ApiManagement/service/groups",
            "name": "[concat(parameters('APIManagementInstanceName'), '/contosogroup')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {
                "displayName": "ContosoGroup",
                "description": "Group containing all developers and services from Contoso who will be consuming our APIs",
                "type": "custom",
                "externalId": null
            },
            "dependsOn": []
        },
        {
            "type": "Microsoft.ApiManagement/service/groups/users",
            "name": "[concat(parameters('APIManagementInstanceName'), '/contosogroup/john-smith-contoso-com')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {},
            "dependsOn": [
                "[resourceId('Microsoft.ApiManagement/service/groups', parameters('APIManagementInstanceName'), 'contosogroup')]"
            ]
        }
    ]
}

What we did here, was add two additional resources, one for the ContosoGroup group, and one to link the user to the group.

And finally, we will add a product for the Contoso consumers. On this product we will set a throttling policy, so these consumers are limited in the number of calls they can make to our APIs. Update the ARM template as following, this will also be the final version of this ARM template.

{
    "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "APIManagementInstanceName": {
          "type": "string",
          "defaultValue": "MyAPIManagementInstance"
        }
    },
    "variables": {},
    "resources": [
        {
            "type": "Microsoft.ApiManagement/service/users",
            "name": "[concat(parameters('APIManagementInstanceName'), '/john-smith-contoso-com')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {
                "firstName": "John",
                "lastName": "Smith",
                "email": "john.smith@contoso.com",
                "state": "active",
                "note": "Developer working for Contoso, one of the consumers of our APIs",
                "confirmation": "invite"
            },
            "dependsOn": []
        },
        {
            "type": "Microsoft.ApiManagement/service/groups",
            "name": "[concat(parameters('APIManagementInstanceName'), '/contosogroup')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {
                "displayName": "ContosoGroup",
                "description": "Group containing all developers and services from Contoso who will be consuming our APIs",
                "type": "custom",
                "externalId": null
            },
            "dependsOn": []
        },
        {
            "type": "Microsoft.ApiManagement/service/groups/users",
            "name": "[concat(parameters('APIManagementInstanceName'), '/contosogroup/john-smith-contoso-com')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {},
            "dependsOn": [
                "[resourceId('Microsoft.ApiManagement/service/groups', parameters('APIManagementInstanceName'), 'contosogroup')]"
            ]
        },
        {
            "type": "Microsoft.ApiManagement/service/products",
            "name": "[concat(parameters('APIManagementInstanceName'), '/contosoproduct')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {
                "displayName": "ContosoProduct",
                "description": "Product which will apply the high-over policies for developers and services of Contoso.",
                "subscriptionRequired": true,
                "approvalRequired": true,
                "state": "published"
            },
            "dependsOn": []
        },
        {
            "type": "Microsoft.ApiManagement/service/products/groups",
            "name": "[concat(parameters('APIManagementInstanceName'), '/contosoproduct/contosogroup')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {},
            "dependsOn": [
                "[resourceId('Microsoft.ApiManagement/service/products', parameters('APIManagementInstanceName'), 'contosoproduct')]",
                "[resourceId('Microsoft.ApiManagement/service/groups', parameters('APIManagementInstanceName'), 'contosogroup')]"
            ]
        },
        {
            "type": "Microsoft.ApiManagement/service/subscriptions",
            "name": "[concat(parameters('APIManagementInstanceName'), '/5ae6ed2358c2795ab5aaba68')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {
                "userId": "[resourceId('Microsoft.ApiManagement/service/users', parameters('APIManagementInstanceName'), 'john-smith-contoso-com')]",
                "productId": "[resourceId('Microsoft.ApiManagement/service/products', parameters('APIManagementInstanceName'), 'contosoproduct')]",
                "displayName": "ContosoProduct subscription",
                "state": "active"
            },
            "dependsOn": [
                "[resourceId('Microsoft.ApiManagement/service/users', parameters('APIManagementInstanceName'), 'john-smith-contoso-com')]",
                "[resourceId('Microsoft.ApiManagement/service/products', parameters('APIManagementInstanceName'), 'contosoproduct')]"
            ]
        },
        {
            "type": "Microsoft.ApiManagement/service/products/policies",
            "name": "[concat(parameters('APIManagementInstanceName'), '/contosoproduct/policy')]",
            "apiVersion": "2017-03-01",
            "scale": null,
            "properties": {
                "policyContent": "<policies>rn  <inbound>rn    <base />rn    <rate-limit calls="20" renewal-period="60" />rn  </inbound>rn  <backend>rn    <base />rn  </backend>rn  <outbound>rn    <base />rn  </outbound>rn  <on-error>rn    <base />rn  </on-error>rn</policies>"
            },
            "dependsOn": [
                "[resourceId('Microsoft.ApiManagement/service/products', parameters('APIManagementInstanceName'), 'contosoproduct')]"
            ]
        }
    ]
}

The steps we added in this template were to create the ContosoProduct product, add ContosoGroup to the product, create a subscription for the Contoso user John Smith and link it to the product, and finally create a policy which implements throttling on the product level. Commit and push this final ARM template to your repository.

Now that we have finished our template, we will create new build definition called API Management CI-CD ARM-CI – Products, users and groups. The exact steps for creating a build pipeline have already been described in the previous blogpost. Make sure to select the correct GIT repository.

Select correct GIT repository

Select correct GIT repository

Set up the build pipeline to validate the ARM template using a continuous integration tirgger and publish if the template is correct, just like in the previous post. Once done make sure to save and queue the build definition.

Set up build pipeline for validation

Set up build pipeline for validation

The next step will be to set up the deployment pipeline, which has also been thoroughly described in the previous post. Create a new continous deployment triggered release definition called API Management products, users and groups and use the artifact we just published from our build pipeline.

Create release pipeline with artifact published from build pipeline

Create release pipeline with artifact published from build pipeline

Set up the test environment to be triggered as soon as the artifact is available, and deploy to your test environment.

Deploy to test environment

Deploy to test environment

Clone the Test environment and update it to deploy to your production environment. Make sure to include an approval before deployment is being done.

Deploy to production environment after approval

We now have completed our CI/CD process for the products, users and groups, so to test this we just need to make a change in the ARM template on our local machine and check this in, after which our build and deployment pipelines will kick off and update our API Management instance.

API Management instance has been updated