Thursday, July 9, 2020

Authorization in Microservices Landscape

Overview

This article outlines a high-level design of authentication and authorization options in Azure per a typical SPA use case interacting with multiple microservices. Compares API gateway pattern versus a direct client-to-API communication in microservices environment.

Use Case

A user should be able to request the following information:
  1. User profile via Azure Graph API.
  2. User documents via SharePoint Online API.
  3. Aggregated data from two other internal systems.
                +----------------------+
            +-> | Azure Graph API      |
            |   +----------------------+
+---------+ |   +----------------------+
| browser |-+-> | Azure SharePoint API |
+---------+ |   +----------------------+
            |   +----------------------+     +--------+
            +-> | App API              |---> | API #1 |
                +----------------------+     +--------+
  +---------------------------+       |      +--------+
  |Microsoft Identity Platform|       +----> | API #2 |
  +---------------------------+              +--------+

Solution

Microsoft Identity Platform
The Microsoft identity platform (v2.0) endpoint supports authentication for different kinds of modern application based on the industry-standard protocols OAuth 2.0 and OpenID Connect.

Microsoft identity platform authenticates users and provides access token to allow a client application to access protected resources on a resource server.
Access Token
An access token is a security token that is issued by an authorization server as part of an OAuth 2.0 flow. It contains information about the user and the app for which the token is intended.

Access tokens are only valid for a limited amount of time. Access tokens are passed to a web API as the bearer token in the Authorization header.
JWT
Microsoft identity platform implements security tokens as JSON Web Tokens (JWTs) that contain claims. A claim provides assertions about one entity (a client application or resource owner) to another entity (a resource server).

JWT payload’s string attribute “aud” (audience, also known as application or client id is assigned in the Azure portal during Active Directory app registration) should be validated and rejected if value does not match current application id. For example, Microsoft Graph API is a separate application, thus it will reject access if access token audience does not match Graph API application id. The same applies to SharePoint Online API, etc.

JWT payload’s string array attribute “scp” represents an OAuth Scope granted for the issued security token.

“aud” and “scp” correspond to a single resource that means access token is valid for a single application. To directly access multiple applications, a caller needs access token issued per application (hence, handle multiple access tokens).
Authentication flows and application scenarios
The use case described above fits the following integration scenarios:
  1. Single-page application (SPA) accesses web API
  2. Protected Web API
  3. Web API that calls to other web APIs
The following sections go into further details about each integration scenario.
Scenario #1. Single-page application accesses Web API
The Microsoft identity platform enables single-page applications to sign in users and get tokens to access web APIs by using the OAuth 2.0 implicit or authorization code flows.

The implicit flow allows the application to get ID tokens to represent the authenticated user and also access tokens needed to call protected APIs.

The authorization code flow enables apps to securely acquire access tokens that can be used to access resources secured by the Microsoft identity platform endpoint, as well as refresh tokens to get additional access tokens, and ID tokens for the signed in user.

Note, while requesting access token, the scopes must all be from a single resource (application registered in Azure Active Directory).

Developers might consider examining the following resources for quick starts.

It is recommended to use auth code flow.
Scenario #2. Protected Web API
It is important to protect Web API so only legitim users can access it.

The app registration in Azure Active Directory must expose at least one scope (see Expose API blade in Azure Portal for Active Directory).

API exposed scopes can correspond to some subset of API functions which user is authorized to perform. For example, consider an API that provides two scopes: readonly and fullaccess. Each request handler of API must assert for corresponding scope, e.g. list of entities asserts for readonly, delete would require fullaccess scope, etc.

Scopes can be used to decompose a complex API into smaller parts, e.g. Microsoft Graph API uses separate scopes for user profile, emails, etc.

The code for the web API must validate the access token used when the web API is called.

Developers might consider examining the following resource for quick start.
Scenario #3. Web API that calls other web APIs
The assumption here is that other web API is a separate Resource (app registration).

A typical use case includes the following:
  1. SPA calls an API (protected web API) and provides an access token
  2. The API validates the token.
  3. The API requests another token from Azure Active Directory so that it can call other API #1 (downstream web API), *on behalf of* the user.
  4. The API can also request tokens for other downstream APIs (e.g. API #2) *on behalf of* the same user.
The app configuration involves using the OAuth 2.0 on behalf of flow to exchange the JWT bearer access token against access token for a downstream API. This token can be added to the token cache and reused later.

Note, OAuth 2.0 *on behalf of* flow assumes the owner of API #1 provides a “secret”. That secret is available under "Certificates and secrets" in Azure portal for Active Directory.

The secret has a limited lifetime (1 year) and must be stored securely, e.g. in Azure Key Vault service.

It is a responsibility of operations team to rotate secrets timely, devops engineer must use CI/CD pipeline to configure the application properly depending on runtime environment.

Application must not store the secret anywhere in the source code, documentation, etc. The secret must not leave security perimeter. Any leak of that sort must be immediately reported with a follow up rotation for compromised secret.

Note, in case App API, API #1 and API #2 are registered as a single Resource (app registration), the *on behalf of* flow is not required since the same JWT bearer access token can be used to pass through to access downstream APIs.

Developers might consider examining the following resource for quick start.

Integration Options

A modern system usually is comprised of integration with multiple microservices (web APIs).
Multiple App Registration
If each microservice corresponds to a separate Resource (in terms of OAuth 2.0) that implies that consumer (SPA, mobile) must obtain a separate access token to each Resource.

That inevitably increases a complexity of frontend application due to a need to obtain multiple access tokens and store/handle them depending on web API.
Single App Registration
One of possible strategies to mitigate the issue related to multiple access tokens is to use a single app registration. That means we decompose services by a functional scope (profile, emails, file, etc).

In this case Web API to other Web API scenario will not require *on behalf of* flow since the same access token can be passed through (assuming it has necessary scopes).

That would work for services we have control over as developers. However, that would not work for 3rd party APIs like Microsoft Graph, SharePoint Online, etc. The frontend still requires a separate access token per Resource.
API Gateway
An API gateway sits between clients and services, decouples clients from services. It acts as a reverse proxy, routing requests from clients to services. It may also perform various cross-cutting tasks such as authentication, SSL termination, ip filtering and rate limiting.

The API Gateway pattern helps address the following issues:
  • Complex client code.
    • Client must keep track of multiple endpoints and handle API failures in a resilient way.
  • Coupling. The client apps need to know how the multiple areas of the application are decomposed in microservices.
    • That makes it harder to maintain the client and harder to refactor services.
    • Client apps need to be updated frequently, making the solution harder to evolve.
  • Too many round trips. Interacting with multiple microservices to build a single UI screen increases the number of round trips across the Internet.
    • This increases latency and complexity on the UI side.
    • Responses can be efficiently aggregated on the server side. This might lead to use OData or GraphQL.
  • Security issues. Implementing security and cross-cutting concerns like security and authorization on every microservice can require significant development effort.
    • A possible approach is to have those services within the Docker host or internal cluster to restrict direct access to them from the outside and implement those cross-cutting concerns in a centralized place, like an API Gateway.
    • Services with public endpoints are a potential attack surface.
  • The API of multiple microservices might not be well designed for the needs of different client applications.
    • For instance, the needs of a mobile app might be different than the needs of a SPA.
    • For mobile apps, you might need to optimize even further so that data requests/responses can be more efficient.
  • Again, a facade or API in between the mobile app and the microservices can be more convenient to developers and operations from management point of view.
 +-------+
 |browser|
 +-------+      +----------------------+
     |      +-> | Azure Graph API      |
     V      |   +----------------------+
+---------+ |   +----------------------+
| API GW  |-+-> | Azure SharePoint API |
+---------+ |   +----------------------+
            |   +----------------------+     +--------+
            +-> | App API              |---> | API #1 |
                +----------------------+     +--------+
  +---------------------------+       |      +--------+
  |Microsoft Identity Platform|       +----> | API #2 |
  +---------------------------+              +--------+
Drawbacks of the API Gateway pattern:
  • Couples with the internal microservices.
    • However, scope of work is within backend developers’ skills.
  • Creates an additional possible single point of failure.
    • It makes sense to rely on PaaS solution, e.g. Azure API Management.
  • Can introduce increased response time due to the additional network call.
    • However, this extra call usually has a lower impact than having a “chatty” client.
  • If not scaled out properly, the API Gateway can become a bottleneck.
    • Additional operational expenses.
  • Requires additional development cost and future maintenance if it includes custom logic and data aggregation.
Azure API Management is a turnkey solution for publishing APIs. It provides features that are useful for managing a public-facing API, including rate limiting, IP control listing, and authentication using Azure Active Directory.
The API gateway pattern versus the Direct client-to-API communication
A direct client-to-microservice communication architecture could be good enough for a small microservice-based application. However, when we build a large and complex microservice-based application (when communicating with dozens of microservices), and especially when the client apps are remote mobile apps or SPA web applications, that approach faces a few issues.

When application has many microservices, handling so many endpoints from the client apps can be a nightmare. Since the client app would be coupled to those internal endpoints, evolving the microservices in the future can cause high impact for the client apps.

Therefore, having an intermediate level or tier of indirection (API Gateway) can be very convenient for microservice heavy applications effectively addressing crosscutting concerns.

No comments :

Post a Comment