Saturday 17 September 2022

API Gateway Security

 In an ideal world, the microservices developer should worry only about the business functionality of a microservice, and the rest should be handled by specialized components with less hassle. The API Gateway and Service Mesh are two architectural patterns that help us reach that ideal. The API Gateway pattern is mostly about edge security, while the Service Mesh pattern deals with service-to-service security. Or, in other words, the API Gateway deals with north/south traffic, while the Service Mesh deals with east/west traffic. We call the software that implements the API Gateway pattern an API gateway--and the software that implements the Service Mesh pattern, a service mesh.


Edge security is about protecting a set of resources (for example, a set of microservices) at the entry point to the deployment, at the API gateway. The API gateway is the only entry point to our microservices deployment for requests originating from outside. In the Service Mesh pattern, the architecture is much more decentralized. Each microservice has its own policy enforcement point much closer to the service--mostly it is a proxy, running next to each microservice. The API gateway is the centralized policy enforcement point to the entire microservices deployment, while in a service mesh, a proxy running along with each microservice provides another level of policy enforcement at the service level.


The need for an API gateway in a microservices deployment
In a typical microservices deployment, microservices are not exposed directly to client applications. In most cases, microservices are behind a set of APIs that is exposed to the outside world via an API gateway. The API gateway is the entry point to the microservices deployment, which screens all incoming messages for security and other QoS features.

Figure 3.1 depicts a microservices deployment that resembles Netflix’s, in which all the microservices are fronted by the Zuul API gateway. Zuul provides dynamic routing, monitoring, resiliency, security, and more. It acts as the front door to Netflix’s server infrastructure, handling traffic from Netflix users around the world. In figure 3.1, Zuul is used to expose the Order Processing microservice via an API. We do not expose Inventory and Delivery microservices from the API gateway, because external applications don’t need access to those.






As figure 3.2 shows, the Order Processing microservice had to worry about the multiple tasks listed here:

  • Extracting the security header (token) from the incoming requests

  • Knowing beforehand the location of the authorization server that it has to talk to in order to validate the security token

  • Being aware of the protocol and message formats for communicating with the authorization server in order to validate the security token

  • Gracefully handling errors in the token validation flow, because the microservice is directly exposed to the client application

  • Performing the business logic related to processing orders




Figure 3.2 The interactions among the client application, microservice, and authorization server. The Order Processing microservice handles more functionality than it ideally should.


SCALING UP THE MICROSERVICE RESULTS IN MORE CONNECTIONS TO THE AUTHORIZATION SERVER






An API gateway helps in decoupling security from a microservice. It intercepts all the requests coming to a microservice, talks to the respective authorization, and dispatches only the legitimate requests to the upstream microservice. Otherwise, it returns an error message to the client application.

An API gateway solution, which usually comes as part of API management software, can bring consistency to the interfaces that are being exposed to the consuming applications. The microservices themselves could be inconsistent, because they’re now hidden from the outside world, and the API gateway can deal with the complications of interacting with the microservices.


The API Gateway architectural pattern is an ideal solution to this problem. It provides the consuming application a single API with two resources (GET and POST). Each resource can be backed by a microservice of its own, providing the scalability and robustness required by the microservices layer (see figure 3.5).




Figure 3.5 Multiple microservices are being exposed as a single API on the gateway. The client application needs to worry about only a single endpoint.


In an organization, both its internal and external (such as third-party) applications could consume microservices. External applications could be mobile applications, web applications on the public internet, applications running on devices or cars, and so on. For these types of applications to work, you need to expose your microservices over the public internet over HTTPS. As a result, you cannot just rely on network-level security policies to prevent access to these microservices. Therefore, you may always have to rely on an upper layer of security to control access. An upper layer of security here refers to the layers in the TCP/IP protocol stack (www.w3.org/People/Frystyk/thesis/TcpIp.html). You need to rely on security that’s applied above the Network layer, such as Transport- or Application-layer protocols including TLS and HTTPS.


Why not basic authentication to secure APIs?

Basic authentication allows a user (or a system) with a valid username and password to access a microservice via an API. In fact, basic authentication (or basic auth) is a standard security protocol introduced with HTTP/1.0 in RFC 1945 a long time back. It allows you to pass the base64-encoded username and password, in the HTTP Authorization header, along with a request to an API. This model fails to meet access delegation requirements we discussed in section 3.2.2 in a microservices deployment, though, for a variety of reasons:

  • The username and password are static, long-living credentials. If a user provides a username and password to an application, the application needs to retain this information for that particular user session to access the microservices. The time during which this information needs to be retained could be as long as the application decides. None of us likes having to authenticate into an application again and again to perform operations. Therefore, if basic authentication is used, the application has to retain this information for long durations of time. The longer this information is retained, the higher the chance of compromise. And because these credentials almost never change, a compromise of this information could have severe consequences.

  • No restrictions on what the application can do. After an application gets access to the username and password of a user, it can do everything that user can do with the microservice. In addition to accessing the microservice, the application can do anything with those credentials, even on other systems.

    Why not mutual TLS to secure APIs?
    Mutual Transport Layer Security is a mechanism by which a client application verifies a server and the server verifies the client application by exchanging respective certificates and proving that each one owns the corresponding private keys. In chapter 6, we discuss mTLS in detail. For the moment, think of mTLS as a technique for building two-way trust between a client application and a server using certificates.

    mTLS solves one of the problems with basic authentication by having a lifetime for its certificates. The certificates used in mTLS are time-bound, and whenever a certificate expires, it’s no longer considered valid. Therefore, even if a certificate and the corresponding private key are compromised, its vulnerability is limited by its lifetime. In some situations, however, certificates have lifetimes as long as years, so the value of mTLS over protocols such as basic authentication is limited. Then again, unlike basic authentication (where you send your password over the wire), when you use mTLS, the corresponding private key never leaves its owner--or is never passed over the wire. That’s the main advantage mTLS has over basic authentication.

    However, just as in basic authentication, mTLS fails to meet access delegation requirements we discussed in section 3.2.2 in a microservices deployment. mTLS doesn’t provide a mechanism to represent the end user who uses the corresponding application. You can use mTLS to authenticate the client application that talks to the microservice, but it does not represent the end user. If you want to pass the end user information with mTLS, you need to follow your own custom techniques, such as sending the username as a custom HTTP header, which is not recommended. Therefore, mTLS is mostly used to secure communication between a client application and a microservice, or communications among microservices. In other words, mTLS is mostly used to secure communications among systems.

    Why OAuth 2.0?

    To understand why OAuth 2.0 is the best security protocol for securing your microservices at the edge, first you need to understand your audience. You need to figure out who wants access to your resources, for what purpose, and for how long. You must properly understand the audience of your microservices through their characteristics and desires:

    • Who--Ensure that only permitted entities are granted access to your resources

    • What purpose--Ensure that the permitted entities can perform only what they’re allowed to perform on your resources

    • How long--Ensure that access is granted for only the desired period

    As we’ve discussed a few times in the book already, the audience of a microservice is a system that acts on behalf of itself, or on behalf of a human user or another system. The owner of a microservice should be able to delegate access to the microservice it owns (or it has privileges to access), to a system. You may have a Netflix account, and to view the trending movies on Netflix on your smart TV, you need to delegate access from your Netflix account to your smart TV. Delegation is a key requirement in securing microservices--and out of all security protocols, OAuth 2.0, which is designed for access delegation, fits best in securing microservices at the edge.

              Securing communication between Zuul and the microservice
    So far, you’ve used the API Gateway pattern to secure access to your microservice. This pattern ensures that no one who lacks valid credentials (a token) gets access to your microservice through the API gateway. But you also have to consider what happens if someone accesses the microservice directly, bypassing the API gateway layer. In this section, we discuss how to secure access to your microservice in such a case.
    3.4.1 Preventing access through the firewall

    First and foremost, you need to make sure that your microservice isn’t directly exposed to external clients, so you need to make sure that it sits behind your organization’s firewall. That way, no external clients get access to your microservices unless they come in via the API gateway (see figure 3.13).




    Figure 3.13 Direct access to the authorization server and microservice is prevented by the firewall, allowing only the API gateway to access them.


Securing the communication between the API gateway and microservices by using mutual TLS
To make sure that your microservice is secure from internal clients and accessible only via the API gateway, you need to build a mechanism in which the microservice rejects any requests coming from clients other than the API gateway. The standard way is to enable mTLS between the API gateway and the microservice. When you use mTLS, you get the microservice to verify the client that talks to it. If the microservice trusts the API gateway, the API gateway can route requests to the microservice.


You may think that you’re burdening the microservice with extra responsibilities by expecting it to verify the client through mTLS. But mTLS verification happens at the Transport layer of the microservice and doesn’t propagate up to the Application layer. Microservices developers don’t have to write any application logic to handle the client verification, which is done by the underlying Transport-layer implementation. Therefore, mTLS verification doesn’t affect the agility of developing the microservice itself and can be used safely without violating microservices principles.

If you’re still worried about performing certificate validation as part of your microservice, an approach to avoid that, using the Service Mesh pattern. With the Service Mesh pattern, a proxy, which runs along with your microservice (each microservice has its own proxy), intercepts all the requests and does the security validation. The certificate validation can be part of that as well.


Figure 3.14 Enabling mutual TLS at the microservice to prevent access by unintended parties. All the requests outside the firewall must be routed via the API gateway.


Summary

  • The API Gateway pattern is used to expose microservices to client applications as APIs.

  • The API gateway helps to expose microservices of different flavors by using a consistent and easy-to-understand interface to the consumers of these microservices.

  • We do not have to expose all microservices through the API gateway. Some microservices are consumed internally only, in which case they will not be exposed through the gateway to the outside world.

  • Protocols such as basic authentication and mutual TLS are not sufficient to secure APIs, and microservices are exposed to the outside world via APIs.

  • OAuth 2.0 is the de facto standard for securing APIs and microservices at the edge.

  • OAuth 2.0 is an extensible authorization framework, which has a wide array of grant types. Each grant type defines the protocol indicating how a client application would obtain an access token to access an API/microservice.

  • We need to choose the right OAuth 2.0 grant type for our client applications based on their security characteristics and trustworthiness.

  • An access token can be a reference token or a self-contained token (JWT). If it is a reference token, the gateway has to talk to the issuer (or the authorization server) always to validate it. For self-contained tokens, the gateway can perform the validation by verifying the token signature.

  • A self-contained access token has its own pitfalls, and one way to get around token revocation is to have short-lived JWTs for self-contained access tokens.

  • The communication between the gateway and the microservice can be protected with either firewall rules or mutual TLS--or a combination of both.

  • All samples in this chapter use HTTP (not HTTPS) endpoints to spare you from having to set up proper certificates and to make it possible for you to inspect messages being passed on the wire (network), if required. In production systems, we do not recommend using HTTP for any endpoint.

No comments:

Post a Comment