Using custom apparmor profiles with Docker containers
The default apparmor profile Docker uses to confine containers can be found here. To override this, specify the option
--security-opt apparmor=<profile>
Eg. To disable apparmor confinement on a docker container add the following to the docker run command.
$ docker run --rm -it --security-opt apparmor=unconfined hello-world
Tips for creating profiles for Docker containers
Profiles for Docker containers are meant to be written without an attachment. If an attachment is present on a profile used for a container, it will be ignored, and the profile's restrictions will be applied to all the binaries in the container.
Recommended profile flags
The flags attach_disconnected
and mediate_deleted
are present in Docker's default profile to help with, respectively, container-host shared resources and deleted files still being present in the overlay file system, so they should be present on custom profiles applied to Docker containers. They should also be present on other profiles that binaries in the container may transition to.
Path filtering, entrypoints, and docker exec
Apparmor profiles applied to a Docker container will not block entrypoints or commands launched via docker exec
from running, even if the profile does not allow the specified binary to execute. However, further actions of the specified binary will be restricted according to the profile. This is in line with the behavior of aa-exec
, but it means that Apparmor profiles for docker containers cannot be used to limit the commands that can be run using docker exec
.
Profile transitioning
Profile transitioning inside a Docker container is still wonky, but transitioning to child profiles seems to work properly. However, child profiles, combined with the way Docker command execution works, can lead to counterintuitive behavior.
For the following sections, we will use the following profile as an example:
profile main_profile flags=(attach_disconnected,mediate_deleted) {
include <abstractions/base>
/usr/local/bin/our_special_binary cxr,
/usr/local/bin/a_different_special_binary cxr,
# other profile stuffs here
profile child_profile flags=(attach_disconnected,mediate_deleted) {
include <abstractions/base>
# other profile stuffs here
}
profile child_profile_w_path /usr/local/bin/a_different_special_binary {
include <abstractions/base>
# other profile stuffs here
}
}
Child profiles and Docker exec
As an elaboration of [Path filtering, entrypoints, and docker exec](#Path filtering, entrypoints, and docker exec), binaries launched with docker exec
are confined by the parent profile that the container was launched with. In particular, this means that docker exec container_name /usr/local/bin/a_different_special_binary
will result in a_different_special_binary
being run under main_profile
, even though it would run under child_profile_w_path
if launched naturally by a process in the container.
Specifying --init
TODO: how does using docker-init interact with indrection layers?
CMD and ENTRYPOINT shell forms
CMD and ENTRYPOINT Dockerfile commands can be in either shell form or exec form. Because the shell form invokes a shell and passes the argument as a script, the main_profile
will apply to the shell, and the child_profile
will apply to any child processes of the shell that match the cx
execution specifier. This can cause issues if, for example, the entrypoint process spawns worker processes using the same binary that should be confined differently: the Dockerfile and profiles must agree on the amount of indirection that occurs.
TODO: profile transitioning needs more testing, and any other potential nits should be written up
Linux capabilities
Docker provides a different mechanism for limiting the Linux capabilities used by a container, described here. If profile transitioning is not used, AppArmor profiles for Docker containers can include the line capabilities,
for a container that needs them and let Docker handle the capabilities filtering. However, if profile transitioning is used, then capabilities can be specified more precisely in each profile, and Docker configured to bound capabilities to the union of the ones required by all the profiles.
In addition, not allowing capabilities on a profile in complain mode can make it easier to identify the capabilities that a container needs.