This blog post was originally written for a company internal blog. I have removed references and screenshots from internal applications. I have also refactored parts of the blog to be more generic.
We still deploy many of our applications on Windows VM. Part of this blog is Windows server specific.
What is it?
The principle of least privilege states that only the minimum necessary rights should be assigned to a subject that requests access to a resource and should be in effect for the shortest duration necessary. It prevents users from obtaining or changing information in unwanted ways. This is important because it helps organisations reduce risk by reducing the potential damage that excessive privilege can cause accidentally or maliciously.
As developers, we need to be aware that this principle not only applies to us not running everything as root or local admins on our development machines. It also applies to service users our applications run as, database users our applications access data with and API users our application access third party APIs with. It even applies to our application design, where we should have appropriate roles for users identified in use cases.
One service user per microservice
It is best practice to have one service user created per microservice per environment. This means if you have different environments for dev, qa, staging and production, you will need four service users per microservice.
This can be a pain for us who work in enterprise enviroments where development teams do not have full admin access to all systems. For example, I need to first get IT to create Windows gMSAs (Group Managed Service Account). Then I need to wait for DBAs to grant database access to them. After that, I can grant the service user folder access permissions on the VMs. If the microservice access other internal APIs, I will then need to service users grant access to them too.
The reason you should take this trouble is so you can limit the access the service user has to strictly what the microservice needs. If you share this service user among many services, then you will likely be granting it access to more databases, more network drives, more APIs. In the worst-case scenario, if you use a single service user, then this user has read, write and execute access to all databases and APIs in your entire software estate. If there is a security breach in one of your microservice, then the hacker will be able to gain more access than they could have had if access is more restricted.
Database access
You should apply the principle of least privilege when requesting database access for service users. If your ‘microservice’ only needs to execute specific stored procedures in a database, make it clear in your DBA request. Do not request full read and write access because it’s easier or you might need it one day. This will be an unlikely scenario in true microservices where you have one database per service. However, many of us have also work with legacy services that need database execute access to many, but only write to a few. Remember that stored procedure execute is less privileged than read. The former restricts the application to access data in ways specified by the stored procedures. In comparison, read access allows arbitrary select queries on all data in the database.
API Roles
Similarly, when adding permissions to API access, we should grant the least privileged roles needed. However, this requires the API you consume have more than one role.
When designing a new API, you should think about the roles of services accessing your endpoints. For example, an order API can have separate roles for creating, viewing and managing orders. Endpoints are then annotated with the appropriate role. In Spring Security, you can achieve this using the @PreAuthorize annotation.
@PostMapping("/order")
@PreAuthorize("hasRole('CREATE')")
CreateResponse createOrder(Order order);
Internal users will be granted all three roles. External users will be granted with only create and view access.
An anti-pattern is creating too many fine-grained roles. The permission system can then become too complicated to understand. I have seem examples where different parts of a end user journey require different permissions. These related permissions rely on each other and user journeys do not work if a user do not have them all. The application permissions become too difficult to maintain and operations team ends up giving end users excessive permissions to reduce support effort.
Configuring service users for microservices
I am still deploying many microservices on virtual machines in a language-specific packaging format. By this, I mean compiling applications into jar files. The jar file and a corresponding batch script are copied to a server VM. A windows service is configured using nssm to log on with the microservice gMSA.
But what other access should you grant your service user? One approach will be to grant local admin access to your service user. Local admins have a lot of power, and you will not need to grant further access to anything else on the VM. This is a terrible approach because if your application is compromised, the hacker will also gain local admin rights.
So what access should a microservice gMSA have on a VM?
- Read and execute for service wrapper binaries (eg nssm, winsw)
- Read and execute for jars and start script
- Read, write and modify for application log folder
- Read, write and delete for temp folder (This is usually not a concern because the default Windows temporary folder for Java applications is %USER%\AppData\Local\Temp)
Configuring service users for automated deployment
If you are using a CI/CD pipeline to deploy your microservice, the CI/CD service account will need to be granted access as well. This user needs
- Local admin rights to start and stop windows service
- Delete and write for deployment folder
- Delete and write for backup folder (Our release policy recommends taking backups of previous deployments for rollbacks independent of CI/CD pipelines)
What if it doesn’t work?
If your Windows service will not start, your first step should be to check the Windows Event Viewer. Go to the application log section and look for the error log event.
Conclusions
I am not a security expert. This blog post is not intended to be a gospel about the application of the principle of least privilege. It’s simply to bring awareness to a very important topic. If you already know about it, I hope it serves as a reminder on why you should keep doing it. (Like our annual security training). If you have not heard of it before, I hope you find you have learned something useful, and further seek out articles on the web to learn more.