In my previous blog post, I looked at Azure API Management in combination with private APIs hosted on Kubernetes. The APIs were exposed via Traefik and an internal load balancer. To make that scenario work, the Azure API Management premium SKU is required, which is quite costly.
This post describes another approach where the APIs are exposed on the public Internet via an Ingress Controller that requires HTTPS in addition to restricting the API caller to the IP address of the Azure API Management instance. Something like this:
Internet client -> Azure API Management --> Ingress Controller (with IP whitelisting per ingress) --> API service (Kubernetes) --> API pods (Kubernetes, part of a Deployment)
Let’s see how this works, shall we?
Deploy Azure API management from the portal. In this case, you can use the other SKUs such as Basic and Standard. Note the IP address of the Azure API Management instance on the Overview page:
As usual, let’s use Traefik. When you have Helm installed, use the following command:
helm install stable/traefik --name traefik --set serviceType=LoadBalancer,rbac.enabled=true,ssl.enabled=true,ssl.enforced=true,acme.enabled=true,email@example.com,onHostRule=true,acme.challengeType=tls-alpn-01,acme.staging=false,dashboard.enabled=true,externalTrafficPolicy=Local --namespace kube-system
Note the use of externalTrafficPolicy=Local. This lets Traefik know the IP address of the actual caller, which is required because we want to restrict access to the IP address of API Management.
When your API is deployed via a deployment and a service of type ClusterIP, use the following ingress definition:
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: func annotations: kubernetes.io/ingress.class: traefik traefik.ingress.kubernetes.io/whitelist-source-range: "YOURIP/32" spec: tls: - hosts: - api.domain.com rules: - host: api.domain.com http: paths: - path: / backend: serviceName: func servicePort: 80
The above ingress object, exposes the internal service func via Traefik. The whitelist-source-range annotation is used to limit access to this resource to the IP address of Azure API Management. Replace YOURIP with that IP address. Obviously, replace the host api.domain.com with a host that resolves to the external IP of the load balancer that provides access to Traefik. The Let’s Encrypt configuration automatically provisions a valid certificate to the service.
When I navigate to the API on my local computer, the following happens:
When I test the API from API Management (after setting the back-end correctly):
What do you do when you do not want to spend money on the premium SKU? The answer is clear: use the lower SKUs if possible and restrict access to the back-end APIs with other means such as IP whitelisting. Other possibilities include using some form of authentication such as basic authentication etc…
3 thoughts on “Azure API Management with public APIs on Kubernetes”
Thanks for the great article ! I have one question, apim with consumption plan doesn’t have IP address which I can use, is there some way I can use the consumption plan apim in above solution ? I cannot place apim in vnet due to some reason so above solution seems to fit in , except the fact that I don’t have apim IP address as it is in consumption tier
With APIM consumption, you should expose the APIs using a public IP and allow only connections from Azure datacenters to those public IPs. See also https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-ip-addresses