# Hardening Kaniko build process with Linux capabilities

## Introduction to Kaniko

Kaniko is a tool to build container images from a Dockerfile, inside a container or Kubernetes cluster. More information on usage, [here](https://github.com/GoogleContainerTools/kaniko).

Kaniko doesn't depend on a Docker daemon and executes each command within a Dockerfile completely in userspace. This enables building container images in environments that can't easily or securely run a Docker daemon, such as a standard Kubernetes cluster.

There are tons of tutorials on [the internet](https://github.com/GoogleContainerTools/kaniko/blob/main/docs/tutorial.md) on how to use Kaniko. Rather than focusing on regular usage, we will take things a notch higher by hardening Kaniko build process to ensure better security.

## Introduction to security concerns

* Kaniko runs as a container to build images
* Kaniko runs as an unprivileged container
* But that container runs as a root user

Running container as a root user is not recommended but here kaniko will be used for building the images (unpacking other images, changing permissions, etc), so kaniko requires a certain level of privileges. Hence, the root user is mandatory.

## Internal working

Running container as the root user is a concern when the container is having a wide range of Linux capabilities that can lead to compromise of the host machine. To prevent this attack, we will drop all the capabilities for this kaniko container. But as discussed above, Kaniko requires a specific set of capabilities to perform operations. Let's try to explicitly add those capabilities to Kaniko container, so it will have the ability to build an image.

I have tried building multiple `Dockerfiles` performing different sets of operations. Post review, I found the following capabilities are required for kaniko to build an image.

* CHOWN
* SETUID
* SETGID
* FOWNER
* DAC_OVERRIDE

## Hands-on experience

I used a simple `Dockerfile` for testing.

```Dockerfile
FROM alpine
ENTRYPOINT ["/bin/sh", "-c", "echo hello"]
```

### Default capabilities list

Build the image

```bash
docker run --name capdefault -v $(pwd)/Dockerfile:/Dockerfile -v $(pwd):/kaniko-context -it gcr.io/kaniko-project/executor:latest -f /Dockerfile -c /kaniko-context --no-push
```

Capture the PID of the above process

```bash
ps -ef | grep capdefault
```

Review the bounding set capabilities for that process. `CapBnd` will help.

```bash
grep Cap /proc/<PID>/status
```

Decode the `CapBnd` value to view the list of capabilities associated with that process.

```bash
capsh --decode=<CapBnd_Value>
```

Finally, we can see a wide range of Linux capabilities associated with the container with default settings that can open a gateway to numerous attacks & privilege escalations.

![capdefault-edit.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642489160412/IPUg9DPGj.png)

### Dropped all capabilities

Try dropping all the capabilities & building the image.

```bash
docker run --name capdropall --cap-drop=all -v $(pwd)/Dockerfile:/Dockerfile -v $(pwd):/kaniko-context -it gcr.io/kaniko-project/executor:latest -f /Dockerfile -c /kaniko-context --no-push
```

When all capabilities are dropped, kaniko won't be able to build an image. 

![capdropall-edit.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642489176022/uBSgTmwyr.png)

### Dropped all capabilities & added only required capabilities

As discussed in the *Internal working* section, drop all capabilities and add the capabilities that are required only for building images.

```bash
docker run --name capdropsome --cap-drop=all --cap-add CHOWN --cap-add=SETUID --cap-add=SETGID --cap-add=FOWNER --cap-add=DAC_OVERRIDE -v $(pwd)/Dockerfile:/Dockerfile -v $(pwd):/kaniko-context -it gcr.io/kaniko-project/executor:latest -f /Dockerfile -c /kaniko-context --no-push
```

![capdropsome-edit.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1642489193456/rvNqwQFBX.png)

## Conclusion

A wide variety of Dockerfiles should be passed to kaniko as unit tests to understand the required list of capabilities for Kaniko. If we feel any additional privileges are required to build specific Dockerfiles, we can add those capabilities to the Kaniko build container explicitly.

