⚠️ Traduction non officielle - Cette documentation est une traduction communautaire non officielle de Docker.

Options de configuration avancées pour ECI

Subscription: Business
For: Administrators

Permissions de montage du socket Docker

Par défaut, quand l'Isolation de Conteneurs Renforcée (ECI) est activée, Docker Desktop ne permet pas le montage par liaison du socket Docker Engine dans les conteneurs :

$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock docker:cli
docker: Error response from daemon: enhanced container isolation: docker socket mount denied for container with image "docker.io/library/docker"; image is not in the allowed list; if you wish to allow it, configure the docker socket image list in the Docker Desktop settings.

Ceci empêche les conteneurs malveillants d'obtenir l'accès au Docker Engine, car un tel accès pourrait leur permettre d'effectuer des attaques de chaîne d'approvisionnement. Par exemple, construire et pousser des images malveillantes dans les dépôts de l'organisation ou similaire.

Cependant, certains cas d'usage légitimes nécessitent que les conteneurs aient accès au socket Docker Engine. Par exemple, le framework populaire Testcontainers monte parfois par liaison le socket Docker Engine dans les conteneurs pour les gérer ou effectuer un nettoyage post-test. De même, certains frameworks Buildpack, par exemple Paketo, nécessitent des montages par liaison de socket Docker dans les conteneurs.

Les administrateurs peuvent optionnellement configurer ECI pour permettre le montage par liaison du socket Docker Engine dans les conteneurs, mais de manière contrôlée.

Ceci peut être fait via la section des permissions de montage du socket Docker dans le fichier admin-settings.json. Par exemple :

{
  "configurationFileVersion": 2,
  "enhancedContainerIsolation": {
    "locked": true,
    "value": true,
    "dockerSocketMount": {
      "imageList": {
        "images": [
          "docker.io/localstack/localstack:*",
          "docker.io/testcontainers/ryuk:*",
          "docker:cli"
        ],
        "allowDerivedImages": true
      },
      "commandList": {
        "type": "deny",
        "commands": ["push"]
      }
    }
  }
}
Tip

Vous pouvez maintenant aussi configurer ces paramètres dans la Console d'Administration Docker.

Comme montré ci-dessus, il y a deux configurations pour le montage par liaison du socket Docker dans les conteneurs : la imageList et la commandList. Celles-ci sont décrites ci-dessous.

Liste d'images

La imageList est une liste d'images de conteneur qui sont autorisées à monter par liaison le socket Docker. Par défaut, la liste est vide, aucun conteneur n'est autorisé à monter par liaison le socket Docker quand ECI est activé. Cependant, un administrateur peut ajouter des images à la liste, en utilisant l'un de ces formats :

Format de Référence d'Image Description
<nom_image>[:<tag>] Nom de l'image, avec tag optionnel. Si le tag est omis, le tag :latest est utilisé. Si le tag est le joker *, alors cela signifie "n'importe quel tag pour cette image."
<nom_image>@<digest> Nom de l'image, avec un digest de dépôt spécifique (par ex., comme rapporté par docker buildx imagetools inspect <image>). Cela signifie que seule l'image qui correspond à ce nom et digest est autorisée.

Le nom de l'image suit la convention standard, donc il peut pointer vers n'importe quel registre et dépôt.

Dans l'exemple précédent, la liste d'images était configurée avec trois images :

"imageList": {
  "images": [
    "docker.io/localstack/localstack:*",
    "docker.io/testcontainers/ryuk:*",
    "docker:cli"
  ]
}

Cela signifie que les conteneurs qui utilisent soit l'image docker.io/localstack/localstack ou l'image docker.io/testcontainers/ryuk (avec n'importe quel tag), ou l'image docker:cli, sont autorisés à monter par liaison le socket Docker quand ECI est activé. Ainsi, ce qui suit fonctionne :

$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker:cli sh
/ #
Tip

Soyez restrictif avec les images que vous autorisez, comme décrit dans Recommandations.

En général, il est plus facile de spécifier l'image en utilisant le format de tag joker, par exemple <nom-image>:*, car alors imageList n'a pas besoin d'être mise à jour chaque fois qu'une nouvelle version de l'image est utilisée. Alternativement, vous pouvez utiliser un tag immuable, par exemple :latest, mais cela ne fonctionne pas toujours aussi bien que le joker parce que, par exemple, Testcontainers utilise des versions spécifiques de l'image, pas nécessairement la dernière.

Quand ECI est activé, Docker Desktop télécharge périodiquement les digests d'image pour les images autorisées depuis le registre approprié et les stocke en mémoire. Ensuite, quand un conteneur est démarré avec un montage par liaison de socket Docker, Docker Desktop vérifie si le digest d'image du conteneur correspond à l'un des digests autorisés. Si oui, le conteneur est autorisé à démarrer, sinon il est bloqué.

En raison de la comparaison de digest, il n'est pas possible de contourner les permissions de montage de socket Docker en re-taguant une image non autorisée avec le nom d'une autorisée. En d'autres termes, si un utilisateur fait :

$ docker image rm <image_autorisée>
$ docker tag <image_non_autorisée> <image_autorisée>
$ docker run -v /var/run/docker.sock:/var/run/docker.sock <image_autorisée>

alors l'opération de tag réussit, mais la commande docker run échoue car le digest d'image de l'image non autorisée ne correspondra pas à celui des images autorisées dans le dépôt.

Permissions de Montage du Socket Docker pour les images dérivées

Requires: Docker Desktop 4.34.0 and later

Comme décrit dans la section précédente, les administrateurs peuvent configurer la liste des images de conteneur qui sont autorisées à monter le socket Docker via la imageList.

Cela fonctionne pour la plupart des scénarios, mais pas toujours, car cela nécessite de connaître à l'avance le nom de la ou des image(s) sur lesquelles les montages de socket Docker devraient être autorisés. Certains outils de conteneur tels que les buildpacks Paketo, construisent des images locales éphémères qui nécessitent des montages par liaison de socket Docker. Puisque le nom de ces images éphémères n'est pas connu à l'avance, la imageList n'est pas suffisante.

Pour surmonter cela, à partir de Docker Desktop version 4.34, les permissions de montage de socket Docker s'appliquent non seulement aux images listées dans la imageList ; elles s'appliquent aussi à toutes les images locales dérivées (c'est-à-dire, construites à partir) d'une image dans la imageList.

C'est-à-dire, si une image locale appelée "myLocalImage" est construite à partir de "myBaseImage" (c'est-à-dire, a un Dockerfile avec un FROM myBaseImage), alors si "myBaseImage" est dans la imageList, à la fois "myBaseImage" et "myLocalImage" sont autorisées à monter le socket Docker.

Par exemple, pour permettre aux buildpacks Paketo de fonctionner avec Docker Desktop et ECI, ajoutez simplement l'image suivante à la imageList :

"imageList": {
  "images": [
    "paketobuildpacks/builder:base"
  ],
  "allowDerivedImages": true
}

Quand le buildpack s'exécute, il créera une image éphémère dérivée de paketobuildpacks/builder:base et montera le socket Docker dessus. ECI permettra cela car il remarquera que l'image éphémère est dérivée d'une image autorisée.

Le comportement est désactivé par défaut et doit être explicitement activé en définissant "allowDerivedImages": true comme montré ci-dessus. En général, il est recommandé de désactiver ce paramètre sauf si vous savez qu'il est requis.

Quelques avertissements :

  • Définir "allowedDerivedImages" :true impactera le temps de démarrage des conteneurs jusqu'à 1 seconde supplémentaire, car Docker Desktop doit effectuer quelques vérifications supplémentaires sur l'image de conteneur.

  • Le paramètre allowDerivedImages s'applique seulement aux images locales uniquement construites à partir d'une image autorisée. C'est-à-dire, l'image dérivée ne doit pas être présente dans un dépôt distant car si elle l'était, vous listeriez simplement son nom dans la imageList.

  • Pour que la vérification d'image dérivée fonctionne, l'image parent (c'est-à-dire, l'image dans la imageList) doit être présente localement (c'est-à-dire, doit avoir été explicitement tirée d'un dépôt). Ce n'est généralement pas un problème car les outils qui ont besoin de cette fonctionnalité (par ex., buildpacks Paketo) feront le pré-tirage de l'image parent.

  • Pour les versions Docker Desktop 4.34 et 4.35 seulement : Le paramètre allowDerivedImages s'applique à toutes les images dans la imageList spécifiées avec un tag explicite (par ex., <n>:<tag>). Il ne s'applique pas aux images spécifiées en utilisant le joker de tag (par ex., <n>:*) décrit dans la section précédente. Dans Docker Desktop 4.36 et ultérieur, cet avertissement ne s'applique plus, signifiant que le paramètre allowDerivedImages s'applique aux images spécifiées avec ou sans tag joker. Cela rend plus facile la gestion de la liste d'images de socket Docker ECI.

Permettre à tous les conteneurs de monter le socket Docker

Dans Docker Desktop version 4.36 et ultérieur, il est possible de configurer la liste d'images pour permettre à n'importe quel conteneur de monter le socket Docker. Vous faites cela en ajoutant "*" à la imageList :

"imageList": {
  "images": [
    "*"
  ]
}

Ceci dit à Docker Desktop de permettre à tous les conteneurs de monter le socket Docker ce qui augmente la flexibilité mais réduit la sécurité. Cela améliore aussi le temps de démarrage des conteneurs lors de l'utilisation de l'Isolation de Conteneurs Renforcée.

Il est recommandé d'utiliser ceci seulement dans des scénarios où lister explicitement les images de conteneur autorisées n'est pas assez flexible.

Liste de commandes

En plus de la imageList décrite dans les sections précédentes, ECI peut restreindre davantage les commandes qu'un conteneur peut émettre via un socket Docker monté par liaison. Ceci est fait via la commandList des permissions de montage de socket Docker, et agit comme un mécanisme de sécurité complémentaire à la imageList (c'est-à-dire, comme une seconde ligne de défense).

Par exemple, disons que la imageList est configurée pour permettre à l'image docker:cli de monter le socket Docker, et un conteneur est démarré avec :

$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock sh
/ #

Par défaut, cela permet au conteneur d'émettre n'importe quelle commande via ce socket Docker (par ex., construire et pousser des images vers les dépôts de l'organisation), ce qui n'est généralement pas désirable.

Pour améliorer la sécurité, la commandList peut être configurée pour restreindre les commandes que les processus à l'intérieur du conteneur peuvent émettre sur le socket Docker monté par liaison. La commandList peut être configurée comme une liste "deny" (par défaut) ou une liste "allow", selon votre préférence.

Chaque commande dans la liste est spécifiée par son nom, comme rapporté par docker --help (par ex., "ps", "build", "pull", "push", etc.) De plus, les jokers de commande suivants sont autorisés pour bloquer un groupe entier de commandes :

Joker de commande Description
"container*" Fait référence à toutes les commandes "docker container ..."
"image*" Fait référence à toutes les commandes "docker image ..."
"volume*" Fait référence à toutes les commandes "docker volume ..."
"network*" Fait référence à toutes les commandes "docker network ..."
"build*" Fait référence à toutes les commandes "docker build ..."
"system*" Fait référence à toutes les commandes "docker system ..."

Par exemple, la configuration suivante bloque les commandes build et push sur le socket Docker :

"commandList": {
  "type": "deny",
  "commands": ["build", "push"]
}

Ainsi, si à l'intérieur du conteneur, vous émettez l'une de ces commandes sur le socket Docker monté par liaison, elles seront bloquées :

/ # docker push myimage
Error response from daemon: enhanced container isolation: docker command "/v1.43/images/myimage/push?tag=latest" is blocked; if you wish to allow it, configure the docker socket command list in the Docker Desktop settings or admin-settings.

De même :

/ # curl --unix-socket /var/run/docker.sock -XPOST http://localhost/v1.43/images/myimage/push?tag=latest
Error response from daemon: enhanced container isolation: docker command "/v1.43/images/myimage/push?tag=latest" is blocked; if you wish to allow it, configure the docker socket command list in the Docker Desktop settings or admin-settings.

Notez que si la commandList avait été configurée comme une liste "allow", alors l'effet aurait été opposé : seules les commandes listées auraient été autorisées. Configurer la liste comme allow ou deny dépend du cas d'usage.

Recommandations

  • Soyez restrictif sur la liste des images de conteneur pour lesquelles vous autorisez le montage par liaison du socket Docker (c'est-à-dire, la imageList). Généralement, autorisez ceci seulement pour les images qui sont absolument nécessaires et en qui vous avez confiance.

  • Utilisez le format de tag joker si possible dans la imageList (par ex., <nom_image>:*), car cela élimine le besoin de mettre à jour le fichier admin-settings.json en raison de changements de tag d'image.

  • Dans la commandList, bloquez les commandes que vous n'attendez pas que le conteneur exécute. Par exemple, pour les tests locaux (par ex., Testcontainers), les conteneurs qui montent par liaison le socket Docker créent / exécutent / suppriment typiquement des conteneurs, volumes, et réseaux, mais ne construisent pas typiquement d'images ou ne les poussent pas dans des dépôts (bien que certains puissent légitimement faire cela). Quelles commandes autoriser ou bloquer dépend du cas d'usage.

    • Notez que toutes les commandes "docker" émises par le conteneur via le socket Docker monté par liaison s'exécuteront aussi sous isolation de conteneur renforcée (c'est-à-dire, le conteneur résultant utilise l'espace de noms utilisateur Linux, les appels système sensibles sont vérifiés, etc.)

Avertissements et limitations

  • Quand Docker Desktop est redémarré, il est possible qu'une image qui est autorisée à monter le socket Docker soit inopinément bloquée de le faire. Cela peut arriver quand le digest d'image change dans le dépôt distant (par ex., une image ":latest" a été mise à jour) et la copie locale de cette image (par ex., d'un docker pull précédent) ne correspond plus au digest dans le dépôt distant. Dans ce cas, supprimez l'image locale et tirez-la à nouveau (par ex., docker rm <image> et docker pull <image>).

  • Il n'est pas possible d'autoriser les montages par liaison de socket Docker sur des conteneurs utilisant des images locales uniquement (c'est-à-dire, des images qui ne sont pas sur un registre) sauf si elles sont dérivées d'une image autorisée ou vous avez autorisé tous les conteneurs à monter le socket Docker. C'est parce que Docker Desktop tire les digests pour les images autorisées depuis le registre, et utilise ensuite cela pour comparer avec la copie locale de l'image.

  • La configuration commandList s'applique à tous les conteneurs qui sont autorisés à monter par liaison le socket Docker. Donc elle ne peut pas être configurée différemment par conteneur.

  • Les commandes suivantes ne sont pas encore supportées dans la commandList :

Commande non supportée Description
compose Docker Compose
dev Environnements de développement
extension Gère les Extensions Docker
feedback Envoie des commentaires à Docker
init Crée des fichiers de démarrage liés à Docker
manifest Gère les manifestes d'image Docker
plugin Gère les plugins
sbom Affiche la Nomenclature des Matériaux Logiciels (SBOM)
scout Docker Scout
trust Gère la confiance sur les images Docker
Note

Les permissions de montage de socket Docker ne s'appliquent pas lors de l'exécution de "vrai" Docker-in-Docker (c'est-à-dire, lors de l'exécution du Docker Engine à l'intérieur d'un conteneur). Dans ce cas, il n'y a pas de montage par liaison du socket Docker de l'hôte dans le conteneur, et donc aucun risque que le conteneur exploite la configuration et les identifiants du Docker Engine de l'hôte pour effectuer une activité malveillante. L'Isolation de Conteneurs Renforcée est capable d'exécuter Docker-in-Docker de manière sécurisée, sans donner au conteneur externe de vraies permissions root dans la VM Docker Desktop.