0
votes

I'm trying to verify Client Certificates in Azure API Management. I created a new instance and I'm using the default Echo API. I followed this documentation https://docs.microsoft.com/en-us/azure/api-management/api-management-howto-mutual-certificates-for-clients and this one for testing with Postman https://medium.com/@jkewley/testing-client-certificate-authentication-to-azure-api-management-with-postman-e1cfae52fc35

I'm using the following Policy in the Echo API All operations Inbound just checking if any certificate is present:

<policies>
    <inbound>
        <choose>
            <when condition="@(context.Request.Certificate == null)">
                <return-response>
                    <set-status code="403" reason="Missing client certificate" />
                </return-response>
            </when>
        </choose>
        <base />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

In the Custom Domains tab, I have my Endpoint Gateway with Negotiate client certificate and Default SSL binding enabled.

When testing without the policy it works fine. With the policy, I get "403 - Missing client certificate".

My PostMan logs show my local pfx file being sent. I have used that same CA certificate successfully with an Apigee setup that I'm trying to replicate.

Postman Console

The APIM Trace shows no sign of that certificate

{
  "traceId": "1e2950a4-7ae9-4489-9175-dd6b7a8e6872",
  "traceEntries": {
    "inbound": [
      {
        "source": "api-inspector",
        "timestamp": "2021-03-08T16:45:36.1300291Z",
        "elapsed": "00:00:00.0002376",
        "data": {
          "request": {
            "method": "POST",
            "url": "https://xxxxxx-poc-apim.azure-api.net/echo/resource",
            "headers": [
              {
                "name": "Ocp-Apim-Subscription-Key",
                "value": "20c7x7x22xa5xdxc8a1x857bb651000a"
              },
              {
                "name": "X-Forwarded-For",
                "value": "76.98.XX.XXX"
              },
              {
                "name": "Connection",
                "value": "keep-alive"
              },
              {
                "name": "Content-Length",
                "value": "102"
              },
              {
                "name": "Content-Type",
                "value": "text/plain"
              },
              {
                "name": "Accept",
                "value": "*/*"
              },
              {
                "name": "Accept-Encoding",
                "value": "gzip,deflate,br"
              },
              {
                "name": "Host",
                "value": "xxxxxxx-poc-apim.azure-api.net"
              },
              {
                "name": "User-Agent",
                "value": "PostmanRuntime/7.26.10"
              }
            ]
          }
        }
      },
      {
        "source": "api-inspector",
        "timestamp": "2021-03-08T16:45:36.1300291Z",
        "elapsed": "00:00:00.0002401",
        "data": {
          "configuration": {
            "api": {
              "from": "/echo",
              "to": {
                "scheme": "http",
                "host": "echoapi.cloudapp.net",
                "port": 80,
                "path": "/api",
                "queryString": "",
                "query": {
                  
                },
                "isDefaultPort": true
              },
              "version": null,
              "revision": "1"
            },
            "operation": {
              "method": "POST",
              "uriTemplate": "/resource"
            },
            "user": "-",
            "product": "-"
          }
        }
      },
      {
        "source": "cors",
        "timestamp": "2021-03-08T16:45:36.1300291Z",
        "elapsed": "00:00:00.0002602",
        "data": "Origin header was missing or empty and the request was classified as not cross-domain. CORS policy was not applied."
      },
      {
        "source": "choose",
        "timestamp": "2021-03-08T16:45:36.1300291Z",
        "elapsed": "00:00:00.0002753",
        "data": {
          "message": "Expression was successfully evaluated.",
          "expression": "context.Request.Certificate == null",
          "value": true
        }
      },
      {
        "source": "set-status",
        "timestamp": "2021-03-08T16:45:36.1300291Z",
        "elapsed": "00:00:00.0002817",
        "data": {
          "message": [
            "Response status code was set to 403",
            "Response status reason was set to 'Missing client certificate'"
          ]
        }
      },
      {
        "source": "return-response",
        "timestamp": "2021-03-08T16:45:36.1300291Z",
        "elapsed": "00:00:00.0002863",
        "data": {
          "message": "Return response was applied",
          "response": {
            "status": {
              "code": "Forbidden",
              "reason": "Missing client certificate"
            },
            "headers": [
              
            ]
          }
        }
      }
    ],
    "outbound": [
      {
        "source": "transfer-response",
        "timestamp": "2021-03-08T16:45:36.1300291Z",
        "elapsed": "00:00:00.0003120",
        "data": {
          "message": "Response headers have been sent to the caller."
        }
      }
    ]
  }
}

I have tried a lot of things. I tried using SoapUI instead of Postman I try with another CA certificate. I tried on another APIM that has a CA certificate but is behind an App Gateway. Always the same result. I'm out of ideas.

1

1 Answers

0
votes

I found the issue. My company is using Netskope for web traffic control and it was messing with the Certificates. I discovered it by testing it from my home computer which was working fine. When connecting to the APIM URL from my work laptop, my Web Browser was not showing the default .azure-api.net certificate but instead a certificate .goskope.com. We added *.azure-api.net domain to bypass Netskope checks and it solved the issue.