Background
Uber relies on microservices to support its operations. Microservices necessitate a flexible authorization policy model to satisfy their unique authorization requirements. Attribute-based access control (ABAC) offers a dynamic, context-aware, and risk-intelligent approach to access control. By leveraging ABAC, access control policies can be crafted based on specific attributes obtained from diverse information systems. This enables Uber to establish a sophisticated access policy management system that facilitates access in a manner that promotes least privilege, enhances efficiency and effectiveness, and, most importantly, maintains consistency across dissimilar information systems when managing access.
Context
Uber implements policy-based access control using a centralized service known as “Charter” to manage all access control policies. This is similar to AWS’ or Google Cloud’s IAM policies. These policies are then distributed to the various microservices. The microservices evaluate and enforce the distributed authorization policies using a local library called “authfx“.
The authorization request can be abstracted as:
An Actor is performing an Action on a Resource in a given Context.
Concepts
Actor
A generic term for an entity which is the subject of an authorization decision. Authentication verifies the actor’s identity and enforces access.
At Uber, the actor is represented in SPIFFE format. A few examples of actors:
Actor ID | Description |
spiffe://personnel.upki.ca/eid/123456 | An Uber employee with employee ID ‘123456’ |
spiffe://customer.upki.ca/user/<uuid> | An Uber customer |
spiffe://prod.upki.ca/workload/service-foo/production | A microservice named ‘service-foo’ in its production deployment |
Action
Describes what the actor is attempting to do to, with, or on a resource. Supported actions are defined as part of a resource type.
Some common actions are create, read, update, delete (CRUD).
Resource
A resource is the object being requested. A resource has a resource type. For example it can be any physical or virtual component or a dataset that is accessible by a person or process.
Examples include:
- An RPC or HTTP endpoint
- A table row or column in a datastore
- A business object like a customer, a ride, an order
A resource is represented in UON (Uber Object Name), a URI with ‘uon’ as scheme. Some examples of UON are listed as below:
- uon://service-foo/production/rpc/foo/method1
- uon://reports/production/report/<uuid>
- uon://documents/production/document/<uuid>
- uon://orders.mysql.storage/production/table/orders
The host portion in the URI is called the policy domain. It is the namespace used by Charter to group policies and configurations that apply to a specific use case.
Basic Policy Model
The introduction of the actor/action/resource concepts also introduces policies to associate them with each other.
The following are a few policies represented in YAML format.
Architecture
Supporting Attribute Based Access Control (ABAC)
The basic policy model above is effective for many use cases that represent business objects as resources and secure them with policies.
However, there are instances where more granular access controls may be needed. Consider the following examples:
- Certain services require the ability to define authorization policies based on additional attributes of resources. For example, a payment support service may need to allow customer support representatives to access payment information only for customers in a particular country, region, or city. In this case, the accessed resources are represented by the payment profile UUID. The basic policy syntax can’t represent additional information than UUID. While the customer’s account and region can be obtained from the payment profile UUID, it would be beneficial to model the policy using additional attributes of resources.
- In addition, certain use cases require authorization policies to be based on the relationships among multiple attributes from resources and actors. For instance, an employee information service may need to allow an employee or their manager to manage the employee profile. To achieve this, the access policy needs to link the employee profile resource (represented by employee ID) with the actor’s identifier or the manager’s identifier.
- A data analytics service requires authorization to be granted to users only if they belong to N different groups simultaneously. While the existing policy model already incorporates the use of groups, it does not provide the capability to define multiple groups in an AND relationship.
Concepts
Attribute: Characteristic of an actor, resource, action, or environment that may be used in authorization policy to evaluate a decision.
Attribute Store: Source of attribute values at authorization runtime. It is also known as Policy information point (PIP) in the authorization framework.
Condition: An expression to be evaluated to a boolean value based on attributes.
Policy Model
We extend the earlier basic policy model to support these additional use cases.
If a condition is specified for a permission, the permission will only take effect if the authorization request matches the permission’s resource, action, and associated action, and if the condition evaluates to true. This allows the attribute values to be taken into consideration when making an authorization decision.
Updated Architecture Supporting ABAC
With attributes used in policy, an attribute store concept is introduced into the authorization runtime architecture. This attribute store is a plugin program that consumer services use to obtain attributes for their specific business use cases. A single service can use multiple attribute stores, and a single attribute store can be used by multiple services to facilitate reusability.
During policy evaluation, the authorization engine requests attribute values from the attribute store, based on the conditions specified in the policy. The condition and attribute values are then sent to an expression engine, which evaluates them and produces a boolean result.
Attribute Store
An attribute store must implement the SupportedAttributes() function. This enables the authorization engine to derive all supported attributes and use them to pre-compile the condition expressions.
At authorization runtime, the Get*Attribute methods will be called when an attribute value is needed when evaluating the condition expression.
Expression Language
To represent the condition based on attributes, an expression language is required even with the attribute definitions and stores in place. Instead of creating a new language, open source projects were explored and evaluated. The Common Expression Language (CEL) from Google was selected for its simplicity and flexibility among open source projects.
CEL supports multiple data types with single or multiple values and includes necessary string, arithmetic, and boolean functions. It also provides built-in macros that are useful for evaluating multi-value attributes.
CEL is supported in Go™ language from google/cel-go project and in Java® from cel-java project by Project Nessie, both of which meet Uber’s backend service requirements. The expression evaluation performance is excellent, taking only a few microseconds. Additionally, both the Go and Java implementations support on-demand fetching of attribute values, which helps improve performance by requesting only the necessary attributes for expression evaluation.
A sample CEL expression is like below:
“resource.paymentType == ‘credit card’ && actor.location == resource.paymentLocation”
Policy with Condition
Adopting ABAC Policy
The attribute-based access control policy and infrastructure enable Uber to implement a range of authorization use cases. 70 Uber services have implemented ABAC policies in order to meet different authorization needs.
For example, Uber has a variety of technological assets, such as services, Kafka® topics, and database instances. To manage the ownership of these assets within the organizational hierarchy, a service called ‘uOwn’ is used. Each asset can have roles defined on the asset itself or inherited from the organizational hierarchy.
When access control is necessary for technological assets, like Securing Kafka® Infrastructure at Uber, authorization policies can be created for Kafka topics. These policies determine which services are allowed to subscribe to a Kafka topic and which services can publish messages to a Kafka topic.
The Kafka topics are represented by resource in format: uon://topics.kafka/production/<topic-name>
With actions: subscribe, publish, admin
The management of policies for Kafka topics with administrative action is restricted to the Kafka team. It would be impractical for a small team to handle policies for the thousands of Kafka topics in use. Conversely, it would be challenging to enable Kafka topic owners to manage policies with simple policies due to the high volume of topics.
By utilizing ownership information for Kafka topics from uOwn, a generic policy could be created that applies to all Kafka topics, as shown below.
An attribute store plugin program will be made available, allowing users to retrieve the user groups with a ‘Develop’ role for a requested Kafka topic from uOwn. This information is obtained as a resource attribute named “resource.uOwnDevelopGroups.” Users with the ‘develop’ role on a Kafka topic are authorized to manage policies for that topic under the ABAC policy.
This solution saves the Kafka team a significant amount of time that would otherwise be spent managing policies for individual topics.
Conclusion
The use of attribute-based access control has enabled many Uber services to create more precise and fine-grained authorization policies based on specific attributes. This allows for more nuanced access control that is tailored to the needs of each service.
Moreover, centralized policy administration in Charter makes it easier for Uber to manage and distribute these policies across multiple services. This not only can improve the security posture of the overall system, but it also can save engineering time and reduce complexity by avoiding the need to implement authorization logic separately in each service.
The introduction of an attribute store and an expression language like CEL allows for more flexibility and scalability in defining authorization policies. This approach allows services to fetch the necessary attribute values only when needed, which can further improve the efficiency of the authorization process.
Beyond these obvious benefits, externalizing access policy to a Policy Administration Point (Charter) enables system owners to flexibly and quickly change their policies without having to build/re-deploy code for such changes. Such changes can be quickly distributed for efficient enforcement in the appropriate systems.
Charter and its related systems enable Uber developers to simply and easily adopt attribute-based access control policy delivering an efficient and scalable authorization framework for all of Uber.
Oracle, Java, MySQL, and NetSuite are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.
Apache®, Apache Kafka®, and Kafka®, are either registered trademarks or trademarks of the Apache Software Foundation in the United States and/or other countries. No endorsement by The Apache Software Foundation is implied by the use of these marks.
Main image attribution: “Data Security” by Visual Content is licensed under CC BY 2.0.
Alan Cao
Alan is a Staff Software Engineer on the Core Security Engineering team at Uber. He works on the unified authorization platform for Uber’s services and infrastructure.
Posted by Alan Cao
Related articles
Most popular
Unified Checkout: Streamlining Uber’s Payment Ecosystem
The Accounter: Scaling Operational Throughput on Uber’s Stateful Platform
Introducing the Prompt Engineering Toolkit
Serving Millions of Apache Pinot™ Queries with Neutrino
Products
Company