Securing Microservices in a Zero Trust Environment
The microservices architecture expands the attack surface with multiple microservices communicating with each other remotely over the network. It’s a common principle in security that the strength of a given system is only as strong as the strength of its weakest link. In a microservices architecture the number of links to be protected can grow from a few to thousands.
Many microservices deployments today, mostly worry about the edge security by exposing the microservices via APIs and protecting those with an API gateway at the edge. Once a request passes the API gateway, the communications among microservices assume a trusted network, and expose endless possibilities to an attacker gaining access to the network to exploit all valuable business assets exposed by the microservices.
In this blog we focus on securing service-to-service communications in a zero-trust environment.
What is a zero-trust environment?
As per John Kindervag, who is well-known as the creator of the zero trust model in 2010, trust is a human emotion that we have injected into the digital systems for no reason at all and people confuse all the time human trust and digital trust. A zero-trust environment is built to eliminate the trust between components in a digital system. When we apply this into a microservices deployment, a microservice should eliminate the trust with other components and the underneath network it interacts with or at least try to minimize.
Securing service-to-service communications
A security design for service-to-service communications worries about securing interactions among microservices, once a request from a client application passes through the security at the edge and enters into the microservices deployment. These interactions can happen over HTTP or gRPC synchronously or over a messaging protocol like Kafka asynchronously.
Irrespective of the communication protocol, in a service-to-service security design, we need to worry about authentication and authorization in service-to-service interactions and passing user context among microservices in cryptographically safe manner.
Authentication and authorization in service-to-service interactions
The most common way of implementing authentication for service-to-service interactions is to use mTLS. Following the zero-trust principle, each microservice must validate the requests it gets at the edge of the microservice itself, not at the edge of the network. Each microservice must validate the certificate of the calling microservice to see whether either the certificate itself or the issuer of the certificate is trusted.
Once the identity of the caller is established, the microservice itself has to perform authorization based on the authentication context and the access control policies to see whether the calling microservice is eligible to do what it wants to do. Typically, a proxy component deployed along with the microservice, which intercepts all the requests coming in and going out of a microservice does these checks. In a service mesh deployment, for example, the envoy proxy carries out these checks.
Passing user context among microservices in cryptographically safe manner
Typically an API gateway at the edge of the microservices deployment validates the user context corresponding to the calling application. The calling application can invoke an API just by being itself, or on-behalf of another user. In either case, the API gateway has to pass the user context to the upstream microservices in a cryptographically safe manner.
Typically, the best way to carry the user context in a cryptographically safe manner in a microservices deployment is to use a JWT. Each microservice at its edge will validate the JWT to make sure it is issued from an issuer it trusts. When one microservice talks to another microservice, the calling microservice can pass the same JWT or exchange it to a new JWT by talking to a security token service that the recipient microservice trusts, and pass the new JWT.
The recipient microservice can authorize the end user based on the claims the JWT carries. As in the case of service-to-service authentication/authorization, a proxy component deployed along with the microservice, which intercepts all the requests coming in and going out of a microservice does these checks.
The technology around securing service-to-service communications following zero trust security principles have evolved a lot in the last couple of years and keeps evolving. Kubernetes has become the de facto deployment for microservices and the service mesh implementations like Istio and Linkerd have increased their support for securing service-to-service communications with mTLS and JWT. Also open source projects like SPIFFE and OPA are becoming mainstream to address key concerns in securing microservices.
Prabath Siriwardena is an identity evangelist, an author, a blogger, and the Deputy CTO (Security) at WSO2 with more than 13 years of industry experience in designing and building critical Identity and Access Management infrastructure for global enterprises, including many Fortune 100/500 companies.
As a technology evangelist, Prabath has published eight books, including Microservices Security in Action (Manning) , OpenID Connect in Action (Manning), Advanced API Security (Apress) and Microservices for the Enterprise (Apress). He blogs on various topics from blockchain, PSD2, GDPR, IAM to microservices security. He also runs a YouTube channel.