Exercise 1.1 - Reproducible and Trustworthy Dockerfiles

Return to Workshop

file

Exercise 1.1 - Reproducible and Trustworthy Dockerfiles

Exercise Description

Now that you’ve gotten a sense of how Cockpit works, we are going to start digging in at the command line on Container security. You can use either the Terminal in Cockpit from your browser, a SSH terminal or Terminal client like PuTTy. The choice is yours.

Section 1: Best Practices

Step 1. Always specify a tag in FROM instructions.

FROM redis is bad, because it pulls the latest tag, which changes over time and can be expected to move with major version changes. FROM redis:3.0 is better, but can still be expected to change with minor updates and bug fixes (which may be exactly what you want). If you want to be certain that the image you are pulling has not been tampered with, you can pull your images by hash rather than tag. This can also be done after you make changes to a image and want to pull that specific image; for example:

Pull an image by sha256
sudo podman images

sudo podman pull docker.io/centos@sha256:67dad89757a55bfdfabec8abd0e22f8c7c12a1856514726470228063ed86593b

Step 2. Securely Downloading Software in Dockerfiles

In the majority of cases, vendors will make signed checksums available for verifying downloads. For example, this Dockerfile snippet fro the official Node.js image repository includes the following:

Example of signed checksums in a Dockerfile
RUN gpg --keyserver pool.sks-keyservers.net \ (1)
--recv-keys 7937DFD2AB06298B2293C3187D33FF9D0246406D \
                        114F43EE0176B71C7BC219DD50A3051F888C628D
ENV NODE_VERSION 0.10.38
ENV NPM_VERSION 2.10.0
RUN curl -SLO "http://nodejs.org/dist/v$NODE_VERSION/node-v\
$NODE_VERSION-linux-x64.tar.gz" \ (2)
&& curl -SLO "http://nodejs.org/dist/v$NODE_VERSION/\
SHASUMS256.txt.asc" \ (3)
&& gpg --verify SHASUMS256.txt.asc \ (4)
&& grep " node-v$NODE_VERSION-linux-x64.tar.gz\$" \
            SHASUMS256.txt.asc | sha256sum -c - (5)
1 Gets the GNU Privacy Guard (GPG) keys used to sign the Node.js download. Here, we do have to trust that these are the correct keys. Downloads the Node.js tarball. Downloads the checksum for the tarball. Uses GPG to verify that the checksum was signed by whoever owns the keys we obtained. Tests that the checksum matches the tarball by using the sha256sum tool.
2 Downloads the Node.js tarball.
3 Downloads the checksum for the tarball.
4 Uses GPG to verify that the checksum was signed by whoever owns the keys we obtained.
5 Tests that the checksum matches the tarball by using the sha256sum tool.

Step 3. Creating an original checksum

Assuming no signed package or checksum is available, creating your own is easy. For example, to create a checksum for a Redis release:

curl http://download.redis.io/releases/redis-5.0.1.tar.gz --output redis.tar.gz --progress-bar
sha1sum -b redis.tar.gz

32a3accc9ac63896eeb7a3bf27ab667b095ba30a *redis.tar.gz

Here, we’re creating a 160-bit SHA-1 checksum. The -b flag tells the sha1sum utility that we are dealing with binary data, not text.

You can use your choice of [ Vi | Vim | Nano ] to copy and paste this into a new file called Dockerfile.

Build the Dockerfile
mkdir ~/redis
cd ~/redis
vim Dockerfile
Copy the text below. Type vim Dockerfile, Press i for Insert, then cut and paste control + v, then escape and write the file esc, :wq.
Dockerfile Redis with verified software download
FROM fedora:29

# Verified sha1sum
RUN cd /tmp && \
    curl -sSL -o redis.tar.gz \
    http://download.redis.io/releases/redis-5.0.1.tar.gz && \
    echo "32a3accc9ac63896eeb7a3bf27ab667b095ba30a *redis.tar.gz" | sha1sum -c -

RUN cd /tmp && \
    tar xvzf redis.tar.gz && \
    cd redis-5.0.1 && \
    dnf install -y make gcc && \
    make && \
    make install && \
    cp -f src/redis-sentinel /usr/local/bin && \
    mkdir -p /etc/redis && \
    cp -f *.conf /etc/redis && \
    rm -rf /tmp/redis-5.0.1* && \
    sed -i 's/^\(bind .*\)$/# \1/' /etc/redis/redis.conf && \
    sed -i 's/^\(daemonize .*\)$/# \1/' /etc/redis/redis.conf && \
    sed -i 's/^\(dir .*\)$/# \1\ndir \/data/' /etc/redis/redis.conf && \
    sed -i 's/^\(logfile .*\)$/# \1/' /etc/redis/redis.conf

# Define mountable directories.
VOLUME ["/data"]

# Define working directory.
WORKDIR /data

# Define default command.
CMD ["redis-server", "/etc/redis/redis.conf"]

# Expose ports.
EXPOSE 6379

Step 4. Build the image

Build the image
sudo buildah bud -t redis:5.0.1

After about 2-3 minutes you should see something similar to below;

Successfully built redis container
...
STEP 8: COMMIT redis:5.0.1
Getting image source signatures
Copying blob b7ba3be6a0d6 skipped: already exists
Copying blob 0a2bd68c4a15 done
Copying config 980e01820e done
Writing manifest to image destination
Storing signatures
980e01820e16f269b906975a35a9157ac861a607429df1ed19b9aaf4954e94af
980e01820e16f269b906975a35a9157ac861a607429df1ed19b9aaf4954e94af

Step 5. Run the container

Run the container to look around.

sudo podman run --rm -it redis:5.0.1 bash

Now you are inside a container. In this example you can see our command shell changed to [root@0636c3c4ee44 data]. Try the following command redis-server.

In a Container
[root@1afa082098ae data]# redis-server
11:C 10 Nov 2018 16:53:04.041 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
11:C 10 Nov 2018 16:53:04.041 # Redis version=5.0.1, bits=64, commit=00000000, modified=0, pid=11, just started
11:C 10 Nov 2018 16:53:04.041 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/re
dis.conf
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 5.0.1 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 11
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

11:M 10 Nov 2018 16:53:04.043 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value o
f 128.
11:M 10 Nov 2018 16:53:04.043 # Server initialized
11:M 10 Nov 2018 16:53:04.043 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overc
ommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
11:M 10 Nov 2018 16:53:04.043 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage iss
ues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in o
rder to retain the setting after a reboot. Redis must be restarted after THP is disabled.
11:M 10 Nov 2018 16:53:04.043 * Ready to accept connections

Type control + c to exit.

control + c
Type exit to quit
[root@1afa082098ae data]# exit

Workshop Details

Domain Red Hat Logo
Workshop
Student ID

Return to Workshop