I configured MSI to table storage in my API Management:
Then, in inboud policy i am setting mocked url to table storage:
<inbound>
<base />
<set-backend-service base-url="https://<storage>.table.core.windows.net/<table>()?$top=10" />
<authentication-managed-identity resource="https://storage.azure.com/" />
</inbound>
And i see, that token is obtained correctly:
And i am getting 403 response as follows:
{
"response": {
"status": {
"code": 403,
"reason": "Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature."
},
My question is, how to call table storage from Api Management using managed identity?
Just add this to inbound policy:
<set-header name="x-ms-version" exists-action="override">
<value>#{string version = "2017-11-09"; return version;}</value>
</set-header>
Related
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
In our organization we have some people that uses Excel to access our APIs. We would like the APIs to be exposed by API Management and to be authenticated using Azure Active Directory.
In excel this can be achieved by using an "Organizational account", but currently I get the message "We couldn't authenticate with the credentials provided. Please try again"
I have followed this guide in order to set up an Active Directory Registered application and configured API Management accordingly.
One additional step I have done is to add the "WWW-Authenticate" header in following in API management configuration, in order to trigger Excel to do authentication against our AD tenant:
<policies>
<inbound>
<base />
<validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid.">
<openid-config url="https://login.microsoftonline.com/<tenant-id>/v2.0/.well-known/openid-configuration" />
<required-claims>
<claim name="aud">
<value>expected-aud</value>
</claim>
</required-claims>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<choose>
<when condition="#(context.Response.StatusCode == 401)">
<set-header name="WWW-Authenticate" exists-action="override">
<value>Bearer realm="<tenant-id>", error="invalid_token", error_description="Access Token missing or malformed.", authorization_uri="https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize", client_id="<client-id>"</value>
</set-header>
</when>
</choose>
<base />
</on-error>
When looking at the HTTP requests in Fiddler, the a request made to login.microsoft.com actually retrieves a token. This is the body of the response:
{
"token_type": "Bearer",
"scope": "some-scope user_impersonation",
"expires_in": "3599",
"ext_expires_in": "3599",
"expires_on": "1600932873",
"not_before": "1600928973",
"resource": "https://api-management-host",
"access_token": "<access-token>",
"refresh_token": "<refresh-token>",
"id_token": "<id-token>"
}
But the following request to API management does not contain the token - the authorization header only has the keyword Bearer:
Authorization: Bearer
Anyone out there that have any experience with this scenario - or can help me solve this issue?
In azure API Management how to setup the 405 (Method not allowed) policy. I am using azure API management APIs and adding different policies like jwt validation, IP filtering, rate limit and all. But I couldn't find a way for add the 405 method not allowed in APIM. I want to setup this for each of the methods. That means I want to block the incoming unrecognized method requests from APIM. (eg: Get instead of POST (Throws 405 method not allowed from APIM). Currently APIM passes the wrong method to backend and it returns the 404 from the application. Anyone know how we can block the wrong request from APIM side and returns 405 instead of passing it to backend and returns 404?.
You could use a Control Flow policy along with the Context Variable on the Inbound policy of each Method to intercept any requests that don't match the defined http method and then use a Set Status policy to return a 405. So for a GET method something along the lines of:
<policies>
<inbound>
<choose>
<when condition="#(context.Request.Method.ToString() != "GET")">
<return-response>
<set-status code="405" reason="No Content" />
</return-response>
</when>
</choose>
<base />
</inbound>
... rest of policies
</policies>
If you've got multiple methods with the same path you might need to apply this at the API level rather than the Method level and make the condition equals methods not in use rather than not equal to method in use
To set this at the API level and check against a collection of methods not in use create a policy along the lines of:
<policies>
<inbound>
<choose>
<when condition="#{
ICollection<string> disallowedMethods = new List<string>() { "POST", "PUT" };
return disallowedMethods.Contains(context.Request.Method.ToString());
}">
<return-response>
<set-status code="405" reason="No Content" />
</return-response>
</when>
</choose>
<base />
</inbound>
... rest of policies
</policies>
The http methods not in use in this example are POST and PUT but you can change the list to whatever applies in your use case.
In Azure APIM, I am trying to create a policy that will validate a JWT. No matter what I try, I always get a "401: Invalid JWT" error. Does anyone know what I'm doing wrong? (Maybe I'm not using the right signing key?)
My base64 encoded security key is Zm9v.
I create sample token at jwt.io and so my Authorization header is:
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.Bm8tu4m18oA96xwhBL8AV_4hRpIU6OrK5UaOmGqBEsk
Here's the policy I am using:
<policies>
<inbound>
<base />
<validate-jwt
header-name="Authorization"
require-expiration-time="false"
require-scheme="Bearer"
>
<issuer-signing-keys>
<key>Zm9v</key>
</issuer-signing-keys>
</validate-jwt>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
HTTP Response:
cache-control: private
content-length: 48
content-type: application/json
ocp-apim-trace-location: https://xxxxxxx
vary: Origin
{
"statusCode": 401,
"message": "Invalid JWT."
}
Problem was my key size was too small.
When testing the API in Azure, there is a Trace tab, but it is missing the On Error section.
You have to go to the Message tab. There is an ocp-apim-trace-location which will show the full trace.
It turns out the key size I was using was too small. It was only 24 and needs to be at least 128.
The token you provided is invalid signature. Go to jwt.io to check your token firstly.
The policy you provided it right. For more details, you could refer to this article.
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>