Graduate Program KB

API Management

  • Made up of API gateway, a management plane and a developer portal
    • All components are Azure-hosted and fully managed by default, API Management is available in various tiers differing in capacity and features
    • API gateway endpoint
      • Accepts API calls and routes them to backend
      • Verifies API keys and other credentials
      • Enforce usage quotas and rate limits
      • Transforms requests and responses specified in policy statements
      • Caches response to improve response latency
      • Emits logs, metrics and traces
    • Management plane is an administrative interface to set up the API program
      • Provision and configure API Management service settings
      • Define or import API schema
      • Package APIs into products
      • Set uo policies like quotas or transformations on the APIs
      • Get insights from analytics
      • Manage users
    • Developer portal is an automatically generated, fully customisable website with your API documentation
      • Read API documentation
      • Call an API via interactive console
      • Create an account and subscribe to get API keys
      • Access analytics on their own usage
      • Download API definitions
      • Manage API keys
  • Products in API Management can have multiple APIs, configured with a title, description and terms of use
    • Can be Open / Protected
    • Must be subscribed to before they can be used
  • Groups manage the visibility of products to developers, API Management has the following immutable system groups:
    • Administrators: Manage API Management service instances and create the APIs, operations and products that are used by developers. Azure subscription administrators are members of this group
    • Developers: Authenticated developer portal users that build applications using your APIs. Developers are granted access to the developer portal and build applications that call the operations of an API
    • Guests: Unauthenticated developer portal users. They can be granted certain read-only access, like the ability to view APIs but not call them
  • Developers represent user accounts in an API Management service instance, they can be created or invited to join by admins or sign up from the Developer portal
  • Policies are a collection of statements that are executed sequentially on the request or response of an API

API Gateways

  • A service component responsible for proxying API requests, applying policies and collecting telemetry
  • Sits between clients and services, can also perform authentication, SSL termination and rate limiting
  • Problems with exposing services directly to clients:
    • Complex client code
    • Coupling between client and backend
    • Single operation might require calls to multiple services
    • Public-facing services must handle authentication, SSL and client rate limiting
    • Services with public endpoints are a potential attack surface
  • Managed gateway is the default gateway component deployed for every API Management instance
  • Self-hosted gateway is an optional, containerised version of the default managed gateway

API Management Policies

  • Applied inside the gateway sitting between the API consumer and managed API
  • Policies can apply changes to both inbound requests and outbound responses
  • Policies are simple XML documents describing a sequence of inbound and outbound statements
    • Divided into inbound, backed, outbound and on-error
    • If an error occurs during processing a request, any remaining steps in the other sections are skipped
    <policies>
    <inbound>
        <!-- statements to be applied to the request go here -->
    </inbound>
    <backend>
        <!-- statements to be applied before the request is forwarded to 
            the backend service go here -->
    </backend>
    <outbound>
        <!-- statements to be applied to the response go here -->
    </outbound>
    <on-error>
        <!-- statements to be applied if there is an error condition go here -->
    </on-error>
    </policies>
    
  • Policy expressions are either a single C# statement enclosed in @(expression) or a multi-statement code block enclosed in @{expression} that returns a value
    • Each expression has access to the implicitly provided context variable and an allowed subset of .NET framework types
    <policies>
        <inbound>
            <base />
            <set-header name="x-request-context-data" exists-action="override">
                <value>@(context.User.Id)</value>
                <value>@(context.Deployment.Region)</value>
        </set-header>
        </inbound>
    </policies>
    
  • Policies can be applied at different scopes
    <policies>
        <inbound>
            <cross-domain />
            <base />
            <find-and-replace from="xyz" to="abc" />
        </inbound>
    </policies>
    
  • Response context can be filtered
    <policies>
    <inbound>
        <base />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
        <choose>
        <when condition="@(context.Response.StatusCode == 200 && context.Product.Name.Equals("Starter"))">
            <!-- NOTE that we are not using preserveContent=true when deserializing response body stream into a JSON object since we don't intend to access it again. See details on /azure/api-management/api-management-transformation-policies#SetBody -->
            <set-body>
            @{
                var response = context.Response.Body.As<JObject>();
                foreach (var key in new [] {"minutely", "hourly", "daily", "flags"}) {
                response.Property (key).Remove ();
            }
            return response.ToString();
            }
        </set-body>
        </when>
        </choose>    
    </outbound>
    <on-error>
        <base />
    </on-error>
    </policies>
    

Creating Advanced Policies

  • API Management policies:
    • Control flow: Conditionally apply policy statements
    • Forward request: Forwards request to backend service
    • Limit concurrency: Prevent enclosed policies from executing more than a specified limit at a time
    • Log to Event Hub: Sends messages in a specified format to an Event Hub defined by a Logger entity
    • Mock response: Aborts pipeline execution and returns a mocked response directly to the caller
    • Retry: Retries execution of the enclosed policy statements, if and until the condition is met
  • Control flow applies policies based on outcome of evaluation of boolean expressions
    <choose>
        <when condition="Boolean expression | Boolean constant">
            <!— one or more policy statements to be applied if the above condition is true  -->
        </when>
        <when condition="Boolean expression | Boolean constant">
            <!— one or more policy statements to be applied if the above condition is true  -->
        </when>
        <otherwise>
            <!— one or more policy statements to be applied if none of the above conditions are true  -->
    </otherwise>
    </choose>
    
  • Forward request
    <forward-request timeout="time in seconds" follow-redirects="true | false"/>
    
  • Limit concurrency
    <limit-concurrency key="expression" max-count="number">
        <!— nested policy statements -->
    </limit-concurrency>
    
  • Log to Event Hub
    <log-to-eventhub logger-id="id of the logger entity" partition-id="index of the partition where messages are sent" partition-key="value used for partition assignment">
    Expression returning a string to be logged
    </log-to-eventhub>
    
  • Mock response
    <mock-response status-code="code" content-type="media type"/>
    
  • Retry
    <retry
        condition="boolean expression or literal"
        count="number of retry attempts"
        interval="retry interval in seconds"
        max-interval="maximum retry interval in seconds"
        delta="retry interval delta in seconds"
        first-fast-retry="boolean expression or literal">
            <!-- One or more child policies. No restrictions -->
    </retry>
    
  • Return response
    • return-response policy aborts pipeline executions and returns either a default or custom response to the caller
    <return-response response-variable-name="existing context variable">
        <set-header/>
        <set-body/>
        <set-status/>
    </return-response>
    

Secure APIs by using subscriptions

  • A subscription key is a unique autogenerated key which can be passed through headers of the client request or a query string parameter
  • Scope and details:
    • All APIs: Applies to every API accessible from the gateway
    • Single API: Applies to a single imported API and all of its endpoints
    • Product: A collection of one or more APIs that you configure in API Management. Can assign APIs to more than one product, which can have different access rules, usage quotas and terms of use
  • Apps must include a valid key in all HTTP requests when hitting an API endpoint
    • Default header name is Ocp-Apim-Subscription-Key and the default query string is subscription-key
    • Example of passing key in the request header using curl:
    curl --header "Ocp-Apim-Subscription-Key: <key string>" https://<apim gateway>.azure-api.net/api/path
    
    • Example passing a key in the URL as a query string using curl:
    curl https://<apim gateway>.azure-api.net/api/path?subscription-key=<key string>
    
    • If neither are provided, a 401 Access Denied response is returned

Secure APIs by using certificates

  • Certificates can provide TLS mutual authentication between the client and API gateway
  • Client can request and check for properties on the certificate:
    • Certificate Authority (CA): Only allow certificates signed by a particular CA
    • Thumbprint: Allow certificates containing a specified thumbprint
    • Subject: Only allow certificates with a specified subject
    • Expiration Date: Don't allow expired certificates
  • Client certificates are signed to ensure they aren't tampered with
    • Two common ways to verify a certificate is checking who issued it and verifying it came from them
  • Accepting client certificates in the Consumption tier requires explicit enabling of its use which can be done on the Custom domains page (don't need to do this in other tiers)
  • Certificate authorisation policies:
    • Check thumbprint of client certificate:
    <choose>
        <when condition="@(context.Request.Certificate == null || context.Request.Certificate.Thumbprint != "desired-thumbprint")" >
            <return-response>
                <set-status code="403" reason="Invalid client certificate" />
            </return-response>
        </when>
    </choose>
    
    • Check thumbprint against certificates uploaded to API Management
    <choose>
        <when condition="@(context.Request.Certificate == null || !context.Request.Certificate.Verify()  || !context.Deployment.Certificates.Any(c => c.Value.Thumbprint == context.Request.Certificate.Thumbprint))" >
            <return-response>
                <set-status code="403" reason="Invalid client certificate" />
            </return-response>
        </when>
    </choose>
    
    • Check the issuer and subject of a client certificate
    <choose>
        <when condition="@(context.Request.Certificate == null || context.Request.Certificate.Issuer != "trusted-issuer" || context.Request.Certificate.SubjectName.Name != "expected-subject-name")" >
            <return-response>
                <set-status code="403" reason="Invalid client certificate" />
            </return-response>
        </when>
    </choose>