What is AuthZ?
Authentication (also known as AuthN) and Authorization (also known as AuthZ) are intricate and multifaceted concepts often overlooked or underestimated in their complexity. While they may start off as specific implementations within individual applications, as a system scales and evolves, they can pose significant challenges. This necessitates development teams to navigate the intricacies of security protocols and ensure the secure management of identities.
When it comes to abstracting these authentication and authorization mechanisms within a broader platform, a host of additional considerations arise. Beyond the obvious technical hurdles of observability and scalability to accommodate all application traffic, it becomes necessary to carefully evaluate the pros and cons of each approach.
As a continuation of our PlatformCon2023 talk, this article provides an in-depth exploration of authentication and authorization approaches, along with potential solutions. We will examine different paths that can be taken, discuss trade-offs inherent in each approach, and analyze how they can impact overall system security and functionality. By gaining a comprehensive understanding of these concepts, developers and stakeholders can make informed decisions to design robust and efficient authentication and authorization frameworks within their platforms.
Concepts
Authentication is the process of identifying the entity interacting with the system, while authorization is the mechanism to determine whether access is permitted or not. To ensure the security of your application, it’s crucial to implement both concepts effectively.
To illustrate this, consider an endpoint in your application called /payments (using the POST verb). This endpoint should only be accessed by providing proper authentication credentials, such as a Bearer Token, Access Token, ID Token, or a self-signed JWT. It should not allow unidentified traffic (which could be possible in an unauthenticated API, for example). Furthermore, only users with a specific role should be granted access. This role can be obtained through a documentation submission and approval process or by following other appropriate procedures.
In this scenario, the identification is achieved through the token, which helps identify the user context making the request. Authorization is then performed by validating the user's role to determine if they possess the necessary permissions to execute the operation.
If the API allows access without these required headers or permits users without the appropriate role to perform the operation, it introduces a significant security vulnerability known as Broken Access Control, which, in the last edition of OWASP, became the biggest risk identified/reported in the applications.
OWASP Top ten ranking
Approaches for this problem
Continuing with our example, there are various possible approaches and trade-offs to consider. If the company has a single monolithic application, authentication and authorization could be implemented at the entry point in a straightforward manner. This wouldn't pose a problem and wouldn't have significant security implications. However, this scenario may not apply to environments that have a platform to assist them.
In a scenario where there are multiple microservices, one option is to create a library and distribute it for application usage. This approach helps maintain standardized control across applications and allows for tracking which applications are using it.
A middleware example that intercepts requests and validates them, written in Go
However, there are some potential drawbacks to this approach:
- Difficult to maintain if the platform uses multiple programming languages: Keeping all the libraries up to date becomes challenging, as each language-specific library needs to be maintained.
- Difficulty coordinating updates with teams: Each application using the library would need to be updated individually, which can lead to potential issues or breakages.
- Incorrect implementation: It's possible that an application may have the library installed but is not calling it in the correct location (e.g., performing validation after performing an action). This can result in an incorrect implementation of authentication and authorization.
- Lack of a single enforcement point for policies: Distributing the library across multiple applications means there is no centralized point to enforce policies consistently.
To overcome these challenges, alternative solutions, such as using API gateways or some proxy, can be explored to provide centralized authentication and authorization enforcement. This is regardless of the underlying technologies or programming languages used in the microservices architecture.
In the approach of validating these two aspects within a bus or gateway, we can address some of the previously mentioned points. However, we must be cautious about introducing a single point of failure (SPOF). This requires ensuring that the component acting as the gateway has high availability and low response times.
To mitigate the risks associated with a SPOF, it’s crucial to design the authentication and authorization gateway with redundancy and fault-tolerant measures. This can involve implementing load balancing, clustering, or deploying multiple instances of the gateway to ensure high availability. By distributing the workload and having failover mechanisms in place, the system can continue to function even if one instance or component becomes unavailable.
Additionally, optimizing the performance of the gateway is essential to maintain low response times. This can involve leveraging caching mechanisms, optimizing code execution, and utilizing efficient algorithms to minimize processing overhead. The goal is to ensure the authentication and authorization process does not introduce significant latency or become a bottleneck in the overall system performance.
By carefully considering the architecture, redundancy, fault tolerance, and performance optimization, it’s possible to mitigate the risks associated with introducing a SPOF. This can be done while maintaining the necessary high availability and low response times required for an effective authentication and authorization gateway.
Become a platform
To incorporate these concepts into the Internal Developer Platform, such as Fury in the case of Mercado Libre, we can aggregate configurations based on the type of traffic for each application (anonymous or non-anonymous). Additionally, we can create simpler rules based on endpoints (using regex to identify patterns, for example), HTTP verbs, and the required role to access those endpoints.
For more complex scenarios that require fine-grained controls, we can employ rules based on REGO. REGO allows for structured rule writing and enables validation not only based on roles but also on all attributes received in the headers of the API call. This approach enables the combination of rules based on IP, user data from headers, user-agent, and other relevant factors.
By leveraging these capabilities, the Internal Developer Platform can provide flexible and customizable authorization mechanisms. It allows for the implementation of both simple rules based on predefined conditions and advanced rule sets using REGO to evaluate multiple attributes and conditions. This ensures granular control over access rights and enables comprehensive and dynamic authorization policies based on a variety of factors, such as user roles, IP addresses, header data, and user-agent information.
Overall, the combination of predefined configurations and flexible rule-based authorization mechanisms empowers the Internal Developer Platform to provide robust and adaptable access control, meeting the diverse needs of applications within the ecosystem.
By implementing these approaches, we can achieve the following benefits:
- Centralized security metrics: Centralized system for monitoring and analyzing security metrics related to authentication and authorization. This enables the identification of potential security risks and allows for proactive measures to be taken.
- External and monitored rules: Creation of rules outside of individual applications, providing a centralized and standardized approach to security. These rules can be easily monitored, updated, and enforced, ensuring consistent security practices across the platform.
- Enforcement point for security rules: Enforcement point for security rules, ensuring that all requests pass through the authentication and authorization mechanisms before accessing protected resources. This helps prevent unauthorized access and strengthens the overall security posture of the system.
- Independent rule changes (hot deploy): With the ecosystem managing authentication and authorization rules separately from the application code, rule changes can be made without requiring code modifications or deployments. This enhances agility and allows for faster adaptation to changing security requirements.
- Mitigation of token leaks: Using an agnostic token after the authentication gateway, instead of the actual token itself, helps mitigate the risk of token leaks. This approach adds an additional layer of security, as sensitive tokens are not exposed beyond the authentication gateway, reducing the potential impact of token compromise.
Overall, these benefits contribute to improved security, streamlined management of authentication and authorization rules, and enhanced flexibility in adapting to evolving security needs within the Internal Developer Platform ecosystem.
Final Takeaways
RBAC (Role-Based Access Control) is not sufficient in many cases. Roles alone may address simpler use cases, but there are scenarios where you need access to additional data and relationships to extend authorization rules and cover other use cases. This helps mitigate other vulnerabilities that may exist.
Resilience and redundancy are crucial for this component and should be globally distributed and consistent. It’s likely that the component requires the highest Service Level Objective (SLO) within your architecture. Ensuring high availability and fault tolerance is essential to minimize downtime and ensure uninterrupted authentication and authorization services.
The concept of AuthZ on an Internal Developer Platform can be complex, so it is important to model and abstract some of the complexities to make it easy for the development team to effectively adopt and utilize the Internal Developer Platform. Providing clear documentation, easy-to-use interfaces, and comprehensive support can aid in the adoption process.
Following the principle of least privilege is important. The Internal Developer Platform should empower applications to configure access rights with precision, allowing only the necessary roles and rules to be assigned. This avoids overly broad permissions and reduces the attack surface. The Internal Developer Platform should also provide metrics and insights to help monitor and enforce the principle of least privilege, ensuring that access permissions are aligned with actual requirements.
By considering these factors, the Internal Developer Platform can provide a robust and flexible authorization framework while simplifying its adoption and usage for development teams. It supports fine-grained access control, resilience, and the principle of least privilege, contributing to a more secure and manageable system.