instruction: Explain AppArmor security profiles for Docker
output: Back
  Ask AI
  Start typing to search or try
  Contact support
  Manuals
  Get started
  Guides
  AppArmor security profiles for Docker
  Page options
  Copy page as Markdown for LLMs
  View page as plain text
  Ask questions with Docs AI
  Claude
  Open in Claude
  AppArmor (Application Armor) is a Linux security module that protects an
  operating system and its applications from security threats. To use it, a system
  administrator associates an AppArmor security profile with each program. Docker
  expects to find an AppArmor policy loaded and enforced.
  Docker automatically generates and loads a default profile for containers named
  docker-default
  . The Docker binary generates this profile in
  tmpfs
  and then
  loads it into the kernel.
  Note
  This profile is used on containers, not on the Docker daemon.
  A profile for the Docker Engine daemon exists but it is not currently installed
  with the
  packages. If you are interested in the source for the daemon
  profile, it is located in
  contrib/apparmor
  in the Docker Engine source repository.
  Understand the policies
  docker-default
  profile is the default for running containers. It is
  moderately protective while providing wide application compatibility. The
  profile is generated from the following
  template
  When you run a container, it uses the
  docker-default
  override it with the
  security-opt
  option. For example, the following
  explicitly specifies the default policy:
  docker run --rm -it --security-opt
  apparmor
  docker-default hello-world
  Load and unload profiles
  To load a new profile into AppArmor for use with containers:
  apparmor_parser -r -W /path/to/your_profile
  Then, run the custom profile with
  --security-opt
  docker run --rm -it --security-opt
  apparmor
  your_profile hello-world
  To unload a profile from AppArmor:
  unload the profile
  apparmor_parser -R /path/to/profile
  Resources for writing profiles
  The syntax for file globbing in AppArmor is a bit different than some other
  globbing implementations. It is highly suggested you take a look at some of the
  below resources with regard to AppArmor profile syntax.
  Quick Profile Language
  Globbing Syntax
  Nginx example profile
  In this example, you create a custom AppArmor profile for Nginx. Below is the
  custom profile.
  #include
  <tunables/global>
  profile
  docker
  nginx
  flags
  attach_disconnected
  mediate_deleted
  #include
  <abstractions/base>
  network
  inet
  network
  inet
  network
  inet
  icmp
  deny
  network
  deny
  network
  packet
  file
  umount
  deny
  /** wl,
  deny /boot/** wl,
  deny /dev/** wl,
  deny /etc/** wl,
  deny /home/** wl,
  deny /lib/** wl,
  deny /lib64/** wl,
  deny /media/** wl,
  deny /mnt/** wl,
  deny /opt/** wl,
  deny /proc/** wl,
  deny /root/** wl,
  deny /sbin/** wl,
  deny /srv/** wl,
  deny /tmp/** wl,
  deny /sys/** wl,
  deny /usr/** wl,
  audit /** w,
  /var/run/nginx.pid w,
  /usr/sbin/nginx ix,
  deny /bin/dash mrwklx,
  deny /bin/sh mrwklx,
  deny /usr/bin/top mrwklx,
  capability chown,
  capability dac_override,
  capability setuid,
  capability setgid,
  capability net_bind_service,
  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}/mem rwklx,
  deny @{PROC}/kmem rwklx,
  deny @{PROC}/kcore rwklx,
  deny mount,
  deny /sys/[^f]*/
  wklx
  deny
  wklx
  deny
  wklx
  deny
  wklx
  deny
  wklx
  deny
  firmware
  /** rwklx,
  deny /sys/kernel/security/** rwklx,
  Save the custom profile to disk in the
  /etc/apparmor.d/containers/docker-nginx
  file.
  The file path in this example is not a requirement. In production, you could
  use another.
  Load the profile.
  sudo apparmor_parser -r -W /etc/apparmor.d/containers/docker-nginx
  Run a container with the profile.
  To run nginx in detached mode:
  docker run --security-opt
  "apparmor=docker-nginx"
  -p 80:80 -d --name apparmor-nginx nginx
  Exec into the running container.
  docker container
  exec
  -it apparmor-nginx bash
  Try some operations to test the profile.
  root@6da5a2a930b9:~# ping 8.8.8.8
  ping: Lacking privilege for raw socket.
  root@6da5a2a930b9:/# top
  bash: /usr/bin/top: Permission denied
  root@6da5a2a930b9:~# touch ~/thing
  touch: cannot touch 'thing': Permission denied
  root@6da5a2a930b9:/# sh
  bash: /bin/sh: Permission denied
  root@6da5a2a930b9:/# dash
  bash: /bin/dash: Permission denied
  You just deployed a container secured with a custom apparmor profile.
  Debug AppArmor
  You can use
  dmesg
  to debug problems and
  aa-status
  check the loaded profiles.
  Use dmesg
  Here are some helpful tips for debugging any problems you might be facing with
  regard to AppArmor.
  AppArmor sends quite verbose messaging to
  dmesg
  . Usually an AppArmor line
  looks like the following:
  [ 5442.864673] audit: type=1400 audit(1453830992.845:37): apparmor="ALLOWED" operation="open" profile="/usr/bin/docker" name="/home/jessie/docker/man/man1/docker-attach.1" pid=10923 comm="docker" requested_mask="r" denied_mask="r" fsuid=1000 ouid=0
  In the above example, you can see
  profile=/usr/bin/docker
  . This means the
  user has the
  docker-engine
  (Docker Engine daemon) profile loaded.
  Look at another log line:
  [ 3256.689120] type=1400 audit(1405454041.341:73): apparmor="DENIED" operation="ptrace" profile="docker-default" pid=17651 comm="docker" requested_mask="receive" denied_mask="receive"
  This time the profile is
  docker-default
  , which is run on containers by
  default unless in
  privileged
  mode. This line shows that apparmor has denied
  ptrace
  in the container. This is exactly as expected.
  Use aa-status
  If you need to check which profiles are loaded, you can use
  aa-status
  . The
  output looks like:
  sudo aa-status
  apparmor module is loaded.
  14 profiles are loaded.
  1 profiles are in enforce mode.
  docker-default
  13 profiles are in complain mode.
  /usr/bin/docker
  /usr/bin/docker///bin/cat
  /usr/bin/docker///bin/ps
  /usr/bin/docker///sbin/apparmor_parser
  /usr/bin/docker///sbin/auplink
  /usr/bin/docker///sbin/blkid
  /usr/bin/docker///sbin/iptables
  /usr/bin/docker///sbin/mke2fs
  /usr/bin/docker///sbin/modprobe
  /usr/bin/docker///sbin/tune2fs
  /usr/bin/docker///sbin/xtables-multi
  /usr/bin/docker///sbin/zfs
  /usr/bin/docker///usr/bin/xz
  38 processes have profiles defined.
  37 processes are in enforce mode.
  docker-default (6044)
  docker-default (31899)
  1 processes are in complain mode.
  /usr/bin/docker (29756)
  0 processes are unconfined but have a profile defined.
  The above output shows that the
  docker-default
  profile running on various
  container PIDs is in
  enforce
  mode. This means AppArmor is actively blocking
  and auditing in
  dmesg
  anything outside the bounds of the
  docker-default
  profile.
  The output above also shows the
  /usr/bin/docker
  (Docker Engine daemon) profile
  is running in
  complain
  mode. This means AppArmor only logs to
  dmesg
  activity outside the bounds of the profile. (Except in the case of Ubuntu
  Trusty, where some interesting behaviors are enforced.)
  Contribute to Docker's AppArmor code
  Advanced users and package managers can find a profile for
  /usr/bin/docker
  (Docker Engine daemon) underneath
  contrib/apparmor
  in the Docker Engine source repository.
  docker-default
  profile for containers lives in
  profiles/apparmor