Posted on: 16 04 2024.

The Basics of Microservices Security

This blog aims to explain microservices and the ways to use them securely. Various security threats are growing exponentially on an hourly basis and to protect our applications we are offering insights into those threats by highlighting the importance of best practices for microservices security and ways to defend against such threats.

What are Microservices?

Microservices, or microservices architecture, is a cloud-native architectural approach in which a single application is composed of many loosely coupled and independently deployable smaller components (services). Those services communicate with each other typically through a combination of representational state transfer (REST) APIs, event streaming, and message brokers. The greatest value of the microservices revolves around their architectural definitions and characteristics which also provide business benefits (code can be updated more easily e.g. new functionalities/features can be added without touching the entire application, possible use of different stacks and different languages for different components, components can be scaled independently and that way reducing the cost of scaling up the entire application because one feature is experiencing too much load).

Because of microservice’s scalability and agility, many organizations are migrating from traditional monolithic (tightly coupled) architecture.

Why is Microservices Security Important?

Due to the complexity of the microservice architecture, it stands to common sense that every module separately must be treated as a potential security risk. To minimize that risk, each service must implement an appropriate security policy.

Prevention of security breaches and attack risk mitigation is essential for every company that uses an application that is completely or partially based on microservice architecture. This way data breaches will be prevented, leading to an increase in the company’s reputation while boosting customer’s trust.

Common Threats to Microservices Security

Injection Attacks (SQL injection, NoSQL injection)

Over the years, we have seen traditional web application injection attacks. Form fields would get used to load in specific injection attacks like SQL injection to manipulate SQL databases, but the injection attacks are slowly moving over to API Injection attacks as well. API injection (NoSQL injection) is an attack that is executed in part of the application which parses, evaluates, or concatenates the attacker string into an API call.

Microservices APIs are susceptible to injection attacks as well, given that for many of the API endpoints, you can, for instance, submit query string parameters, specific payload in the form of JSON, or even, malicious payloads that could very well lead to issues when sent. Therefore, during API development, ensure you apply proper data validation, handle special characters properly in the right place, and disallow special characters in places where they are unnecessary. If API interfaces with a SQL or even NoSQL database underneath it, make sure that attackers cannot send known SQL injection attacks as part of the API endpoint, parameters, or payload by properly sanitizing this data. Also inspecting the request in headers to make sure they do not include elements for a harmful injection attack is something that helps attack prevention.

Broken Authentication and Authorization

Broken authentication is an exploit of an authentication mechanism in which attackers aim for complete or partial control over other people’s accounts in the system to perform sensitive actions while impersonating them. The authentication mechanism is an easy target for attackers since it is exposed to everyone. Although more advanced technical skills may be required to exploit some authentication issues, exploitation tools are available. Therefore, authentication endpoints and flows are assets that need to be protected.

Broken authorization, also known as broken access control or privilege escalation is a hypernym for the wide specter of flows that rise due to the poorly implemented authorization checks to designate user access privileges. Vulnerabilities like this may affect any application architecture reliant on authorization controls. In a successful attack, the perpetrator may be able to access, modify, remove unauthorized content, or even get full control of the host system.

Insecure Deserialization

Developing a web application sometimes requires you to transfer an object. In simple terms, the object contains a bunch of variables that contain data. However, an object cannot be transferred directly, so it must be converted into something else first.

This conversion is called serialization. Serialization is the process of taking an object and translating it into plaintext. This plaintext can then be encrypted or signed, as well as simply used the way it is. The reverse process is called deserialization when the plaintext is converted back to an object.

In the simplest use case, it is possible to just JSON-encode all the data in the object and use it as it is. Even when developers know that user input is not to be trusted, serialized objects are seen as something different, and the security mindset is forgotten. In these scenarios, insecure deserialization is just another way of sending the payload which then affects an underlying vulnerability.

In many languages, there are native implementations of serialization that are more flexible. It might be possible to overwrite existing variables or define what should be done if it is not possible to deserialize. In the case of compiled source code, it might be possible for an attacker to replace the code that will be executed on the server and thus achieve remote code execution.

Insecure deserialization got on the OWASP top 10 based on survey data, not quantifiable data. As such, it is hard to say just how common it is.

The impact depends on how the serialized object is used. Remote code execution or remote command execution, which would be considered the most critical, is absolutely a possibility given the circumstances. In many cases insecure deserialization is just a way of transferring the payload, which then affects another vulnerability, making it hard to classify the general impact.

Data Exposure and Information Leakage

Data transfer and exchange of information through APIs are essential for each microservice architecture. Since these transfers often include private or sensitive data (potential data leaks), either accidentally or through malicious attacks, they provide a high-security risk. When an application, via API response, returns more information than necessary for a user to perform a specific action, an attacker can take advantage of it to gain sensitive information.

While there are different techniques, like using data encryption or authentication protocols to secure the data exchange, only a few strategies are known to reduce the damage when an actual data breach happens. According to OWASP, excessive data exposure is consistently in the top three of the top ten API security threats.

Denial-of-Service (DoS) Attacks

Denial of Service (DoS) attacks are an important and challenging security threat. Despite the existing defense mechanisms, attackers manage to turn applications or devices unable to deliver their services to legitimate users. If the attack is successful it leads to target resource exhaustion.

Two main types of DoS attacks at the application layer are high and low-volume attacks. In high-volume attacks, regular POST and GET requests are used to look like regular users but requests are sent in high frequency. In a low-volume attack, those requests are sent slowly meaning that the attacker is sending new requests without waiting for previous ones to finish (the server will not have open sockets to respond). Both types of DoS attacks mentioned previously lead to resource exhaustion.

Best Practices for Microservices Security

Securing microservice APIs to prevent various scenarios of malicious intentions by attackers is crucial. Proper mechanisms for access control, TLS, authentication, and authorization must be set in place. Vulnerability checks and assessments need to be performed regularly. Regarding testing, we need to ensure that penetration testing is also part of the quality assurance process to detect potential security leaks. Regarding users, all user identities and control access must be implemented according to the identity access management (IAM). Each service must have fine-grained access control and enforce the principle of the least privilege.

Implement Role-Based Access Control (RBAC)

RBAC – Role-based access control (RBAC) is a method of regulating access to computer or network resources based on the roles of individual users within an enterprise. In this context, access is the ability of an individual user to perform a specific task, such as view, create, or modify a file.

To use RBAC for role management, a detailed analysis must be performed to determine which user needs access to specific resources. As a result of such analysis, we can group users into roles based on common responsibilities. Users can have one or more roles assigned to them, in this case, permissions are the union of the role assignments. The best practice here is to give the user only the minimum required roles so that they can perform their tasks (which is one of the main reasons for analysis).

For example, if you were using RBAC to control access for an application, you could give specific managers a role that allows them to update employee details, while other employees would be able to view only their details.

Use Transport Layer Security (TLS) for Communication

TLS is a cryptographic protocol that provides end-to-end security for data sent between applications over the Internet. It is mostly familiar to users through its use in secure web browsing, and in particular, the padlock icon that appears in web browsers when a secure session is established. However, it can and indeed should also be used for other applications such as e-mail, file transfers, video/audioconferencing, instant messaging, and voice-over-IP, as well as Internet services such as DNS and NTP.

TLS evolved from Secure Socket Layers (SSL), originally developed by Netscape Communications Corporation in 1994 to secure web sessions. SSL 1.0 was never officially released, whilst SSL 2.0 was quickly replaced by SSL 3.0 on which TLS is based.

There are three main components to what the TLS protocol accomplishes:

  • Encryption: hides the data being transferred from third parties.
  • Authentication: ensures that the parties exchanging information are who they claim to be.
  • Integrity: verifies that the data has not been forged or tampered with.

Regarding TLS there is not much difference between monolithic architecture and microservices architecture. TLS provides safeguards for all data transmitted. We just need to ensure that mTLS (mutual client-server TLS) is enabled between services as it is best practice.

Implement OAuth 2.0 for Authorization and Authentication

OAuth 2 (open authorization) is a protocol that is used to manage authorization over the network of web-enabled microservice APIs. Although OAuth is an authorization protocol it provides mechanisms for user authentication. An OAuth 2.0 flow has the following roles:

  • Resource Owner: Entity that can grant access to a protected resource. Typically, this is the end-user.
  • Resource Server: Server hosting the protected resources. This is the API you want to access.
  • Client: Application requesting access to a protected resource on behalf of the Resource Owner.
  • Authorization Server: Server that authenticates the Resource Owner and issues access tokens after getting proper authorization.

In the authorization/authentication workflow application requests authorization to access service resources from the user and if the user authorizes the request, the application receives an authorization granted. The application then requests an access token from the authorization server (API) by presenting authentication of its own identity, and the authorization granted. If the application identity is authenticated and the authorization grant is valid, the authorization server (API) issues an access token to the application. With this authorization completed, then the application requests the resource from the resource server (API) and presents the access token for authentication and if the access token is valid, the resource server (API) serves the resource to the application.

Implement JWT for Stateless Authentication

JSON Web Token (JWT) is an open standard (RFC 7519), it is used for secure data transfer between parties as a JSON object. JWT structure contains 3 main parts, those are header, payload, and signature.

The header contains two parts, token type (JWT) and information on the signing algorithm being used.

The payload contains claims which represent statements about the user and other data. Claims can be registered, public or private.

The signature is created by encoding the header and payload using Base64url encoding (RFC 4648). A signature created that way is used to verify who is the sender and that the payload is not altered in any way.

Stateless authentication is enabled using stateless tokens (JWT). The authentication server generates these tokens, which are self-contained and carry all necessary details about the session and the user. To avoid the backend from having to keep track of any session ID and session data, the client stores this token and includes it in subsequent requests.

Implement API Gateways for Access Control

API Gateway in microservice architecture presents a single-entry point for external communication. On an architectural level, its place is in front of the microservices, and it decouples the complexity of the application from its clients.

API Gateway is responsible for security policy enforcement, routing, and composition. It also acts as a security barrier between the client and microservices in the backend, ensuring that sensitive data is protected, and only authorized clients can access the microservices.

These are the best practices related to the API Gateway security:

  • Centralized authentication: APIs provide access to sensitive and restricted data, so strong authentication is essential. Centralizing authentication at the gateway removes the risk of each microservice trying to securely implement what is a complex task. It also makes code easier to write, read, and maintain. Better still is using a centralized authentication server to manage the authentication and token issuance processes.
  • Traffic encryption: Implementing HTTPS for all API traffic is best done at the API gateway level and not on individual microservices. This ensures consistency and avoids the need for repetitive configuration across multiple systems, preventing potential mistakes.
  • Input Validation and Data Sanitization: Validating API requests before the gateway forwards them to back-end services, halts erroneous requests and mitigates the risk of injection attacks. Also, it standardizes error responses to prevent exposing sensitive information in the error message.
  • Rate Limiting and Throttling: By controlling the number of API requests, a gateway can prevent excessive malicious or genuine API requests from overwhelming services. This prevents DDoS attacks from taking services down and limiting cascading failures in an overloaded system.
  • Distributed Tracing and Monitoring: API gateways can generate execution and access logs and then send them for further analysis and the detection of potential threats and problems. The visibility and metrics the gateway can provide into API usage help solve client access and request issues, as well as spot if deprecated APIs are still in use.

Regularly Update and Patch Dependencies

Regular updates and patches for microservices security are extremely important in the prevention of security breaches. Applying those updates must be treated precisely and with the utmost care. During updates, services must be available and without significant performance drop, to achieve that we need to follow a set of predefined rules and strategies listed below:

  • Identify which services will be affected by the latest security updates, and how they communicate with other services and external systems. Make prioritization based on the criticality of the security issue. Review which libraries, frameworks, and platforms your services use, and the security standards and protocols they follow.
  • Create a backup plan and rollback strategy.
  • Implement automated vulnerability scans, patching, functionality testing, monitoring, and security policy enforcement.
  • For the deployment of microservices use zero downtime techniques.
  • Enforce zero trust privilege for each service affected by the security update to prevent potential security breaches during the patching window.
  • Monitor and audit your microservices for any security issues or incidents and respond promptly and appropriately.

Consider Implementing Zero-Trust Architecture

Zero-Trust Architecture (ZTA) is based on the concept “Never trust, always verify” which means that no connection can be trusted or previously authenticated user/account. In traditional network security, external connections were never trusted but internal connections (connections that reside within the corporate network) were mostly trusted by default. The same goes for the users, during authentication user is challenged to prove his identity only once, and afterward, it’s trusted by default. Therefore, if we classify connections and users as entities, we can then say that in traditional network security, only external entities were never trusted, which is the opposite of internal entities. In comparison to the traditional approach in zero-trust architecture, there is no trusted entity, and every component is evaluated all the time (evaluation of the components depends on the specifics of their performed or requested action).

According to the zero-trust architectural guide, all zero-trust solutions must be designed to follow the principles mentioned below:

  • Any access to resources should be governed by company policies, which should consider multiple factors including the user, operational attributes such as IP address and operating system, work schedules, and locations.
  • Access to corporate resources or networks must be on a per-request basis and must require secure user authentication.
  • Authentication of a user or device should not automatically provide access to other resources.
  • All communications with or between corporate resources and networks must be encrypted and authenticated to provide secure access. Systems must apply the appropriate security level depending on the user’s context, for example, whether a request comes from within the network or a remote access point.
  • All devices and data must be defined as corporate resources and secured using zero-trust principles. This includes servers, workstations, mobile devices, and any device with access to corporate networks or data.

Although zero-trust architecture is one of the best models it comes with challenges of its own when it comes to actual implementation. Implementation of this model can be hard when it comes to hybrid or legacy application architectures, and because of the need for extensive setup and system adjustments, it can become potentially expensive also. However, the fortification of corporate cybersecurity outweighs the difficulties imposed with implementation.

Implement Container Security Best Practices

Docker is the most popular containerization technology. When used correctly, it can enhance security compared to running applications directly on the host system. However, certain misconfigurations can reduce security levels or introduce new vulnerabilities. To avoid those misconfigurations following best practices rules will help reduce security threats:

  • Regular updates of host and docker.
  • Do not expose the docker daemon socket.
  • Configure the container to use unprivileged users to prevent privilege escalation attacks.
  • Grant only necessary capabilities to docker needed by the container (do not use default capabilities and never grant all the with –privileged flag).
  • Prevent in-container privilege escalation (always run docker with –security-opt=no-new-privileges flag).
  • Be mindful of inter-container connectivity (define specific network configuration using granular control).
  • Use security modules (SELinux, Seccomp, AppArmor, etc.) depending on OS.
  • Limit resources (RAM, CPU, file descriptors, processes, restarts).
  • Set the filesystem and volumes to read-only.
  • Integrate container scanning tools into the CI/CD pipeline.
  • Keep Docker daemon logging level at info.
  • Run Docker in rootless mode.
  • Utilize docker secrets for sensitive data management.
  • Enhance supply chain security (trusted registry, image signing, secure deployment, SBOM generation, documenting the origin and history of container images to ensure traceability and integrity).

Conclusion

With microservices architecture usage exponentially increasing over the years, we can safely say that this approach has become the unofficial standard for cloud-native application development, and as such it comes with its solutions for cloud security which are constantly evolving and adapting as new threats emerge. Those tools are extensively tested and should be used during the implementation of the microservices hence they will greatly improve the speed of the implementation itself and provide security and general stability of microservices. Regarding microservices security itself, it all boils down to understanding the importance and processes behind the mentioned best practices which are a result of accumulated knowledge acquired over the years in real use case examples. Developer culture plays a very important role here meaning that developers should not only be aware of a proper way of doing things but acknowledge them and incorporate them into their implementations which will gradually become standard during development (zero-trust mindset). To further enhance your team’s adoption of these best practices and boost your microservices architecture’s security and efficiency, explore our services offering today.