18

Docker seems to support both apparmor and seccomp. Docker also allows to drop capabilities when running a container.

However I couldn't find any documentation or guideline on when to use which approach.

There seems to be a significant overlap in what they can be used for, I couldn't figure out any general guideline on when to use which of these options.

Can someone provide any guideline?

In my case, I have to run a lot of students code on the server. I want to allow them to run Java and c++ programs. Allow write access to one directory (data volume). They don't need network access, or anything complicated.

Please provide some guideline how to secure.

forest
  • 65,613
  • 20
  • 208
  • 262
JackDaniels
  • 281
  • 2
  • 5

2 Answers2

28

You can use all of them.

Each of these security features have different purposes, and there is actually little overlap. They all function to reduce the damage that a process can cause once it has been compromised. They are all very low-overhead and can be used to significantly improve the security of software.

Seccomp is a Linux feature that allows a userspace program to set up syscall filters. These filters specify which system calls are permitted, and what arguments they are permitted to have. It is a very low-level filter that reduces the attack surface area of the kernel. For example, a bug in keyctl() that allows simple calls to that syscall to elevate privileges would not necessarily be usable for privesc in a program which has restricted access to that call. Writing a good seccomp policy is more involved than using Docker. You must modify the source code of the program to get the most out of seccomp, otherwise the most you can do is restrict the obviously unsafe syscalls.

AppArmor is a Mandatory Access Control framework that functions as an LSM (Linux Security Module). It is used to whitelist or blacklist a subject's (program's) access to an object (file, path, etc.). AppArmor may be used to allow a program to have read access to /etc/passwd, but not /etc/shadow. The policies can also be used to restrict capabilities, or even limit network access.

Capabilities and capability dropping is a general technique whereby a privileged process revokes a subset of the privileges it is endowed with. A root process can drop, for example, the capabilities required to create raw connections to the network, or the capabilities required to bypass standard UNIX file permissions (DAC), even though it remains root. This technique is not very fine-grained as there are only a limited number of capabilities that can be dropped, but it reduces the damage a program can do if it has been compromised nonetheless. Furthermore, some capabilities are root-equivalent in certain situations, meaning that they can be used to regain full root privileges.

In general, you should know that:

  • Seccomp reduces the chance that a kernel vulnerability will be successfully exploited.

  • AppArmor prevents an application from accessing files it should not access.

  • Capability dropping reduces the damage a compromised privileged process can do.

See also How is Sandboxing implemented? and Difference between linux capabities and seccomp

forest
  • 65,613
  • 20
  • 208
  • 262
7

Well answered by @forest, but I'd like to add a few suggestions that reflect my view on security frameworks and security design in general. Enforcing security goes in hand with knowing what you are protecting yourself against, or at least what you are protecting. All that, however, must start with a security policy. Once the policy is formulated, the choice is easier to make. Let's consider a few cases, which may or may not reflect your use cases. But before considering them, it may be helpful to narrow down the available options to the following:

  1. If you cannot modify the target program, the only options you have are MAC --Mandatory Access Control-- (at best), since all you need is provide a security policy by which a given program will be evaluated. No matter the program, no matter the implementation language, since the operating system's security layers take care of it. Sandboxes are another option, but they fall in category 3.
  2. If you are [re-]writing (or can modify) your program: good luck then, because you actually can write a security-aware program by invoking certain security primitives provided by a framework of your choice [more below]. However, you may be limited in that the framework you choose does not have any bindings in your programming language, as most of them tend to be low-level. Is it C, Java, Go, or Javascript (yeah, as if!)? You may be on your own in most cases, so, welcome to the club. But there are options. And silly ones sometimes.
  3. You don't care and just want to keep things from exploding in your face (i.e. none of the above is worth your time): sandboxes then? Maybe something as dramatic as a VM, or if you are in the mood for the unknown, application containers are your best friends. However, the most security-savvy minds out there do warn that containers do not contain. But you still at least benefit from some resource isolation without having to know the internals of your programs. Unprivileged containers are strongly recommended. But otherwise, VMs are still cool.

And now, the cases:

  • I want to run a program in a way that is immune to malicious exploitation: since that means any attack, known or unknown, nothing is guaranteed to satisfy your requirement (every security framework should tell you this). But at least, restricting your program to the fewest possible system calls reduces its attack surface, although you can still be attacked from anywhere even if it's a 1% of the possible ways. However, if stripping privileges off applications to make them less useful to the attacker, system call filtering and capability systems will be helpful. Seccomp (available on Linux), Capsicum (available on FreeBSD, and soon on Linux), and POSIX capabilities are options here.
  • I want to restrict my programs to known/expected behavior: easy (for simple programs) - if you can define runtime behavior in terms of accessed files or kernel objects, then MAC frameworks can help you (AppArmor, SELinux, ...). However, you will also have to make choices as to what level of abstraction you want to express your policies, so preciseness and flexibility will be pulling you in different directions (are paths precise enough, are inodes manageable for you, what about memory segments?).
  • I often find myself needing to run programs with elevated privileges and worry it may be too risky: we've all been there. Dropping capabilities is probably the most reasonable option. It is OS-specific (and so are all the others), but at least implementation-independent if done as part of access control on a given machine (as opposed to invoking the capabilities interface programmatically, which will depend on available bindings in your language).
Butshuti
  • 71
  • 1
  • 1