Monday, June 6, 2016

Dockerfiles ... creating your own docker images

In this post we are going to build our first image to go over the basics. We are going to build an OpenSSH server and expose it.
Creating a Dockerfile
The complete reference can be found at but I am going to use only a part of the possibilities. 

The Dockerfile is a set of instructions that allows you to build an image that can be used to a container

The first step is to create the Dockerfile
touch Dockerfile

In you favorite editor you open your Dockerfile and write
FROM ubuntu
MAINTAINER your_name _email>

We need the following line so we can spin up the container with as argurment the SSH root password.
ARG SSHD_Root_Password

Since it is best practice to keep an OS up-to-date you will need to add the following

  apt-get update && \
  apt-get dist-upgrade -y && \
  apt-get autoremove -y && \
  apt-get clean

The instructions above will pull down all the updates for the OS when you spin up your container.

To install the OpenSSH server we do the following

  apt-get install -y openssh-server && \
  apt-get clean

Lets make a backup of the original config file and change the permissions so it can't be read by the whole world.

RUN cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
RUN chmod a-w /etc/ssh/sshd_config.orig

We still need to set the root password based on the argument given to the container. To change the root password you add the following line
RUN echo "root:$SSHD_ROOT_PASSWORD" | chpasswd

It is not a security best practice to allow a root user to log in over ssh, but for simplicity sake we are going to allow it in this configuration. Never use this for production.
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config

Now we need to specify the default command that runs when the container starts, it takes a json format input and that is why the command and argument are between double quotes.
CMD ["/usr/sbin/sshd", "-D"]

Finally we need to expose the SSH port to the network

Now that the Dockerfile is ready we need to actually build an image from it.

Building the image
Building an image is the next step that is done with docker build -t .

Notice the "." at the end, it is something you can sometimes miss.

To make it concrete the command is
docker build -t xiobe/sshd --build-arg SSHD_ROOT_PASSWORD=demo

xiobe/sshd is just the name I gave the image but it can be anything you like and as you can see we give the building argument SSHD_ROOT_PASSWORD a value of demo.

Remember that it might be handy to have the same SSH password everywhere as an admin but as an attack it is even handier since I need to obtain only one password. A better way would be to build in ssh-keys if you would like to but that is not the purpose of this demo.

Spinning the container up
The only thing that we still need to do is spin up the container. This is done with
docker run -d -P xiobe/sshd

the -d means that the docker container runs in background, when you use this option it returns the ID of the container.

the -P is to publish the exposed port to a random port this means when you spin it up docker will choose a random port on the host machine and map it to the port 22 of the container.

To see that the container is running you do
docker ps 

which also shows something like>22/tcp what means the randomly selected port was in this case 32768.

When you are exposing real apps you will often do mappings with -p. In this case you would for example map port 22 on the host to the guest's 22. This would look like
docker run -d -p 22:22 xiobe/sshd

Removing an image
If you are building and it fails for some reason you will probably want to remove images after you are done. This can be done with

docker rmi

To make up your cleanup a bit faster you can clean up the untagged and unnamed images like this

docker images -q --no-trunc -f dangling=true | xargs docker rmi

Running the image after a successful build

Before you get to production grade you will most likely have to build a couple of images and run them to see if you are happy with the result.  Instead of cleaning up containers after you are done you can specify the -rm on your docker run command. This will automatically clean up after a run.