<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>API Management on Andrew Wilson's Blog</title><link>https://andrewilson.co.uk/tags/api-management/</link><description>Recent content in API Management on Andrew Wilson's Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Sun, 02 Jun 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://andrewilson.co.uk/tags/api-management/index.xml" rel="self" type="application/rss+xml"/><item><title>Azure API Management | Enable Tracing for an API</title><link>https://andrewilson.co.uk/post/2024/06/apim-enable-tracing-for-an-api/</link><pubDate>Sun, 02 Jun 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/06/apim-enable-tracing-for-an-api/</guid><description>&lt;h2 id="background"&gt;Background&lt;/h2&gt;
&lt;p&gt;For a while now I have made good use of the Trace functionality in the API Management (APIM) Test Client. If you haven&amp;rsquo;t, I would highly advise having a &lt;a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-api-inspector#trace-a-call-in-the-portal"&gt;look&lt;/a&gt;. The Trace functionality allows us to unveil (debug) the complexity and inner workings of our reverse proxy APIs (their routing / hierarchical policies / alternate backends / caching / etc.). With the Portal this is fairly trivial to do, you simply:&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="background">Background</h2>
<p>For a while now I have made good use of the Trace functionality in the API Management (APIM) Test Client. If you haven&rsquo;t, I would highly advise having a <a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-api-inspector#trace-a-call-in-the-portal">look</a>. The Trace functionality allows us to unveil (debug) the complexity and inner workings of our reverse proxy APIs (their routing / hierarchical policies / alternate backends / caching / etc.). With the Portal this is fairly trivial to do, you simply:</p>
<ol>
<li>Navigate to your API Management instance.</li>
<li>Select one of your APIs that you would like to Trace.</li>
<li>Select the Test tab.</li>
<li>Select one of the Operations to send a request to.</li>
<li>Select Trace.</li>
</ol>
<p>
  <img src="/images/posts/2024/06/APIMTracePortal.png" alt="API Tracing Portal">

</p>
<p>By enabling tracing on the API you are now able to inspect each part of the request:</p>
<ul>
<li><strong>Inbound</strong> | The original request received from the caller and the policies applied.</li>
<li><strong>Backend</strong> | The requests API Management sent to the backend and the response it received.</li>
<li><strong>Outbound</strong> | The policies applied to the response before sending back to the caller.</li>
<li><strong>On error</strong> | The errors that occurred during processing of the request and any policies applied to those errors.</li>
</ul>
<blockquote>
<p>⚠️ <strong>Important</strong></p>
<p>Be careful when enabling tracing as it can expose sensitive information in the trace data.</p>
</blockquote>
<h2 id="problem-space">Problem Space</h2>
<p>Although the APIM Test client has certainly proven useful, I have wondered if there are any other methods of enabling and obtaining the trace for a given API. More importantly, brining the development experience back to something that we are use to such as Visual Studio Code, Postman, etc.</p>
<p>Just over a week ago, I had a conversation with the APIM product group, of which they mentioned that the service has a REST API that can be used to enable trace functionality. After a bit of digging, I found the <a href="https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-api-inspector#enable-tracing-for-an-api">documentation</a> around this and thought I would share my findings and implementation with you.</p>
<blockquote>
<p>⚠️ <strong>Important</strong></p>
<p>Before we get started, please bare in mind:</p>
<ul>
<li>The API Management REST API version 2023-05-01-preview or later is required.</li>
<li>The Identity used to call the REST API must be assigned the Contributor or higher role on the API Management instance.</li>
</ul>
</blockquote>
<p>Enabling tracing on an API through the REST API is a four step process:</p>
<ol>
<li>We need to obtain trace credentials using the <a href="https://learn.microsoft.com/en-us/rest/api/apimanagement/gateway/list-debug-credentials?view=rest-apimanagement-2023-05-01-preview&amp;tabs=HTTP">List Debug Credentials API</a>.</li>
<li>Enable Tracing on your API by adding the Trace Credential token as a header (<code>Apim-Debug-Authorization</code>) to your request.</li>
<li>Given that the Trace Credential token was valid, we need to retrieve the Trace ID from the response header <code>Apim-Trace-Id</code>.
<blockquote>
<p>Invalid Cases Include:</p>
<ul>
<li>
<p><strong>Token expired</strong> | The response will include a <code>Apim-Debug-Authorization-Expired</code> header with information about expiration date.</p>
</li>
<li>
<p><strong>Token obtained for wrong API</strong> | The response will include a <code>Apim-Debug-Authorization-WrongAPI</code> header with an error message.</p>
</li>
</ul>
</blockquote>
</li>
<li>We need to retrieve the trace log by calling the <a href="https://learn.microsoft.com/en-us/rest/api/apimanagement/gateway/list-trace?view=rest-apimanagement-2023-05-01-preview&amp;tabs=HTTP">List Trace API</a> using the Trace ID from the previous step.</li>
</ol>
<p>In both steps 1 and 4, you will need to provide a valid Authorization Bearer token where the identity is assigned Contributor or higher on the APIM instance.</p>
<p>Given that this is not the simplicity that we know and love in the Test Client, making and orchestrating these various Rest calls can and most certainly will take time when conducted singularly. What we need is tooling or extensions to such tooling that will enable us to orchestrate these various calls so that we can obtain the trace logs with repeatable ease.</p>
<h2 id="my-solution">My Solution</h2>
<p>I required a solution that would allow me to orchestrate the various calls with repeatable ease whilst also keeping me close to the tooling that I know and love. My solution is the <a href="https://marketplace.visualstudio.com/items?itemName=humao.rest-client">REST Client</a> extension in VS Code. Using this extension I can:</p>
<ol>
<li>
<p>Orchestrate the various Rest calls required.</p>
</li>
<li>
<p>Use variables to make as much of the calls required somewhat generic.</p>
</li>
<li>
<p>The extension provides me the ability to obtain an AAD (Entra ID) token.</p>
<p>By default if a token has already been obtained, the extension will reuse the previous token for the specified directory from an in-memory cache. Expired tokens are refreshed automatically. (The token cache can be manually cleared, or is by default cleared upon closure of VS Code).</p>
</li>
</ol>
<p>The implementation that I have come to is as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-http" data-lang="http"><span style="display:flex;"><span># ***************************************************************************************************************
</span></span><span style="display:flex;"><span># Enable tracing for an APIM API
</span></span><span style="display:flex;"><span># ------------------------------
</span></span><span style="display:flex;"><span>#
</span></span><span style="display:flex;"><span># ⚠️Note:
</span></span><span style="display:flex;"><span>#    The following steps require API Management REST API version 2023-05-01-preview or later. 
</span></span><span style="display:flex;"><span>#    You must be assigned the Contributor or higher role on the API Management instance to call the REST API.
</span></span><span style="display:flex;"><span>#
</span></span><span style="display:flex;"><span>#  Steps:
</span></span><span style="display:flex;"><span>#  1. Obtain trace credentials by calling the List debug credentials API.
</span></span><span style="display:flex;"><span>#  2. Call the API with the trace credentials.
</span></span><span style="display:flex;"><span>#  3. Retrieve trace logs.
</span></span><span style="display:flex;"><span>#
</span></span><span style="display:flex;"><span>#  Author: Andrew Wilson
</span></span><span style="display:flex;"><span># ***************************************************************************************************************
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># -----------------
</span></span><span style="display:flex;"><span># Custom Variables 
</span></span><span style="display:flex;"><span># -----------------
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>@subscriptionId = REPLACEME
</span></span><span style="display:flex;"><span>@resourceGroup = REPLACEME
</span></span><span style="display:flex;"><span>@apimServiceName = REPLACEME
</span></span><span style="display:flex;"><span>@apiName = REPLACEME
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># -----------------
</span></span><span style="display:flex;"><span>#    Rest Steps
</span></span><span style="display:flex;"><span># -----------------
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>### 1.Obtain trace credentials by calling the List debug credentials API.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># @name TraceCreds
</span></span><span style="display:flex;"><span>POST https://management.azure.com/subscriptions/{{subscriptionId}}/resourceGroups/{{resourceGroup}}/providers/Microsoft.ApiManagement/service/{{apimServiceName}}/gateways/managed/listDebugCredentials
</span></span><span style="display:flex;"><span>?api-version=2023-05-01-preview
</span></span><span style="display:flex;"><span>Content-Type: application/json
</span></span><span style="display:flex;"><span>Authorization: {{$aadToken}}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    &#34;credentialsExpireAfter&#34;: &#34;PT1H&#34;,
</span></span><span style="display:flex;"><span>    &#34;apiId&#34;: &#34;/subscriptions/{{subscriptionId}}/resourceGroups/{{resourceGroup}}/providers/Microsoft.ApiManagement/service/{{apimServiceName}}/apis/{{apiName}}&#34;,
</span></span><span style="display:flex;"><span>    &#34;purposes&#34;: [&#34;tracing&#34;]
</span></span><span style="display:flex;"><span>}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>### 2.Call the API with the trace credentials.
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># @name ApiOperationTracing
</span></span><span style="display:flex;"><span>Author your API request here but make sure to keep the following Header in place.
</span></span><span style="display:flex;"><span>Apim-Debug-Authorization: {{TraceCreds.response.body.$.token}}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>### 3.Retrieve Trace Logs
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span># @name ObtainedTraceLogs
</span></span><span style="display:flex;"><span>POST https://management.azure.com/subscriptions/{{subscriptionId}}/resourceGroups/{{resourceGroup}}/providers/Microsoft.ApiManagement/service/{{apimServiceName}}/gateways/managed/listTrace
</span></span><span style="display:flex;"><span>?api-version=2023-05-01-preview
</span></span><span style="display:flex;"><span>Content-Type: application/json
</span></span><span style="display:flex;"><span>Authorization: {{$aadToken}}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>{
</span></span><span style="display:flex;"><span>    &#34;traceId&#34;: &#34;{{ApiOperationTracing.response.headers.Apim-Trace-Id}}&#34;
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>Have a play and see if this extends your tracing capabilities.</p>
]]></content:encoded></item><item><title>Azure API Management | Unintentional Removal of Request Forwarding to Backend</title><link>https://andrewilson.co.uk/post/2024/05/apim-policy-hierarchy-request-forwarding/</link><pubDate>Fri, 03 May 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/05/apim-policy-hierarchy-request-forwarding/</guid><description>&lt;h2 id="problem-space"&gt;Problem Space&lt;/h2&gt;
&lt;p&gt;I have recently been working on an API scoped policy within API Management, the policy ideally should not be impacted by any policies defined higher up in the hierarchy.&lt;/p&gt;
&lt;p&gt;For reference, this means that any policies defined at the Product, Workspace, or Global level will not be inherited at the API scope for the given API Definition. See diagram below:&lt;/p&gt;
&lt;p&gt;
&lt;img src="https://andrewilson.co.uk/images/posts/2024/05/APIMPolicyScopes.png" alt="Policy Scopes"&gt;
&lt;/p&gt;
&lt;p&gt;Ideally this means that my API traffic will start at my non-hierarchical policy definition, conduct any policy processing prior to being sent off to the backend, and then sent back to the calling outbound system.&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="problem-space">Problem Space</h2>
<p>I have recently been working on an API scoped policy within API Management, the policy ideally should not be impacted by any policies defined higher up in the hierarchy.</p>
<p>For reference, this means that any policies defined at the Product, Workspace, or Global level will not be inherited at the API scope for the given API Definition. See diagram below:</p>
<p>
  <img src="/images/posts/2024/05/APIMPolicyScopes.png" alt="Policy Scopes">

</p>
<p>Ideally this means that my API traffic will start at my non-hierarchical policy definition, conduct any policy processing prior to being sent off to the backend, and then sent back to the calling outbound system.</p>
<blockquote>
<p>Example Policy definition with the removal of <code>&lt;base /&gt;</code> which indicates inheritance:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span> <span style="color:#ff79c6">&lt;policies&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&lt;inbound&gt;</span>
</span></span><span style="display:flex;"><span>  		...
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&lt;/inbound&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&lt;backend&gt;</span>
</span></span><span style="display:flex;"><span>  		...
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&lt;/backend&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&lt;outbound&gt;</span>
</span></span><span style="display:flex;"><span>  		...
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&lt;/outbound&gt;</span>
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&lt;on-error&gt;</span>
</span></span><span style="display:flex;"><span>  		...
</span></span><span style="display:flex;"><span>   <span style="color:#ff79c6">&lt;/on-error&gt;</span>
</span></span><span style="display:flex;"><span> <span style="color:#ff79c6">&lt;/policies&gt;</span>
</span></span></code></pre></div></blockquote>
<p>In practice this is not what happened.</p>
<p>The API that I had defined should have successfully returned with a Status Code of 200 and a Json Payload. However, what I actually received was a successful API run with a return of Status Code 200 but no Json Payload.</p>
<p>Further investigation into this highlighted that the API request was never making it out to the Backend.</p>
<p>This being the case, a reviewal of the higher scoped policies showed that there was indeed a policy that is core to the APIM reverse proxy behaviour, and I had excluded this due to my lack of inheritance.</p>
<blockquote>
<p>Offending Policy that was excluded due to my lack of inheritance</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#282a36;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-xml" data-lang="xml"><span style="display:flex;"><span>  <span style="color:#ff79c6">&lt;backend&gt;</span>
</span></span><span style="display:flex;"><span>  	<span style="color:#ff79c6">&lt;forward-request</span> <span style="color:#ff79c6">/&gt;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#ff79c6">&lt;/backend&gt;</span>
</span></span></code></pre></div></blockquote>
<p>For reference, the <a href="https://learn.microsoft.com/en-us/azure/api-management/forward-request-policy">forward-request policy</a> forwards the incoming request to the backend service specified in the request context. And more importantly the policy is included in the Global Backend Policy by default.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Two things came from this,</p>
<ol>
<li>I fixed my problem by applying the forward-request policy in my API policy definition.</li>
<li><strong>More importantly</strong>, Always review hierarchical policies when removing inheritance as there may be behaviour that you will require, even if you didn&rsquo;t place it there.</li>
</ol>
]]></content:encoded></item><item><title>Azure API Management | Governing Product Visibility and Access via Groups</title><link>https://andrewilson.co.uk/post/2024/04/apim-users-and-groups/</link><pubDate>Tue, 30 Apr 2024 00:00:00 +0000</pubDate><guid>https://andrewilson.co.uk/post/2024/04/apim-users-and-groups/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;In API Management, users and groups are a core aspect of the Developer Portal and are used to manage the visibility and access to respective products and their APIs.&lt;/p&gt;
&lt;p&gt;One of the common questions that I often get asked is, &amp;ldquo;how do I appropriately govern the groups effectively so that I can ensure that the correct groups and users have access to the appropriate resources and those who don&amp;rsquo;t&amp;hellip; well don&amp;rsquo;t?&amp;rdquo;.&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="overview">Overview</h2>
<p>In API Management, users and groups are a core aspect of the Developer Portal and are used to manage the visibility and access to respective  products and their APIs.</p>
<p>One of the common questions that I often get asked is, &ldquo;how do I appropriately govern the groups effectively so that I can ensure that the correct groups and users have access to the appropriate resources and those who don&rsquo;t&hellip; well don&rsquo;t?&rdquo;.</p>
<h2 id="background">Background</h2>
<p>API Management has three immutable built in system groups used to govern access:</p>
<p>
  <img src="/images/posts/2024/04/APIMSystemGroups.png" alt="Overview">

</p>
<ul>
<li>
<p><strong>Administrators</strong> | These are not consumers or customers of your APIs but are rather the users who build and manage the API Management service instances, creating the APIs, operations, and products that are used by developers. You can&rsquo;t add users to this group.</p>
<p>The group contains the admin email account provided at the time of service creation. Azure subscription administrators are members of this group.</p>
</li>
<li>
<p><strong>Developers</strong> | These are customers and consumers that build applications using your APIs. Developers are granted access to and are authenticated into the developer portal. Membership to this group is managed by the system and cannot be added to by you.</p>
<blockquote>
<p><code>Developers (Authenticated Users) invited, created, pulled from external groups, or otherwise signed up are all created as a developer and gain automatic membership to this group.</code></p>
</blockquote>
</li>
<li>
<p><strong>Guests</strong> | These are users such as prospective customers and are able to visit the developer portal without having to be authenticated. APIs that guests can view are managed by yourself as well as the type of access such as read-only access (the ability to view APIs but not call them). As with the previous two groups, membership is managed by the system.</p>
</li>
</ul>
<p>Then there is the ability to create custom groups and or use external groups in associated Microsoft Entra tenants. These custom groups can be used to further govern developer visibility and access to API products.</p>
<blockquote>
<p><strong><code>Note:</code></strong></p>
<p><code>User accounts from MS Entra ID or B2C groups are still created as new developer user entities within APIM and associated with the Developers System group as well as the desired Entra ID group.</code></p>
</blockquote>
<p>
  <img src="/images/posts/2024/04/CustomGroupsAndAssociations.png" alt="Custom Groups and Associations">

</p>
<h2 id="governing-access">Governing Access</h2>
<p>The key to understanding Group Access is to remember that all developers (no matter how they have been created) are associated with the Developers System group. In effect this means that any product that has been associated with the Developers system group will be accessible to all users (except Guests given association).</p>
<p>Therefore do not blindly associate the Developer System group to your products unless you expect all users past, present, and future to have access to them.</p>
<p>Rather in answer create custom groups/associate Entra ID groups of which can be used to provide access to specific products. Further to this, granularity is key for security, following the good practice of least privilege (<em><code>A user or entity should only have access to the specific data, resources and applications needed to complete a required task.</code></em>).</p>
<p>
  <img src="/images/posts/2024/04/Governance.png" alt="Group Governance">

</p>
<p>Have a play, and hope this helps.</p>
]]></content:encoded></item></channel></rss>