Zero Trust; you’ve probably, at the very least, heard of the term. Some may have worked on a project where a Zero Trust policy was in effect, and others may well be working for a company with a company wide Zero Trust policy in effect. But do you know what Zero Trust actually entails? And if you know, do you know how best to develop software that has to comply to a Zero Trust policy?
Depending on your level of exposure to Zero Trust, you may well have had a bad experience with it, may not want to have anything to do with it, or may not want to develop in such an environment at all. If you had a bad experience, it is most likely due to the company or project not understanding the Zero Trust methodology and implementing it incorrectly; but that is a subject for different blog post. Regardless of your experience with (or opinion of) Zero Trust, this post will give you some helpful hints on how to best develop for a Zero Trust environment.
What is Zero Trust?
For those of you unfamiliar (and for those who could do with a refresher), Zero Trust is a methodology where security is tightened for a company’s business critical processes to limit damage in the case of a security breach. Because Zero Trust, as a whole, is a methodology that also covers multiple areas and disciplines outside of the IT and software domain, this blog will be limited to parts that are directly applicable to software development.
What do I need to know about Zero Trust?
To explain Zero Trust we have to first define Trust. When we take a scientific approach to defining Trust, we get something more comprehensive than just the emotional feelings of trust that we have as human beings in each other. Broken down there are two major axes that are applicable to the IT and software development domain.
The first axis is access management. Access management in the software development domain is nothing new. We have all, at one point in our careers, developed software where a user had to login in to a system. Once a user has successfully logged in, either by our own software implementation or by an outside authority like OpenID, the user is considered Trusted and is allowed access to the software.
The second axis is propagation. Especially back-end software applications are designed to run in a trusted environment, where authentication and authorization are delegated to the user facing software interfaces. Once authenticated and authorized, the software will either fully trust on the user facing components to handle all access management or propagate the rights as determined during the centralized login. This inter dependency is where one software components Trusts an other’s determination and as such created a Trusted environment.
If these concepts are unfamiliar to you then you may want to familiarize yourself with these concepts first, before reading the rest of this blog. For everyone who knows these concepts, you probably recognize the components of a "regular" setup of a trusted environment. So how do we take the Trust out of the equation?
From trust to Zero Trust
In our traditional trusted environment model, a user is authenticated for the environment and once authenticated is trusted and free to move around the environment or application as the user desires. To eliminate the trusted state, an authenticated user after gaining access to the application should be treated as an unauthenticated user again for its next action. This requires the application to re-asses the user’s credentials for every subsequent action taken by the user.
Role and rights management first
As a key feature of Zero Trust is the limitation of access to data to limit the damage in case of a security breach, a good start is to implement a fine grained rights and role check for every page, function and action. Creating a minimum set of roles, separated in read, create, modify and delete that in turn can be applied to each authenticated user is a well known security pattern for many methodologies.
The next step in access separation would be to make the roles content aware as well. This way, a user who, for example, has read/write access in a web application to a page for editing a database record can be further limited to only be allowed read/write access to certain records while all other records are only read accessible. In the other dimension, extending roles to cover parts of a page so a user can have certain parts of a record editable while other parts remain read only is another step into removing trust.
By now you may think that making role management so that each field in each record on each page has its own fine grained access rules is the best implementation, and while that may be the best implementation of a Zero Trust, it is prohibitively expensive both to develop and to use.
Like with every model, the requirements of your specific application or organization will determine what the smallest protected parts have to be, beyond which there is no benefit in splitting it into smaller parts. This just increases the amount of effort taken for the development as well as effort for the IT department who have to assign roles and rights.
Verify, validate, check and recheck
Another important feature of Zero Trust is the elimination of propagation. Traditionally, software that consist of multiple independent tiers, especially micro service architectures, are implemented with security on the public facing components only, e.g. a RESTful API with a HTML front end component with authentication only on the front end. Often times in these applications the back-end component will serve anything the public facing component requests, relying on the public facing component doing all the access, roles and rights checks for the system as a whole. In case of a security breach, it leaves the system open to any data that a bad actor wants to take.
In the Zero Trust world, each component should do its own authorizations and determine what parts of the data or functionality should be accessible to users coming in, directly or via other components. By limiting access at every tier to only the data or functionality that should be available to the requesting users credentials, if one component is compromised the remaining components will limit the amount of data breached as other components no longer grant access to all data in their domain.
Tightening down security, regardless of Zero Trust, is a good way to limit damage to a system upon a security breach. It, at the very least, will limit the amount of damage done to/data stolen from the system.
However, this comes at the cost of creating more fine grained role and rights management with and additional development work. It should therefore be limited to software components that require the extra layer of protection rather than applied as a company/project wide policy.
Even when developing a high risk software component with Zero Trust, limit its application to only the necessary components. There is a point at which a finer grained rights management no longer limits damage upon a breach and instead only complicates development.
Keep in mind that with every level of access control comes the need to mange these rights. If the amount of work required to determine and set up each users access rights becomes too complicated, people will stop using the system as a whole and just grant everyone all rights. This would put your system back into a trusted state and sets back your Zero Trust efforts to square one.
A well implemented Zero Trust application will, despite the extra efforts involved, give a solid layer of security that will limit damage and repair time to a critical system. When applied correctly, it is a methodology deserving of your extra time and effert as a developer.