https://wiki.ubuntu.com/AppArmor
Apparmor can be used to limit different permissions for a userspace on side of the kernel. In other words we can decide what a program (... inside a docker container) can do. Ubuntu runs apparmor by default. This Readme targets docker and skips the aa_genprof workflow (see: https://www.youtube.com/watch?v=Uq1d60TLebE&t=155s) for standalone applications (Haven't found a way to use it with docker daemon)
To follow these steps you need to install apparmor-utils
sudo apt-get install -y apparmor-utils
Overview Linux capabilities: https://blog.container-solutions.com/linux-capabilities-in-practice
sudo apparmor_status
vim my_profile
sudo cp my_profile /etc/apparmor/my_profile
sudo apparmor_parser -r -W /etc/apparmor.d/containers/my_profile
A good tool for profile generation: https://github.com/genuinetools/bane
Apparmor profiles can have different modes. We can decide if the profile is active (enfore) or if it just complains.
sudo aa-enforce /etc/apparmar.d/my_profile
sudo aa-complain /etc/apparmar.d/my_profile
We can check rule violation in logs
grep -i complain /var/log/syslog
On Ubuntu docker per default applies a standard profile called docker-default
. As one cannot find this profile readable on disc (See: https://lucascavalare.github.io/2020-03-15-AppArmor_Docker/), this is how it looks like:
#include <tunables/global>
profile docker-default flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network,
capability,
file,
umount,
signal (receive) peer=unconfined
,
signal (send,receive) peer=docker-default,
deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir)
# deny write to files not in /proc/<number>/** or /proc/sys/**
deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w,
deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel)
deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/
deny @{PROC}/sysrq-trigger rwklx,
deny @{PROC}/kcore rwklx,
deny mount,
deny /sys/[^f]*/** wklx,
deny /sys/f[^s]*/** wklx,
deny /sys/fs/[^c]*/** wklx,
deny /sys/fs/c[^g]*/** wklx,
deny /sys/fs/cg[^r]*/** wklx,
deny /sys/firmware/** rwklx,
deny /sys/kernel/security/** rwklx,
# suppress ptrace denials when using 'docker ps' or using 'ps' inside a container
ptrace (trace,read) peer=docker-default,
}
We can start from this default template for defining more restrictive profiles.
sudo cp docker-default /etc/apparmor.d/containers/docker-default-secure
sudo apparmor_parser -r -W /etc/apparmor.d/containers/docker-default-secure
sudo vim /etc/apparmor.d/containers/docker-default-secure
# make changes
for example deny access to read/write to /tmp/a/**
deny /tmp/a/** rwlx,
or deny some linux capability, which is interesting to cut permissions for a root user inside the container:
deny capability fsetid,
After changing the profile we need to reload it:
sudo apparmor_parser -r /etc/apparmor.d/containers/docker-default-secure
reload, changes are immediately applied to containers
docker run --security-opt="apparmor:docker-default-secure" -d nginx
In case of a violation you will see a denied message in syslog or the containers stdout.
or in docker-compose:
# Nginx is serving django static and media files and proxies to django and geonode
geonode:
image: geonode/nginx:3.x
build: ./scripts/docker/nginx/
container_name: nginx4${COMPOSE_PROJECT_NAME}
environment:
- HTTPS_HOST=${HTTPS_HOST}
- HTTP_HOST=${HTTP_HOST}
- HTTPS_PORT=${HTTPS_PORT}
- HTTP_PORT=${HTTP_PORT}
- LETSENCRYPT_MODE=${LETSENCRYPT_MODE}
- RESOLVER=127.0.0.11
ports:
- "${HTTP_PORT}:80"
- "${HTTPS_PORT}:443"
volumes:
- nginx-confd:/etc/nginx
- nginx-certificates:/geonode-certificates
- statics:/mnt/volumes/statics
restart: on-failure
security_opt:
- apparmor:docker-default-secure
... try to read the user capabilities
https://man7.org/linux/man-pages/man7/capabilities.7.html
apt update
apt-get install libcap2-bin
capsh --print
or try to create a file (see deny example above)
touch /tmp/a/