The Aporeto Trireme project provides the mechanism end-to-end authentication and authorization for containers and Linux services. In this series of posts, we discuss several features of Trireme and how they can be used to secure a cloud infrastructure.
Trireme associates a contextual identity with every application and uses this identity to transparently insert authentication and authorization in any communication between applications. Through this mechanism, it achieves detailed access control in any Linux environment without the need for firewall rules, ACLs, or a complex infrastructure. The end-to-end authorization approach makes it especially useful in multi-cloud or multi-availability-zone environments, where dealing with network primitives is operationally challenging.
Although we have documented in detail how Trireme works in Docker and Kubernetes environments, the library is designed to work with any Linux service. In this blog we describe how Trireme can be used with Linux processes and what are the underlying mechanisms that make this possible.
In order to illustrate how to use Trireme with Linux processes we will use the Trireme example with default settings.
% sudo trireme-example daemon --hybrid
The above command will start the Trireme daemon supporting both Linux Processes and docker containers and basic PSK authentication. You will be able to see all the Trireme messages in the window.
% sudo trireme-example run --ports=80 --label=app=web nginx
Note, that we use sudo for this since nginx requires root access by default. The additional parameters are:
% curl https://127.0.0.1
You will see that the curl command fails to connect to the nginx server, even though the server is running and listening on port 80.
% trireme-example run --label=app=web curl -- https://127.0.0.1
In this case your curl command will succeed.
% trireme-example run --label=app=web /bin/bash
We essentially started just a standard bash shell within the Trireme context and protected by Trireme. In this case our bash shell can actually access the nginx server. A simple curl will succeed.
We started the Trireme daemon and started an nginx server protected by Trireme. By default only authorized traffic will be able to reach this nginx server and authorization is controlled through identities. There is no need for firewall ACLs or other networking based rules. Even processes in the same host will be unable to reach the nginx server, unless they are also protected with Trireme and they are explicitly authorized.
In this section we will describe how Trireme introduces the transparent authorization for every Linux Process. This has several use cases that we will illustrate in some subsequent blogs. Some examples are:
For several reasons the Linux kernel does not have an easy method to differentiate traffic based on the source or destination process. However, it has a very important facility that is not very well documented, but very useful. One of the control groups (cgroup) is known as net_cls. When a process is associated with this cgroup, the Linux kernel will mark all packets initiated by a process with a mark that is set in the configuration of the cgroup. For example, in a standard Ubuntu distribution you can see the mark in /sys/fs/cgroup/net_cls/net_cls.classid. The default value is 0, indicating that there is no mark placed on the packets.
In the case of Trireme, you will find a trireme directory under this controller in /sys/fs/cgroup/net_cls/trireme and Trireme will create a sub-directory there for every protected process. Let’s assume that the nginx process in the example above had a process ID of 100. Then Trireme will create the directory /sys/fs/cgroup/net_cls/trireme/100 and it will populate the net_cls.classid file with a corresponding mark value.
Once Trireme does that, all packets out of the nginx server or any of its children will be marked with the same mark. We can now apply the Trireme ACLs that capture Syn/SynAck traffic only on packets with this mark. As a result, we can apply policy to a specific Linux processes and not just a container.
Of course we need some more work. Eventually the process will die and we need to clean up. Fortunately, there is a kernel facility for that. The file /sys/fs/cgroup/net_cls/trireme/100/notify_on_release is populated with 1, meaning that the kernel should notify a release agent that there are no more processes associated with the particular cgroup. The file /sys/fs/cgroup/net_cls/release_agent identifies the binary that should be executed when such an event happens and Trireme automatically populates these files with the right values.
We can now put all the parts together.
One of the most powerful features of the Trireme approach is the metadata extractor. In the above example we used a simple method where the labels that are forming the identity are provided by the user. However, these are not the only attributes that Trireme identifies and it can be extended to actually associate any attribute with this identity model.
By default the metadata extractor will capture the following information:
The result is that a user can define an authorization policy across any of these attributes. For example, you can define a policy that only a binary with a specific checksum can access a database. Or, that only a process with a given User ID can access an application. Or, that users with sudo capability can never talk to the Internet.
One can enhance this metadata extractor with additional sources. For example in an AWS environment, the AMI ID, VPC ID, subnet, SELinux/AppArmor labels and so on. The possibilities are unlimited.
By associating custom and system metadata with a process, Trireme allows you to create a “contextual identity” for every Linux process. You can then use this identity to control access over the network without worrying about IP addresses and port numbers. It is the identity that matters.