Docker for Mac and Kubernetes

From this article you will learn how to create a local Kubernetes cluster using Docker for Mac
28 February 2018   5312

Since version 17.12 CE Edge, Docker for Mac comes with Kubernetes. Now, to create a local Kubernetes cluster, there is no need to use additional tools like Minikube. As an experiment, let's try to deploy a small service on the cluster and see what happens.

At the time of writing, I have the latest version of Docker for Mac - 18.02.0.

DockerDocker

For the experiment, I wrote a simple short links generator on Go — brevity. The service is divided into 2 parts: an API for generating short links and their handler. PostgreSQL is used for data storage.

To deploy it and all the necessary dependencies, we need Helm — a package manager for Kubernetes, which significantly simplifies the process of deployment and further support of various services. To install it, we use Homebrew:

$ brew install kubernetes-helm

After installation, we need to initialize Helm:

$ helm init

If you have access to several Kubernetes clusters, then you will need to switch to local:

$ kubectl config use-context docker-for-desktop

The preparation is complete, now we are ready to install the necessary services. The first step is to install PostgreSQL:

$ helm install --name pg --namespace db --set postgresPassword=postgres,persistence.size=1Gi stable/postgresql

Helm allows you to override the default values and thereby configure the service for your own needs. The list of services that can be installed through Helm can be found here — hub.kubeapps.com

Now we need to make sure that the service is installed and working correctly:

$ kubectl get pods -n db
NAME                            READY     STATUS                       RESTARTS   AGE
pg-postgresql-bbd4bbb5c-njkzs   0/1       CreateContainerConfigError   0          

The service was not started because of an error. To learn more, just run the following command:

$ kubectl describe pods -n db pg-postgresql-bbd4bbb5c-njkzs | tail -n 1
Warning  Failed                  (x4 over 19s)  kubelet, docker-for-desktop  Error: lstat /Users/mgrachev/.docker/Volumes/pg-postgresql/pvc-588afa8b-0e90-11e8-8d22-025000000001: no such file or directory

Kubernetes does not see the directory, although it actually exists. It turned out that Docker for Mac does not understand the subPath option in the PostgreSQL configuration for Kubernetes. In Minikube there was such a problem too, but it was already fixed.

To solve this problem, we will need to edit Deployment for PostgreSQL:

$ kubectl edit deployment -n db pg-postgresql

And delete the following line:

subPath: postgresql-db

Now, if we look again at the list of running pods, we would see that there are no errors and the service is launched:

$ kubectl get pods -n db
NAME                             READY     STATUS    RESTARTS   AGE
pg-postgresql-5c954c46c6-6bt2t   1/1       Running   0          26s

Next, we need to create a database for brevity. First we go into the container:

$ kubectl exec -it -n db pg-postgresql-5c954c46c6-6bt2t bash

Inside the container, run psql on behalf of the postgres user and create the database:

root@pg-postgresql-5c954c46c6-6bt2t:/# gosu postgres psql
postgres=# CREATE DATABASE brevity_production;

In order for our application to be accessible from the cluster, we need the Ingress Controller. For these purposes, nginx would be fine:

$ helm install --name nginx stable/nginx-ingress

Go to the installation brevity. We clone the project and run the helm install command, but as an argument we pass the path to the pre-prepared chart (the packages in Helm are called the charts):

$ git clone https://github.com/mgrachev/brevity
$ cd brevity
$ helm install --name brevity ./helm

Let’s check that all services are running:

$ kubectl get pods
NAME                                                   READY     STATUS    RESTARTS   AGE
brevity-brevity-778799dd4-zlb6g                        1/1       Running   0          1h
nginx-nginx-ingress-controller-c8cf56768-h4txk         1/1       Running   0          1h
nginx-nginx-ingress-default-backend-864c9484bf-rfdq4   1/1       Running   0          1h

Next, we'll try to generate a short link by sending a POST request to the brevity API:

$ curl -X "POST" "http://localhost/api/v1/shortlink" --data-urlencode "url=https://github.com/mgrachev"
{"shortlink":"http://localhost/MyAyEy"}

We go to it to make sure that everything works. We can also look at the logs: 

$ kubectl logs brevity-brevity-778799dd4-zlb6g
time="2018-02-19T09:31:03Z" level=info msg="HTTP Server started at port: 80"
time="2018-02-19T09:32:35Z" level=info msg="Successful returns a short link, short: http://localhost/MyAyEy, original: https://github.com/mgrachev"
time="2018-02-19T09:32:43Z" level=info msg="Redirect to https://github.com/mgrachev, using token: MyAyEy"

As can be seen from the logs, the service successfully processed a short link and redirected to github.com/mgrachev. This completes our experiment.

In conclusion, I'm glad to see Docker for Mac with Kubernetes support. It's enough to make one click in the settings and at your disposal there will be a completely ready-to-work cluster with Kubernetes on board. On the other hand, I note that this is still an unstable version and there may be various kinds of errors. But even now, it is quite suitable for local development and testing.

Mikhail Grachev, senior ruby developer, Evrone

Vulnerability to be Found in Docker

The problem that allows access to the host environment from the container manifests itself in all versions of Docker and remains uncorrected
29 May 2019   250

A vulnerability revealed in the Docker, which allows to get access to the host environment from the container under certain circumstances, only if it is possible to launch own images in the system or when accessing the executable container. The problem manifests itself in all versions of Docker and remains uncorrected.

Vulnerability allows extracting files from the container to an arbitrary part of the host system's FS when executing the "docker cp" command. Extracting files is performed as root, which makes it possible to read or write any files in the host environment, which is enough to gain control over the host system (for example, you can rewrite /etc/shadow).

The attack can be made only when the administrator executes the "docker cp" command to copy files into or out of the container. Thus, an attacker needs to somehow convince the Docker administrator of the need to perform this operation and predict the path used when copying. On the other hand, an attack can be made, for example, when cloud services provide tools to copy configuration files into a container, built using the "docker cp" command.

The problem is caused by a flaw in the application of the FollowSymlinkInScope function, which calculates the absolute path in the main file system based on the relative path that takes into account the placement of the container. During the execution of the "docker cp" command, a short-term race condition occurs in which the path has already been verified, but the operation has not yet been completed. Since the copying is done in the context of the host’s main FS in a specified period of time, you can replace the link to another path and initiate copying data to an arbitrary place in the file system outside the container.

The time window for the manifestation of the race condition is limited in the prepared prototype of the exploit. So, during the copying operations from the container, it was possible to achieve a successful attack in less than 1% of cases with a cyclic replacement of the symbolic link in the path used in the copy operation. A successful attack was made after approximately 10 seconds of attempts to continuously copy the file using the "docker cp".

When performing a copy operation to a container, you can achieve a repeated attack on overwriting a file in the host system in just a few iterations. The possibility of an attack is due to the fact that when copying into a container, the concept of "chrootarchive" is used, according to which the archive.go process retrieves the archive not in the container's chroot root, but in the chroot of the parent directory of the target path controlled by the attacker and does not stop the container (chroot is used as a flag to exploit the race condition).