Table des matières

Version : 2024.01

Dernière mise-à-jour : 2024/02/21 13:40

DOF607 - Gestion de la Sécurité de Docker

Contenu du Module

LAB #1 - Utilisation des Docker Secrets

Les secrets Docker sont une façon sécurisée de stocker des informations sensibles telles les noms d'utiisateurs, les mots de passe voire les fichiers. Ils ne sont compatibles qu'avec Docker en mode Swarm.

Considérez l'exemple suivant d'un fichier Docker stack servant à créer un conteneur PostgreSQL :

version: '3.1'

services:

  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: database

  adminer:
    image: adminer
    ports:
     - 8080:8080

On peut constater dans ce fichier la présence des informations sensibles en non-sécurisées :

Afin de sécuriser ces informations, commencez par créer le contexte postgres :

root@manager:~# mkdir postgres

Créez ensuite un Docker Secret appelé pg_user :

root@manager:~# cd postgres
root@manager:~/postgres# echo "postgres" | docker secret create pg_user -
lpk8eq80qvfiqw7z1686fmj5t

Important : Notez l'utilisation du caractère - à la fin de la ligne. Celui-ci indique à la commande docker secret de lire le contenu du secret pg_user à partir de l'entrée standard.

Pour visualiser la liste des secrets, utilisez la commande docker secrets ls :

root@manager:~/postgres# docker secret ls
ID                          NAME                DRIVER              CREATED              UPDATED
lpk8eq80qvfiqw7z1686fmj5t   pg_user                                 About a minute ago   About a minute ago

Important : Notez que la colonne DRIVER est vide. Ceci indique que le gestion des secrets est accomplie par Docker lui-même au lieu d'être déléguée à un plugin tiers.

Créez maintenant les secrets pg_password et pg_database :

root@manager:~/postgres# echo "postgres" | docker secret create pg_password -
h9tsfbfwz6o0sd35roklwpopi
root@manager:~/postgres# echo "database" | docker secret create pg_database -
5lx4zydpfocwgpdto0yy1jod9

Important : Notez qu'un secret Docker est immuable.

Vérifiez la prise en compte de vos commandes :

root@manager:~/postgres# docker secret ls
ID                          NAME                DRIVER              CREATED             UPDATED
5lx4zydpfocwgpdto0yy1jod9   pg_database                             2 minutes ago       2 minutes ago
h9tsfbfwz6o0sd35roklwpopi   pg_password                             3 minutes ago       3 minutes ago
lpk8eq80qvfiqw7z1686fmj5t   pg_user                                 5 minutes ago       5 minutes ago

Pour obtenir de l'information concernant un secret, il convient d'utiliser la commande docker secret inspect :

root@manager:~/postgres# docker secret inspect pg_database
[
    {
        "ID": "5lx4zydpfocwgpdto0yy1jod9",
        "Version": {
            "Index": 23
        },
        "CreatedAt": "2021-04-15T03:49:36.344367554Z",
        "UpdatedAt": "2021-04-15T03:49:36.344367554Z",
        "Spec": {
            "Name": "pg_database",
            "Labels": {}
        }
    }
]

Important : On peut constater dans la sortie de cette commande la valeur CreatedAt qui correspond à la date de création du secret ainsi que UpdatedAt qui correspond à la date de modification du secret.

L'option –pretty de la commande fait apparaître ces informations plus clairement :

root@manager:~/postgres# docker secret inspect --pretty pg_database
ID:              5lx4zydpfocwgpdto0yy1jod9
Name:              pg_database
Driver:            
Created at:        2021-04-15 03:49:36.344367554 +0000 utc
Updated at:        2021-04-15 03:49:36.344367554 +0000 utc

Créez maintenant le fichier compose postgres-secrets.yaml :

root@manager:~/postgres# vi postgres-secrets.yaml
root@manager:~/postgres# cat postgres-secrets.yaml
version: '3.1'

services:

    db:
        image: postgres
        restart: always
        environment:
            POSTGRES_USER_FILE: /run/secrets/pg_user
            POSTGRES_PASSWORD_FILE: /run/secrets/pg_password
            POSTGRES_DB_FILE: /run/secrets/pg_database
        secrets:
           - pg_password
           - pg_user
           - pg_database

    adminer: 
        image: adminer 
        ports: 
         - 8080:8080

secrets:
  pg_user:
    external: true
  pg_password:
    external: true
  pg_database:
    external: true

Notez que dans ce fichier les trois variables POSTGRES_USER, POSTGRES_PASSWORD et POSTGRES_DB ont un suffixe _FILE car elles référencent des fichiers contenant des informations plutôt que des informations elles-mêmes. Ces fichiers se trouvent dans le répertoire /run/secrets du conteneur.

Deuxièmement la section suivantes spécifie les noms des secrets à utiliser avec le service :

        secrets:
           - pg_password
           - pg_user
           - pg_database

La dernière section spécifie que les secrets sont externes :

secrets:
  pg_user:
    external: true
  pg_password:
    external: true
  pg_database:
    external: true

Important : Le terme externe indique que les secrets ne seront pas stockés dans l'image construite mais uniquement dans le conteneur créé.

Déployez maintenant le service en utilisant la commande docker stack :

root@manager:~/postgres# docker stack deploy -c postgres-secrets.yaml postgres
Ignoring unsupported options: restart

Creating network postgres_default
Creating service postgres_db
Creating service postgres_adminer

Important : Notez a présence de l'erreur Ignoring unsupported options: restart. Celle-ci est due au fait que la directive restart est compatible avec la commande docker-compose mais pas avec la commande docker stack. La directive qui aurait du être utilisée dans le fichier est restart_policy:.

Connectez-vous maintenant à Apache Guacamole et ouvrez un navigateur web dans la machine virtuelle. Naviguez ensuite à l'adresse du Manager sur le port 8080 et renseignez les valeurs des secrets :

Validez le formulaire et vérifiez que les secrets ont été pris en compte :

Dernièrement, supprimez le service :

root@manager:~/postgres# docker stack ls
NAME                SERVICES            ORCHESTRATOR
postgres            2                   Swarm
root@manager:~/postgres# docker stack rm postgres
Removing service postgres_adminer
Removing service postgres_db
Removing network postgres_default

LAB #2 - Création d'un Utilisateur de Confiance pour Contrôler le Daemon Docker

Au contraire des solutions classiques de gestion de machines virtuelles où l'accès est souvent conditionné à l'attribution de rôles, Docker ne possède pas ce type de mécanisme. De ce fait toute personne ayant accès à l'hôte soit par sudo soit en étant membre du groupe docker peut accéder à tous les conteneurs voire les arrêter, supprimer et en créer d'autres.

root@manager:~# cat /etc/group | grep docker
docker:x:999:
root@manager:~# usermod -aG docker trainee
root@manager:~# exit
déconnexion
trainee@manager:~$ docker ps
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.40/containers/json: dial unix /var/run/docker.sock: connect: permission denied
trainee@manager:~$ newgrp docker
trainee@manager:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                        PORTS                 NAMES
d02c6115724c        alpine              "/bin/sh"                6 days ago          Exited (0) 6 days ago                               alpine1
trainee@manager:~$ docker rm alpine1
alpine1
trainee@manager:~$ docker run -d --name alpine1 alpine sleep 99999
a214e2df0499c97e8da25a6c9ea751ac75344c9bcd7d238f8cb8d5c777510ab9
trainee@manager:~$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
a214e2df0499        alpine              "/bin/sh"           6 seconds ago       Up 5 seconds                            alpine1

LAB #3 - Le Script docker-bench-security.sh

Le Center for Internet Security (CIS) est une organisation indépendante à but non-lucratif qui publie des best practices dans de nombreux domaines de l'informatique. Le guide pour Docker peut être téléchargé à partir de l'adresse https://www.cisecurity.org/benchmark/docker/.

Le guide est divisé en plusieurs sections :

Ce guide est à utiliser avec le script Docker Benchmark Security.

Clonez le script docker-bench-security.sh en utilisant git :

trainee@manager:~$ su -
Password: fenestros

root@manager:~# git clone https://github.com/docker/docker-bench-security.git
Cloning in 'docker-bench-security'...
remote: Enumerating objects: 18, done.
remote: Counting objects: 100% (18/18), done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 1921 (delta 5), reused 6 (delta 2), pack-reused 1903
Receiving objects: 100% (1921/1921), 2.90 MiB | 908.00 KiB/s, done.
Delta resolution: 100% (1339/1339), done.

Exécutez maintenant le script Docker Benchmark Security :

root@manager:~# cd docker-bench-security/

root@manager:~/docker-bench-security# ./docker-bench-security.sh
# --------------------------------------------------------------------------------------------
# Docker Bench for Security v1.6.0
#
# Docker, Inc. (c) 2015-2023
#
# Checks for dozens of common best-practices around deploying Docker containers in production.
# Based on the CIS Docker Benchmark 1.6.0.
# --------------------------------------------------------------------------------------------

Initializing 2023-12-17T14:22:08+01:00


Section A - Check results

[INFO] 1 - Host Configuration
[INFO] 1.1 - Linux Hosts Specific Configuration
[WARN] 1.1.1 - Ensure a separate partition for containers has been created (Automated)
[INFO] 1.1.2 - Ensure only trusted users are allowed to control Docker daemon (Automated)
[INFO]       * Users: trainee
[WARN] 1.1.3 - Ensure auditing is configured for the Docker daemon (Automated)
[WARN] 1.1.4 - Ensure auditing is configured for Docker files and directories -/run/containerd (Automated)
[WARN] 1.1.5 - Ensure auditing is configured for Docker files and directories - /var/lib/docker (Automated)
[WARN] 1.1.6 - Ensure auditing is configured for Docker files and directories - /etc/docker (Automated)
[WARN] 1.1.7 - Ensure auditing is configured for Docker files and directories - docker.service (Automated)
[INFO] 1.1.8 - Ensure auditing is configured for Docker files and directories - containerd.sock (Automated)
[INFO]        * File not found
[WARN] 1.1.9 - Ensure auditing is configured for Docker files and directories - docker.socket (Automated)
[WARN] 1.1.10 - Ensure auditing is configured for Docker files and directories - /etc/default/docker (Automated)
[INFO] 1.1.11 - Ensure auditing is configured for Dockerfiles and directories - /etc/docker/daemon.json (Automated)
[INFO]        * File not found
[WARN] 1.1.12 - 1.1.12 Ensure auditing is configured for Dockerfiles and directories - /etc/containerd/config.toml (Automated)
[INFO] 1.1.13 - Ensure auditing is configured for Docker files and directories - /etc/sysconfig/docker (Automated)
[INFO]        * File not found
[WARN] 1.1.14 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd (Automated)
[WARN] 1.1.15 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim (Automated)
[INFO] 1.1.16 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v1 (Automated)
[INFO]         * File not found
[INFO] 1.1.17 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v2 (Automated)
[INFO]         * File not found
[WARN] 1.1.18 - Ensure auditing is configured for Docker files and directories - /usr/bin/runc (Automated)
[INFO] 1.2 - General Configuration
[NOTE] 1.2.1 - Ensure the container host has been Hardened (Manual)
[PASS] 1.2.2 - Ensure that the version of Docker is up to date (Manual)
[INFO]        * Using 19.03.4, verify is it up to date as deemed necessary

[INFO] 2 - Docker daemon configuration
[NOTE] 2.1 - Run the Docker daemon as a non-root user, if possible (Manual)
[WARN] 2.2 - Ensure network traffic is restricted between containers on the default bridge (Scored)
[PASS] 2.3 - Ensure the logging level is set to 'info' (Scored)
[PASS] 2.4 - Ensure Docker is allowed to make changes to iptables (Scored)
[PASS] 2.5 - Ensure insecure registries are not used (Scored)
[PASS] 2.6 - Ensure aufs storage driver is not used (Scored)
[INFO] 2.7 - Ensure TLS authentication for Docker daemon is configured (Scored)
[INFO]      * Docker daemon not listening on TCP
[INFO] 2.8 - Ensure the default ulimit is configured appropriately (Manual)
[INFO]      * Default ulimit doesn't appear to be set
[WARN] 2.9 - Enable user namespace support (Scored)
[PASS] 2.10 - Ensure the default cgroup usage has been confirmed (Scored)
[PASS] 2.11 - Ensure base device size is not changed until needed (Scored)
[WARN] 2.12 - Ensure that authorization for Docker client commands is enabled (Scored)
[WARN] 2.13 - Ensure centralized and remote logging is configured (Scored)
[WARN] 2.14 - Ensure containers are restricted from acquiring new privileges (Scored)
[WARN] 2.15 - Ensure live restore is enabled (Scored)
[WARN] 2.16 - Ensure Userland Proxy is Disabled (Scored)
[PASS] 2.17 - Ensure that a daemon-wide custom seccomp profile is applied if appropriate (Manual)
[PASS] 2.18 - Ensure that experimental features are not implemented in production (Scored)

[INFO] 3 - Docker daemon configuration files
[PASS] 3.1 - Ensure that the docker.service file ownership is set to root:root (Automated)
[PASS] 3.2 - Ensure that docker.service file permissions are appropriately set (Automated)
[PASS] 3.3 - Ensure that docker.socket file ownership is set to root:root (Automated)
[PASS] 3.4 - Ensure that docker.socket file permissions are set to 644 or more restrictive (Automated)
[PASS] 3.5 - Ensure that the /etc/docker directory ownership is set to root:root (Automated)
[PASS] 3.6 - Ensure that /etc/docker directory permissions are set to 755 or more restrictively (Automated)
[INFO] 3.7 - Ensure that registry certificate file ownership is set to root:root (Automated)
[INFO]      * Directory not found
[INFO] 3.8 - Ensure that registry certificate file permissions are set to 444 or more restrictively (Automated)
[INFO]      * Directory not found
[INFO] 3.9 - Ensure that TLS CA certificate file ownership is set to root:root (Automated)
[INFO]      * No TLS CA certificate found
[INFO] 3.10 - Ensure that TLS CA certificate file permissions are set to 444 or more restrictively (Automated)
[INFO]       * No TLS CA certificate found
[INFO] 3.11 - Ensure that Docker server certificate file ownership is set to root:root (Automated)
[INFO]       * No TLS Server certificate found
[INFO] 3.12 - Ensure that the Docker server certificate file permissions are set to 444 or more restrictively (Automated)
[INFO]       * No TLS Server certificate found
[INFO] 3.13 - Ensure that the Docker server certificate key file ownership is set to root:root (Automated)
[INFO]       * No TLS Key found
[INFO] 3.14 - Ensure that the Docker server certificate key file permissions are set to 400 (Automated)
[INFO]       * No TLS Key found
[PASS] 3.15 - Ensure that the Docker socket file ownership is set to root:docker (Automated)
[PASS] 3.16 - Ensure that the Docker socket file permissions are set to 660 or more restrictively (Automated)
[INFO] 3.17 - Ensure that the daemon.json file ownership is set to root:root (Automated)
[INFO]       * File not found
[INFO] 3.18 - Ensure that daemon.json file permissions are set to 644 or more restrictive (Automated)
[INFO]       * File not found
[PASS] 3.19 - Ensure that the /etc/default/docker file ownership is set to root:root (Automated)
[PASS] 3.20 - Ensure that the /etc/default/docker file permissions are set to 644 or more restrictively (Automated)
[INFO] 3.21 - Ensure that the /etc/sysconfig/docker file permissions are set to 644 or more restrictively (Automated)
[INFO]       * File not found
[INFO] 3.22 - Ensure that the /etc/sysconfig/docker file ownership is set to root:root (Automated)
[INFO]       * File not found
[PASS] 3.23 - Ensure that the Containerd socket file ownership is set to root:root (Automated)
[PASS] 3.24 - Ensure that the Containerd socket file permissions are set to 660 or more restrictively (Automated)

[INFO] 4 - Container Images and Build File
[INFO] 4.1 - Ensure that a user for the container has been created (Automated)
[INFO]      * No containers running
[NOTE] 4.2 - Ensure that containers use only trusted base images (Manual)
[NOTE] 4.3 - Ensure that unnecessary packages are not installed in the container (Manual)
[NOTE] 4.4 - Ensure images are scanned and rebuilt to include security patches (Manual)
[WARN] 4.5 - Ensure Content trust for Docker is Enabled (Automated)
[WARN] 4.6 - Ensure that HEALTHCHECK instructions have been added to container images (Automated)
[WARN]      * No Healthcheck found: [nginx:latest]
[WARN]      * No Healthcheck found: [alpine:latest]
[WARN]      * No Healthcheck found: [ubuntu:latest]
[WARN]      * No Healthcheck found: [centos:latest]
[PASS] 4.7 - Ensure update instructions are not used alone in the Dockerfile (Manual)
[NOTE] 4.8 - Ensure setuid and setgid permissions are removed (Manual)
[PASS] 4.9 - Ensure that COPY is used instead of ADD in Dockerfiles (Manual)
[NOTE] 4.10 - Ensure secrets are not stored in Dockerfiles (Manual)
[NOTE] 4.11 - Ensure only verified packages are installed (Manual)
[NOTE] 4.12 - Ensure all signed artifacts are validated (Manual)

[INFO] 5 - Container Runtime
[INFO]   * No containers running, skipping Section 5

[INFO] 6 - Docker Security Operations
[INFO] 6.1 - Ensure that image sprawl is avoided (Manual)
[INFO]      * There are currently: 4 images
[INFO]      * Only 0 out of 4 are in use
[INFO] 6.2 - Ensure that container sprawl is avoided (Manual)
[INFO]      * There are currently a total of 0 containers, with 0 of them currently running

[INFO] 7 - Docker Swarm Configuration
[WARN] 7.1 - Ensure swarm mode is not Enabled, if not needed (Automated)
[PASS] 7.2 - Ensure that the minimum number of manager nodes have been created in a swarm (Automated) (Swarm mode not enabled)
[PASS] 7.3 - Ensure that swarm services are bound to a specific host interface (Automated) (Swarm mode not enabled)
[PASS] 7.4 - Ensure that all Docker swarm overlay networks are encrypted (Automated)
[PASS] 7.5 - Ensure that Docker's secret management commands are used for managing secrets in a swarm cluster (Manual) (Swarm mode not enabled)
[PASS] 7.6 - Ensure that swarm manager is run in auto-lock mode (Automated) (Swarm mode not enabled)
[PASS] 7.7 - Ensure that the swarm manager auto-lock key is rotated periodically (Manual) (Swarm mode not enabled)
[PASS] 7.8 - Ensure that node certificates are rotated as appropriate (Manual) (Swarm mode not enabled)
[PASS] 7.9 - Ensure that CA certificates are rotated as appropriate (Manual) (Swarm mode not enabled)
[PASS] 7.10 - Ensure that management plane traffic is separated from data plane traffic (Manual) (Swarm mode not enabled)


Section C - Score

[INFO] Checks: 86
[INFO] Score: 1

Ce script sert à automatiser le contrôle des points précédemment cités et produit un rapport contenant des annotations :

LAB #4 - Sécurisation de la Configuration de l'Hôte Docker

Lors de l'exécution du script, vous devez obtenir un résultat similaire à ceci en ce qui concerne la Sécurité de la Configuration de l'hôte Docker :

...
[INFO] 1 - Host Configuration
[INFO] 1.1 - Linux Hosts Specific Configuration
[WARN] 1.1.1 - Ensure a separate partition for containers has been created (Automated)
[INFO] 1.1.2 - Ensure only trusted users are allowed to control Docker daemon (Automated)
[INFO]       * Users: trainee
[WARN] 1.1.3 - Ensure auditing is configured for the Docker daemon (Automated)
[WARN] 1.1.4 - Ensure auditing is configured for Docker files and directories -/run/containerd (Automated)
[WARN] 1.1.5 - Ensure auditing is configured for Docker files and directories - /var/lib/docker (Automated)
[WARN] 1.1.6 - Ensure auditing is configured for Docker files and directories - /etc/docker (Automated)
[WARN] 1.1.7 - Ensure auditing is configured for Docker files and directories - docker.service (Automated)
[INFO] 1.1.8 - Ensure auditing is configured for Docker files and directories - containerd.sock (Automated)
[INFO]        * File not found
[WARN] 1.1.9 - Ensure auditing is configured for Docker files and directories - docker.socket (Automated)
[WARN] 1.1.10 - Ensure auditing is configured for Docker files and directories - /etc/default/docker (Automated)
[INFO] 1.1.11 - Ensure auditing is configured for Dockerfiles and directories - /etc/docker/daemon.json (Automated)
[INFO]        * File not found
[WARN] 1.1.12 - 1.1.12 Ensure auditing is configured for Dockerfiles and directories - /etc/containerd/config.toml (Automated)
[INFO] 1.1.13 - Ensure auditing is configured for Docker files and directories - /etc/sysconfig/docker (Automated)
[INFO]        * File not found
[WARN] 1.1.14 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd (Automated)
[WARN] 1.1.15 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim (Automated)
[INFO] 1.1.16 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v1 (Automated)
[INFO]         * File not found
[INFO] 1.1.17 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim-runc-v2 (Automated)
[INFO]         * File not found
[WARN] 1.1.18 - Ensure auditing is configured for Docker files and directories - /usr/bin/runc (Automated)
[INFO] 1.2 - General Configuration
[NOTE] 1.2.1 - Ensure the container host has been Hardened (Manual)
[PASS] 1.2.2 - Ensure that the version of Docker is up to date (Manual)
[INFO]        * Using 19.03.4, verify is it up to date as deemed necessary
...

Les problèmes de sécurité qu'il convient à résoudre sont indiqués par les annotations [WARN].

[WARN] 1.1.1 - Ensure a separate partition for containers has been created (Automated)

Par défaut, tous les fichiers de Docker sont stockés dans le répertoire /var/lib/docker, y compris toutes les images, tous les conteneurs et tous les volumes. Sur un système hôte n'ayant qu'une seule partition il y a un risque, tous comme le risque lié au répertoire /var/log/, que le disque devient saturé.

[WARN] 1.1.3 - Ensure auditing is configured for the Docker daemon (Automated)

[WARN] 1.1.4 - Ensure auditing is configured for Docker files and directories -/run/containerd (Automated)
[WARN] 1.1.5 - Ensure auditing is configured for Docker files and directories - /var/lib/docker (Automated)
[WARN] 1.1.6 - Ensure auditing is configured for Docker files and directories - /etc/docker (Automated)
[WARN] 1.1.7 - Ensure auditing is configured for Docker files and directories - docker.service (Automated)
[WARN] 1.1.9 - Ensure auditing is configured for Docker files and directories - docker.socket (Automated)
[WARN] 1.1.10 - Ensure auditing is configured for Docker files and directories - /etc/default/docker (Automated)
[WARN] 1.1.12 - Ensure auditing is configured for Dockerfiles and directories - /etc/containerd/config.toml (Automated)
[WARN] 1.1.14 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd (Automated)
[WARN] 1.1.15 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim (Automated)
[WARN] 1.1.18 - Ensure auditing is configured for Docker files and directories - /usr/bin/runc (Automated)

Ces avertissements sont présents parce que auditd n'est pas installé et parce qu'il n'y a pas de règles spécifiques au daemon Docker et ses répertoires et fichiers associés.

Editez le fichier /etc/apt/sources.list selon l'exemple suivant :

root@manager:~/docker-bench-security# vi /etc/apt/sources.list

root@manager:~/docker-bench-security# cat /etc/apt/sources.list
deb http://archive.debian.org/debian/ stretch main
deb-src http://archive.debian.org/debian/ stretch main
deb http://archive.debian.org/debian-security stretch/updates main
deb-src http://archive.debian.org/debian-security stretch/updates main
deb [arch=amd64] https://download.docker.com/linux/debian stretch stable

Exécutez la commande apt-update :

root@manager:~/docker-bench-security# apt update
Ign:1 http://archive.debian.org/debian stretch InRelease
Atteint:2 http://archive.debian.org/debian-security stretch/updates InRelease
Atteint:3 http://archive.debian.org/debian stretch Release
Réception de:4 https://download.docker.com/linux/debian stretch InRelease [44,8 kB]
44,8 ko réceptionnés en 0s (107 ko/s)                     
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances       
Lecture des informations d'état... Fait
254 packages can be upgraded. Run 'apt list --upgradable' to see them.

Pour installer auditd, utilisez apt-get :

root@manager:~/docker-bench-security# apt-get install auditd -y

Modifiez ensuite le fichier /etc/audit/rules.d/audit.rules :

root@manager:~/docker-bench-security# vi /etc/audit/rules.d/audit.rules

root@manager:~/docker-bench-security# cat /etc/audit/rules.d/audit.rules
## First rule - delete all
-D

## Increase the buffers to survive stress events.
## Make this bigger for busy systems
-b 8192

## This determine how long to wait in burst of events
--backlog_wait_time 0

## Set failure mode to syslog
-f 1

##Docker
-w /usr/bin/docker -p wa
-w /var/lib/docker -p wa
-w /etc/docker -p wa
-w /lib/systemd/system/docker.service -p wa
-w /lib/systemd/system/docker.socket -p wa
-w /etc/default/docker -p wa
-w /etc/docker/daemon.json -p wa
-w /usr/bin/docker-containerd -p wa
-w /usr/bin/docker-runc -p wa
-w /usr/bin/containerd -p wa
-w /run/containerd -p wa
-w /etc/containerd/config.toml -p wa
-w /usr/bin/containerd-shim -p wa
-w /usr/bin/runc -p wa

Important : L'option -w indique watch et concerne le fichier qui suit. L'option -p journalise les modifications éventuelles.

Re-démarrez ensuite auditd :

root@manager:~/docker-bench-security# systemctl restart auditd

Vérifiez ensuite la prise en charge des règles :

root@manager:~/docker-bench-security# cat /etc/audit/audit.rules
## This file is automatically generated from /etc/audit/rules.d
-D
-b 8192
-f 1
--backlog_wait_time 0
-w /usr/bin/docker -p wa
-w /var/lib/docker -p wa
-w /etc/docker -p wa
-w /lib/systemd/system/docker.service -p wa
-w /lib/systemd/system/docker.socket -p wa
-w /etc/default/docker -p wa
-w /etc/docker/daemon.json -p wa
-w /usr/bin/docker-containerd -p wa
-w /usr/bin/docker-runc -p wa
-w /usr/bin/containerd -p wa
-w /run/containerd -p wa
-w /etc/containerd/config.toml -p wa
-w /usr/bin/containerd-shim -p wa
-w /usr/bin/runc -p wa

Important - Pour plus d'information concernant la création de règles personalisées avec auditd, consultez cette page.

Ré-exécutez le script Docker Benchmark Security :

root@manager:~/docker-bench-security# ./docker-bench-security.sh 
...
[PASS] 1.1.4 - Ensure auditing is configured for Docker files and directories -/run/containerd (Automated)
[PASS] 1.1.5 - Ensure auditing is configured for Docker files and directories - /var/lib/docker (Automated)
[PASS] 1.1.6 - Ensure auditing is configured for Docker files and directories - /etc/docker (Automated)
[PASS] 1.1.7 - Ensure auditing is configured for Docker files and directories - docker.service (Automated)
[PASS] 1.1.9 - Ensure auditing is configured for Docker files and directories - docker.socket (Automated)
[PASS] 1.1.10 - Ensure auditing is configured for Docker files and directories - /etc/default/docker (Automated)
[PASS] 1.1.12 - Ensure auditing is configured for Dockerfiles and directories - /etc/containerd/config.toml (Automated)
[PASS] 1.1.14 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd (Automated)
[PASS] 1.1.15 - Ensure auditing is configured for Docker files and directories - /usr/bin/containerd-shim (Automated)
[PASS] 1.1.18 - Ensure auditing is configured for Docker files and directories - /usr/bin/runc (Automated)
...

LAB #5 - Sécurisation de la Configuration du daemon Docker

Exécutez de nouveau le script docker-bench-security.sh. Vous devez obtenir un résultat similaire à ceci en ce qui concerne la sécurité de la configuration du daemon Docker :

...
[INFO] 2 - Docker daemon configuration
[NOTE] 2.1 - Run the Docker daemon as a non-root user, if possible (Manual)
[WARN] 2.2 - Ensure network traffic is restricted between containers on the default bridge (Scored)
[PASS] 2.3 - Ensure the logging level is set to 'info' (Scored)
[PASS] 2.4 - Ensure Docker is allowed to make changes to iptables (Scored)
[PASS] 2.5 - Ensure insecure registries are not used (Scored)
[PASS] 2.6 - Ensure aufs storage driver is not used (Scored)
[INFO] 2.7 - Ensure TLS authentication for Docker daemon is configured (Scored)
[INFO]      * Docker daemon not listening on TCP
[INFO] 2.8 - Ensure the default ulimit is configured appropriately (Manual)
[INFO]      * Default ulimit doesn't appear to be set
[WARN] 2.9 - Enable user namespace support (Scored)
[PASS] 2.10 - Ensure the default cgroup usage has been confirmed (Scored)
[PASS] 2.11 - Ensure base device size is not changed until needed (Scored)
[WARN] 2.12 - Ensure that authorization for Docker client commands is enabled (Scored)
[WARN] 2.13 - Ensure centralized and remote logging is configured (Scored)
[WARN] 2.14 - Ensure containers are restricted from acquiring new privileges (Scored)
[WARN] 2.15 - Ensure live restore is enabled (Scored)
[WARN] 2.16 - Ensure Userland Proxy is Disabled (Scored)
[PASS] 2.17 - Ensure that a daemon-wide custom seccomp profile is applied if appropriate (Manual)
[PASS] 2.18 - Ensure that experimental features are not implemented in production (Scored)
...

Les problèmes de sécurité qu'il convient à résoudre sont indiqués par les annotations [WARN].

[WARN] 2.2 - Ensure network traffic is restricted between containers on the default bridge (Scored)

Par défaut Docker permet un trafic réseau sans restrictions entre des conteneurs sur le même hôte. Il est cependant possible de modifier la configuration par défaut. Pour empêcher ceci, il faut fixer la valeur de icc à false. De cette façon, docker crée des conteneurs qui peuvent communiquer entre eux uniquement s'il existe un lien.

Pour plus d'informations, consultez cette page.

[WARN] 2.9 - Enable user namespace support (Scored)

Cet avertissement nous indique que l'utilisation des user namespaces n'est pas activée. Le support des user namespaces du noyau Linux permet d'attribuer une plage d'UIDs et de GIDs unique à un processus et donc à un conteneur, en dehors de la plage traditionnelle utilisée par l'hôte Docker. L'avantage ici est que les processus ayant l'UID de root dans le conteneur seront mappés à un UID sans privilèges dans l'hôte Docker. Pour utiliser user namespace, il faut fixer la valeur de userns-remap à default. Dans ce cas précis Docker crée un utilisateur dénommé dockremap. Notez qu'il est aussi possible de fixer vos propres valeurs avec “userns-remap”: “user:group”.

Pour plus d'informations, consultez cette page.

[WARN] 2.12 - Ensure that authorization for Docker client commands is enabled (Scored)

Par défaut, Docker permet un accès sans restrictions aux daemon Docker. Il est possible de restreindre l'accès à des utilisateurs authentifiés en utilisant un plug-in. Cette ligne est sans importance parce que l'accès au socket local Docker est limité aux membres du groupe docker (voir DOF202 - La Sécurité de la Configuration de l'Hôte Docker)

Pour plus d'informations, consultez cette page.

[WARN] 2.13 - Ensure centralized and remote logging is configured (Scored)

Cet avertissement indique que la configuration de rsyslog ne permet pas l'envoie des traces vers un serveur de journalisation distant. Elle indique aussi que la valeur de log-driver n'a pas été spécifiée. Pour activer cette configuration, il faut fixer la valeur de log-driver à syslog puis configurer syslog ainsi que la valeur de log-opts correctement.

Pour plus d'informations, consultez cette page.

[WARN] 2.14 - Ensure containers are restricted from acquiring new privileges (Scored)

Par défaut un conteneur peut obtenir une escalade de privilèges en utilisant les binaires setuid ou setgid. Pour interdire ceci il faut fixer la valeur de no-new-privileges à true.

Pour plus d'informations, consultez cette page.

[WARN] 2.15 - Ensure live restore is enabled (Scored)

L'option –live-restore permet une prise en charge complète des conteneurs sans démon dans Docker. Elle garantit que Docker n'arrête pas les conteneurs lors de l'arrêt ou de la restauration et qu'il se reconnecte correctement au conteneur lors du redémarrage.

[WARN] 2.16 - Ensure Userland Proxy is Disabled (Scored)

Il existe deux méthodes pour qu'un conteneur puisse router vers l'extérieur :

Il est préférable d'utiliser le mode Hairpin NAT qui peut utilise Iptables et qui possède de meilleures performances. La plupart des systèmes d'opération modernes peuvent utiliser le mode Hairpin NAT. Pour désactiver Userland Proxy, il faut fixer la valeur de userland-proxy à false.

Pour plus d'informations, consultez cette page.

5.1 - Le Fichier /etc/docker/daemon.json

Créez le fichier /etc/docker/daemon.json :

root@manager:~/docker-bench-security# vi /etc/docker/daemon.json

root@manager:~/docker-bench-security# cat /etc/docker/daemon.json
{
    "icc": false,
    "userns-remap": "default",
    "log-driver": "syslog",
    "live-restore": true,
    "userland-proxy": false,
    "no-new-privileges": true
}

Re-démarrez le service Docker :

root@manager:~/docker-bench-security# systemctl restart docker

Vérifiez la présence de l'utilisateur dénommé dockremap :

root@manager:~/docker-bench-security# id dockremap
uid=116(dockremap) gid=121(dockremap) groupes=121(dockremap)

Ré-exécutez le script Docker Benchmark Security :

root@manager:~/docker-bench-security# ./docker-bench-security.sh 
...
[PASS] 2.2 - Ensure network traffic is restricted between containers on the default bridge (Scored)
[PASS] 2.3 - Ensure the logging level is set to 'info' (Scored)
[PASS] 2.4 - Ensure Docker is allowed to make changes to iptables (Scored)
[PASS] 2.5 - Ensure insecure registries are not used (Scored)
[PASS] 2.6 - Ensure aufs storage driver is not used (Scored)
[PASS] 2.9 - Enable user namespace support (Scored)
[PASS] 2.10 - Ensure the default cgroup usage has been confirmed (Scored)
[PASS] 2.11 - Ensure base device size is not changed until needed (Scored)
[PASS] 2.13 - Ensure centralized and remote logging is configured (Scored)
[PASS] 2.14 - Ensure containers are restricted from acquiring new privileges (Scored)
[PASS] 2.15 - Ensure live restore is enabled (Scored)
[PASS] 2.16 - Ensure Userland Proxy is Disabled (Scored)
[PASS] 2.17 - Ensure that a daemon-wide custom seccomp profile is applied if appropriate (Manual)
[PASS] 2.18 - Ensure that experimental features are not implemented in production (Scored)
...

Pour plus d'informations, consultez cette page.

LAB #6 - Sécurisation des Images et les Fichiers de Construction

Créez le conteneur mysql :

root@manager:~/docker-bench-security# apt install  --only-upgrade docker-ce
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances       
Lecture des informations d'état... Fait
Le paquet suivant a été installé automatiquement et n'est plus nécessaire :
  libsasl2-modules
Veuillez utiliser « apt autoremove » pour le supprimer.
Les paquets suivants seront mis à jour :
  docker-ce
1 mis à jour, 0 nouvellement installés, 0 à enlever et 252 non mis à jour.
Il est nécessaire de prendre 22,7 Mo dans les archives.
Après cette opération, 497 ko d'espace disque supplémentaires seront utilisés.
Réception de:1 https://download.docker.com/linux/debian stretch/stable amd64 docker-ce amd64 5:19.03.15~3-0~debian-stretch [22,7 MB]
22,7 Mo réceptionnés en 0s (26,0 Mo/s)
Lecture des fichiers de modifications (« changelog »)... Terminé
(Lecture de la base de données... 112865 fichiers et répertoires déjà installés.)
Préparation du dépaquetage de .../docker-ce_5%3a19.03.15~3-0~debian-stretch_amd64.deb ...
Dépaquetage de docker-ce (5:19.03.15~3-0~debian-stretch) sur (5:19.03.4~3-0~debian-stretch) ...
Paramétrage de docker-ce (5:19.03.15~3-0~debian-stretch) ...
Traitement des actions différées (« triggers ») pour systemd (232-25+deb9u14) ...

root@manager:~/docker-bench-security# docker container run -d --name mysql -e MYSQL_ROOT_PASSWORD=password mysql
Unable to find image 'mysql:latest' locally
latest: Pulling from library/mysql
e9f2695d7e5b: Pull complete 
80c6055edb33: Pull complete 
c646ab461d8b: Pull complete 
012006c6a591: Pull complete 
929d5fa34b95: Pull complete 
17e0243877fa: Pull complete 
1850b459cd2f: Pull complete 
8dceaed53baf: Pull complete 
197b834ea1cd: Pull complete 
8df78c25b227: Pull complete 
Digest: sha256:ceb98918916bd5261b3e9866ac8271d75d276b8a4db56f1dc190770342a77a9b
Status: Downloaded newer image for mysql:latest
e503dd98f88992ae6ed5ec4dcaa2e18982ade8ec74966869515a120763418f74

root@manager:~/docker-bench-security# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
e503dd98f889        mysql               "docker-entrypoint.s…"   2 minutes ago       Up 2 minutes        3306/tcp, 33060/tcp   mysql

Exécutez de nouveau le script docker-bench-security.sh. Vous devez obtenir un résultat similaire à ceci en ce qui concerne la sécurité des images et les fichiers de leur construction :

root@manager:~/docker-bench-security# ./docker-bench-security.sh
...
[INFO] 4 - Container Images and Build File
[WARN] 4.1 - Ensure that a user for the container has been created (Automated)
[WARN]      * Running as root: mysql
[NOTE] 4.2 - Ensure that containers use only trusted base images (Manual)
[NOTE] 4.3 - Ensure that unnecessary packages are not installed in the container (Manual)
[NOTE] 4.4 - Ensure images are scanned and rebuilt to include security patches (Manual)
[WARN] 4.5 - Ensure Content trust for Docker is Enabled (Automated)
[WARN] 4.6 - Ensure that HEALTHCHECK instructions have been added to container images (Automated)
[WARN]      * No Healthcheck found: [mysql:latest]
[PASS] 4.7 - Ensure update instructions are not used alone in the Dockerfile (Manual)
[NOTE] 4.8 - Ensure setuid and setgid permissions are removed (Manual)
[PASS] 4.9 - Ensure that COPY is used instead of ADD in Dockerfiles (Manual)
[NOTE] 4.10 - Ensure secrets are not stored in Dockerfiles (Manual)
[NOTE] 4.11 - Ensure only verified packages are installed (Manual)
[NOTE] 4.12 - Ensure all signed artifacts are validated (Manual)
...

[WARN] 4.1 - Ensure that a user for the container has been created (Automated)

Les processus dans le conteneur mysql tourne sous l'UID de root. Ceci est l'action par défaut de Docker.

Pour plus d'informations, consultez cette page.

[WARN] 4.5 - Ensure Content trust for Docker is Enabled (Automated)

Cette ligne indique que le support de Content trust n'a pas été activé. Content trust permet de s'assurer de la provenance des images utilisées car celles-ci sont signées.

Pour activer le Content trust, il faut positionner la valeur de la variable DOCKER_CONTENT_TRUST à 1 :

root@manager:~/docker-bench-security# echo "DOCKER_CONTENT_TRUST=1" | sudo tee -a /etc/environment
DOCKER_CONTENT_TRUST=1

root@manager:~/docker-bench-security# source /etc/environment

Re-démarrez la machine virtuelle Manager et démarrez le conteneur mysql :

root@manager:~/docker-bench-security# reboot
Connection to 10.0.2.62 closed by remote host.
Connection to 10.0.2.62 closed.

root@debian11:~# ssh -l trainee 10.0.2.62
trainee@10.0.2.62's password: trainee
Linux manager.i2tch.loc 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Dec 17 18:39:07 2023 from 10.0.2.46

trainee@manager:~$ su -
Mot de passe : fenestros

root@manager:~# cd docker-bench-security/

root@manager:~/docker-bench-security#

root@manager:~/docker-bench-security# docker start mysql
mysql

Exécutez de nouveau le script et notez le contenu de la section 4 :

root@manager:~/docker-bench-security# ./docker-bench-security.sh
...
[INFO] 4 - Container Images and Build File
[WARN] 4.1 - Ensure that a user for the container has been created (Automated)
[WARN]      * Running as root: mysql
[NOTE] 4.2 - Ensure that containers use only trusted base images (Manual)
[NOTE] 4.3 - Ensure that unnecessary packages are not installed in the container (Manual)
[NOTE] 4.4 - Ensure images are scanned and rebuilt to include security patches (Manual)
[PASS] 4.5 - Ensure Content trust for Docker is Enabled (Automated)
[WARN] 4.6 - Ensure that HEALTHCHECK instructions have been added to container images (Automated)
[WARN]      * No Healthcheck found: [mysql:latest]
[PASS] 4.7 - Ensure update instructions are not used alone in the Dockerfile (Manual)
[NOTE] 4.8 - Ensure setuid and setgid permissions are removed (Manual)
[PASS] 4.9 - Ensure that COPY is used instead of ADD in Dockerfiles (Manual)
[NOTE] 4.10 - Ensure secrets are not stored in Dockerfiles (Manual)
[NOTE] 4.11 - Ensure only verified packages are installed (Manual)
[NOTE] 4.12 - Ensure all signed artifacts are validated (Manual)
...

Pour plus d'informations, consultez cette page.

[WARN] 4.6 - Ensure that HEALTHCHECK instructions have been added to container images

Quand une image est construite il est possible d'y mettre un HEALTHCHECK dont le statut peut être vérifié par Docker afin de relancer le conteneur si nécessaire.

Pour mettre en place un HEALTHCHECK, il conviendrait, par exemple, d'inclure la ligne suivante dans le fichier DOCKERFILE servant à construire l'image :

HEALTHCHECK --interval=20s --timeout=3s CMD curl -f http://localhost:8000/ || exit 1

Ce test permet de vérifier que le conteneur peut atteindre l'URL indiqué tous les 20 secondes et produit une erreur au bout de 3 secondes.

Pour plus d'informations, consultez cette page.

LAB #7 - Sécurisation du Container Runtime

Exécutez de nouveau le script docker-bench-security.sh, vous devez obtenir un résultat similaire à ceci en ce qui concerne la sécurité du Container Runtime :

root@manager:~/docker-bench-security# ./docker-bench-security.sh
...
[INFO] 5 - Container Runtime
[WARN] 5.1 - Ensure that, if applicable, an AppArmor Profile is enabled (Automated)
[WARN]      * No AppArmorProfile Found: mysql
[WARN] 5.2 - Ensure that, if applicable, SELinux security options are set (Automated)
[WARN]      * No SecurityOptions Found: mysql
[PASS] 5.3 - Ensure that Linux kernel capabilities are restricted within containers (Automated)
[PASS] 5.4 - Ensure that privileged containers are not used (Automated)
[PASS] 5.5 - Ensure sensitive host system directories are not mounted on containers (Automated)
[PASS] 5.6 - Ensure sshd is not run within containers (Automated)
[PASS] 5.7 - Ensure privileged ports are not mapped within containers (Automated)
[PASS] 5.8 - Ensure that only needed ports are open on the container (Manual)
[PASS] 5.9 - Ensure that the host's network namespace is not shared (Automated)
[WARN] 5.10 - Ensure that the memory usage for containers is limited (Automated)
[WARN]       * Container running without memory restrictions: mysql
[WARN] 5.11 - Ensure that CPU priority is set appropriately on containers (Automated)
[WARN]       * Container running without CPU restrictions: mysql
[WARN] 5.12 - Ensure that the container's root filesystem is mounted as read only (Automated)
[WARN]       * Container running with root FS mounted R/W: mysql
[PASS] 5.13 - Ensure that incoming container traffic is bound to a specific host interface (Automated)
[WARN] 5.14 - Ensure that the 'on-failure' container restart policy is set to '5' (Automated)
[WARN]       * MaximumRetryCount is not set to 5: mysql
[PASS] 5.15 - Ensure that the host's process namespace is not shared (Automated)
[PASS] 5.16 - Ensure that the host's IPC namespace is not shared (Automated)
[PASS] 5.17 - Ensure that host devices are not directly exposed to containers (Manual)
[INFO] 5.18 - Ensure that the default ulimit is overwritten at runtime if needed (Manual)
[INFO]       * Container no default ulimit override: mysql
[PASS] 5.19 - Ensure mount propagation mode is not set to shared (Automated)
[PASS] 5.20 - Ensure that the host's UTS namespace is not shared (Automated)
[PASS] 5.21 - Ensure the default seccomp profile is not Disabled (Automated)
[NOTE] 5.22 - Ensure that docker exec commands are not used with the privileged option (Automated)
[NOTE] 5.23 - Ensure that docker exec commands are not used with the user=root option (Manual)
[PASS] 5.24 - Ensure that cgroup usage is confirmed (Automated)
[PASS] 5.25 - Ensure that the container is restricted from acquiring additional privileges (Automated)
[WARN] 5.26 - Ensure that container health is checked at runtime (Automated)
[WARN]       * Health check not set: mysql
[INFO] 5.27 - Ensure that Docker commands always make use of the latest version of their image (Manual)
[WARN] 5.28 - Ensure that the PIDs cgroup limit is used (Automated)
[WARN]       * PIDs limit not set: mysql
[INFO] 5.29 - Ensure that Docker's default bridge 'docker0' is not used (Manual)
[INFO]       * Container in docker0 network: mysql
[PASS] 5.30 - Ensure that the host's user namespaces are not shared (Automated)
[PASS] 5.31 - Ensure that the Docker socket is not mounted inside any containers (Automated)
...

Les problèmes de sécurité qu'il convient à résoudre sont indiqués par les annotations [WARN].

[WARN] 5.1 - Ensure that, if applicable, an AppArmor Profile is enabled (Automated)

Cet avertissement est présent parce que le conteneur n'utilise pas AppArmor.

Pour plus d'informations, consultez cette page.

[WARN] 5.2 - Ensure that, if applicable, SELinux security options are set (Automated)

Cet avertissement est présent parce que le conteneur n'utilise pas SELinux.

Pour plus d'informations, consultez cette page.

[WARN] 5.10 - Ensure that the memory usage for containers is limited (Automated)

Cet avertissement est du au fait que les conteneurs ont automatiquement accès à la totalité de la RAM de l'hôte Docker :

root@manager:~# docker run -d -p 8081:80 nginx
b04b2a6f0dd93da21a8b7640afc319406e42868a141f90936dbcf52ab5bffb0d
root@manager:~# docker stats
CONTAINER ID        NAME                 CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
b04b2a6f0dd9        dazzling_blackburn   0.00%               1.789MiB / 1.957GiB   0.09%               2.38kB / 0B         0B / 0B             2
^C

Supprimez le conteneur et re-créez le avec une limite de mémoire :

root@manager:~/docker-bench-security# docker run -d -p 8081:80 nginx
Unable to find image 'nginx:latest' locally
sha256:10d1f5b58f74683ad34eb29287e07dab1e90f10af243f151bb50aa5dbb4d62ee: Pulling from library/nginx
1f7ce2fa46ab: Pull complete 
9b16c94bb686: Pull complete 
9a59d19f9c5b: Pull complete 
9ea27b074f71: Pull complete 
c6edf33e2524: Pull complete 
84b1ff10387b: Pull complete 
517357831967: Pull complete 
Digest: sha256:10d1f5b58f74683ad34eb29287e07dab1e90f10af243f151bb50aa5dbb4d62ee
Status: Downloaded newer image for nginx@sha256:10d1f5b58f74683ad34eb29287e07dab1e90f10af243f151bb50aa5dbb4d62ee
Tagging nginx@sha256:10d1f5b58f74683ad34eb29287e07dab1e90f10af243f151bb50aa5dbb4d62ee as nginx:latest
e14d5112c2feb71e6f37252bcf99d03603d6b7a3e200bff0d55611a0e9a25e2b

root@manager:~/docker-bench-security# docker stats
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
e14d5112c2fe        strange_bassi       0.00%               2.215MiB / 1.957GiB   0.11%               2.16kB / 0B         0B / 0B             2
e503dd98f889        mysql               0.51%               351.3MiB / 1.957GiB   17.53%              5.54kB / 0B         167MB / 118MB       37
^C

Supprimez le conteneur et re-créez-le avec une limite de mémoire :

root@manager:~/docker-bench-security# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                  NAMES
e14d5112c2fe        nginx               "/docker-entrypoint.…"   About a minute ago   Up About a minute   0.0.0.0:8081->80/tcp   strange_bassi
e503dd98f889        mysql               "docker-entrypoint.s…"   18 minutes ago       Up 7 minutes        3306/tcp, 33060/tcp    mysql

root@manager:~/docker-bench-security# docker rm -f e14
e14

root@manager:~/docker-bench-security# docker run -d -p 8081:80 --memory="256m" nginx
38e91e096c83f7cbe78089617a4d70110bd273f53339f8fed8df2503d3cd65ca

root@manager:~/docker-bench-security# docker stats
CONTAINER ID        NAME                CPU %               MEM USAGE / LIMIT     MEM %               NET I/O             BLOCK I/O           PIDS
38e91e096c83        sweet_vaughan       0.00%               2.223MiB / 256MiB     0.87%               2.16kB / 0B         0B / 0B             2
e503dd98f889        mysql               0.49%               351.3MiB / 1.957GiB   17.53%              5.61kB / 0B         167MB / 118MB       37
^C

Pour plus d'informations, consultez cette page.

[WARN] 5.11 - Ensure that CPU priority is set appropriately on containers (Automated)

Cet avertissement est du au fait que les conteneurs ont automatiquement accès à tous les CPU de l'hôte Docker. Pour limiter cet accès, plusieurs options sont possibles dont le plus couramment utilisée est –cpu-shares.

La valeur de cpu-shares est relative à la valeur par défaut de 1024. Un valeur de 512 permet au conteneur d'accéder à 50% des cycles du CPU mais uniquement quand les cycles sont limités. Quand les cycles de CPU ne sont par restreints, chaque conteneur utilise autant qu'il en a besoin.

Pour plus d'informations, consultez cette page.

[WARN] 5.12 - Ensure that the container's root filesystem is mounted as read only (Automated)

Afin de minimiser le risque de compromettre un conteneur par la présence de code malicieux, il est conseillé de démarrer les conteneurs en lecture seule, sauf pour les volumes qui nécessitent un accès en écriture/lecture.

Créez le fichier write_a_file dans le conteneur mysql :

root@manager:~/docker-bench-security# docker container exec mysql touch /write_a_file

La Commande docker container diff indique les différences apportées au conteneur par rapport à l'image dont il est issu :

root@manager:~/docker-bench-security# docker diff mysql
C /run
C /run/mysqld
A /run/mysqld/mysqld.pid
A /run/mysqld/mysqld.sock
A /run/mysqld/mysqld.sock.lock
A /run/mysqld/mysqlx.sock
A /run/mysqld/mysqlx.sock.lock
A /write_a_file

Important : Notez que la sortie indique les changements apportés au conteneur.

Arrêtez et supprimez le conteneur :

root@manager:~/docker-bench-security# docker stop mysql
mysql

root@manager:~/docker-bench-security# docker rm  mysql
mysql

Lancez un conteneur mysql en lecture seule :

root@manager:~/docker-bench-security# docker run -d --name mysql --read-only -v /var/lib/mysql -v /tmp -v /var/run/mysqld -e MYSQL_ROOT_PASSWORD=password mysql
711ab28bdfb41220c84246c1658bcde398681a78291bbbe7d3bbfd9bc317d41b

Créez le fichier write_a_file dans le conteneur mysql :

root@manager:~/docker-bench-security# docker container exec mysql touch /write_a_file
touch: cannot touch '/write_a_file': Read-only file system

Important : Notez l'erreur touch: cannot touch '/write_a_file': Read-only file system.

Exécutez la commande docker container diff :

root@manager:~/docker-bench-security# docker container diff mysql
root@manager:~/docker-bench-security# 

Important : Notez que la commande ne retourne aucune sortie. En effet le conteneur étant en lecture seule, aucun changement ne peut intervenir.

[WARN] 5.14 - Ensure that the 'on-failure' container restart policy is set to '5' (Automated)

Cet avertissement concerne la politique de re-démarrage du conteneur. La politique on-failure[:max-retries] implique que le conteneur est re-démarré en cas d'arrêt du à une erreur qui se manifeste en tant que code de retour autre que zéro. La valeur de max-retries est le nombre de fois que Docker va essayer de re-démarrer le conteneur. Cette politique peut être mise en place au démarrage du conteneur, par exemple :

# docker container run -d --name mysql --read-only --restart on-failure:5 -v /var/lib/mysql -v /tmp -v /var/run/mysqld -e MYSQL_ROOT_PASSWORD=password mysql

Pour plus d'informations, consultez cette page.

[WARN] 5.26 - Ensure that container health is checked at runtime (Automated)

Voir l'avertissement 4.6.

[WARN] 5.28 - Ensure that the PIDs cgroup limit is used (Automated)

Sans l'utilisation de l'option –pids-limit un conteneur pourrait être victime d'une attaque de type Fork Bomb, un type spécifique de dénie de service. Ce type d'attaque peut faire crasher l'hôte Docker et le seul remède est de re-démarrer l'hôte. Voici un exemple d'un Fork Bomb :

root@manager:~/docker-bench-security# docker run -u 1000 ubuntu bash -c ":() { : | : & }; :; while [[ true ]]; do sleep 1; done"

L'hôte Docker manager crash. Après avoir re-démarrer la machine virtuelle, créez de nouveau le conteneur en utilisant l'option –pids-limit :

root@manager:~/docker-bench-security# docker run -u 1000 --pids-limit 100 ubuntu bash -c ":() { : | : & }; :; while [[ true ]]; do sleep 1; done"
Unable to find image 'ubuntu:latest' locally
sha256:6042500cf4b44023ea1894effe7890666b0c5c7871ed83a97c36c76ae560bb9b: Pulling from library/ubuntu
a48641193673: Pull complete 
Digest: sha256:6042500cf4b44023ea1894effe7890666b0c5c7871ed83a97c36c76ae560bb9b
Status: Downloaded newer image for ubuntu@sha256:6042500cf4b44023ea1894effe7890666b0c5c7871ed83a97c36c76ae560bb9b
Tagging ubuntu@sha256:6042500cf4b44023ea1894effe7890666b0c5c7871ed83a97c36c76ae560bb9b as ubuntu:latest
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
environment: fork: retry: Resource temporarily unavailable
^P^Q

Pour plus d'informations, consultez cette page.

Supprimez maintenant tous les conteneurs déjà créées :

root@manager:~/docker-bench-security# docker rm -f `docker ps -aq`
db5ae43c3e55
f3b2528fbac0
711ab28bdfb4

root@manager:~/docker-bench-security# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

Re-créez le conteneur mysql en intégrant les points vus ci-dessus :

root@manager:~/docker-bench-security# docker run -d --name mysql --read-only --restart on-failure:5 --security-opt="no-new-privileges:true" --pids-limit 100 --memory="256m" --cpu-shares 512 -v /var/lib/mysql -v /tmp -v /var/run/mysqld -e MYSQL_ROOT_PASSWORD=password mysql
f49d1ffdeae2e83435e8cc3a2e03fb2e0b33e5609d266e5a3403ff8859e5d122

root@manager:~/docker-bench-security# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                 NAMES
f49d1ffdeae2        mysql               "docker-entrypoint.s…"   16 seconds ago      Up 15 seconds       3306/tcp, 33060/tcp   mysql

Exécutez de nouveau le script docker-bench-security.sh, vous devez obtenir un résultat similaire à ceci en ce qui concerne la sécurité du Container Runtime :

root@manager:~/docker-bench-security# ./docker-bench-security.sh
...
[PASS] 5.2 - Ensure that, if applicable, SELinux security options are set (Automated)
[PASS] 5.10 - Ensure that the memory usage for containers is limited (Automated)
[PASS] 5.11 - Ensure that CPU priority is set appropriately on containers (Automated)
[PASS] 5.12 - Ensure that the container's root filesystem is mounted as read only (Automated)
[PASS] 5.14 - Ensure that the 'on-failure' container restart policy is set to '5' (Automated)
[PASS] 5.28 - Ensure that the PIDs cgroup limit is used (Automated)
...

LAB #8 - Sécurisation des Images avec Docker Content Trust

Docker Content Trust (DCT) a été introduit avec Docker Engine 1.8 et Docker CS Engine 1.9.0. DCT permet la vérification de l'authenticité, de l'intégrité et la date de publication d'une image Docker dans un registry. Par défaut, DCT est désactivé.

DCT est utilisé par le Docker Hub Registry mais peut aussi être mis en place dans des Registry privés, notamment grâce à la mise en place du Docker Container Registry qui est inclus avec Docker Enterprise.

DCT est basé sur l'utilisation de l'outil Docker Notary pour publier et gérer du contenu ainsi que The Update Framework (TUF).

Pour plus d'information concernant DCT, consultez cette page.

8.1 - DOCKER_CONTENT_TRUST

Pour utiliser Docker Content Trust (DCT), il convient de vérifier que la valeur de la variable DOCKER_CONTENT_TRUST est 1 :

root@manager:~# echo $DOCKER_CONTENT_TRUST
1

Dans le cas contraire, il faut fixer la valeur de la variable à 1 :

root@manager:~# export DOCKER_CONTENT_TRUST=1
root@manager:~# echo $DOCKER_CONTENT_TRUST
1

8.2 - DCT et la commande docker pull

Afin d'utiliser un registry privé du Docker Hub, il est nécessaire de se connecter :

root@manager:~# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: <votre_compte>
Password: <votre_mot_de_passe>
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

Pour constater l'impact de l'utilisation de DCT, il convient simplement de faire un pull d'une image non-signée :

root@manager:~# docker image pull i2tch/docker:unsigned
Error: remote trust data does not exist for docker.io/i2tch/docker: notary.docker.io does not have trust data for docker.io/i2tch/docker

Important : Notez l'erreur Error: remote trust data does not exist for docker.io/i2tch/docker …. En effet Docker Trust empêche l'utilisation des images non-signées.

Par contre, toutes les images de type official sont signées :

root@manager:~# docker image pull centos
Using default tag: latest
Pull (1 of 1): centos:latest@sha256:f94c1d992c193b3dc09e297ffd54d8a4f1dc946c37cbeceb26d35ce1647f88d9
sha256:f94c1d992c193b3dc09e297ffd54d8a4f1dc946c37cbeceb26d35ce1647f88d9: Pulling from library/centos
729ec3a6ada3: Pull complete 
Digest: sha256:f94c1d992c193b3dc09e297ffd54d8a4f1dc946c37cbeceb26d35ce1647f88d9
Status: Downloaded newer image for centos@sha256:f94c1d992c193b3dc09e297ffd54d8a4f1dc946c37cbeceb26d35ce1647f88d9
Tagging centos@sha256:f94c1d992c193b3dc09e297ffd54d8a4f1dc946c37cbeceb26d35ce1647f88d9 as centos:latest
docker.io/library/centos:latest

Cette image est maintenant présente sur manager.i2tch.loc :

root@manager:~# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              775349758637        9 days ago          64.2MB
nginx               latest              540a289bab6c        2 weeks ago         126MB
alpine              latest              965ea09ff2eb        2 weeks ago         5.55MB
mysql               latest              c8ee894bd2bd        3 weeks ago         456MB
centos              latest              0f3e07c0138f        5 weeks ago         220MB

L'option disable-content-trust

Il est aussi possible d'activer ou de désactiver l'utilisation de DCT avec les options –disable-content-trust=false/true lors de l'utilisation des commandes docker build, docker push et docker pull, docker create et docker run :

root@manager:~# docker image pull --disable-content-trust=true i2tch/docker:unsigned
unsigned: Pulling from i2tch/docker
10d70a43a9f9: Pull complete 
4f4fb700ef54: Pull complete 
8951e3a91277: Pull complete 
d1814ff35b8b: Pull complete 
ff2a2bbf6141: Pull complete 
b7205da5c3c9: Pull complete 
458ea241cc75: Pull complete 
74d1c0702786: Pull complete 
c66f3692932d: Pull complete 
9224bd1b9757: Pull complete 
Digest: sha256:885fc831cb853700ded04029b4fa70ed502947042f6f154e432395cb35619d11
Status: Downloaded newer image for i2tch/docker:unsigned
docker.io/i2tch/docker:unsigned

root@manager:~# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              775349758637        9 days ago          64.2MB
nginx               latest              540a289bab6c        2 weeks ago         126MB
alpine              latest              965ea09ff2eb        2 weeks ago         5.55MB
mysql               latest              c8ee894bd2bd        3 weeks ago         456MB
centos              latest              0f3e07c0138f        5 weeks ago         220MB
i2tch/docker        unsigned            9b915a241e29        3 years ago         212MB

root@manager:~# docker rmi i2tch/docker:unsigned
Untagged: i2tch/docker:unsigned
Untagged: i2tch/docker@sha256:885fc831cb853700ded04029b4fa70ed502947042f6f154e432395cb35619d11
Deleted: sha256:9b915a241e29dc2767980445e3109412b1905b6f1617aea7098e7ac1e5837ae2
Deleted: sha256:27eb08aec7b41dbfa2fd49bc2b3fad9b020fe40b0bc8289af7f53770f0843e7d
Deleted: sha256:7ad0aff4b88909fcff6372fdd26c24d688803b06845426b5a90bcd2f2cae93f4
Deleted: sha256:b93bcd594116ac8886f2daa0fc8d75a59da00161731dab24ababea853d031908
Deleted: sha256:54eda0a22e4b2a1b166cf996eb0651a4f53dec7e9dfad3549bbfe6078f2238a4
Deleted: sha256:36575f1e2764d54fdb92b5296cf4e993499836d6dd9a006f32e173865835070e
Deleted: sha256:27074774f844bdeba18e786585604c8b6352e925a7bd560deb66252bc8ccb861
Deleted: sha256:0da68695f8bc66fcea8f09004b5cb078861f5d99748f8b7ed035690e02c41477
Deleted: sha256:5dbda9873cdda8ff912b0ae5c34790ee06d7117fa27b193610fa2f7063bf55ff
Deleted: sha256:149690c37bdc8680ec66b0e2cc138f6d63caad74b091acf86a2a18111b90ea79
Deleted: sha256:2caf8a80130d6e9f4ed22e1ec1c3abd2c3f4330d2df9ec62f3b751300190b9e4
Deleted: sha256:1445a9131f2b28a12ff6396faebd6b4beb2cccd7af8eae28d5ff659d65de03ad
Deleted: sha256:4d9799a0754804f5cd623ab744757d16ec81862ee6e5d6986d9d1b0c5e5d5637
Deleted: sha256:dd833146402e8e6e67c48a6ae79a3c86101123e3d6ab1fc7999685eeea06ccba
Deleted: sha256:08d8e6ed6c3a5ac1bfee00f7b11f0a870d6bdc4af6d34169fa1e032c241a63a6
Deleted: sha256:0f3637356bb908638dda037c9c6aa4a2be8a19dbcf452a00cd733a8a456077ac
Deleted: sha256:aedb1b3b3b6e70ae4a342dfdcea874495b9d095ed6ba8eb4bc08f90ad9e83125
Deleted: sha256:05903cd969529ea56beec880bbeb7e90f1bdc281882f1cf3755760e41b181409
Deleted: sha256:d124781fc06a73b05a8644958397994bae668aba2f06f397fe1387c676b0d86f

8.3 - DCT et la commande docker push

Pour envoyer l'image dont l'IMAGE ID est 965ea09ff2eb dans le registry privé, le tag de l'image doit être modifié :

root@manager:~# docker image tag alpine:latest <votre_compte>/docker:alpine

L'image dont l'IMAGE ID est 965ea09ff2eb a maintenant deux tags alpine:latest et <votre_compte>/docker:alpine :

root@manager:~# docker image ls
REPOSITORY             TAG                 IMAGE ID            CREATED             SIZE
ubuntu                 latest              775349758637        9 days ago          64.2MB
nginx                  latest              540a289bab6c        2 weeks ago         126MB
<votre_compte>/docker  alpine              965ea09ff2eb        2 weeks ago         5.55MB
alpine                 latest              965ea09ff2eb        2 weeks ago         5.55MB
mysql                  latest              c8ee894bd2bd        3 weeks ago         456MB
centos                 latest              0f3e07c0138f        5 weeks ago         220MB

Lors du push vers le registry privé, il faut créer des passphrases pour deux clefs :

root@manager:~# docker push <votre_compte>/docker:alpine
The push refers to repository [docker.io/<votre_compte>/docker]
77cae8ab23bf: Mounted from library/alpine 
alpine: digest: sha256:e4355b66995c96b4b468159fc5c7e3540fcef961189ca13fee877798649f531a size: 528
Signing and pushing trust metadata
You are about to create a new root signing key passphrase. This passphrase
will be used to protect the most sensitive key in your signing system. Please
choose a long, complex passphrase and be careful to keep the password and the
key file itself secure and backed up. It is highly recommended that you use a
password manager to generate the passphrase and keep it safe. There will be no
way to recover this key. You can find the key in your config directory.
Enter passphrase for new root key with ID 192fc7e: fenestros
Repeat passphrase for new root key with ID 192fc7e: fenestros
Enter passphrase for new repository key with ID 168c754: fenestros
Repeat passphrase for new repository key with ID 168c754: fenestros
Finished initializing "docker.io/<votre_compte>/docker"
Successfully signed docker.io/<votre_compte>/docker:alpine

Les clefs sont stockées dans le répertoire ~/.docker/trust/private :

root@manager:~# ls -l ~/.docker/trust
total 8
drwx------ 2 root root 4096 nov.  10 14:49 private
drwx------ 3 root root 4096 nov.   8 13:48 tuf

root@manager:~# ls -l ~/.docker/trust/private
total 8
-rw------- 1 root root 447 nov.  10 14:49 168c754ea8f36ce7fbcbe2299b6d91fc0f4d594c9ed9b86916687b618d8438ac.key
-rw------- 1 root root 416 nov.  10 14:49 192fc7ed9543ad4bceec58886ab1d605b7433c35f7462d7343d0780d8fddf1db.key
root@manager:~# cat ~/.docker/trust/private/168c754ea8f36ce7fbcbe2299b6d91fc0f4d594c9ed9b86916687b618d8438ac.key 
-----BEGIN ENCRYPTED PRIVATE KEY-----
gun: docker.io/i2tch/docker
role: targets

MIHuMEkGCSqGSIb3DQEFDTA8MBsGCSqGSIb3DQEFDDAOBAhm7HwR0y8FFAICCAAw
HQYJYIZIAWUDBAEqBBC729tU73wKHFQSbmZ1EVZaBIGgmGiFSs4lM5tElSGukl1B
HrELT9aFooFgW7oSXNLM8aFfF/vJ+BSjsgfqWLdvuH+DUXXdUidxcoGMEWnVZNIC
3m40g3MywHilW4rUcjoHVTTUXABGXUQ3f7h+nI15CXcZ11qRLyWbf2uywE9yYH9O
M7GLUcE+pTENJKfZAhRGBEL+LgXNfGI1aAVqaEbBDcDnKKf4Uj1Xu4oLJ7je8+nT
dg==
-----END ENCRYPTED PRIVATE KEY-----

root@manager:~# cat ~/.docker/trust/private/192fc7ed9543ad4bceec58886ab1d605b7433c35f7462d7343d0780d8fddf1db.key 
-----BEGIN ENCRYPTED PRIVATE KEY-----
role: root

MIHuMEkGCSqGSIb3DQEFDTA8MBsGCSqGSIb3DQEFDDAOBAiAtCzEar3AhgICCAAw
HQYJYIZIAWUDBAEqBBAO7hHWVoqOo6xcETQQDXRdBIGgPUoLzTz07Ajx8K3D8+Vv
2NUiflMYhH/0I9PL6iA2JJCmD0l+8Ueljy+vHRCu7UAIyWXyIHFN5Aab40mk9/Pg
V2BwSlXp7t1Cnqp/ah7g0T40+OnT64JkTS+l3cS0CaCf2E4l6nY8g4cl40hZIFJz
KREO8uEq3v7HcSBBqFm0+TU+92d7hVuDApPaj0lZYP+3f7H6AjUOqu6hUoK8Ck/Y
Ig==
-----END ENCRYPTED PRIVATE KEY-----

8.4 - DCT et la commande docker build

L'exemple suivant démontre un Dockerfile qui référence une image parente non signée :

root@manager:~# mkdir nottrusted

root@manager:~# cd nottrusted/

root@manager:~/nottrusted# vi Dockerfile

root@manager:~/nottrusted# cat Dockerfile
FROM docker/trusttest:latest
RUN echo

Lors du build de l'image <votre_compte>/docker:nottrusted qui utilise ce Dockerfile, une erreur est retournée car sa création n'est pas conforme à l'utilisation de DCT :

root@manager:~/nottrusted# docker build -t <votre_compte>/docker:nottrusted .
Sending build context to Docker daemon 

error during connect: Post http://%2Fvar%2Frun%2Fdocker.sock/v1.40/build?buildargs=%7B%7D&cachefrom=%5B%5D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=0&dockerfile=Dockerfile&labels=%7B%7D&memory=0&memswap=0&networkmode=default&rm=1&shmsize=0&t=i2tch%2Fdocker%3Anottrusted&target=&ulimits=null&version=1: Error: remote trust data does not exist for docker.io/docker/trusttest: notary.docker.io does not have trust data for docker.io/docker/trusttest

L'utilisation de l'option –disable-content-trust permet la construction de l'image <votre_compte>/docker:nottrusted :

root@manager:~/nottrusted# docker build --disable-content-trust -t <votre_compte>/docker:nottrusted .
Sending build context to Docker daemon  2.048kB
Step 1/2 : FROM docker/trusttest:latest
latest: Pulling from docker/trusttest
Image docker.io/docker/trusttest:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
aac0c133338d: Pull complete 
a3ed95caeb02: Pull complete 
Digest: sha256:50c0cdd0577cc7ab7c78e73a0a89650b222f6ce2b87d10130ecff055981b702f
Status: Downloaded newer image for docker/trusttest:latest
 ---> cc7629d1331a
Step 2/2 : RUN echo
 ---> Running in 694e79d3cd88

Removing intermediate container 694e79d3cd88
 ---> 686e85ee76b8
Successfully built 686e85ee76b8
Successfully tagged <votre_compte>/docker:nottrusted

Lors du push de l'image <votre_compte>/docker:nottrusted vers le repositry distant, celle-ci est signée :

root@manager:~/nottrusted# docker push <votre_compte>/docker:nottrusted
The push refers to repository [docker.io/<votre_compte>/docker]
5f70bf18a086: Layer already exists 
c22f7bc058a9: Mounted from docker/trusttest 
nottrusted: digest: sha256:1183c62a5d31e202b5f5f528e9e7cdc36140aa3212c938e1d471c6b3b59f01bc size: 734
Signing and pushing trust metadata
Enter passphrase for repository key with ID 168c754: fenestros
Successfully signed docker.io/<votre_compte>/docker:nottrusted

Important : Notez l'utilisation de la même root key que lors du push de l'image <votre_compte>/docker:alpine car il s'agit du même repositry.

Créer un deuxième Repositry

Par contre en modifiant le tag de l'image <votre_compte>/docker:nottrusted à <votre_compte>/otherimage:latest, un autre repositry sera créé lors du push de l'image renommée :

root@manager:~/nottrusted# docker tag <votre_compte>/docker:nottrusted <votre_compte>/otherimage:latest

root@manager:~/nottrusted# docker images
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
<votre_compte>/docker        nottrusted          686e85ee76b8        9 minutes ago       5.03MB
<votre_compte>/otherimage    latest              686e85ee76b8        9 minutes ago       5.03MB
ubuntu                       latest              775349758637        9 days ago          64.2MB
nginx                        latest              540a289bab6c        2 weeks ago         126MB
<votre_compte>/docker        alpine              965ea09ff2eb        2 weeks ago         5.55MB
alpine                       latest              965ea09ff2eb        2 weeks ago         5.55MB
mysql                        latest              c8ee894bd2bd        3 weeks ago         456MB
centos                       latest              0f3e07c0138f        5 weeks ago         220MB
docker/trusttest             latest              cc7629d1331a        4 years ago         5.03MB

root@manager:~/nottrusted# docker push docker.io/<votre_compte>/otherimage:latest
The push refers to repository [docker.io/<votre_compte>/otherimage]
5f70bf18a086: Mounted from <votre_compte>/docker 
c22f7bc058a9: Mounted from <votre_compte>/docker 
latest: digest: sha256:1183c62a5d31e202b5f5f528e9e7cdc36140aa3212c938e1d471c6b3b59f01bc size: 734
Signing and pushing trust metadata
Enter passphrase for root key with ID 192fc7e: fenestros
Enter passphrase for new repository key with ID 7b13d02: fenestros
Repeat passphrase for new repository key with ID 7b13d02: fenestros
Finished initializing "docker.io/<votre_compte>/otherimage"
Successfully signed docker.io/<votre_compte>/otherimage:latest

Important : Notez la création d'une deuxième repositry key (ID 7b13d02 au lieu de ID 168c754) lors du push de l'image <votre_compte>/otherimage:latest car il s'agit d'un autre repositry.

La présence de cette deuxième repositry key (7b13d02d74264624fb201e7ae13ae694286b9f761aa86adddefd0408c7234a58.key) peut être constatée dans le répertoire ~/.docker/trust/private :

root@manager:~/nottrusted# ls -l ~/.docker/trust/private
total 12
-rw------- 1 root root 447 nov.  10 14:49 168c754ea8f36ce7fbcbe2299b6d91fc0f4d594c9ed9b86916687b618d8438ac.key
-rw------- 1 root root 416 nov.  10 14:49 192fc7ed9543ad4bceec58886ab1d605b7433c35f7462d7343d0780d8fddf1db.key
-rw------- 1 root root 451 nov.  10 17:37 7b13d02d74264624fb201e7ae13ae694286b9f761aa86adddefd0408c7234a58.key

En inspectant les clefs des images créées, l'utilisation des différentes clefs est démontrées très clairement :

root@manager:~/nottrusted# docker trust inspect <votre_compte>/docker:alpine
[
    {
        "Name": "<votre_compte>/docker:alpine",
        "SignedTags": [
            {
                "SignedTag": "alpine",
                "Digest": "e4355b66995c96b4b468159fc5c7e3540fcef961189ca13fee877798649f531a",
                "Signers": [
                    "Repo Admin"
                ]
            }
        ],
        "Signers": [],
        "AdministrativeKeys": [
            {
                "Name": "Root",
                "Keys": [
                    {
                        "ID": "d4074334a4ff5a9a43ebd1320ad77c2df88c990ec812f90eb045c603c01ab698"
                    }
                ]
            },
            {
                "Name": "Repository",
                "Keys": [
                    {
                        "ID": "168c754ea8f36ce7fbcbe2299b6d91fc0f4d594c9ed9b86916687b618d8438ac"
                    }
                ]
            }
        ]
    }
]
root@manager:~/nottrusted# docker trust inspect <votre_compte>/docker:nottrusted
[
    {
        "Name": "<votre_compte>/docker:nottrusted",
        "SignedTags": [
            {
                "SignedTag": "nottrusted",
                "Digest": "1183c62a5d31e202b5f5f528e9e7cdc36140aa3212c938e1d471c6b3b59f01bc",
                "Signers": [
                    "Repo Admin"
                ]
            }
        ],
        "Signers": [],
        "AdministrativeKeys": [
            {
                "Name": "Root",
                "Keys": [
                    {
                        "ID": "d4074334a4ff5a9a43ebd1320ad77c2df88c990ec812f90eb045c603c01ab698"
                    }
                ]
            },
            {
                "Name": "Repository",
                "Keys": [
                    {
                        "ID": "168c754ea8f36ce7fbcbe2299b6d91fc0f4d594c9ed9b86916687b618d8438ac"
                    }
                ]
            }
        ]
    }
]

Important : Notez que les clefs utilisées sont les mêmes pour les deux images.

root@manager:~/nottrusted# docker trust inspect <votre_compte>/otherimage:latest
[
    {
        "Name": "<votre_compte>/otherimage:latest",
        "SignedTags": [
            {
                "SignedTag": "latest",
                "Digest": "1183c62a5d31e202b5f5f528e9e7cdc36140aa3212c938e1d471c6b3b59f01bc",
                "Signers": [
                    "Repo Admin"
                ]
            }
        ],
        "Signers": [],
        "AdministrativeKeys": [
            {
                "Name": "Root",
                "Keys": [
                    {
                        "ID": "26f00698f51be2824c6fe85a14722c279bbd487125fe8fa18c0fc8f76dd6280d"
                    }
                ]
            },
            {
                "Name": "Repository",
                "Keys": [
                    {
                        "ID": "7b13d02d74264624fb201e7ae13ae694286b9f761aa86adddefd0408c7234a58"
                    }
                ]
            }
        ]
    }
]

Important : Notez que les clefs utilisées sont différentes.

Supprimer une Signature

Dernièrement il est possible de supprimer la signature d'une image avec la commande docker trust revoke :

root@manager:~# docker trust revoke <votre_compte>/docker:alpine
Enter passphrase for repository key with ID 168c754: 
Successfully deleted signature for <votre_compte>/docker:alpine
root@manager:~# docker trust inspect <votre_compte>/docker:alpine
[
    {
        "Name": "<votre_compte>/docker:alpine",
        "SignedTags": [],
        "Signers": [],
        "AdministrativeKeys": [
            {
                "Name": "Root",
                "Keys": [
                    {
                        "ID": "d4074334a4ff5a9a43ebd1320ad77c2df88c990ec812f90eb045c603c01ab698"
                    }
                ]
            },
            {
                "Name": "Repository",
                "Keys": [
                    {
                        "ID": "168c754ea8f36ce7fbcbe2299b6d91fc0f4d594c9ed9b86916687b618d8438ac"
                    }
                ]
            }
        ]
    }
]

Important : Il existe un autre mécanisme de signatures cryptographiques qui permet de certifier le contenu des images mises à disposition sur une Registry. Appelé Notary, ce système a été développé par la communauté Docker et intègre une partie de la spécification de The Update Framework (TUF). Pour plus d'informations, consultez cet article.

LAB #9 - Sécurisation du Socket du Daemon Docker

Par défaut le daemon Docker peut être contacté en utilisant un socket Unix local ce qui implique qu'il faut une connexion SSH vers l'hôte Docker. Docker peut cependant utiliser un socket http.

Pour pouvoir contacter de daemon Docker via le réseau d'une manière sécurisée il faut installer, configurer et activer le support TLS grâce aux options tlsverify et tlscacert.

La configuration implique que :

La mise en place nécessite openssl :

root@manager:~# which openssl
/usr/bin/openssl

9.1 - Création du Certificat de l'Autorité de Certification

Commencez par créer une clef privée ca-key.pem pour le CA :

root@manager:~# openssl genrsa -aes256 -out ca-key.pem 4096
Generating RSA private key, 4096 bit long modulus
......................................................................................................................++++
...............................................................................................................................................................++++
e is 65537 (0x010001)
Enter pass phrase for ca-key.pem:fenestros
Verifying - Enter pass phrase for ca-key.pem:fenestros

Ensuite, créez le certificat ca.pem du CA :

root@manager:~# openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
Enter pass phrase for ca-key.pem:fenestros
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:GB
State or Province Name (full name) [Some-State]:SURREY
Locality Name (eg, city) []:ADDLESTONE
Organization Name (eg, company) [Internet Widgits Pty Ltd]:I2TCH LIMITED
Organizational Unit Name (eg, section) []:TRAINING
Common Name (e.g. server FQDN or YOUR name) []:manager.i2tch.loc
Email Address []:infos@i2tch.co.uk

9.2 - Création du Certificat du Serveur Hôte du Daemon Docker

Les clefs du CA ayant été créées, créez une clef server-key.pem pour le serveur hôte du daemon Docker :

root@manager:~# openssl genrsa -out server-key.pem 4096
Generating RSA private key, 4096 bit long modulus
.................................................................................................................................++++
...........................++++
e is 65537 (0x010001)

Créez ensuite un Certificate Signing Request (CSR) server.csr :

root@manager:~# echo $HOSTNAME
manager.i2tch.loc
root@manager:~# openssl req -subj "/CN=`echo $HOSTNAME`" -sha256 -new -key server-key.pem -out server.csr

Une connexion TLS peut être effectuée en utilisant un FQDN ou une adresse IP. Pour cette raison, créez le fichier extfile.cnf :

root@manager:~# echo subjectAltName = DNS:`echo $HOSTNAME`,IP:10.0.2.62,IP:127.0.0.1 >> extfile.cnf

Fixez l'attribut étendu de l'utilisation de la clef du daemon à serverAuth :

root@manager:~# echo extendedKeyUsage = serverAuth >> extfile.cnf

Vérifiez que votre fichier a été correctement créé :

root@manager:~# cat extfile.cnf 
subjectAltName = DNS:manager.i2tch.loc,IP:10.0.2.62,IP:127.0.0.1
extendedKeyUsage = serverAuth

Signez maintenant le CSR du serveur server.csr avec la clef privée du CA ca-key.pem afin de produire le certificat du serveur server-cert.pem :

root@manager:~# openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf
Signature ok
subject=CN = manager.i2tch.loc
Getting CA Private Key
Enter pass phrase for ca-key.pem:fenestros

9.3 - Création du Certificat du Client

Créez ensuite la clef privée key.pem du client qui se connectera au daemon à partir du réseau :

root@manager:~# openssl genrsa -out key.pem 4096
Generating RSA private key, 4096 bit long modulus
...................................................................................................................................++++
...............++++
e is 65537 (0x010001)

Modifiez l'entrée pour l'adresse 10.0.2.45 dans le fichier /etc/hosts du manager :

root@manager:~# vi /etc/hosts
root@manager:~# cat /etc/hosts
127.0.0.1	localhost
10.0.2.46	debian11.i2tch.loc	debian11
10.0.2.45	myregistry.i2tch.loc    myregistry
10.0.2.62	manager.i2tch.loc	manager
10.0.2.63	worker1.i2tch.loc	worker1
10.0.2.64	worker2.i2tch.loc	worker2	

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

Créez ensuite le CSR du client client.csr :

root@manager:~# openssl req -subj '/CN=myregistry.i2tch.loc' -new -key key.pem -out client.csr

Fixez l'attribut étendu de l'utilisation de la clef du client à clientAuth :

root@manager:~# echo extendedKeyUsage = clientAuth > extfile-client.cnf

Signez le CSR du client client.csr avec la clef privée du CA ca-key.pem afin de créer le certificat du client cert.pem :

root@manager:~# openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile-client.cnf
Signature ok
subject=CN = myregistry.i2tch.loc
Getting CA Private Key
Enter pass phrase for ca-key.pem:fenestros

Vérifiez la présence des fichiers générés :

root@manager:~# ls -l
total 60
-rw------- 1 root root 3326 nov.  11 10:53 ca-key.pem
-rw-r--r-- 1 root root 2163 nov.  11 10:57 ca.pem
-rw-r--r-- 1 root root   17 nov.  11 11:15 ca.srl
-rw-r--r-- 1 root root 1907 nov.  11 11:15 cert.pem
-rw-r--r-- 1 root root 1594 nov.  11 11:12 client.csr
drwxr-xr-x 5 root root 4096 nov.   8 12:58 docker-bench-security
-rw-r--r-- 1 root root 1707 nov.   8 12:35 docker-stack.yml
-rw-r--r-- 1 root root   30 nov.  11 11:13 extfile-client.cnf
-rw-r--r-- 1 root root   95 nov.  11 11:06 extfile.cnf
-rw------- 1 root root 3243 nov.  11 11:10 key.pem
drwxr-xr-x 2 root root 4096 nov.  10 17:21 nottrusted
-rw-r--r-- 1 root root 1964 nov.  11 11:08 server-cert.pem
-rw-r--r-- 1 root root 1594 nov.  11 11:01 server.csr
-rw------- 1 root root 3243 nov.  11 10:59 server-key.pem
-rw-r--r-- 1 root root  882 oct.  27 15:46 stats

Supprimez les fichiers ayant déjà été utilisés, à savoir les deux CSR et les deux fichiers des extensions :

root@manager:~# rm -v client.csr server.csr extfile.cnf extfile-client.cnf
'client.csr' supprimé
'server.csr' supprimé
'extfile.cnf' supprimé
'extfile-client.cnf' supprimé

Modifiez les permissions des clefs privées :

root@manager:~# chmod -v 0400 ca-key.pem key.pem server-key.pem
le mode de 'ca-key.pem' a été modifié de 0600 (rw-------) en 0400 (r--------)
le mode de 'key.pem' a été modifié de 0600 (rw-------) en 0400 (r--------)
le mode de 'server-key.pem' a été modifié de 0600 (rw-------) en 0400 (r--------)

Ainsi que les permissions des certificats :

root@manager:~# chmod -v 0444 ca.pem server-cert.pem cert.pem
le mode de 'ca.pem' a été modifié de 0644 (rw-r--r--) en 0444 (r--r--r--)
le mode de 'server-cert.pem' a été modifié de 0644 (rw-r--r--) en 0444 (r--r--r--)
le mode de 'cert.pem' a été modifié de 0644 (rw-r--r--) en 0444 (r--r--r--)

Arrêtez et supprimez le conteneur mysql :

root@manager:~# docker stop mysql
mysql
root@manager:~# docker rm mysql
mysql

9.4 - Démarrage du Daemon Docker avec une Invocation Directe

Arrêtez et désactivez le service Docker :

root@manager:~# systemctl stop docker
Warning: Stopping docker.service, but it can still be activated by:
  docker.socket
root@manager:~# systemctl disable docker
Synchronizing state of docker.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable docker

Lancez un invocation directe de dockerd afin que le daemon n'acceptent que des connexions de clients fournissant un certificat signé par le CA :

root@manager:~# dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376 &
[1] 1868
root@manager:~# INFO[2019-11-11T12:01:43.638540628+01:00] Starting up                                  
INFO[2019-11-11T12:01:43.639187816+01:00] User namespaces: ID ranges will be mapped to subuid/subgid ranges of: dockremap:dockremap 
INFO[2019-11-11T12:01:43.641133642+01:00] User namespaces: ID ranges will be mapped to subuid/subgid ranges of: dockremap:dockremap 
INFO[2019-11-11T12:01:43.646949782+01:00] parsed scheme: "unix"                         module=grpc
INFO[2019-11-11T12:01:43.648299396+01:00] scheme "unix" not registered, fallback to default scheme  module=grpc
INFO[2019-11-11T12:01:43.648633123+01:00] ccResolverWrapper: sending update to cc: {[{unix:///run/containerd/containerd.sock 0  <nil>}] <nil>}  module=grpc
INFO[2019-11-11T12:01:43.650756512+01:00] ClientConn switching balancer to "pick_first"  module=grpc
INFO[2019-11-11T12:01:43.656738368+01:00] parsed scheme: "unix"                         module=grpc
INFO[2019-11-11T12:01:43.657165991+01:00] scheme "unix" not registered, fallback to default scheme  module=grpc
INFO[2019-11-11T12:01:43.660938142+01:00] ccResolverWrapper: sending update to cc: {[{unix:///run/containerd/containerd.sock 0  <nil>}] <nil>}  module=grpc
INFO[2019-11-11T12:01:43.661309281+01:00] ClientConn switching balancer to "pick_first"  module=grpc
INFO[2019-11-11T12:01:43.663242717+01:00] [graphdriver] using prior storage driver: overlay2 
WARN[2019-11-11T12:01:43.681131788+01:00] Your kernel does not support cgroup rt period 
WARN[2019-11-11T12:01:43.681397622+01:00] Your kernel does not support cgroup rt runtime 
INFO[2019-11-11T12:01:43.681845166+01:00] Loading containers: start.                   
INFO[2019-11-11T12:01:43.824330430+01:00] Default bridge (docker0) is assigned with an IP address 172.17.0.0/16. Daemon option --bip can be used to set a preferred IP address 
INFO[2019-11-11T12:01:43.887849374+01:00] Loading containers: done.                    
INFO[2019-11-11T12:01:43.908567890+01:00] Docker daemon                                 commit=9013bf583a graphdriver(s)=overlay2 version=19.03.4
INFO[2019-11-11T12:01:43.908851991+01:00] Daemon has completed initialization          
INFO[2019-11-11T12:01:43.969272646+01:00] API listen on [::]:2376                      
[Entrée]
root@manager:~#

Vérifiez que le processus tourne :

root@manager:~# ps aux | grep docker
root      1868  0.2  4.0 421876 82236 pts/0    Sl   12:01   0:00 dockerd --tlsverify --tlscacert=ca.pem --tlscert=server-cert.pem --tlskey=server-key.pem -H=0.0.0.0:2376
root      1995  0.0  0.0  12780   964 pts/0    S+   12:02   0:00 grep docker

Installez le paquet net-tools qui contient le binaire netstat :

root@manager:~# apt install -y net-tools

Vérifiez que le port 2376 est à l'écoute :

root@manager:~# netstat -anp | grep 2376
tcp6       0      0 :::2376                 :::*                    LISTEN      1868/dockerd 

9.5 - Configuration du Client

Transférez ensuite le certificat du CA ainsi que le certificat et la clef privée du client vers la VM 10.0.2.45 :

root@manager:~# scp ca.pem key.pem cert.pem trainee@10.0.2.45:/home/trainee/
The authenticity of host '10.0.2.45 (10.0.2.45)' can't be established.
ECDSA key fingerprint is SHA256:sEfHBv9azmK60cjqF/aJgUc9jg56slNaZQdAUcvBOvE.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '10.0.2.45' (ECDSA) to the list of known hosts.
trainee@10.0.2.45's password: trainee
ca.pem                                                                                                                                 100% 2163   917.8KB/s   00:00    
key.pem                                                                                                                                100% 3243     3.0MB/s   00:00   
cert.pem                                                                                                                               100% 1907   921.7KB/s   00:00 

Lancez la commande docker version sur la VM 10.0.2.45 :

trainee@myregistry:~$ docker --tlsverify --tlscacert=ca.pem --tlscert=cert.pem --tlskey=key.pem -H=manager.i2tch.loc:2376 version
Client: Docker Engine - Community
 Version:           19.03.4
 API version:       1.40
 Go version:        go1.12.10
 Git commit:        9013bf583a
 Built:             Fri Oct 18 15:52:34 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.4
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.10
  Git commit:       9013bf583a
  Built:            Fri Oct 18 15:51:05 2019
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.2.10
  GitCommit:        b34a5c8af56e510852c35414db4c1f4fa6172339
 runc:
  Version:          1.0.0-rc8+dev
  GitCommit:        3e425f80a8c931f88e6d94a8c831b9d5aa481657
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

Afin de faciliter l'utilisation des commandes sur le serveur à partir de myregistry, créez le répertoire ~/.docker :

trainee@myregistry:~$ mkdir -pv ~/.docker
mkdir: création du répertoire '/home/trainee/.docker'

Copiez ensuite les fichiers *.pem dans le répertoire ~/.docker :

trainee@myregistry:~$ cp -v {ca,cert,key}.pem ~/.docker
'ca.pem' -> '/home/trainee/.docker/ca.pem'
'cert.pem' -> '/home/trainee/.docker/cert.pem'
'key.pem' -> '/home/trainee/.docker/key.pem'

Créez les deux variables DOCKER_HOST et DOCKER_TLS_VERIFY :

trainee@myregistry:~$ export DOCKER_HOST=tcp://manager.i2tch.loc:2376 DOCKER_TLS_VERIFY=1

Maintenant la connexion est sécurisée par défaut :

trainee@myregistry:~$ docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
i2tch/docker        nottrusted          686e85ee76b8        19 hours ago        5.03MB
i2tch/otherimage    latest              686e85ee76b8        19 hours ago        5.03MB
ubuntu              latest              775349758637        10 days ago         64.2MB
nginx               latest              540a289bab6c        2 weeks ago         126MB
alpine              latest              965ea09ff2eb        2 weeks ago         5.55MB
i2tch/docker        alpine              965ea09ff2eb        2 weeks ago         5.55MB
mysql               latest              c8ee894bd2bd        3 weeks ago         456MB
centos              latest              0f3e07c0138f        5 weeks ago         220MB
docker/trusttest    latest              cc7629d1331a        4 years ago         5.03MB

Copyright © 2024 Hugh Norris.