Skip to content

Commit 894f31d

Browse files
author
Mano Marks
authored
Merge pull request docker#229 from nigelpoulton/nigel
Adding new files for Dockercon security workshop and updating some ol…
2 parents 370b002 + bcc5f9e commit 894f31d

File tree

17 files changed

+1529
-63
lines changed

17 files changed

+1529
-63
lines changed

security/README.md

+10-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@
22

33
This directory contains tutorials on how to take advantage of a non-exhaustive collection of Docker security features. Moreover, the tutorials are designed to explain and demonstrate the strong security defaults in Docker for each feature.
44

5+
## Docker
6+
* [Content Trust](trust/README.md)
7+
* [Content Trust Basics](trust-basics/README.md)
8+
* [Secrets Management](secrets/README.md)
9+
* [Secrets Management with Docker Datacenter](secrets-ddc/README.md)
10+
* [Secure Networking Basics](networking/README.md)
11+
* [Security Scanning](scanning/README.md)
12+
* [Swarm Mode Security Basics](swarm/README.md)
513

14+
## Linux
615
* [AppArmor](apparmor/README.md)
716
* [Capabilities](capabilities/README.md)
8-
* [Content Trust](trust/README.md)
917
* [Control Groups](cgroups/README.md)
1018
* [Seccomp](seccomp/README.md)
11-
* [User Namespaces](userns/README.md)
19+
* [User Namespaces](userns/README.md)

security/apparmor/README.md

+58-39
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
> **Time**: Approximately 25 minutes
66
7-
AppArmor (Application Armor) is a Linux Security Module (LSM). It protects the operating system by applying profiles to individual applications. In contrast to managing *capabilities* with `CAP_DROP` and syscalls with *seccomp*, AppArmor allows for much finer-grained control. For example, AppArmor can restrict file operations on specified paths.
7+
AppArmor (Application Armor) is a Linux Security Module (LSM). It protects the operating system by applying profiles to individual applications or containers. In contrast to managing *capabilities* with `CAP_DROP` and syscalls with *seccomp*, AppArmor allows for much finer-grained control. For example, AppArmor can restrict file operations on specified paths.
88

99
In this lab you will learn the basics of AppArmor and how to use it with Docker for improved security.
1010

@@ -24,7 +24,7 @@ You will need all of the following to complete this lab:
2424
- A Linux-based Docker Host with AppArmor enabled in the kernel (most Debian-based distros)
2525
- Docker 1.12 or higher
2626

27-
The following command shows you how to check if AppArmor is enabled in your system's kernel:
27+
The following command shows you how to check if AppArmor is enabled in your system's kernel and available to Docker:
2828

2929
Check from Docker 1.12 or higher
3030
```
@@ -36,11 +36,11 @@ The following command shows you how to check if AppArmor is enabled in your syst
3636

3737
# <a name="primer"></a>Step 1: AppArmor primer
3838

39-
By default, Docker applies the `docker-default` AppArmor profile to new containers. This profile is located in `/etc/apparmor.d/docker/` and you can find more information about it in the [documentation](https://docs.docker.com/engine/security/apparmor/#understand-the-policies).
39+
By default, Docker applies the `docker-default` AppArmor profile to new **containers**. In Docker 1.13 and later this is profile is created in `tmpfs` and then loaded into the kernel. On Docker 1.12 and earlier it is located in `/etc/apparmor.d/docker/`. You can find more information about it in the [documentation](https://docs.docker.com/engine/security/apparmor/#understand-the-policies).
4040

4141
Here are some quick pointers for how to understand AppArmor profiles:
4242

43-
- `Include` statements, such as `#include <abstractions/base>`, behave just like their `C` counterparts by expanding to additional AppArmor profile contents.
43+
- `include` statements, such as `#include <abstractions/base>`, behave just like their `C` counterparts by expanding to additional AppArmor profile contents.
4444

4545
- AppArmor `deny` rules have precedence over `allow` and `owner` rules. This means that `deny` rules cannot be overridden by subsequent `allow` or `owner` rules for the same resource. Moreover, an `allow` will be overridden by a subsequent `deny` on the same resource
4646

@@ -52,7 +52,7 @@ For more information, see the [official AppArmor documentation wiki](http://wiki
5252

5353
In this step you will check the status of AppArmor on your Docker Host and learn how to identify whether or not Docker containers are running with an AppArmor profile.
5454

55-
1. View the status of AppArmor on your Docker Host with the `apparmor_status` command.
55+
1. View the status of AppArmor on your Docker Host with the `apparmor_status` command. You may need to preceed the command with `sudo`.
5656

5757
```
5858
$ apparmor_status
@@ -77,22 +77,20 @@ In this step you will check the status of AppArmor on your Docker Host and learn
7777
0 processes are unconfined but have a profile defined.
7878
```
7979

80-
The command may require admin credentials.
81-
8280
Notice the `docker-default` profile is in enforce mode. This is the AppArmor profile that will be applied to new containers unless overridden with the `--security-opts` flag.
8381

8482
2. Run a new container and put it in the back ground.
8583

8684
```
87-
$ sudo docker run -dit alpine sh
85+
$ docker container run -dit --name apparmor1 alpine sh
8886
```
8987

9088
3. Confirm that the container is running.
9189

9290
```
93-
$ sudo docker ps
94-
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
95-
1bb16561bc06 alpine "sh" 2 seconds ago Up 2 seconds sick_booth
91+
$ docker container ls
92+
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
93+
1bb16561bc06 alpine "sh" 2 secs ago Up 2 seconds apparmor1
9694
```
9795

9896
4. Run the `apparmor_status` command again.
@@ -120,10 +118,8 @@ In this step you will check the status of AppArmor on your Docker Host and learn
120118

121119
5. Stop and remove the container started in the previous steps.
122120

123-
The example below uses the Container ID "1bb16561bc06". This will be different in your environment.
124-
125121
```
126-
$ sudo docker rm -f 1bb16561bc06
122+
$ docker container rm -f appamror1
127123
1bb16561bc06
128124
```
129125

@@ -136,22 +132,24 @@ In this step you will see how to run a new container without an AppArmor profile
136132
1. If you haven't already done so, stop and remove all containers on your system.
137133

138134
```
139-
$ sudo docker rm -f $(docker ps -aq)
135+
$ docker container rm -f $(docker container ls -aq)
140136
```
141137

142138
2. Use the `--security-opt apparmor=unconfined` flag to start a new container in the background without an AppArmor profile.
143139

144140
```
145-
$ sudo docker run -dit --security-opt apparmor=unconfined alpine sh
146-
ace79581a19ace7b85009480a64fd378d43844f82559bd1178fce431e292277d
141+
$ docker container run -dit --name apparmor2 \
142+
--security-opt apparmor=unconfined \
143+
alpine sh
144+
ace79581a19a....559bd1178fce431e292277d
147145
```
148146

149147
3. Confirm that the container is running.
150148

151149
```
152-
$ sudo docker ps
153-
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
154-
ace79581a19a alpine "sh" 41 seconds ago Up 40 seconds sharp_knuth
150+
$ docker container ls
151+
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
152+
ace79581a19a alpine "sh" 41 secs ago Up 40 secs apparmor2
155153
```
156154

157155
4. Use the `apparmor_status` command to verify that the new container is not running with an AppArmor profile.
@@ -170,31 +168,29 @@ ace79581a19a alpine "sh" 41 seconds ago
170168

171169
5. Stop and remove the container started in the previous steps.
172170

173-
The example below uses the Container ID "ace79581a19a". This will be different in your environment.
174-
175171
```
176-
$ sudo docker rm -f ace79581a19a
172+
$ docker container rm -f apparmor2
177173
ace79581a19a
178174
```
179175

180176
In this step you learned that the `--security-opt apparmor=unconfined` flag will start a new container without an AppArmor profile.
181177

182178
# <a name="depth"></a>Step 4: AppArmor and defense in depth
183179

184-
Defense in depth is a model where multiple different lines of defense work together to provide increased overall defensive capabilities. Docker uses AppArmor, seccomp, and Capabilities to form a deep defense system.
180+
Defense in depth is a model where multiple different lines of defense work together to provide increased overall defensive capabilities. Docker uses many Linux technologies, such as AppArmor, seccomp, and Capabilities, to form a deep defense system.
185181

186182
In this step you will see how AppArmor can protect a Docker Host even when other lines of defense such as seccomp and Capabilities are not effective.
187183

188184
1. If you haven't already done so, stop and remove all containers on your system.
189185

190186
```
191-
$ sudo docker rm -f $(docker ps -aq)
187+
$ docker container rm -f $(docker container ls -aq)
192188
```
193189

194190
2. Start a new Ubuntu container with seccomp disabled and the `SYS_ADMIN` *capability* added.
195191

196192
```
197-
$ sudo docker run --rm -it --cap-add SYS_ADMIN --security-opt seccomp=unconfined ubuntu sh
193+
$ docker container run --rm -it --cap-add SYS_ADMIN --security-opt seccomp=unconfined ubuntu sh
198194
#
199195
```
200196

@@ -211,12 +207,12 @@ In this step you will see how AppArmor can protect a Docker Host even when other
211207

212208
The operation failed because the `default-docker` AppArmor profile denied the operation.
213209

214-
4. Exit the container.
210+
4. Exit the container using the `exit` command.
215211

216212
5. Confirm that it was the `default-docker` AppArmor profile that denied the operation by starting a new container without an AppArmor profile and retrying the same operation.
217213

218214
```
219-
$ sudo docker run --rm -it --cap-add SYS_ADMIN --security-opt seccomp=unconfined --security-opt apparmor=unconfined ubuntu sh
215+
$ docker container run --rm -it --cap-add SYS_ADMIN --security-opt seccomp=unconfined --security-opt apparmor=unconfined ubuntu sh
220216
221217
# mkdir 1; mkdir 2; mount --bind 1 2
222218
# ls -l
@@ -230,6 +226,8 @@ In this step you will see how AppArmor can protect a Docker Host even when other
230226

231227
The operation succeeded this time. This proves that it was the `default-docker` AppArmor profile that prevented the operation in the previous attempt.
232228

229+
6. Exit the container with the `exit` command.
230+
233231
In this step you have seen how AppArmor works together with seccomp and Capabilities to form a defense in depth security model for Docker. You saw a scenario where even with seccomp and Capabilities not preventing an action, AppArmor still prevented it.
234232

235233
# <a name="custom"></a>Step 5: Custom AppArmor profile
@@ -265,7 +263,7 @@ In this step we'll show how a custom AppArmor profile could have protected Docke
265263
3. View the contents of the Docker Compose YAML file.
266264

267265
```
268-
cat docker-compose.yml
266+
$ cat docker-compose.yml
269267
wordpress:
270268
image: endophage/wordpress:lean
271269
links:
@@ -299,8 +297,12 @@ mysql:
299297

300298
4. Bring the application up.
301299

300+
It may take a minute or two to bring the application up. Once the application is up you will need to hit the <Return> key to bring the prompt to the foreground.
301+
302+
You may need to install `docker-compose` to complete this step. If your lab machine does not already have Docker Compose isntalled, you can install it with the following commands `sudo apt-get update` and `sudo apt-get install docker-compose`.
303+
302304
```
303-
$ sudo docker-compose up &
305+
$ docker-compose up &
304306
Pulling mysql (mariadb:10.1.10)...
305307
10.1.10: Pulling from library/mariadb
306308
03e1855d4f31: Pull complete
@@ -330,19 +332,28 @@ In the next few steps you'll apply a new Apparmor profile to a new WordPress con
330332

331333
9. Bring the WordPress application down.
332334

333-
Run this command from the shell of your Docker Host, not the shell of the `wordpress` container.
335+
Run these commands from the shell of your Docker Host, not the shell of the `wordpress` container.
334336

335337
```
336-
$ sudo docker-compose down
337-
Stopping wordpress_wordpress_1 ...
338-
Stopping wordpress_mysql_1 ...
339-
<SNIP>
338+
$ docker-compose stop
339+
Stopping wordpress_wordpress_1 ... done
340340
Stopping wordpress_mysql_1 ... done
341+
$
342+
$ docker-compose rm
343+
Going to remove wordpress_wordpress_1, wordpress_mysql_1
344+
Are you sure? [yN] y
341345
Removing wordpress_wordpress_1 ... done
342346
Removing wordpress_mysql_1 ... done
343347
```
344348

345-
10. Add the `wparmor` profile to the `wordpress` service in the `docker-compose.yml` file.
349+
10. Add the `wparmor` profile to the `wordpress` service in the `docker-compose.yml` file. You do this by deleting the two lines starting with `#` and replacing them with the following two lines:
350+
351+
```
352+
security_opt:
353+
- apparmor=wparmor
354+
```
355+
356+
Be sure to add the lines with the correct indentation as shown below.
346357

347358
```
348359
wordpress:
@@ -387,7 +398,7 @@ In the next few steps you'll apply a new Apparmor profile to a new WordPress con
387398
13. Bring the Docker Compose WordPress app back up.
388399

389400
```
390-
$ sudo docker-compose up &
401+
$ docker-compose up &
391402
Pulling mysql (mariadb:10.1.10)...
392403
10.1.10: Pulling from library/mariadb
393404
03e1855d4f31: Pull complete
@@ -401,7 +412,7 @@ In the next few steps you'll apply a new Apparmor profile to a new WordPress con
401412
14. Verify that the app is up.
402413

403414
```
404-
$ sudo docker-compose ps
415+
$ docker-compose ps
405416
Name Command State Ports
406417
--------------------------------------------------------------------------------------
407418
wordpress_mysql_1 /docker-entrypoint.sh mysqld Up 0.0.0.0:32770->3306/tcp
@@ -413,7 +424,15 @@ In the next few steps you'll apply a new Apparmor profile to a new WordPress con
413424
16. Bring the application down.
414425

415426
```
416-
$ sudo docker-compose down
427+
$ docker-compose stop
428+
Stopping wordpress_wordpress_1 ... done
429+
Stopping wordpress_mysql_1 ... done
430+
$
431+
$ docker-compose rm
432+
Going to remove wordpress_wordpress_1, wordpress_mysql_1
433+
Are you sure? [yN] y
434+
Removing wordpress_wordpress_1 ... done
435+
Removing wordpress_mysql_1 ... done
417436
```
418437

419438
Congratulations! You've secured a WordPress instance against adding malicious plugins :)

security/capabilities/README.md

+10-10
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ You will complete the following steps as part of this lab.
1717

1818
You will need all of the following to complete this lab:
1919

20-
- A Linux-based Docker Host running Docker 1.12 or higher
20+
- A Linux-based Docker Host running Docker 1.13 or higher
2121

2222
# <a name="cap_intro"></a>Step 1: Introduction to capabilities
2323

@@ -87,23 +87,23 @@ In this step you will start various new containers. Each time you will use the c
8787
1. Start a new container and prove that the container's root account can change the ownership of files.
8888

8989
```
90-
$ sudo docker run --rm -it alpine chown nobody /
90+
$ docker container run --rm -it alpine chown nobody /
9191
```
9292

9393
The command gives no return code indicating that the operation succeeded. The command works because the default behavior is for new containers to be started with a root user. This root user has the CAP_CHOWN capability by default.
9494

9595
2. Start another new container and drop all capabilities for the containers root account other than the CAP\_CHOWN capability. Remember that Docker does not use the "CAP_" prefix when addressing capability constants.
9696

9797
```
98-
$ sudo docker run --rm -it --cap-drop ALL --cap-add CHOWN alpine chown nobody /
98+
$ docker container run --rm -it --cap-drop ALL --cap-add CHOWN alpine chown nobody /
9999
```
100100

101101
This command also gives no return code, indicating a successful run. The operation succeeds because although you dropped all capabilities for the container's `root` account, you added the `chown` capability back. The `chown` capability is all that is needed to change the ownership of a file.
102102

103103
3. Start another new container and drop only the `CHOWN` capability form its root account.
104104

105105
```
106-
$ sudo docker run --rm -it --cap-drop CHOWN alpine chown nobody /
106+
$ docker container run --rm -it --cap-drop CHOWN alpine chown nobody /
107107
chown: /: Operation not permitted
108108
```
109109

@@ -112,7 +112,7 @@ In this step you will start various new containers. Each time you will use the c
112112
4. Create another new container and try adding the `CHOWN` capability to the non-root user called `nobody`. As part of the same command try and change the ownership of a file or folder.
113113

114114
```
115-
$ sudo docker run --rm -it --cap-add chown -u nobody alpine chown nobody /
115+
$ docker container run --rm -it --cap-add chown -u nobody alpine chown nobody /
116116
chown: /: Operation not permitted
117117
```
118118

@@ -130,7 +130,7 @@ There are two main sets of tools for managing capabilities:
130130

131131
Below are some useful commands from both.
132132

133-
> You may need to manually install the packages required for some of these commands.
133+
> You may need to manually install the packages required for some of these commands.`sudo apt-get install libcap-dev`, `sudo apt-get install libcap-ng-dev`, `sudo apt-get install libcap-ng-utils`.
134134
135135
## **libcap**
136136

@@ -151,7 +151,7 @@ The remainder of this step will show you some examples of `libcap` and `libcap-n
151151
The following command will start a new container using Alpine Linux, install the `libcap` package and then list capabilities.
152152

153153
```
154-
$ sudo docker run --rm -it alpine sh -c 'apk add -U libcap; capsh --print'
154+
$ docker container run --rm -it alpine sh -c 'apk add -U libcap; capsh --print'
155155
156156
(1/1) Installing libcap (2.25-r0)
157157
Executing busybox-1.24.2-r9.trigger
@@ -167,7 +167,7 @@ The following command will start a new container using Alpine Linux, install the
167167
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
168168
```
169169

170-
**Current** is multiple sets separated by spaces. Multiple capabilities within the same set are separated by commas `,`. The letters following the `+` at the end of each set are as follows:
170+
In the output above, **Current** is multiple sets separated by spaces. Multiple capabilities within the same *set* are separated by commas `,`. The letters following the `+` at the end of each set are as follows:
171171
- `e` is effective
172172
- `i` is inheritable
173173
- `p` is permitted
@@ -203,7 +203,7 @@ usage: capsh [args ...]
203203
```
204204

205205
> Warning:
206-
> `--drop` sounds like what you want to do, but it only affects the bounding set. This can be very confusing because it doesn't actually take away the capability from the effective or inheritable set. You almost always want to use `--caps`.
206+
> `--drop` sounds like what you want to do, but it only affects the bounding set. This can be very confusing because it doesn't actually take away the capability from the effective or inheritable set. You almost always want to use `--caps`, `sudo apt-get install attr`.
207207
208208
### Modifying capabilities
209209

@@ -214,7 +214,7 @@ Libcap and libcap-ng can both be used to modify capabilities.
214214
The command below shows how to set the CAP_NET_RAW capability as *effective* and *permitted* on the file represented by `$file`. The `setcap` command calls on libcap to do this.
215215

216216
```
217-
$ setcap cap_net_raw=ep $file
217+
$ sudo setcap cap_net_raw=ep $file
218218
```
219219

220220
2. Use libcap-ng to set the capabilities of a file.

0 commit comments

Comments
 (0)