We’ve said it before, and whether they realize it or not, almost every organization today operates like a software company. Dev teams everywhere at associations, startups, non-profits, or Fortune 500 companies are building and re-architecting a growing number of applications on a daily basis. Securing those applications and workloads requires two critical pillars of application security: authentication and authorization. Authentication is responsible for verifying the identity of the requester, while authorization is responsible for putting guardrails around what this identity is entitled to do within the application or resource.
The two pillars of enforcing permissions in applications are through Role Based Access Control (RBAC) and Attribute Based Access Control (ABAC). The first part of this blog series focused on RBAC best practices with Open Policy Agent while this post will address best practices for ABAC.
This post explains the basics of ABAC and provide best practices along the way, including how to implement a solid ABAC framework in the early stages of a program’s lifecycle. Our hypothetical use case will be that of a pet store management system, and we will demonstrate how to enforce policies in an application using ABAC with almost zero code changes.
Where does RBAC fall short?
Current identity and access management (IAM) roles and user permissions lack substance with respect to dynamic, contextual data. RBAC lacks context to help understand the nature of a request and what we know about the requester. Roles like “Admin”, “SuperUser” and “EMEAReportsOfBob” are ambiguous, cryptic and very prone to error in the way that they are used. Regardless, these fundamental IAM frameworks are still very popular with development teams building and maintaining authorization for their application. How often do enterprise IT teams re-use the same set of roles and permissions that have already been created? How often are groups or permissions shared across multiple users? New sets of permissions and roles are being spun up on a daily basis. This identity and access management dilemma is known as role explosion. The business meaning or context behind these permissions is often lost in the forest of random, often times one-off roles and permissions. Managing this ‘basic’ set of permissions consumes a lot of engineering resources and presents security vulnerabilities that can easily lead to data breaches. On top of all that, managing something like this becomes very manual and laborious.
Managing a large number of roles with little distinctions and very poor naming conventions has a significant impact on key IAM lifecycle phases such as Access Assignment, Access Authorization, Access Review and Access Reconciliation. To help compensate for the lack of business context in IAM roles, application developers have to hard code authorization logic into their applications. Another nagging challenges becomes synchronizing logic (policy) across multiple applications. Often times these applications are built in different languages, frameworks, or versions, and the developers that build and maintain them are often on different teams. Separation of Duties (SoD) is yet another challenge to manage across multiple applications. Manual security reviews are usually done very quickly and details are often overlooked. The ‘across the board’ approach to security reviews is usually erroneous, it impact a team’s productivity, and poses a series of regulatory concerns. This can create a great deal of frustration across teams and often times a lack of confidence in the authorization system, leading to more time and energy being spent hard coding access logic into the applications themselves.
To build better authorization policy we are going to do three things
- Leverage attribute based access control to create more contextual roles
- Decouple the logic for our access controls and have it live outside of the applications for better visibility, control and flexibility across a vast landscape of cloud apps.
- Use policy-as-code, leveraging GitOps to properly integrate it into your SDLC. git is a more efficient alternative to spreadsheets filled with roles, permissions and business use cases. Everything is audited, versioned, reviewed, tested and only then is it enforced.
What is Attribute Based Access Control (ABAC)?
ABAC uses attributes, a set of data properties, to determine who has access to what resources. Attributes include those related to identity, resources, environment or policies. Attributes can include anything from the geo-location of identities, job titles, IP addresses, devices, and much more.
As the administrator of a system using ABAC, you can set permissions by:
- Identity: A person’s job title, typical tasks, or seniority level that would determine the scope of their permissions.
- Resource attributes: The type of file, the person who created it, or the API’s sensitivity.
- Environment: The geo-location of the identity, the time of day the request is made, or the day of a week/month/year.
Administrators have a great deal of nuanced control in systems like these. Permissions can be built based on a variety of attributes and in a perfect world they are all working together to keep resources safe.
In ABAC, elements work together in a coordinated fashion. A way to approach this is:
- Identities: Who is trying to do the work? (eg. user claim extracted from a JWT token)
- Resources: What API within the network is the user trying to access ? (eg. the HTTP path components of the API request)
- Operation. What is the person trying to do with said API? (eg. The HTTP method of an API request)
Relationships are defined by if/then statements. For example:
- If the user is in accounting, then the person may access accounting APIs.
- If the person is a manager, then that person may read/write (GET / UPDATE / POST).
- If the company policy specifies ‘no access allowed on Saturday’ and today is Saturday, the request would be denied.
When your roles and permissions have business context by leveraging properties on an account status in Salesforce, a string of text in a Slack channel or a status of a pending ticket in Jira, your access control begins to align with virtually any attribute from any cloud application.
Benefits of ABAC
There’s almost certainly someone reading this saying to themselves, “But I REALLY only need RBAC. Basic user, manager & admin roles and permissions will do the job” There are many times, particularly within the first year or so of building an application where RBAC is enough. As your application matures, the need for more intricate access controls that are attribute-based quickly becomes a business requirement. ABAC does offer a number of benefits for managing permissions regardless of the complexity of your current authorization requirements. ABAC allows you to do the following:
- Automatically update permissions as rules change
- Easily establish segregation of duties
- Greatly reduce administrative overhead
- Offer better application security
ABAC eliminates having to make very manual updates to permissions for roles and groups. Every time your business rules and requirements are changing, extensive resources are put into updating and maintaining access controls to reflect those changes. Once attributes are defined you can let the data automate the entire permissions system. That’s where access is either permitted or denied based on the attributes of the identity and the resource. These fine-grained, dynamic access controls make managing authorization a considerably easier task. If identities or environments change, so do the resources they can access. Administrators only need to change attribute values rather than constantly making manual updates to the relationships between identities and resources.
ABAC also provides the ability to easily define and enforce segregation of duties, for example:
- A Billing Manager doesn’t have the ability to approve an invoice that he or she generated.
- An HR Administrator isn’t able to access their manager’s HR file
Business rules and access permissions are changing on a daily basis. As identity attributes change there’s less of an administrative burden to onboard new users or services. For example, you don’t need to assign authorization to identities before they need access to resources.
Limitations of ABAC
The power of ABAC brings with it a set of complexities when it comes to setting up and managing permissions. Defining rules and permissions for different users from a long list of external data sources isn’t an easy task. When you have the power to create policy based on virtually any attributable data source, you’re required to manage rules across a lot of sources and authorization quickly becomes a very multi-dimensional problem with a lot of moving parts. The three main challenges that come with ABAC are:
- Deep complexity
- Difficult to audit
- Limited scalability
ABAC can become very difficult to configure and maintain, particularly in environments where a lot of data is being shared from a variety of sources. The admin is tasked with building numerous policies composed of a long list of rules in order to determine what attributes users need to have in order to access different resources. Managing attributes across hundreds or thousands of different users can become very tedious.
Another key challenge with ABAC is the inherent complexity it presents to conducting audits. For security and regulatory compliance purposes, it’s vital to be able to see the exact list of resources that an individual user has access to. This is much easier to do with role based access control as you can just look at the static privileges the user has been granted and be able to quickly understand what they have access to. The dynamic and multi-dimensional nature of ABAC makes it difficult to look up users and have clear visibility into what they have permission to access. Auditing something like this would require you to check each object against the access policy.
Similarly, the scalability of ABAC also presents its own set of challenges. Trying to manage systems with hundreds or thousands of policy rules is a challenge in and of itself. Being able to build authorization framework that can return a decision with sub-millisecond latency is even more difficult. Because of that, designing a system that can return decisions quickly across numerous policies for multiple applications becomes very daunting.
Open Policy Agent helps to make the policy enforcement piece of authorization a bit easier. Let’s dig in.
What is Open Policy Agent
The Open Policy Agent (OPA, pronounced “oh-pa”) is an open source, general-purpose policy engine that unifies policy enforcement across the stack. OPA provides high-level declarative language that lets users specify policy as code and gives APIs the ability to offload policy decision-making from their software. OPA can help enforce policies in microservices, Kubernetes, CI/CD pipelines, API gateways, and more. Its key lies in decoupling policy decision-making from policy enforcement. Whenever an application needs to make policy decisions, it can simply query OPA and supply structured data (e.g., JSON) as the input.
OPA generates policy decisions by evaluating the query input against the policy and data.
Putting it all together…
Working with a sample application from the Open Policy Agent Playground, let’s assume we’re running a system to manage a pet store. The pet store has its users, its pets are the inventory, and both have a different set of attributes. For users those attributes will be tenure and title, and for pets those will include id, name, adopted, age and breed.
Let’s say we want to build a policy that stipulates the following rules:
i) Allow action if the user’s title is “owner”
ii) If the user is an employee (and not an owner) then only allow “read” requests
iii) If an employee wants to make updates to a record (and not just read it), their tenure needs to be more than 8 years.
iv) Customers can read information about pets only if the adopted attribute has a value of false.
The first rule could probably be achieved using Role Based Access Control, but all the other rules are attribute based. Far too often these rules are coded into applications right beside the business logic even though these are pure access control policies.
Using OPA, the policy above can be expressed in the rego language as displayed here.
The rego language is declarative, and as you can see in the playground link above, provides the ability to test policy between the input, the data and the rules to understand what decision would be generated based on different circumstances. The playground is a great tool to gain familiarity with the language and play with the policy you’re building using different data or inputs. The data set is static and in this case is relatively simple in this short example. However, OPA provides us the ability to scale our access controls seamlessly. We could very easily define a multitude of users, roles and permissions or leverage external databases and third party services that store different types of data attributes. This is where OPA shines – giving you the ability to develop an authorization framework that can easily scale as your business requirements change or become more complex.
It’s important to mention that the generated decision doesn’t have to be an allow or deny boolean. It could also be a list of permissions for example, or any other object that can be expressed in JSON format.
Connecting this policy to your application can be done in couple of ways:
- Using a reverse proxy (eg. Envoy) that will intercept the incoming requests, and in turn delegate them, with all required information to the OPA server to make a decision. Envoy comes with a “plug and play” external authorization plugin that works well with OPA. You can see an example of this here. This approach can be used to enforce ABAC with zero code changes in the application.
- Using a middleware or SDK in a growing ecosystem of integrations. By using these middlewares and/or SKDs, the application developer can hook OPA to make a decision before any request hits the business layer of the app.
In short, some organizations may find that RBAC is suitable to handle basic permissions management. However, as the application grows, business requirements often require building permissions that RBAC simply can’t address. While attribute-based rules provide a lot of flexibility to build dynamic, context-based access control, managing those permissions as they grow and scale quickly becomes overwhelming. By leveraging OPA, you are able to address ABAC’s scaling limitations while still leveraging the power that attribute based access controls can offer. To learn more about when ABAC is a better option than RBAC, read our post on Role-based Access Control vs. Attribute-based Access Control for API authorization.
- The NIST Model for Role-Based Access Control: Towards a Unified Standard. (July 2007). National Institute of Standards and Technology.
- Identity and access management taxonomy. (March 2016). International Communication Union.
- RBAC-vs-ABAC. Okta.