Uber’s infrastructure operates on thousands of microservices, each processing authorization decisions millions of times daily. This encompasses every API call, database query, and message published to Kafka. Crucially, these decisions must occur within microseconds to ensure an optimal user experience.
Traditional access control mechanisms proved inadequate for such complexity. For example, policies might dictate that “service A can call service B” or “employees in the admin group can access this database.” While effective for smaller systems, these rules become insufficient when granular control is required. Consider scenarios necessitating access restrictions based on user location, time of day, or intricate data relationships.
Consequently, Uber sought an enhanced methodology. The engineering team developed Charter, an attribute-based access control (ABAC) system designed to evaluate complex conditions against attributes dynamically retrieved from diverse sources during runtime.
To comprehend attribute-based access control (ABAC) at Uber, it is essential to first grasp the company’s approach to authorization. Every access request is conceptualized as a fundamental query:
Can an Actor perform an Action on a Resource in a given Context?
Each constituent of this statement warrants further examination:
An Actor represents the entity initiating the request. Within Uber’s ecosystem, this can be an employee, a customer, or another microservice. The SPIFFE format is employed by Uber for actor identification. For instance, an employee might be identified as spiffe://personnel.upki.ca/eid/123456, where 123456 signifies their employee ID. A microservice operating in a production environment would be designated as spiffe://prod.upki.ca/workload/service-foo/production.
An Action delineates the desired operation by the actor. Common actions include create, read, update, and delete, frequently abbreviated as CRUD. Services also possess the capability to define custom actions, such as invoke for API calls, subscribe for message queues, or publish for event streams.
A Resource refers to the object being accessed. Uber utilizes UON (Uber Object Name) to represent resources, which adheres to a URI-style format exemplified by uon://service-name/environment/resource-type/identifier. For example, a specific database table could be uon://orders.mysql.storage/production/table/orders.
The host segment of the UON is designated as the policy domain. This serves as a namespace, facilitating the organization of related policies and configurations.
As previously indicated, Uber developed Charter, a centralized service, to oversee all authorization policies. Charter functions as a comprehensive policy repository where administrators define access permissions. This centralized strategy presents notable benefits compared to individual services implementing their distinct authorization logic.
See the diagram below:

Policies configured within Charter are disseminated to individual services. Each service incorporates authfx, a local library responsible for evaluating these distributed policies.
The architectural flow operates as follows:
authfx library to assess policies for incoming requests.The most straightforward policy configuration at Uber establishes connections between actors and resources via defined actions.

A typical basic policy, when expressed in YAML format, might appear as:
This policy signifies: “Allow service-bar to invoke method1 of service-foo.” Another illustration demonstrates how access can be granted to employees:
This policy translates to: “Allow employees in the querybuilder-development group to read and write query reports.”
While these basic policies are effective for uncomplicated authorization scenarios, real-world requirements frequently present greater complexity.
Uber experienced several constraints when utilizing the basic policy model.
For instance, consider a payment support service. Customer support representatives require access to payment information to assist customers. Nevertheless, due to privacy and compliance mandates, support representatives should only access payment data pertaining to customers within their designated region. The basic policy syntax merely permits a representative to access a payment profile by its UUID, failing to articulate the necessity for the representative’s region to align with the customer’s region.
Another instance pertains to employee data. An employee information service must enable employees to view and modify their own profiles, in addition to permitting their managers to access these profiles. The fundamental policy model is incapable of expressing this “self or manager” relationship, as it would necessitate verifying if the actor’s employee ID corresponds to either the resource’s employee ID or the resource’s manager ID.
A third scenario involves data analytics, where certain reports should only be accessible to users who are members of multiple specified groups concurrently. The existing model facilitated checking if a user belonged to any group within a list, but lacked the capability to verify membership in all groups within a list.
In essence, Uber required a method to integrate supplementary context and attributes into authorization decisions, leading to the adoption of attribute-based access control (ABAC).
Attribute-based access control (ABAC) augments the foundational policy model by incorporating conditions. A condition functions as a Boolean expression, yielding either true or false based on specific attributes. If a permission integrates a condition, access is granted solely when that condition evaluates to true.

Attributes represent characteristics pertaining to actors, resources, actions, or the ambient environment. For instance:
Attribute Stores serve as the repositories that supply attribute values at the point of authorization. In formal authorization parlance, these are known as Policy Information Points (PIPs). During condition evaluation, the authorization engine queries the relevant attribute store to retrieve the requisite values.
The refined policy model introduces an optional condition field to each permission. An illustrative example follows:
This policy empowers employees to execute CRUD operations on payment records, contingent upon the fulfillment of two specific conditions: the payment type must be a credit card, and the employee’s location must correspond with the payment’s location.
Upon the activation of attribute-based access control (ABAC), the authorization architecture incorporates additional specialized components.
The authfx library now integrates an authorization engine responsible for orchestrating policy evaluation. When a request is received, the engine initially verifies the fulfillment of basic requirements: actor match, action match, and resource match. If these preliminary checks are successful and a condition is present, the engine proceeds to evaluate the condition.
The authorization engine interfaces with an expression engine that processes the condition expression. The expression engine identifies necessary attributes and retrieves them from the pertinent attribute stores. Refer to the diagram below:

Uber has delineated four distinct types of attribute store interfaces:
ActorAttributeStore retrieves attributes pertaining to the actor initiating the request. This may encompass their employee ID, group memberships, location, or department.ResourceAttributeStore fetches attributes concerning the resource being accessed. Such attributes could include the resource’s owner, creation date, sensitivity classification, or any custom business attributes.ActionAttributeStore obtains attributes related to the action being executed, though its usage is less frequent compared to actor and resource attributes.EnvironmentAttributeStore procures contextual attributes, such as the current timestamp, day of the week, or request metadata.Each attribute store is mandated to implement a SupportedAttributes() function, which declares the specific attributes it is capable of providing. This functionality empowers the authorization engine to pre-compile condition expressions and confirm the availability of all required attributes. During runtime, when an attribute value is needed, the engine invokes the appropriate method on the corresponding store.
See the code snippet below:

Source: Uber Engineering Blog
This design facilitates the utilization of multiple attribute stores by a single service, and also permits a single attribute store to be shared across numerous services, enhancing reusability.
The implementation of attribute-based conditions necessitated a robust expression language for Uber. Rather than developing a new language, the engineering team thoroughly assessed existing open-source alternatives.
Their selection was the Common Expression Language (CEL), originated by Google. CEL presented several compelling benefits for Uber’s authorization system:
CEL further offers macros, which are particularly advantageous for interacting with collections. For example, the expression actor.groups.exists(g, g == 'admin') can be utilized to verify if an actor is a member of a group named “admin.”
The performance attributes of CEL were deemed exceptional. Expression evaluation typically concludes within a few microseconds. Both Go and Java implementations of CEL are accessible, aligning with Uber’s backend service prerequisites. Moreover, both implementations facilitate lazy attribute fetching, implying that only the attribute values genuinely required for expression evaluation are requested, thereby enhancing operational efficiency.
A representative CEL expression is structured as follows:
This expression undergoes evaluation against attribute values retrieved during runtime to yield a Boolean (true or false) outcome.
To exemplify the practical advantages of attribute-based access control (ABAC), one can examine Uber’s methodology for managing authorization concerning Apache Kafka topics.
Uber leverages thousands of Kafka topics for comprehensive event streaming throughout its platform. Each topic mandates specific access controls to designate which services are authorized to publish messages and which are permitted to subscribe and receive them. The Kafka infrastructure team bears the responsibility for governing these policies.
Under a basic policy framework, the Kafka team would be compelled to formulate individual policies for every single topic. Given the substantial number of topics, this approach would prove both impractical and exceedingly time-consuming.
Uber employs a service named uOwn, which meticulously tracks ownership and roles for various technological assets. Every Kafka topic can have roles directly assigned or inherited via the organizational hierarchy. A prominent role is “Develop,” indicating accountability for the development and maintenance of that specific topic.
Through the implementation of ABAC, the Uber engineering team devised a solitary, generic policy applicable across all Kafka topics:
Source: Uber Engineering Blog (URL: https://www.uber.com/en-IN/blog/attribute-based-access-control-at-uber/?uclick_id=5e0683f9-63d8-4e7b-a00c-530d8ad1e6f9)
The wildcard character within the resource pattern signifies that this policy extends its applicability to every Kafka topic. The embedded condition ascertains whether the actor is a member of any Active Directory group that possesses the “Develop” role for the particular topic in question.
An attribute store plugin retrieves the compilation of groups holding the “Develop” role for each topic directly from uOwn. This retrieved information is then transformed into the resource.uOwnDevelopGroups attribute. Consequently, when an employee endeavors to execute an administrative action on a topic, the authorization engine evaluates whether that employee is a constituent of one of the designated authorized groups.
This ABAC solution significantly alleviated the Kafka team’s workload. Rather than maintaining thousands of individual policies, they now manage a single, overarching generic policy. Furthermore, as ownership details evolve within uOwn, authorization permissions automatically adapt without requiring any manual policy updates.
The successful implementation of attribute-based access control (ABAC) yielded numerous advantages throughout Uber’s expansive infrastructure.
Authorization policies achieved enhanced precision and granularity. Decisions could now incorporate any pertinent attribute, transcending mere basic identity and group membership. This capability facilitated the creation of security policies that more accurately reflected intricate business requirements.
The entire system gained increased dynamism. When attribute values undergo changes in foundational source systems, such as uOwn or employee directories, authorization decisions automatically adjust. This eliminates the necessity for code deployment or manual policy updates, a level of agility crucial within a rapidly evolving organization.
Scalability experienced significant improvements. A thoughtfully engineered ABAC policy possesses the capacity to govern authorization for thousands, and potentially millions, of distinct resources.
Centralization, achieved through the Charter system, streamlined policy management. Instead of distributing authorization logic across hundreds of individual services, security teams gained the ability to audit and manage policies from a single, unified location.
Performance consistently remained excellent. Notwithstanding the increased complexity introduced by condition evaluation and attribute fetching, authorization decisions are consistently finalized within microseconds, attributed to efficient local evaluation and on-demand attribute retrieval.
Furthermore, and critically, ABAC established a clear separation between policy and code. System owners now possess the flexibility to modify authorization policies without the need for developing and deploying new code. This separation of concerns enables security policies to evolve independently from underlying application logic.
Since the integration of ABAC, 70 Uber services have successfully adopted attribute-based policies to address their unique authorization requirements. The framework delivers a cohesive approach across a diverse spectrum of use cases, ranging from safeguarding microservice endpoints and securing database access to effectively managing infrastructure resources.
References: