This is an article from DZone’s 2022 Enterprise Application Security Trend Report.
According to a 2020 Gartner report, it is estimated that by 2023, 75 percent of cybersecurity incidents will result from inadequate management of identities and excessive privileges. To a large extent, this is attributable to the increased number of identities used by modern cloud infrastructures. Applications run as microservices in fully virtualized environments that consist of dynamically orchestrated clusters of multiple containers in the cloud.
The security requirements in such environments are significantly different compared to monolithic applications running on-premises. First, the concept of the perimeter does not exist in the cloud. Second, organizations are now handling thousands of dynamically created workloads and identities. Applying traditional IAM tools to manage the dynamic nature of these identities is not adequate. Using static, long-lived, and often excessive access permissions enables attackers to perform lateral movement.
To address these issues, a security model is needed that better satisfies today’s application security and identity requirements. Zero-trust security is a proactive security model that uses continuous verification and adaptive security controls to protect endpoints and access to applications as well as the data that flows between them. Zero trust replaces the outdated assumption that everything running inside an organization’s network can be implicitly trusted. This security model has proven to minimize the attack surface, offer threat protection against internal and external attackers, reduce the lateral movement of attackers, increase operational efficiency, and help support continuous compliance with regulations such as PCI-DSS and the White House’s 2021 Cybersecurity Executive Order.
Since its inception, zero trust has evolved and expanded, touching almost every corner of the enterprise. This article will provide an overview of how the zero-trust principles can be applied in a microservices environment and what security controls should be implemented on the back end.
Zero trust is primarily based on the concepts of “never trust, always verify” and “assume everything is hostile by default.” It is driven by three core principles: assume breach, verify explicitly, and the principle of least privilege.
Always assume that cyber attacks will happen, the security controls have been compromised, and the network has been infiltrated. This requires using redundant and layered security controls, constant monitoring, and collection of telemetry to detect anomalies and respond in real-time.
No network traffic, component, action, or user is inherently trusted within a zero-trust security model, regardless of location, source, or identity. Trust only to the extent that you verify the identity, authenticity, permissions, data classification, etc.
Principle of Least Privilege
Always grant the least number of privileges. Only give access for the time that it is needed and remove access when it is not needed anymore. Least privilege access is essential to reduce the attack surface, limit the “blast radius,” and minimize an attacker’s opportunity to move laterally within an environment in case of compromise.
Zero-Trust Security in a Microservices Environment
When a microservice is compromised, it may maliciously influence other services. By applying the principles of zero trust to a microservices environment, the trust between services, components, and networks is eliminated or minimized.
Identity and Access Management
Identity and access management is the backbone of zero trust, which requires strong authentication and authorization of end-user identities, services, functions, workloads, and devices. To enable authentication and authorization, we must first ensure that each workload is automatically assigned a cryptographically secure identity that is validated on every request. Importantly, ensure that there is an automated mechanism to reliably distribute, revoke in case of compromise, and frequently rotate the services’ certificates and secrets. Use a cloud-neutral identity for workloads, such as SPIFFE for authentication and OPA for unified authorization across the stack.
Secure Service-To-Service Communications
In zero trust, it is fundamental to treat the network as adversarial. Thus, all communication between services, APIs, and storage layers must be encrypted. The standard way of protecting data in transit is to use HTTPS and strict mTLS everywhere. Similarly, a strong authentication mechanism should be enforced across all microservices. It must be understood that not every service that can be authenticated should be authorized. Authorization must be done based on the authentication context and on access control policies, and it should be performed at the edge of each microservice — not at the network edge.
- Automatic certificate management
- Traffic interception
- Secure service-to-service communication without application code changes
- Micro-segmentation (via authorization policies)
This reduces the blast radius of an attack and prevents attackers from pivoting from one compromised service into other parts of the infrastructure. In a container orchestration environment, such as Kubernetes, define network policies for egress and ingress isolation at a granular level. Enforce zero trust for all traffic (east-west and north-south) by specifying network policies and service-to-service level RBAC policies that limit access per cluster and per source, following the need-to-know principle.
Secure Access to Resources
External entities must not access the microservices environment directly. Instead, use an API gateway as a single entry point to the microservices deployment. To pass the user context or the identity of the caller, implement a pattern, such as the phantom token pattern (API Security in Action, part 11.6.1) or the passport pattern. Validate the external access token and user context at the edge and generate a new short-lived token that represents the external entity identity and is cryptographically signed by the trusted issuer and propagated to back-end microservices. Ensure that the new token’s scope of access is as limited as the scope of the identity of the external entity.
Most importantly, assume that access tokens can be stolen and create access tokens with a short lifespan on a resource-by-resource basis. Use a service mesh to verify the validity of the access tokens at the microservice edge. In all cases, access to resources should be granted using fine-grained role-based access controls with the least privileges.
Figure 1: Data in-transit, data at-rest, and data in-use encryption
It is essential to ensure that all data is classified according to their secrecy and confidentiality. Create a data registry to know which microservice handles what data. Then, implement multiple layers of data encryption, depending on the data classification. Do not trust only the encryption of external components (including databases and messaging systems like Kafka). Use application-level encryption (ALE) to transfer personally identifiable information (PII) and highly confidential data between microservices. To mitigate the risk of unauthorized data modification, perform data integrity checksums throughout the data lifecycle.
Adopting an immutable infrastructure has become standard. Use Infrastructure as Code to provision components upfront and never change them after deployment. Do not trust the storage mediums (persistent or temporary) and do not store any sensitive data or secrets in an unencrypted form. All secrets, certificates, and API keys should be securely stored in access-controlled centralized key vaults.
Zero trust always assumes that the network is compromised. To contain a possible compromise and prevent lateral spreading through the rest of the network, implement network micro-segmentation, create software-defined perimeters in each segment, and place microservices in each segment according to their functionality, business domain, and data classification. Communication between segments should be well-defined and controlled through API gateways. Consider adopting a cell-based architecture for inter-segment communication.
Container and Cluster Security
Zero trust requires the explicit verification of container images, containers, and cluster nodes. Thus, use container images that are signed only from trusted issuers and registries. Allow images to be used only if they are scanned in the DevSecOps pipeline and have no vulnerabilities. To reduce the risk of privilege escalation, run the Docker daemon and all containers without root privileges. One standard way is to run Docker in rootless mode. Logically isolate high-risk applications and workloads in the same cluster for the least number of privileges.
Consider running security-sensitive microservices on confidential virtual machines in hardware-based trusted execution environments with encrypted memory. To reduce the risk of rogue or compromised nodes in the cluster, verify the integrity of nodes, VMs, and containers by running them on instances enabled with Secure Boot and Virtual Trusted Platform Module.
Also, by running containers in read-only mode, filesystem integrity is achieved and attackers are prevented from making modifications. Finally, we can reduce our trust for the runtime by adopting a RASP solution that inspects all code executed by the runtime and dynamically stops the execution of malicious code.
Figure 2: Zero-trust runtime via confidential computing and RASP
Image adapted from “Application enclave support with Intel SGX based confidential computing nodes on AKS,” Microsoft Azure Documentation
Implementing a zero-trust architecture is a critical defense-in-depth strategy and has become a mandatory security model in modern IT infrastructures. It is important to understand that implementing a zero-trust architecture does not mean zero security incidents. The goal is to continually layer security controls to increase the cost of attacks. As we introduce more friction into the cyber-attack kill chain, the attacker’s value proposition will be reduced, and potential attacks will be disrupted.
The key to a successful implementation of a zero-trust architecture is to follow the guidance of whitepapers such as NIST’s “Planning for a Zero Trust Architecture” and the U.S. Office of Management and Budget’s “Moving the U.S. Government Towards Zero Trust Cybersecurity Principles.”
In this article, we provided an overview of how to apply the core principles of the zero-trust model in a microservices environment, and we examined the critical areas and the zero-trust security goals of microservices that need to be achieved. The highly distributed and heterogeneous nature of a microservice deployment and its complex communication patterns has increased the number of different components and the volume of data that is exposed on the network. This provides a broader attack surface compared to a traditional deployment of a monolithic application.
Because the security of a system is as good as its weakest link, applying the zero-trust core principles to proactively secure all layers and components of a microservices deployment is fundamental for a modern, reliable, and mature cybersecurity strategy. With a proper zero-trust strategy for microservices, the risk of compromised clusters, lateral movement, and data breaches in most cases can be eliminated.
Zero trust is a necessary evolution to security; however, its implementation should not be a destination. It is a continuous journey and an organization-wide commitment. Since its inception, zero trust has become a widely deployed security model and a business-critical cybersecurity priority. Microsoft’s 2021 Zero Trust Adoption Report confirms that point on page 11, indicating that 76 percent of organizations have started adopting a zero-trust strategy. The industry is rapidly adopting zero trust across the whole infrastructure and not just on end-user access.
This is an article from DZone’s 2022 Enterprise Application Security Trend Report.