📦
secure-kubernetes-development
  • README
  • Setup
    • Requirements and Setup
      • Setup Google GKE
  • Linux Security Basics
    • Linux & Container Basics
  • Application Security
    • Sample Spring Boot Application
  • Container Security
    • Root Container
    • Rootless Container
    • Rootless Container with JIB
    • Rootless Container with Paketo
  • Kubernetes Security
    • Initial Unsafe K8s Deployment
    • Safe K8s Deployment with Pod Security Context
    • Safe K8s Deployment with Pod Security Admission
    • Safe K8s Deployment with Open Policy Agent
  • Further Resources
    • Kubernetes Authorization (RBAC)
    • Helpful Tools for Container & K8s Security
    • List of Further Resources
Powered by GitBook
On this page
  • Java Base Images
  • Standard Dockerfile
  • Build the Docker Image
  • Runs with Root by default
  • Linux capabilities
  • Linux CGroups
  • Check image for Vulnerabilities
  • Next

Was this helpful?

  1. Container Security

Root Container

PreviousSample Spring Boot ApplicationNextRootless Container

Last updated 6 months ago

Was this helpful?

This demo builds a standard docker image from the demo application just using a standard Dockerfile. For details on the demo application see .

Java Base Images

Standard Dockerfile

FROM openjdk:11.0.9-jre-slim-buster
COPY step2-hello-root-1.0.0-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT java -jar /app.jar

Build the Docker Image

To build the docker image just run

./gradlew clean build docker

To push the docker image to a docker registry please specify your target registry in gradle.properties before performing the next command:

./gradlew clean build dockerPush

Runs with Root by default

When using defaults for building a container image the container will run using the root user by default.

You can prove this by using these commands:

docker container run --rm --detach --name hello-root \
-p 8080:8080 andifalk/hello-root:latest-arm64
docker exec hello-root whoami

This should return the following user information (it really is root)

root

Finally, stop the running container by using the following command:

docker stop hello-root

Linux capabilities

Back in the old days the only way in Linux has been to either execute a process in privileged (root) or unprivileged mode (all other users).

With linux capabilities you can now break down privileges used by executing processes/threads to just grant the least privileges required to successfully run a thread.

Just look up the detailed docs for linux capabilities by

man capabilities

Docker runs with a balanced set of capabilities between security and usability of containers. You can print the default capabilities set by docker by using this command:

docker container run --rm -it alpine sh -c 'apk add -U libcap; capsh --print'

If you even run the container in privileged mode (you should usually never do that) then you get full privileged root access with all linux capabilities set:

docker container run --privileged --rm -it alpine sh -c 'apk add -U libcap; capsh --print'

In privileged mode you can for example list and change partition tables:

docker container run --privileged --rm -it alpine sh -c 'apk add -U libcap; capsh --print; fdisk -l'
docker container run --cap-drop=ALL --cap-add=net_bind_service --rm -it alpine sh -c 'apk add -U libcap; capsh --print'

Linux CGroups

Docker uses the Linux cgroups to limit resource usage of containers.

To limit the container to use a maximum of 200MiB and only one half of a cpu use this command:

docker container run --cpu-shares=0.5 --memory=200m --rm --detach --name hello-root -p 8080:8080 andifalk/hello-root:latest-arm64

You will recognize that the spring boot application start up is much slower in this container due to less cpu power.

You can always check the state of the app by issuing the logs:

docker logs hello-root

To see the actual resource consumption of the container use the docker stats command:

docker stats hello-root

Check image for Vulnerabilities

Now let's check our image for vulnerabilities of critical and high severity using these commands:

 trivy clean --scan-cache
 trivy image --severity=HIGH,CRITICAL andifalk/hello-root:latest-arm64

You only need the first command to clear the cache when using images with latest tag.

Note: It is a good practice to always use specific version tags instead of the latest tag. For demo purposes, this just makes things easier.

Next

You should also be able to reach the dockerized application via .

Usually you even don't need the default capabilities defined by docker. A common use case is to run a container listening on a , e.g. using a http server. For this you just need the capability CAP_NET_BIND_SERVICE:

For more details on docker security consult the .

All details on limiting resources can be found in .

hello spring boot application
OpenJDK
AdoptJDK
Google Distroless
Amazon Corretto
localhost:8080
privileged tcp port (below 1024)
docker security docs
docker resource constraints
Next: Rootless Container