Signed-off-by: Jess Frazelle <jess@mesosphere.com>
| ... | ... |
@@ -20,8 +20,8 @@ Docker automatically loads container profiles. The Docker binary installs |
| 20 | 20 |
a `docker-default` profile in the `/etc/apparmor.d/docker` file. This profile |
| 21 | 21 |
is used on containers, _not_ on the Docker Daemon. |
| 22 | 22 |
|
| 23 |
-A profile for the Docker Engine Daemon exists but it is not currently installed |
|
| 24 |
-with the deb packages. If you are interested in the source for the Daemon |
|
| 23 |
+A profile for the Docker Engine daemon exists but it is not currently installed |
|
| 24 |
+with the `deb` packages. If you are interested in the source for the daemon |
|
| 25 | 25 |
profile, it is located in |
| 26 | 26 |
[contrib/apparmor](https://github.com/docker/docker/tree/master/contrib/apparmor) |
| 27 | 27 |
in the Docker Engine source repository. |
| ... | ... |
@@ -72,15 +72,15 @@ explicitly specifies the default policy: |
| 72 | 72 |
$ docker run --rm -it --security-opt apparmor=docker-default hello-world |
| 73 | 73 |
``` |
| 74 | 74 |
|
| 75 |
-## Loading and Unloading Profiles |
|
| 75 |
+## Load and unload profiles |
|
| 76 | 76 |
|
| 77 |
-To load a new profile into AppArmor, for use with containers: |
|
| 77 |
+To load a new profile into AppArmor for use with containers: |
|
| 78 | 78 |
|
| 79 |
-``` |
|
| 79 |
+```bash |
|
| 80 | 80 |
$ apparmor_parser -r -W /path/to/your_profile |
| 81 | 81 |
``` |
| 82 | 82 |
|
| 83 |
-Then you can run the custom profile with `--security-opt` like so: |
|
| 83 |
+Then, run the custom profile with `--security-opt` like so: |
|
| 84 | 84 |
|
| 85 | 85 |
```bash |
| 86 | 86 |
$ docker run --rm -it --security-opt apparmor=your_profile hello-world |
| ... | ... |
@@ -97,39 +97,174 @@ $ apparmor_parser -R /path/to/profile |
| 97 | 97 |
$ /etc/init.d/apparmor start |
| 98 | 98 |
``` |
| 99 | 99 |
|
| 100 |
-## Debugging AppArmor |
|
| 100 |
+### Resources for writing profiles |
|
| 101 |
+ |
|
| 102 |
+The syntax for file globbing in AppArmor is a bit different than some other |
|
| 103 |
+globbing implementations. It is highly suggested you take a look at some of the |
|
| 104 |
+below resources with regard to AppArmor profile syntax. |
|
| 105 |
+ |
|
| 106 |
+- [Quick Profile Language](http://wiki.apparmor.net/index.php/QuickProfileLanguage) |
|
| 107 |
+- [Globbing Syntax](http://wiki.apparmor.net/index.php/AppArmor_Core_Policy_Reference#AppArmor_globbing_syntax) |
|
| 108 |
+ |
|
| 109 |
+## Nginx example profile |
|
| 110 |
+ |
|
| 111 |
+In this example, you create a custom AppArmor profile for Nginx. Below is the |
|
| 112 |
+custom profile. |
|
| 113 |
+ |
|
| 114 |
+``` |
|
| 115 |
+#include <tunables/global> |
|
| 116 |
+ |
|
| 117 |
+ |
|
| 118 |
+profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
|
|
| 119 |
+ #include <abstractions/base> |
|
| 120 |
+ |
|
| 121 |
+ network inet tcp, |
|
| 122 |
+ network inet udp, |
|
| 123 |
+ network inet icmp, |
|
| 124 |
+ |
|
| 125 |
+ deny network raw, |
|
| 126 |
+ |
|
| 127 |
+ deny network packet, |
|
| 128 |
+ |
|
| 129 |
+ file, |
|
| 130 |
+ umount, |
|
| 131 |
+ |
|
| 132 |
+ deny /bin/** wl, |
|
| 133 |
+ deny /boot/** wl, |
|
| 134 |
+ deny /dev/** wl, |
|
| 135 |
+ deny /etc/** wl, |
|
| 136 |
+ deny /home/** wl, |
|
| 137 |
+ deny /lib/** wl, |
|
| 138 |
+ deny /lib64/** wl, |
|
| 139 |
+ deny /media/** wl, |
|
| 140 |
+ deny /mnt/** wl, |
|
| 141 |
+ deny /opt/** wl, |
|
| 142 |
+ deny /proc/** wl, |
|
| 143 |
+ deny /root/** wl, |
|
| 144 |
+ deny /sbin/** wl, |
|
| 145 |
+ deny /srv/** wl, |
|
| 146 |
+ deny /tmp/** wl, |
|
| 147 |
+ deny /sys/** wl, |
|
| 148 |
+ deny /usr/** wl, |
|
| 149 |
+ |
|
| 150 |
+ audit /** w, |
|
| 151 |
+ |
|
| 152 |
+ /var/run/nginx.pid w, |
|
| 153 |
+ |
|
| 154 |
+ /usr/sbin/nginx ix, |
|
| 155 |
+ |
|
| 156 |
+ deny /bin/dash mrwklx, |
|
| 157 |
+ deny /bin/sh mrwklx, |
|
| 158 |
+ deny /usr/bin/top mrwklx, |
|
| 159 |
+ |
|
| 160 |
+ |
|
| 161 |
+ capability chown, |
|
| 162 |
+ capability dac_override, |
|
| 163 |
+ capability setuid, |
|
| 164 |
+ capability setgid, |
|
| 165 |
+ capability net_bind_service, |
|
| 166 |
+ |
|
| 167 |
+ deny @{PROC}/{*,**^[0-9*],sys/kernel/shm*} wkx,
|
|
| 168 |
+ deny @{PROC}/sysrq-trigger rwklx,
|
|
| 169 |
+ deny @{PROC}/mem rwklx,
|
|
| 170 |
+ deny @{PROC}/kmem rwklx,
|
|
| 171 |
+ deny @{PROC}/kcore rwklx,
|
|
| 172 |
+ deny mount, |
|
| 173 |
+ deny /sys/[^f]*/** wklx, |
|
| 174 |
+ deny /sys/f[^s]*/** wklx, |
|
| 175 |
+ deny /sys/fs/[^c]*/** wklx, |
|
| 176 |
+ deny /sys/fs/c[^g]*/** wklx, |
|
| 177 |
+ deny /sys/fs/cg[^r]*/** wklx, |
|
| 178 |
+ deny /sys/firmware/efi/efivars/** rwklx, |
|
| 179 |
+ deny /sys/kernel/security/** rwklx, |
|
| 180 |
+} |
|
| 181 |
+``` |
|
| 182 |
+ |
|
| 183 |
+1. Save the custom profile to disk in the |
|
| 184 |
+`/etc/apparmor.d/containers/docker-nginx` file. |
|
| 185 |
+ |
|
| 186 |
+ The file path in this example is not a requirement. In production, you could |
|
| 187 |
+ use another. |
|
| 188 |
+ |
|
| 189 |
+2. Load the profile. |
|
| 190 |
+ |
|
| 191 |
+ ```bash |
|
| 192 |
+ $ sudo apparmor_parser -r -W /etc/apparmor.d/containers/docker-nginx |
|
| 193 |
+ ``` |
|
| 194 |
+ |
|
| 195 |
+3. Run a container with the profile. |
|
| 196 |
+ |
|
| 197 |
+ To run nginx in detached mode: |
|
| 198 |
+ |
|
| 199 |
+ ```bash |
|
| 200 |
+ $ docker run --security-opt "apparmor=docker-nginx" \ |
|
| 201 |
+ -p 80:80 -d --name apparmor-nginx nginx |
|
| 202 |
+ ``` |
|
| 203 |
+ |
|
| 204 |
+4. Exec into the running container |
|
| 205 |
+ |
|
| 206 |
+ ```bash |
|
| 207 |
+ $ docker exec -it apparmor-nginx bash |
|
| 208 |
+ ``` |
|
| 209 |
+ |
|
| 210 |
+5. Try some operations to test the profile. |
|
| 211 |
+ |
|
| 212 |
+ ```bash |
|
| 213 |
+ root@6da5a2a930b9:~# ping 8.8.8.8 |
|
| 214 |
+ ping: Lacking privilege for raw socket. |
|
| 215 |
+ |
|
| 216 |
+ root@6da5a2a930b9:/# top |
|
| 217 |
+ bash: /usr/bin/top: Permission denied |
|
| 218 |
+ |
|
| 219 |
+ root@6da5a2a930b9:~# touch ~/thing |
|
| 220 |
+ touch: cannot touch 'thing': Permission denied |
|
| 221 |
+ |
|
| 222 |
+ root@6da5a2a930b9:/# sh |
|
| 223 |
+ bash: /bin/sh: Permission denied |
|
| 224 |
+ |
|
| 225 |
+ root@6da5a2a930b9:/# dash |
|
| 226 |
+ bash: /bin/dash: Permission denied |
|
| 227 |
+ ``` |
|
| 228 |
+ |
|
| 229 |
+ |
|
| 230 |
+Congrats! You just deployed a container secured with a custom apparmor profile! |
|
| 231 |
+ |
|
| 232 |
+ |
|
| 233 |
+## Debug AppArmor |
|
| 234 |
+ |
|
| 235 |
+You can use `demsg` to debug problems and `aa-status` check the loaded profiles. |
|
| 101 | 236 |
|
| 102 |
-### Using `dmesg` |
|
| 237 |
+### Use dmesg |
|
| 103 | 238 |
|
| 104 | 239 |
Here are some helpful tips for debugging any problems you might be facing with |
| 105 | 240 |
regard to AppArmor. |
| 106 | 241 |
|
| 107 | 242 |
AppArmor sends quite verbose messaging to `dmesg`. Usually an AppArmor line |
| 108 |
-will look like the following: |
|
| 243 |
+looks like the following: |
|
| 109 | 244 |
|
| 110 | 245 |
``` |
| 111 | 246 |
[ 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 |
| 112 | 247 |
``` |
| 113 | 248 |
|
| 114 |
-In the above example, the you can see `profile=/usr/bin/docker`. This means the |
|
| 249 |
+In the above example, you can see `profile=/usr/bin/docker`. This means the |
|
| 115 | 250 |
user has the `docker-engine` (Docker Engine Daemon) profile loaded. |
| 116 | 251 |
|
| 117 | 252 |
> **Note:** On version of Ubuntu > 14.04 this is all fine and well, but Trusty |
| 118 | 253 |
> users might run into some issues when trying to `docker exec`. |
| 119 | 254 |
|
| 120 |
-Let's look at another log line: |
|
| 255 |
+Look at another log line: |
|
| 121 | 256 |
|
| 122 | 257 |
``` |
| 123 | 258 |
[ 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" |
| 124 | 259 |
``` |
| 125 | 260 |
|
| 126 | 261 |
This time the profile is `docker-default`, which is run on containers by |
| 127 |
-default unless in `privileged` mode. It is telling us, that apparmor has denied |
|
| 128 |
-`ptrace` in the container. This is great. |
|
| 262 |
+default unless in `privileged` mode. This line shows that apparmor has denied |
|
| 263 |
+`ptrace` in the container. This is exactly as expected. |
|
| 129 | 264 |
|
| 130 |
-### Using `aa-status` |
|
| 265 |
+### Use aa-status |
|
| 131 | 266 |
|
| 132 |
-If you need to check which profiles are loaded you can use `aa-status`. The |
|
| 267 |
+If you need to check which profiles are loaded, you can use `aa-status`. The |
|
| 133 | 268 |
output looks like: |
| 134 | 269 |
|
| 135 | 270 |
```bash |
| ... | ... |
@@ -162,17 +297,17 @@ apparmor module is loaded. |
| 162 | 162 |
0 processes are unconfined but have a profile defined. |
| 163 | 163 |
``` |
| 164 | 164 |
|
| 165 |
-In the above output you can tell that the `docker-default` profile running on |
|
| 166 |
-various container PIDs is in `enforce` mode. This means AppArmor will actively |
|
| 167 |
-block and audit in `dmesg` anything outside the bounds of the `docker-default` |
|
| 165 |
+The above output shows that the `docker-default` profile running on various |
|
| 166 |
+container PIDs is in `enforce` mode. This means AppArmor is actively blocking |
|
| 167 |
+and auditing in `dmesg` anything outside the bounds of the `docker-default` |
|
| 168 | 168 |
profile. |
| 169 | 169 |
|
| 170 |
-The output above also shows the `/usr/bin/docker` (Docker Engine Daemon) |
|
| 171 |
-profile is running in `complain` mode. This means AppArmor will _only_ log to |
|
| 172 |
-`dmesg` activity outside the bounds of the profile. (Except in the case of |
|
| 173 |
-Ubuntu Trusty, where we have seen some interesting behaviors being enforced.) |
|
| 170 |
+The output above also shows the `/usr/bin/docker` (Docker Engine daemon) profile |
|
| 171 |
+is running in `complain` mode. This means AppArmor _only_ logs to `dmesg` |
|
| 172 |
+activity outside the bounds of the profile. (Except in the case of Ubuntu |
|
| 173 |
+Trusty, where some interesting behaviors are enforced.) |
|
| 174 | 174 |
|
| 175 |
-## Contributing to AppArmor code in Docker |
|
| 175 |
+## Contribute Docker's AppArmor code |
|
| 176 | 176 |
|
| 177 | 177 |
Advanced users and package managers can find a profile for `/usr/bin/docker` |
| 178 | 178 |
(Docker Engine Daemon) underneath |