Skip to main content

Written by Brett Henderson

Introduction

I often quip that “All non-trivial projects begin as an identity project”. I used to say it in jest but it now feels more like an axiom. Knowing who we’re dealing with and making sure they don’t do bad things with evil or mistaken intent is important.

Mantel Group builds solutions, it doesn’t sell (or re-sell) individual technology platforms. However, IAM (Identity and Access Management) is so fundamental to most of our solutions that it forms a key part of our offering.

Rather than attempting to define a one size fits all solution, it is more useful to discuss topics that are interesting and/or challenging. This won’t include a complete explanation of standards such as OAuth 2.0 but will often refer to them. A large percentage of Mantel Group solutions incorporate APIs, so this will naturally be API focused.

It is assumed that readers are familiar with terms like authentication and authorisation so won’t define them here, there are plenty of resources out there that can introduce these topics.

This first piece will build up context around what aspects of IAM are being referring to. What checks do we need to perform? Where do they fit into a typical microservice architecture? Subsequent pieces will delve into more interesting and useful topics such as:

  1. Standards – What standards do we typically use and how are they evolving?
  2. Modelling entitlements – How can we implement fine-grained resource authorisation
    checks in a microservices architecture?

Typical Auth Workflow

If you squint a bit, the majority of service operations perform the following steps:

  1. Receive request – Accept a request from a caller.
  2. Establish identity – Determine who is making the call.
  3. Authorise operation – Ensure that the caller is allowed to invoke the operation.
  4. Load resource – Retrieve the resource from persistent storage or from an upstream API.
  5. Authorise resource – Ensure that the caller is allowed to invoke the operation on this specific resource instance.
  6. Update resource – Make changes (if required) to the resource and persist to storage or upstream API.
  7. Return resource – Return details about the resource to the caller.

Implementation

So now let’s look at how these steps typically map onto a microservice architecture.

There are a few points to note:

  1. Establishing identity is a common concern that most endpoints will require. This allows a gateway or service mesh to be used. Separating this from service implementations provides a number of benefits. There is less duplication which can simplify long term maintenance and evolution, and the use of well-vetted components and multiple network zones can make it harder to compromise.
  2. Authorising the operation is also a common concern and can also be implemented in a gateway or service mesh. Techniques such as RBAC (role-based access control) may be used to group common sets of privileges and simplify management at scale.
  3. Authorising the resource is more complicated and there are pros and cons between implementing centrally or per-service. Non-trivial authorisation checks typically require having access to resource attributes such as owner attributes and this cannot be done without either invoking the service or making a large amount of resource state available to the authorisation component.
    1. Implementing fine-grained authorisation in the service tends to be simpler but can lead to duplication and divergent solutions.
    2. Implementing fine-grained authorisation in a common component can be more powerful and consistent but requires access to domain knowledge and domain resource attributes.
  4. Finding a good balance between domain independence and consistency across domains is a challenge. Addressing this requires finding a clean boundary between domain specific service responsibilities and authorisation component responsibilities. I’ll explore ways of tackling this in future posts.

Sensible Defaults

When designing a solution it is useful to have a set of sensible defaults to act as a starting point. Deviation from these defaults is possible and often required, but requires justification. Sticking to sensible defaults results in a solution that more people will be familiar with and introduces less risk.

Here are some sensible defaults that are typically followed:

  • Protect APIs with token based authorisation based on OAuth 2.0. More specific OAuth 2.0 recommendations will be provided later.
  • Use an API Gateway to provide a single point of entry for all services.
  • Verify request identity in the API Gateway. This requires validating the JWT and ensuring it contains an identity.
  • Authorise the operation in the API Gateway. This requires validating that the JWT contains the correct scope(s).
  • Do not perform message transformation or business logic in the API Gateway, this is a service concern.
  • Avoid service meshes until the number of services justifies the investment, the tipping point is typically in the order of dozens of services.
  • Use JWT (JSON Web Token) access tokens.
  • Implement fine grained authorisation checks in the service. It must be stressed that this is just a starting point but it significantly reduces complexity if you can get away with it. Options for avoiding duplication between services will be discussed later.
  • Secure user initiated and system to system requests with a common OAuth 2.0 implementation. Only the access token issuance steps should vary. OAuth 2.0 provides different flows to support these use cases.

Conclusion

In this article we’ve discussed:

  • The importance of IAM as a fundamental building block of Mantel Group solutions.
  • The types of authentication and authorisation checks that need to be performed within a service oriented solution.
  • How the various authentication and authorisation checks map onto a typical microservice architecture.
  • The sensible defaults we use as a starting point when proposing and designing solutions.

The next blog will identify and discuss the standards relating to OAuth 2.0, their history, and key callouts to be aware of. These standards provide building blocks that can be used to identify users and API callers, and to authorise them to invoke specific operations.