1. Secure API Gateways and Perimeter Defense
2. Secure Network Communications
3. Authentication and Authorization
5. Rate Limiting and DDoS Protection
Today, microservices architecture is popular, accounting for the infrastructure of 85% of enterprise companies. Microservices are modular, with each service (e.g., authentication, billing, data access) developed and scaled independently. However, microservices architecture also creates a challenge; every node is a possible entry point for an exploit. Accordingly, companies building with microservices need to take robust measures to protect themselves against attacks.
As a baseline, each microservice should be treated with the same security afforded to a monolithic stack. Otherwise, a microservices infrastructure is only as secure as the weakest service. The network that microservices transact across—while typically private—should also be treated with the same zero trust as the common internet. This attitude mitigates the damage of an attack if a microservice becomes compromised.
Most of these practices follow the principle of least privilege, where a client (e.g., a service or user) is granted only the necessary permissions. Through that framing, let’s discuss these practices in depth.
Because a microservices architecture typically exposes multiple endpoints, it’s wise to establish a strong first line of defense. You can achieve this by implementing secure API gateways—which receive traffic through well-monitored and protected entry points. Companies often consolidate access with a single API gateway.
Think of a gateway as airport security. It checks IDs (authentication), determines who gets access to VIP areas (authorization), and keeps troublemakers (malicious traffic) from entering in the first place. Without this strong, single entry point, you’d need extreme security at every gate in the airport. Instead, with API gateways, you get strong protection where you need it most.
Consider using a proven solution, like Amazon API Gateway, when implementing an API gateway. Solutions like this offer built-in security features designed specifically for microservices architectures. Additionally, you can deploy a web application firewall (WAF) to detect and block common attack patterns before they even reach the API gateway.
Once you’ve secured your gateway, it’s easy to assume that communication between services is secure. After all, the network is strictly private. This is a misconception. Good security should not only protect against attacks but also limit them. By treating traffic between microservice nodes with the same zero trust that we afford Internet transactions, you’ll create a network that’s robust against a network-wide breach.
Notably, traffic between nodes can be subject to even stronger security than traffic across the Internet. Servers traditionally use TLS (Transport Layer Security) to communicate with client devices, where the client can ensure that only the server can decrypt transmitted data. However, with microservices architecture, engineers have access to both nodes.
In this case, you should use mutual TLS (mTLS), where both nodes must verify each other’s identity through trusted credential certificates before they can exchange data.
mTLS reduces reliance on the total system’s security perimeter. It combats man-in-the-middle (MITM) attacks, where an attacker intercepts data between nodes.
Beyond the network layer, you should protect communication between nodes (and access to nodes) with authentication and authorization. While often conflated, authentication and authorization are distinct concepts. Authentication is a matter of identity, e.g., “Who are you?”. Authorization is a measure of permissions, e.g., “Are you allowed to do this?”.
Robust microservices architecture could employ various authentication and authorization measures. Common frameworks include:
Unfortunately, no single model is sufficient for real-world authorization policies. For robust security, you’ll end up with elements of various models. For example, authorization in multi-server applications is often determined by relationships between the resources managed by services. ReBAC alone isn’t sufficient; sometimes, siloed attributes are better at defining security for an instance. Authorization patterns for microservices are generally complex, and delivering strong security is a matter of mixing models to fit your application’s features.
Irrespective of authorization and authentication patterns, every service (and node) should have a separate identity. For example, if an attacker breaches a service with a database account that only has access to relevant data, the exploit can levy limited damage.
The downside of a centralized authorization service is traffic: It can be burdened by thousands (or millions) of authorization requests for the entire backend system. To combat this, you can implement JSON Web Tokens (or JWT Tokens) to authenticate systems at scale without dispatching an authorization query for each request. Services fetch a JWT from a token service once, outlining the user’s authorization. The JWT will exclusively grant access without making subsequent round-trip calls to the service. The JWT is verified with JSON Web Key Sets (JWKS), issued by the same authorization service.
JWTs reduce traffic, minimizing round trips to the server and limiting load. They also minimize the latency of requests by keeping communication between services. However, there are challenges, too—JWTs might carry a lot of authorization data depending on granted permissions. Additionally, JWTs must be cancelable if permissions change, or companies need to tolerate some misaligned permissions until a JWT expires.
To facilitate JWTs and server-to-server communication, you should implement OAuth 2.0. OAuth 2.0 provides an out-of-the-box system for implementing authentication, supporting JWTs, JWKS, and attribute-based authorization. When your authorization needs outgrow your JWTs, you can use an external provider like Oso that provides an authorization language for modeling complex access policies.
Any service that’s publicly exposed could potentially face a barrage of requests. This might be due to a legitimate usage spike or a malicious distributed denial-of-service (DDoS) attack. Either way, the result is the same: Your services can’t keep up with the requests, meaning your users can’t access your application. This hazard is multiplied with microservices architecture if multiple nodes are publicly facing.
To protect against this, nodes should implement DDoS protection, where a service monitors traffic and identifies IP addresses that might be participating in a DDoS attack. Additionally, in systems where an API key provides access, keys can be rate-limited to avoid abuse. This protects against malicious and innocuous sources of traffic spikes.
Maintaining good microservices security also requires assuming that a vulnerability exists. Because of this, it’s important to heavily monitor systems.
Most microservices architecture will use a service mesh to register services and make them discoverable. Common providers include Istio and Linkerd.
A service mesh uses sidecar proxy services to handle routing between microservices. This positions it as a fantastic observability candidate: the control mesh can study traffic to flag discrepancies.
You can also implement these meshes to rate-limit traffic between microservices, serving as another measure to minimize damage in the case of an attack.
Microservices often have to use secrets (e.g., API keys) to access external services—or even internal services within the private network. By definition, these secrets are sensitive data that should never be hard-coded. To implement secrets robustly, you should use a secrets management system (e.g., Doppler, HashiCorp Vault, AWS Secrets Manager) to avoid hard-coding secrets.
You should also routinely rotate secrets to minimize the impact of an undetected theft of keys. This ensures that even if your secrets are compromised, the intruder can only access key systems or sensitive data for a set duration. The more often you rotate your keys, the shorter that duration will be.
Finally, you should create different secrets for different services. When possible, these keys should be scoped to the minimum set of required permissions, reinforcing the principle of least privilege. Additionally, if a key is breached, you can cut off access by deleting the key without breaking other services.
Microservices architecture should always include logs with high cardinality to ensure there’s a record system in the case of an attack. And, because microservices talk to each other, a single request should have a unique ID to generate a trace: a child-parent hierarchy of transactions as they percolate through the entire microservices system. Each service should identify itself in the trace so you can aggregate traces on a per-service basis.
A common open-source library for implementing this tracing process is OpenTelemetry, with events dispatched to an analysis tool (e.g., HyperDX, Datadog). Enterprise-grade solutions like Splunk combine traffic across networks, devices, nodes, and more to identify attacks. These tools make identifying anomalies easier through visualizations.
Microservices are typically run within containers (e.g., Docker) and managed by container orchestrators (e.g., Kubernetes). These services are only as secure as the containers they’re embedded within.
To protect your microservices against a container exploit, ensure your containers and orchestrators are up to date with the latest versions. Also, make sure that your containers spawned from trusted base images and that your services run with non-root user permissions. This will help you avoid a host-wide exploit.
Microservices architecture security is a layered and modular process. You should reinforce security at the system, service, and container level. Additionally, you should protect every ingress and egress from breach. Generally speaking, strong microservices security requires consistent application of the principle of least privilege and achievement of zero trust between nodes.
With comprehensive measures, you can minimize the likelihood of an attack and reduce the damage if an attack happens. You will also improve your security posture, earn the trust of your customers, and enable your system to scale without the headache.
How do I implement security in microservices?
You should keep two core principles in mind:
Zero-trust policy: Do not assume that any device or user is inherently trustworthy, even within your own systems
Principle of least privilege: Services should have the minimum access necessary to complete their task.
You also want to secure every access point and communication between nodes. Finally, it’s important to use strong authentication and authorization for every request, implement an API gateway, encrypt data, and manage secrets securely.
What are the security challenges of a microservices architecture?
Unlike monolith architecture, where a single service needs to be secured, microservices architecture multiplies the attack surface, as every service is a potential attack vector. Communications between services are also vulnerable. Accordingly, you need to implement strong security measures such as API gateways, authorization, authentication, service mesh observability, secrets storage, data access, etc.
How can I implement authorization within microservices?
Several popular access frameworks exist, such as RBAC, ABAC, and ReBAC. Large, complex applications require a mix of frameworks to achieve total protection. Using identity providers like OAuth 2.0 and authorization services like Oso will help you lay a successful security foundation without the headache.