Journal Docker 1.10 et les user namespace.

Posté par (page perso) . Licence CC by-sa
37
23
fév.
2016

La version 1.10 de Docker est sortie la semaine dernière et apporte de nombreuses fonctionnalités intéressantes. La fonctionnalité la plus intéressante est sans aucun doute l'ajout des Users Namespaces.

Les namespaces permettent de créer des groupes de processus isolés du reste de la machine, c'est l'outil de base pour création des containers sous Linux.

Docker supportait déjà la plupart des namespaces:

  • PID namespace, chaque conteneur a ses propres id de processus
  • UTS namespace, pour avoir son propre hostname
  • IPC namespace, qui permet d'isoler les Communications Inter-Processus
  • Network namespace, chaque conteneur peux avoir sa propre interface réseau, son ip, ses règles de filtrage

Ces namespaces permettaient bonne isolation des containers dans Docker, mais il manquait le plus important d'entre eux. L'utilisateur root à l'intérieur d'un container docker était le même utilisateur root que la machine hôte.

A l'aide d'une faille de sécurité de docker et/ou linux permettant de remonter jusqu'à la machine hôte, un pirate aurait donc pû théoriquement se retrouver directement root sur la machine hôte.

Grâce à l'implémentation des user namespaces dans Docker, il va être désormais possible de mapper un utilisateur différents et ainsi limiter les droits d'un "utilisateur containerisé" sur la machine hôte.

Concrètement, à l'intérieur le container pense utiliser un utilisateur root, mais à l'extérieur sur la machine hôte, l'utilisateur root ne serait en fait qu'un utilisateur lambda aux droits très limités. C'est donc une très bonne nouvelle pour la sécurité avec Docker.

Docker 1.10 (en anglais)
Docker Sécurité, 10 bonnes pratiques (en français)

  • # Ce n'est qu'une première étape.

    Posté par . Évalué à 10.

    Ceci n'est qu'une première étape puisque avec l'architecture actuelle de docker (daemon), le namespace user est le meme pour l'ensemble des conteneurs. Tu peux dire UID O du conteneur et l'UID 10049 à l'extérieur du conteneur mais ce mapping ce fera pour l'ensemble des conteneurs.

    Cette fonctionnalité arrive tard dans docker par rapport à LXC par exemple qui le gère depuis longtemps. Ceci est lié au fait que docker étant basé sur du Go (golang), il a fallut attendre que les syscalls permettant d'activer les usernamespace soit implémenté dans ce langage, ce qui est arrivé avec le version 1.4 de Go. Ensuite la limitation proposé par l'architecture daemon a pas mal fait réfléchir les dévellopeurs sur la meilleur stratégie à appliquer. Voir ici un excellent résumé : http://events.linuxfoundation.org/sites/events/files/slides/User%20Namespaces%20-%20ContainerCon%202015%20-%2016-9-final_0.pdf

    Il y a une deuxième feature de sécurité apporté par la version 1.10 qui j'attendais depuis très longtemps, c'est l'intégration par défaut de seccomp. Voir ici : https://github.com/docker/docker/blob/master/docs/security/seccomp.md
    La on a vraiment une "power feature" je trouve, les users namespace c'est sympa mais ça va pas changer grand chose à ma vie (mes conteneurs ont tous un utilisateur non root et les binaires à l'intérieur de mes conteneurs n'ont pas de setuid).

    • [^] # Re: Ce n'est qu'une première étape.

      Posté par . Évalué à 3.

      Wow j'étais absolument ignorant de ce genre de limitation. Je pensais aussi que Docker était plus proche que ça de l'implémentation de LXC (je pensais que c'était plus une couche d'API, l'intégration du fs en pelure d’oignon et plein d'autres outils, pas une ré-implémentation sur la base du noyau)
      Merci pour le journal et ce commentaire !

      • [^] # Re: Ce n'est qu'une première étape.

        Posté par . Évalué à 5.

        Historiquement Docker était une surcouche à LXC, jusqu’à la version 0.7 si mais souvenirs sont bons.
        Et puis le développeur de docker ont eu pas mal d’écueils avec LXC, pas les même version suivant les distributions, des cassage d'API/ABI trop souvent et pas documenté et ils ont alors décidés d'implémenter leur propre solution en Go.

        Maintenant la "full picture" est plus complète, docker c'est l'API haut niveau qui est compatible avec plusieurs "backend", par défault ça utilise "libcontainer" mais tu peux aussi explicitement spécifier d'utiliser LXC ou LMCTFY (https://blog.docker.com/2014/03/docker-0-9-introducing-execution-drivers-and-libcontainer/). Et même un backend Windows maintenant (https://msdn.microsoft.com/en-us/virtualization/windowscontainers/quick_start/manage_docker).

        Et en dessous de libcontainer maintenant tu as runC (https://blog.docker.com/2015/06/runc/) qui est uniquement le runtime de container (sans toute la tuyauterie réseaux ). runC est du code Docker qui a était donné au projet Open Container Format de la linux fondation (dont docker est membre). C'est une réponse au "pseudo-standard" Rocket/Appc fait par CoreOS.

        Y a aussi Ubuntu qui tente de vivre de son sponsoring de LXC en créant LXD.

        La prochaine "feature" de Docker qui risque de faire du bruit c'est un meilleur support du Checkpoint/Restore (http://linuxplumbersconf.org/2015/ocw//system/presentations/2619/original/2015-08-20-CRIU_Support_in_Docker_for_Native_Checkpoint_and_Restore.pdf).

        • [^] # Re: Ce n'est qu'une première étape.

          Posté par (page perso) . Évalué à 8.

          Tu as oublié aussi rkt, qui est globalement né de la frustration des gens de coreos à traité avec docker, et qui se veux être plus sur en ayant pas un demon central, une approche vu plus sur et plus intégré avec des choses comme systemd, la ou docker réinvente beaucoup de choses étant déjà dans systemd, sans avoir le même niveau d'intégration avec l'OS, vu que docker inc. cherche à surtout faire passer le message que la plateforme sous jacente n'est plus importante, ce qui est faux).

          • [^] # Re: Ce n'est qu'une première étape.

            Posté par . Évalué à 5.

            Effectivement docker et systemd sont en conflit ouvert je dirais, voir à ce sujet le dernier billet sur LWN.

            Après dire que la plateforme sous jacente n'est plus importante n'est pas forcément faux, si tu passe tout dans des conteneurs tu te moque de la plateforme (modulo la version de ton kernel). Y en a qui ont appliqué ce principe à l’extrême c'est rancherOS (http://rancher.com/rancher-os/) ou tu te retrouve sur un système ou tu as juste un docker "système" et un docker "user" et rien d'autre, tous le reste tourne dans des conteneurs.

            On verra qui gagne la bataille du conteneur entre systemd et docker mais je dirais que pour l'instant docker à une longueur d'avance pas sur le plan technique car effectivement l'approche daemon n'est pas la meilleur mais niveau eco-system/buzz ils sont loin devant. Le fait que les Windows conteneur utilisent l'API Docker c'est plutôt impressionnant je trouve. Et docker Inc travaille sur une approche non daemon aussi , ça s'appelle containerd (https://github.com/docker/containerd).

            • [^] # Re: Ce n'est qu'une première étape.

              Posté par (page perso) . Évalué à 4.

              en conflit ouvert

              oui, enfin "conflit" ouvert, faut pas exagérer, ça reste des divergences techniques, rien de plus. Y a pas de violences ou de combats.

              Après dire que la plateforme sous jacente n'est plus
              importante n'est pas forcément faux, si tu passe tout dans des
              conteneurs tu te moque de la plateforme (modulo la version de
              ton kernel).

              Pas vraiment. Déjà, le kernel importe pas mal pour les perfs, pour le support matériel, pour tout un tas de trucs.

              Ensuite, go est compilé en statique, mais y a plein de dépendances ignorés dans docker et/ou kubernetes.

              Par exemple, il faut qu'iptables soit la ce qui pose la question de la future migration à nftables, pour ne citer que ça.

              Autre exemple, kubernetes à un un type de volume gitRepo, qui requiert d'avoir git dispo pour le kubelet, et ça fait parti de la plateforme (et par défaut, il est pas par exemple dans les images docker que Google fourni pour hyperkube).

              3eme exemple, pour assurer la sécurité et l'isolation des containers docker, une des méthode est d'utiliser un équivalent de sVirt (ie, mettre chaque containeur dans un domaine selinux séparé, ce qui fait que root a pas trop d'accès dans le containeur, même si il en sort), et ça, ça requiert une platforme qui supporte avec la policy, etc. Pareil pour l'équivalent avec apparmor.

              Y a plein d'exemple comme ça. La portabilité, c'était déjà la promesse de java il y a 10 ans, et c'est pas vraiment ce qui est arriver en pratique. Et je pense pas que les ingénieurs de l'époque soient moins bon que maintenant.

              Y en a qui ont appliqué ce principe à l’extrême c'est
              rancherOS (http://rancher.com/rancher-os/) ou tu te retrouve
              sur un système ou tu as juste un docker "système" et un docker
              "user" et rien d'autre, tous le reste tourne dans des
              conteneurs

              Donc tu va utiliser tes conteneurs comme un rpm mais sans dépendances. Et sans facilité pour combiner les binaires (exemple, si je veux rajouter git et iptables sur l'image, bah, j'ai quand même besoin d'avoir un paquet pour rajouter à l'image de base, vu que ton image ne peux dépendre que d'une image à la fois).

              On verra qui gagne la bataille du conteneur entre systemd et
              docker mais je dirais que pour l'instant docker à une longueur
              d'avance pas sur le plan technique car effectivement
              l'approche daemon n'est pas la meilleur mais niveau
              eco-system/buzz ils sont loin devant.

              Je ne pense pas que systemd cherche à gagner une bataille quelconque. Systemd supporte de démarrer un container docker, donc bon, les options sont déjà la. Et globalement, vu que docker engine est plus une brique de base qu'autre chose, tu es obligé d'avoir des outils à coté, notamment pour l'orchestration, et les outils de docker inc sont trop simplistes pour ça. Donc tu as tout un écosystème qui supporte plus que docker (genre kubernetes supporte rkt, mesos supporte kubernetes ou docker en natif, etc, etc). Donc la question se pose pas vraiment comme ça.

              Le fait que les Windows conteneur utilisent l'API Docker c'est
              plutôt impressionnant je trouve.

              Ben c'est logique, ils vont bénéficier de l’écosystème sans rien faire.

              Et docker Inc travaille sur
              une approche non daemon aussi , ça s'appelle containerd
              (https://github.com/docker/containerd).

              Bah, donc même docker inc voit que leur approche de démon centralisé n'est pas suffisante.
              Il faut bien voir que runc, c'est juste une réaction suite à la sortie de rkt. Et pendant que docker inc tente d'éviter que les gens aillent ailleurs, rkt bosse sur la sécurité en profondeur, avec l'attestation des images, une approche federé pour les images de base, etc).

              À la fin, utiliser runc/rkt (ou systemd-nspawn) est plus propre pour un orchestrateur (qui va être capable de surveiller le processus, de récuperer les logs, de ne pas attendre que docker incorpore les derniers changements niveau noyau, etc). Donc je pense que les gens vont migrer vers ça à terme.

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.