Azure API Management - Service Fabric Application Policy Settings - azure

I have created an Azure Service Fabric application and deployed to the Azure cluster. I have created an API Management service, created Backend pointing to my Service Fabric Instance. I am having a simple GET API in the service fabric. I have created inbound processing policy like below, but its not working - getting 500 internal server error.
<policies>
<inbound>
<base />
<set-backend-service backend-id="dev-sfc-backend" sf-resolve-condition="#(context.LastError?.Reason == "BackendConnectionFailure")" sf-service-instance-name="fabric:/M_HelloModelServices/M_HelloModelService" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
Below is the trace while testing API.
service-fabric-backend (1,014.098 ms){
"messages": [
"Unable to connect to the remote server",
"Error occured while calling backend service.",
"No connection could be made because the target machine actively refused it <IP>:20000"
]}
Could someone configured API Management service for Service Fabric Cluster please share how we can configure this.

Related

Azure APIM with certificate authentication error using .pfx certificate

Helle, everyone.
I am experiencing issue with configuring APIm operation with InBound policy, which handled calls to remote endpoint. I have saved certificate which was provided to me by external service and using thumbprint in policie. Remote endpoint validates requests using certificate.
<policies>
<inbound>
<base />
<send-request mode="new" response-variable-name="result" timeout="300" ignore-error="false">
<set-url>https://ip:port/path</set-url>
<set-method>POST</set-method>
<set-header name="Accept" exists-action="override">
<value>*/*</value>
</set-header>
<set-header name="Content-Type" exists-action="override">
<value>application/xml</value>
</set-header>
<set-body>#(context.Request.Body.As<string>())</set-body>
<authentication-certificate thumbprint="thubprint" password="password" />
</send-request>
<return-response response-variable-name="result" />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
But as a response I am getting 500 error
send-request (259.918 ms)
{
"messages": [
"Error occured while calling backend service.",
"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.",
"The remote certificate is invalid according to the validation procedure."
]
}
Thanks beforehands. Would appreciate any help.
As discussed in the comments, adding gist as a community wiki answer to help community members who might face a similar issue.
But as a response I am getting 500 error
If you are using self-signed certificates, you will need to disable certificate chain validation for API Management to communicate with the backend system. Otherwise, it will return a 500 error code.
Try the following code snippet taken from the document:
$context = New-AzApiManagementContext -resourcegroup 'ContosoResourceGroup' -servicename 'ContosoAPIMService'
New-AzApiManagementBackend -Context $context -Url 'https://contoso.com/myapi' -Protocol http -SkipCertificateChainValidation $true
Note: As of now disabling certificate chain validation is only possible for backend policy.
You can refer to Azure API Management - Validate incoming client certificate and Send cert to backend, Is disabling Validate certificate chain safe? and Protect your APIs with Azure API Management

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.

How Do I Configure API Management With Multiple Back Ends?

I am hosting a service for clients where we have the same application deployed per client in Azure.
It is essentially this per client:
Application Gateway ->
App Service Environment ->
API Management ->
VM with Application back end ->
Remote Azure SQl Data
The first 3 layers increase the costs quite significantly.
Is it possible to configure it like this?
Application Gateway ->
App Service Environment ->
API Management ->
- Client 1
VM1 with Application back end ->
Remote Azure SQl Data1
- Client 2
VM2 with Application back end ->
Remote Azure SQl Data2
- Client 3
VM3 with Application back end ->
Remote Azure SQl Data3
i.e. the web layers route to the appropriate back end somehow
e.g. Maybe each client would access the web layer with a different URL.
http://client1.rest-application.azure.com
http://client2.rest-application.azure.com
but they all go through the same application gateway.
You need to use APIM policy to route the traffic to different backend pool based on the HTTP header information.
Here is the sample policy which routes the traffic based on the request body size.
The policy defined in this file demonstrates how to route requests based on the size of the message body.
Content-Length header contains the size of the message body.
256 KB, a limitation on message size in the Azure Service Bus.
he snippet checks if the message is smaller than 256000 bytes. If it's larger, request is routed somewhere else.
Copy the following snippet into the inbound section.
<policies>
<inbound>
<base/>
<set-variable name="bodySize" value="#(context.Request.Headers["Content-Length"][0])"/>
<choose>
<when condition="#(int.Parse(context.Variables.GetValueOrDefault<string>("bodySize"))<256000)">
<!-- let it pass through by doing nothing -->
</when>
<otherwise>
<rewrite-uri template="{{alternate-path-and-query}}"/>
<set-backend-service base-url="{{alternate-host}}"/>
</otherwise>
</choose>
<!-- In rare cases where Content-Length header is not present we'll have to read the body to get its length. -->
<!--
<choose>
<when condition="#(context.Request.Body.As<string>(preserveContent: true).Length<256000)">
</when>
<otherwise>
<rewrite-uri template=""/>
<set-backend-service base-url=""/>
</otherwise>
</choose>
-->
</inbound>
<backend>
<base/>
</backend>
<outbound>
<base/>
</outbound>
<on-error>
<base/>
</on-error>

Azure APIM as pure proxy

I am trying to deal with an Backend API(REST) with no swagger documents to be accessed through Azure APIM.
I want all the calls directed to the Backend API with me not manually creating GET/PUT/POST for all the resources. My inbound policies for all operations is below
'
<policies>
<inbound>
<set-variable name="requestPath" value="#(context.Request.Url.Path)" />
<base/>
<set-backend-service base-url="https://*****/****/" />
<rewrite-uri template="#(context.Request.Url.Path)" copy-unmatched-params="true" />
</inbound>
<backend>
<base/>
</backend>
<outbound>
<base/>
</outbound>
</policies>
`
However when hit the APIM i was given
{
"statusCode": 404,
"message": "Resource not found"
}
Any help is appreciated Thanks
The easy way to do this is to create one operation for each HTTP method you support and use /* for the template. This will match any inbound path/query and forward it to the backend.

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