AppArmor is a Linux kernel security module that you can use to restrict the capabilities of processes running on the host operating system. Each process can have its own security profile. The security profile allows or disallows specific capabilities, such as network access or file read/write/execute permissions.
You can use AppArmor with the Docker containers running on your Container-Optimized OS instances. For any given container, you can apply either the default AppArmor security profile that comes with Docker, or a custom security profile that you provide.
Using the default Docker AppArmor security profile
When you start a container on your Container-Optimized OS instance, the system
automatically applies the docker-default
AppArmor security profile. The following
example command runs a container with the docker-default
security profile:
docker run --rm -it debian:jessie bash -i
To test the docker-default
security profile, you can try to read the
/proc/sysrq-trigger
file with the cat
command, as follows:
root@88cef496c1a5:/# cat /proc/sysrq-trigger
The output should contain a "Permission Denied" error, similar to the following:
cat: /proc/sysrq-trigger: Permission denied
Applying a custom security profile
To apply a different security profile, use the apparmor=<profile-name>
command-line option when you run your container. The following example command
runs a container with a security profile called no-ping
:
docker run --rm -i --security-opt apparmor=no-ping debian:jessie bash -i
See Creating a custom security profile
later in this topic for more information on creating the no-ping
profile
specified in the example.
You can also specify unconfined
with the apparmor
option to indicate that
the container is to be run with no security profile, as in the following
example:
docker run --rm -it --security-opt apparmor=unconfined debian:jessie bash -i
Viewing the active AppArmor security profiles
You can see what AppArmor profile, if any, applies to the processes on your
Container-Optimized OS instance by inspecting the /proc/<pid>/attr/current
file, where <pid>
is the process ID.
Suppose you have the following processes running on your instance (shown by the
ps -ef | grep '[b]ash -i'
command):
root 1903 1897 0 21:58 pts/3 00:00:00 docker run --rm -it debian:jessie bash -i
root 1927 1913 0 21:58 pts/4 00:00:00 bash -i
root 1978 1001 0 22:01 pts/0 00:00:00 docker run --rm -it --security-opt apparmor=unconfined debian:jessie bash -i
root 2001 1988 0 22:01 pts/2 00:00:00 bash -i
If you inspect /proc/1927/attr/current
, you should see the following output
that indicates the process (pid 1927
) was run with the default Docker security
profile:
# cat /proc/1927/attr/current
docker-default (enforce)
If you inspect /proc/2001/attr/current
, you should see the following output
that indicates the process (pid 2001
) was run with no security profile (that
is, with the option apparmor=unconfined
):
# cat /proc/2001/attr/current
unconfined
Creating a custom security profile
If process requires a different security profile than docker-default
,
you can write your own custom profile. To use a custom profile, you must create
the profile file and then load that file into AppArmor.
For example, suppose you want a security profile that disallows all raw network
traffic. The following script creates a file for a security profile called
no-ping
at /etc/apparmor.d/no_raw_net
:
cat > /etc/apparmor.d/no_raw_net <<EOF
#include <tunables/global>
profile no-ping flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network inet tcp,
network inet udp,
network inet icmp,
deny network raw,
deny network packet,
file,
mount,
}
EOF
Once you've created the security profile file, you can use apparmor_parser
to
load the profile into AppArmor:
/sbin/apparmor_parser --replace --write-cache /etc/apparmor.d/no_raw_net
Once loaded, you can test the no-ping
profile as follows:
$ docker run --rm -i --security-opt apparmor=no-ping debian:jessie ping -c3 8.8.8.8
The command creates a container with the no-ping
security profile and attempts
to run ping
from within the container. The security profile should disallow
the traffic, resulting in an error like the following:
ping: Lacking privilege for raw socket.
To ensure that your custom security profile is present when your
Container-Optimized OS instance boots, and remains persistent across reboots,
you can use cloud-init
to install the profile in /etc/apparmor.d
. To do so,
add a cloud-config
script to your instance's metadata as the value of the
user-data
key.
The following cloud-config
script adds the no-ping
profile to
/etc/apparmor.d
:
#cloud-configs
write_files:
- path: /etc/apparmor.d/no_raw_net
permissions: 0644
owner: root
content: |
#include <tunables/global>
profile no-ping flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network inet tcp,
network inet udp,
network inet icmp,
deny network raw,
deny network packet,
file,
mount,
}
To ensure that your service file loads your custom profile into AppArmor and tells Docker to use it, run the following commands on your instance:
ExecStartPre=/sbin/apparmor_parser -r -W /etc/apparmor.d/no_raw_net
ExecStart=/usr/bin/docker run --security-opt apparmor=no-ping ...
After you've run the commands, reboot your instance, and you can then run your container confined by your custom AppArmor profile.