17 docker
Ryan Lee edited this page 2024-09-04 16:33:31 +00:00

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.

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.

TODO: other tips

References