Can I call different backend on Azure API Management - azure

I am trying to achieve that, when I call an APIM Endpoint based on the request headers It should different endpoint. for e.g when user call https://test.azure-api.net/testsvc-dev/api/test APIM should be able to send the request to https://testappv1:80/test or https://testappv2:80. right now I can see in the serviceURL, I can add only one. Is there any policy that I can use to do these kind of operations.
little more context: I am trying to access two different version of API on a single call. Instead of caller choosing which one to call,I am trying to make the APIM to decide based on the user.

You are probably looking for the set-backend-service policy.
Here an example from the Microsoft docs that changes the backend service based on a query parameter:
<policies>
<inbound>
<choose>
<when condition="#(context.Request.Url.Query.GetValueOrDefault("version") == "2013-05")">
<set-backend-service base-url="http://contoso.com/api/8.2/" />
</when>
<when condition="#(context.Request.Url.Query.GetValueOrDefault("version") == "2014-03")">
<set-backend-service base-url="http://contoso.com/api/9.1/" />
</when>
</choose>
<base />
</inbound>
<outbound>
<base />
</outbound>
</policies>
Certainly, you could adopt the sample and query for the desired headers ;-)

Related

URL Based routing on Azure

I am trying to do URL based routing for my APIs but I am not able to achieve as my API endpoints contain a wildcard in the middle of the URL, like:
/prodapi/v1.0/{appId}/level
/prodapi/v1.0/{appId}/products
appId is my customers white label ID, so it's unique for all our customers.
So far I have tried :
Azure application gateway [ But you can only handle at the end of your URL]
Azure Fron door [Have the same settings]
API management [ Not allowing me to do wildcard]
Can someone help me with any azure native or Out of the box solution.
If you want to route the traffic depending on a specific path parameter, you could use Api management service and write a inbound policy as such:
<policies>
<inbound>
<base />
<set-variable name="appId" value="#(context.Request.MatchedParameters["appId"])" />
<choose>
<when condition="#(int.Parse(context.Variables.GetValueOrDefault<string>("appId")) == 1)">
<set-backend-service base-url="https://google.com/" />
</when>
<when condition="#(int.Parse(context.Variables.GetValueOrDefault<string>("appId")) == 2)">
<set-backend-service base-url="https://twitter.com/" />
</when>
<otherwise>
<set-backend-service base-url="https://facebook.com/" />
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Replacing the backend-service with your prefer url ofc :)
API management is very powerful, so I'm sure that you'll find the solution there if this is not what you were looking for.

Azure API Management with multiple backends

I have an Azure API Management set and running. The API calls are made to a Docker container running FastAPI on an Azure virtual machine. This backend container is responsible for running some AI models based on the queries it receives. It all works fine for a single user.
The thing is: these AI models are defined in a config file inside the container and are user-specific.
I want to use Azure API Management to route requests based on, say, the user subscription. In other words, given a subscription, I want to know which backend to call (each backend would be a container running a specific AI model for that particular user/company on an Azure virtual machine).
What is the best way to approach this?
I found out that you can use inbound policies to specify which backend to use depending on what group the user belongs to. The reference to my answer comes from here.
Go to your API Management, choose Groups and create groups that are relevant to your users. Then add your users to their respective groups.
Go to your API, select inbound rules and specify your backends using something like this:
<policies>
<inbound>
<choose>
<when condition="#(context.User.Groups.Select(g => g.Name).Contains("org1"))">
<set-backend-service base-url="https://abc-apim.azure-api.net/org1app" />
</when>
<when condition="#(context.User.Groups.Select(g => g.Name).Contains("org2"))">
<set-backend-service base-url="https://abc-apim.azure-api.net/org2app" />
</when>
<otherwise>
<return-response>
<set-status code="401" reason="Unauthorized" />
<set-header name="WWW-Authenticate" exists-action="override">
<value>Bearer error="Invalid user group"</value>
</set-header>
</return-response>
</otherwise>
</choose>
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
I undestand this approach is not so elegant, since you have to hard code the backend routing in your policy. But it works.

Forward requests to regional API based on a specific JWT claim

Is it possible to forward requests to regional API based on a specific JWT claim?
The platform I'm working on has one API per region, and our customers are required to know it in order to build the base request URL - e.g.: https://{region}.service.com
Unfortunately, the only reliable way to try and figure out which regional api to call automatically from Azure APIM (e.g.: calling a single endpoint at https://api.service.com), in our scenario, would be by analyzing a claim that always comes with the bearer token (which we already do at the APIM level.)
Has anybody had the need to do it this way? Thanks in advance!
APIM policy expressions along with "choose" policy allow you to create arbitrary processing logic: https://learn.microsoft.com/en-us/azure/api-management/api-management-policy-expressions.
Access to JWT is available as
context.Request.Headers.GetValueOrDefault("Authorization").AsJwt()
It returns Jwt object (look for it's properties on the same page above).
All this combined with "set-backend-service" policy should be sufficient to do the job.
Vitaly's answer was the key to figuring this one out. Here is the complete answer, in case anybody is looking for the same thing.
<policies>
<inbound>
<!-- Extract Token from Authorization header parameter -->
<set-variable name="token" value="#(context.Request.Headers.GetValueOrDefault("Authorization",string.Empty).Split(' ').Last().AsJwt())" />
<choose>
<when condition="#(context.Variables["token"] != null)">
<set-variable name="api_uri" value="#(((Jwt)context.Variables["token"]).Claims.GetValueOrDefault("api_uri", string.Empty))" />
<choose>
<when condition="#(context.Variables["api_uri"] != string.Empty)">
<set-backend-service base-url="#((string)context.Variables["api_uri"])" />
</when>
<otherwise />
</choose>
</when>
<otherwise />
</choose>
<base />
</inbound>
</policies>

Is it possible to use the subscription-key query string parameter with Azure API Management SOAP-passthrough?

We use API Management to expose several API's. One of the API's we expose is configured as a SOAP-passthrough API but we are facing some issues with it regarding authentication of APIM.
When we use the Ocp-Apim-Subscription-Key header for passing the query string it all works correct and the API is returning it's content correct.
When we use the subscription-key query string parameter the API is returning a 401 Unauthorized. I tested this behavior in Postman and changing the way of sending the subscription key is resulting in this behavior.
An implementation detail of this API is that it exposes an existing WSDL and routes this SOAPAction to an Azure Function via the policy. In the Application Insights of the function I can verify that the function is never invoked when I get a 401 but it is invoked when I get a successful call (using the header).
Is this normal behavior? Am I doing things wrong? Or is it a bug in APIM?
This might be an issue with the way we do routing for SOAP Passthrough. You will notice in the API setup that we add on a query parameter to identify the SoapAction that an operation will be matched to. It may be that your the api key query parameter is getting overwritten when adding the SoapAction parameter to the inbound request. I will investigate and let your know.
We currently use a workaround around this problem with the following policy. Instead of changing the backend-server url in the policy we send a request and set the response of that request as a response for this api. Below you can find our policy which is working with the subscription-key in the query string.
<policies>
<inbound>
<base />
<send-request mode="copy" response-variable-name="response" timeout="20" ignore-error="false">
<set-url>{{BackendServer_URL}}</set-url>
</send-request>
<!--return-response response-variable-name="reponse" /-->
<choose>
<!-- If StatusCode is not OK, return Unauthorized with the reason. -->
<when condition="#(((IResponse)context.Variables["response"]).StatusCode != 200)">
<return-response response-variable-name="reponse">
<set-status code="401" reason="Unauthorized" />
<set-body>#(((IResponse)context.Variables["response"]).Body.As<string>())</set-body>
</return-response>
</when>
<otherwise>
<return-response response-variable-name="reponse">
<set-status code="200" />
<set-header name="Content-Type" exists-action="override">
<value>text/xml; charset=utf-8</value>
</set-header>
<set-body>#(((IResponse)context.Variables["response"]).Body.As<string>())</set-body>
</return-response>
</otherwise>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>

Are there rest calls for these Api Management actions?

Say I want to automate API Management, I would want to
Create Api (https://learn.microsoft.com/en-us/rest/api/apimanagement/apis#Apis_CreateOrUpdate)
Create certificate (https://learn.microsoft.com/en-us/rest/api/apimanagement/certificates#Certificates_CreateOrUpdate)
Tie certificate to API (¿?)
Create API Policy (¿?)
I've went through all the calls one by one, and wasn't able to identify anything meaningful.
edit: or a confirmation that this is not yet possible with the API.
edit: looking at the swagger definition of ApiManagement, I don't think its there?
edit: exported configuration to Git, doesn't look like it contains the cert, so this also wouldn't help?
The client Certificate is not represented in the model of the ApiContract. When you want to tie a Certificate to an API, we create a policy authentication certificate policy in the API Scope.
<policies>
<inbound>
<base />
<authentication-certificate thumbprint="***19B22E********5E2E**820" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
You can create an API Policy using https://learn.microsoft.com/en-us/rest/api/apimanagement/apimanagementrest/azure-api-management-rest-api-api-entity#SetAPIPolicy

Resources