Confine User Guide

This is the user guide for working with Confine. A more detailed step-by-step tutorial can be found here.

NOTE: It is assumed that the Installation Guide has been followed.

There are four main sections in this guide:

Docker Commands Guide

Working with Docker Commands

Confine generates Seccomp profiles which can be used in launching Docker containers. In this section, we will show the basics of running and killing containers. All Docker commands should be run as root, so we will be using sudo.

1. View list of containers:

sudo docker container ls -a

The output will show a list of containers both running and killed. The format is as follows:

CONTAINER ID        IMAGE         COMMAND                 CREATED        STATUS              PORTS               NAMES

2. Let's launch a container with the default Seccomp policy. The format of the command format is: sudo docker run --name [any-name] -td [docker-image-name].

sudo docker run --name test1 -td nginx

3. Now let's view the list of containers again:

sudo docker container ls -a

The output will show a list of containers both running and killed. The format is as follows:

CONTAINER ID        IMAGE        COMMAND                  CREATED        STATUS              PORTS               NAMES
[long hash]         nginx        "/docker-entrypoint.…"   2 seconds ago  Up 1 second         80/tcp              test1
        

4. If we try to launch another container with the same name we will get an error from Docker. So each container should have a unique name. Run the following command:

sudo docker run --name test1 -td nginx

You should get an error with the following format:

docker: Error response from daemon: Conflict. The container name "/test1" is already in use by container "[long hash]". You have to remove (or rename) that container to be able to reuse that name.
        

5. Now we will kill the previously launched container.

sudo docker kill test1

6. Let's view the list of containers again.

sudo docker container ls -a

The output should be as follows:

CONTAINER ID    IMAGE     COMMAND                  CREATED            STATUS                      PORTS          NAMES
[long hash]     nginx     "/docker-entrypoint.…"   [x] minutes ago    Exited(137) seconds ago     80/tcp         test1
        

7. Now we will delete the previously launched container.

sudo docker rm test1

8. Run a container with a custom Seccomp profile. sudo docker run --name [any-name] --security-opt seccomp=[path-to-seccomp-profile] -td [docker-image-name]

sudo docker run --name container-hardened --security-opt seccomp=results/nginx.seccomp.json -td nginx

9. Connect to a running container instance and launch bash/sh/. sudo docker exec -it [container-name] [any-shell]

sudo docker exec -it nginx-container /bin/bash

10. Extract IP address of running container: sudo docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' [container-name]

sudo docker  inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nginx-container


Using Confine to Harden a Docker Image

The main script in this repo is the confine.py file which uses previously created call graphs for musl-libc and glibc, along with a list of images and creates respective Seccomp profiles for each.

-l: glibc callgraph

-m: musl-libc callgraph

-i: input file containing JSON of images (more details provided below)

-o: path to store binaries and libraries extracted from container

-p: path to Docker default seccomp profile

-r: path to store results (seccomp profiles created)

-g: path to special cases containers like golang ones (more details provided
below)

-d: debugging enabled or disabled

--skip: [Optional] In case you set this option, the script will not run the
analysis for previously run images which have their results inserted into the
profile.results.csv file.

-f: [Optional] glibc shared object

-n: [Optional] musl-libc shared object

--finegrain: [Optional] Passing this argument enables the fine grained
policy generation. Using this feature is not advised, since it is under
development.

--othercfgfolder: [Optional] In case you enable the fine grained analysis
through setting --finegrain, you must set this option as well. This folder
should contain the call graph for the other libraries used in the fine grained
analysis.

--allbinaries: [Optional] Passing this argument causes the extraction of all
binaries instead of only the ones run during the 30 seconds. This would cause
an extremely more conservative filter.

Change your current working directory to the root of the respository (/home/ubuntu/confine).

cd /home/ubuntu/confine

Execute the main script to generate Seccomp profiles for the enabled images.

sudo python3.7 confine.py -l libc-callgraphs/glibc.callgraph -m libc-callgraphs/musllibc.callgraph -i images.json -o output/ -p default.seccomp.json -r results/ -g go.syscalls/

The JSON input file has the following format:

{
    "nginx": {
        "enable": "false",
        "image-name": "nginx",
        "image-url": "nginx",
        "category": [
            "ApplicationInfrastructure"
        ],
        "options": "",
        "args": "",
        "dependencies": {}
    }
}

Note: The only keys which are required for any item in the JSON file are enable, image-name and image-url. The rest are optional. Some Docker images need a set of options to run correctly. Such as passing configuration options or setting environment variables. Docker supports two types of arguments, one is for options which are used by Docker and the other is args which are arguments passed directly to the application running in the container. For example the MySQL Docker image must be run with the options below:

-e MYSQL_ROOT_PASSWORD=my-secret-pw
These options are typically specified in the image page on Docker Hub.