Docker Capabilities

Le noyau Linux est capable de décomposer les privilèges de l’utilisateur root en unités distinctes appelées capabilities. Par exemple, la capabilities CAP_CHOWN est ce qui permet à l’utilisateur root d’apporter des modifications arbitraires aux UID et aux GID de fichier. La fonctionnalité CAP_DAC_OVERRIDE permet à l’utilisateur root de contourner les vérifications des autorisations du noyau pour les opérations de lecture, d’écriture et d’exécution de fichier. Presque tous les pouvoirs spéciaux associés à l’utilisateur root Linux sont décomposés en capacités individuelles.

Introduction aux capabilities

Le noyau Linux est capable de décomposer les privilèges de l’utilisateur root en unités distinctes appelées capacités. Par exemple, la capacité CAP_CHOWN est ce qui permet à l’utilisateur root d’apporter des modifications arbitraires aux UID et aux GID de fichier. La fonctionnalité CAP_DAC_OVERRIDE permet à l’utilisateur root de contourner les vérifications des autorisations du noyau pour les opérations de lecture, d’écriture et d’exécution de fichier. Presque tous les pouvoirs spéciaux associés à l’utilisateur root Linux sont décomposés en capacités individuelles.

Cette décomposition des privilèges root en capacités granulaires vous permet de :

  • Supprimez les fonctionnalités individuelles du compte utilisateur root, le rendant moins puissant/dangereux.
  • Ajoutez des privilèges aux utilisateurs non root à un niveau très granulaire.

Les capacités s’appliquent aux fichiers et aux threads. Les fonctionnalités de fichier permettent aux utilisateurs d’exécuter des programmes avec des privilèges plus élevés. Ceci est similaire au fonctionnement du bit setuid. Les capacités de threads gardent une trace de l’état actuel des capacités dans les programmes en cours d’exécution.

Le noyau Linux vous permet de définir des ensembles de limites de capacité qui imposent des limites aux capacités qu’un fichier/thread peut obtenir.

Docker impose certaines limitations qui rendent le travail avec des fonctionnalités beaucoup plus simple. Par exemple, les fonctionnalités de fichier sont stockées dans les attributs étendus d’un fichier, lesquels sont supprimés lors de la création des images Docker. Cela signifie que vous ne devrez normalement pas trop vous préoccuper des capacités de fichier dans les conteneurs.

Il est bien sûr possible d’obtenir des capacités de fichiers dans les conteneurs au moment de l’exécution, mais cela n’est pas recommandé.

Dans un environnement dépourvu de fonctionnalités basées sur des fichiers, il est impossible pour les applications d’élever leurs privilèges au-delà du jeu de limites (jeu au-delà duquel les capacités ne peuvent pas croître). Docker définit le groupe de reliure avant de démarrer un conteneur. Vous pouvez utiliser les commandes Docker pour ajouter ou supprimer des fonctionnalités au jeu de limites.

Par défaut, Docker supprime toutes les fonctionnalités, à l’exception de celles qui sont nécessaires en utilisant une approche de liste blanche :

// DefaultCapabilities returns a Linux kernel default capabilities
func DefaultCapabilities() []string {
return []string{
"CAP_CHOWN",
"CAP_DAC_OVERRIDE",
"CAP_FSETID",
"CAP_FOWNER",
"CAP_MKNOD",
"CAP_NET_RAW",
"CAP_SETGID",
"CAP_SETUID",
"CAP_SETFCAP",
"CAP_SETPCAP",
"CAP_NET_BIND_SERVICE",
"CAP_SYS_CHROOT",
"CAP_KILL",
"CAP_AUDIT_WRITE",
}
}

Un des principaux risques liés à l’exécution de conteneurs Docker est que l’ensemble par défaut de fonctionnalités et de montages donnés à un conteneur peut fournir une isolation incomplète, soit indépendamment, soit en combinaison avec des vulnérabilités du noyau.

Docker prend en charge l’ajout et la suppression de fonctionnalités, ce qui permet d’utiliser un profil autre que celui par défaut. Cela peut rendre Docker plus sûr grâce à la suppression de fonctionnalités ou moins sécurisé grâce à l’ajout de fonctionnalités.

Les conteneurs Docker sont, par défaut, assez sécurisés, surtout si vous vous occupez d’exécuter vos processus à l’intérieur des conteneurs en tant qu’utilisateurs non privilégiés (c’est-à-dire non root).

Utiliser les capabilities

Il existe 3 options pour utiliser les capabilities :

  • Exécutez les conteneurs :
    • en root avec des capabilities et gérer manuellement les capabilities du conteneur (à éviter).
    • en root avec des capabilities limitées et ne pas les modifier dans un conteneur (la plus réaliste).
    • en tant qu’utilisateur sans privilèges et sans capabilities (idéale mais pas réaliste).

Pour supprimer des capabilities du compte root d’un conteneur.

# docker run --rm -it --cap-drop $CAP alpine sh

Pour ajouter des capabilities du compte root d’un conteneur.

# docker run --rm -it --cap-add $CAP alpine sh

Supprimer toutes les capabilities, puis ajouter explicitement des capabilities individuelles au compte root d’un conteneur.

# docker run --rm -it --cap-drop ALL --cap-add $CAP alpine sh

Le noyau Linux préfixe toutes les constantes de capabilities avec CAP_. Par exemple, CAP_CHOWN, CAP_NET_ADMIN, CAP_SETUID, CAP_SYSADMIN, etc. Les constantes de fonctionnalité Docker ne portent pas le préfixe CAP_ mais correspondent aux constantes du noyau.

Liste des capabilities

Pour plus d’informations sur les capabilities, y compris une liste complète, voir la page de manuel relative aux capabilities : http://man7.org/linux/man-pages/man7/capabilities.7.html.

La liste suivante montre les capabilities implémentées sous Linux et
les opérations ou comportements qu’elles permettent :

CAP_AUDIT_CONTROL (since Linux 2.6.11)
Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules.

CAP_AUDIT_READ (since Linux 3.16)
Allow reading the audit log via a multicast netlink socket.

CAP_AUDIT_WRITE (since Linux 2.6.11)
Write records to kernel auditing log.

CAP_BLOCK_SUSPEND (since Linux 3.5)
Employ features that can block system suspend (epoll(7 EPOLLWAKEUP, /proc/sys/wake_lock).

CAP_CHOWN
Make arbitrary changes to file UIDs and GIDs (see chown(2)).

CAP_DAC_OVERRIDE
Bypass file read, write, and execute permission checks. (DAC is an abbreviation of "discretionary access control".)

CAP_DAC_READ_SEARCH
* Bypass file read permission checks and directory read an execute permission checks;
* invoke open_by_handle_at(2);
* use the linkat(2) AT_EMPTY_PATH flag to create a link to a file referred to by a file descriptor.

CAP_FOWNER
* Bypass permission checks on operations that normally require the filesystem UID of the process to match the UID of the file (e.g., chmod(2), utime(2)), excluding those operations covered by CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH;
* set inode flags (see ioctl_iflags(2)) on arbitrary files;
* set Access Control Lists (ACLs) on arbitrary files;
* ignore directory sticky bit on file deletion;
* specify O_NOATIME for arbitrary files in open(2) and fcntl(2).

CAP_FSETID
* Don't clear set-user-ID and set-group-ID mode bits when a file is modified;
* set the set-group-ID bit for a file whose GID does not match the filesystem or any of the supplementary GIDs of the calling process.

CAP_IPC_LOCK
Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2)).

CAP_IPC_OWNER
Bypass permission checks for operations on System V IPC objects.

CAP_KILL
Bypass permission checks for sending signals (see kill(2)).
This includes use of the ioctl(2) KDSIGACCEPT operation.

CAP_LEASE (since Linux 2.4)
Establish leases on arbitrary files (see fcntl(2)).

CAP_LINUX_IMMUTABLE
Set the FS_APPEND_FL and FS_IMMUTABLE_FL inode flags (see ioctl_iflags(2)).

CAP_MAC_ADMIN (since Linux 2.6.25)
Allow MAC configuration or state changes. Implemented for the
Smack Linux Security Module (LSM).

CAP_MAC_OVERRIDE (since Linux 2.6.25)
Override Mandatory Access Control (MAC). Implemented for the Smack LSM.

CAP_MKNOD (since Linux 2.4)
Create special files using mknod(2).

CAP_NET_ADMIN
Perform various network-related operations:
* interface configuration;
* administration of IP firewall, masquerading, and accounting;
* modify routing tables;
* bind to any address for transparent proxying;
* set type-of-service (TOS)
* clear driver statistics;
* set promiscuous mode;
* enabling multicasting;
* use setsockopt(2) to set the following socket options: SO_DEBUG, SO_MARK, SO_PRIORITY (for a priority outside the range 0 to 6), SO_RCVBUFFORCE, and SO_SNDBUFFORCE.

CAP_NET_BIND_SERVICE
Bind a socket to Internet domain privileged ports (port numbers less than 1024).

CAP_NET_BROADCAST
(Unused) Make socket broadcasts, and listen to multicasts.

CAP_NET_RAW
* Use RAW and PACKET sockets;
* bind to any address for transparent proxying.

CAP_SETGID
* Make arbitrary manipulations of process GIDs and supplementary GID list;
* forge GID when passing socket credentials via UNIX domain sockets;
* write a group ID mapping in a user namespace (see user_namespaces(7)).

CAP_SETFCAP (since Linux 2.6.24)
Set arbitrary capabilities on a file.

CAP_SETPCAP
If file capabilities are supported (i.e., since Linux 2.6.24): add any capability from the calling thread's bounding set to its inheritable set; drop capabilities from the bounding set (via prctl(2) PR_CAPBSET_DROP); make changes to the securebits flags.

If file capabilities are not supported (i.e., kernels before permitted capability set to or from any other process. (This configured to support file capabilities, since CAP_SETPCAP has entirely different semantics for such kernels.)

CAP_SETUID
* Make arbitrary manipulations of process UIDs (setuid(2), setreuid(2), setresuid(2), setfsuid(2));
* forge UID when passing socket credentials via UNIX domain sockets;
* write a user ID mapping in a user namespace (see user_namespaces(7)).

CAP_SYS_ADMIN
Note: this capability is overloaded; see Notes to kernel
developers, below.

* Perform a range of system administration operations including: quotactl(2), mount(2), umount(2), swapon(2), setdomainname(2);
* perform privileged syslog(2) operations (since Linux 2.6.37, CAP_SYSLOG should be used to permit such operations);
* perform VM86_REQUEST_IRQ vm86(2) command;
* perform IPC_SET and IPC_RMID operations on arbitrary System V IPC objects;
* override RLIMIT_NPROC resource limit;
* perform operations on trusted and security Extended Attributes (see xattr(7));
* use lookup_dcookie(2);
* use ioprio_set(2) to assign IOPRIO_CLASS_RT and (before Linux 2.6.25) IOPRIO_CLASS_IDLE I/O scheduling classes;
* forge PID when passing socket credentials via UNIX domain sockets;
* exceed /proc/sys/fs/file-max, the system-wide limit on the number of open files, in system calls that open files (e.g., accept(2), execve(2), open(2), pipe(2));
* employ CLONE_* flags that create new namespaces with clone(2) and unshare(2) (but, since Linux 3.8, creating user namespaces does not require any capability);
* call perf_event_open(2);
* access privileged perf event information;
* call setns(2) (requires CAP_SYS_ADMIN in the target namespace);
* call fanotify_init(2);
* call bpf(2);
* perform privileged KEYCTL_CHOWN and KEYCTL_SETPERM keyctl(2) operations;
* perform madvise(2) MADV_HWPOISON operation;
* employ the TIOCSTI ioctl(2) to insert characters into the input queue of a terminal other than the caller's controlling terminal;
* employ the obsolete nfsservctl(2) system call;
* employ the obsolete bdflush(2) system call;
* perform various privileged block-device ioctl(2) operations;
* perform various privileged filesystem ioctl(2) operations;
* perform privileged ioctl(2) operations on the /dev/random device (see random(4));
* install a seccomp(2) filter without first having to set the no_new_privs thread attribute;
* modify allow/deny rules for device control groups;
* employ the ptrace(2) PTRACE_SECCOMP_GET_FILTER operation to dump tracee's seccomp filters;
* employ the ptrace(2) PTRACE_SETOPTIONS operation to suspend the tracee's seccomp protections (i.e., the PTRACE_O_SUSPEND_SECCOMP flag);
* perform administrative operations on many device drivers.

CAP_SYS_BOOT
Use reboot(2) and kexec_load(2).

CAP_SYS_CHROOT
* Use chroot(2);
* change mount namespaces using setns(2).

CAP_SYS_MODULE
* Load and unload kernel modules (see init_module(2) and delete_module(2));
* in kernels before 2.6.25: drop capabilities from the system wide capability bounding set.

CAP_SYS_NICE
* Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes;
* set real-time scheduling policies for calling process, and set scheduling policies and priorities for arbitrary processes (sched_setscheduler(2), sched_setparam(2), sched_setattr(2));
* set CPU affinity for arbitrary processes (sched_setaffinity(2));
* set I/O scheduling class and priority for arbitrary processes (ioprio_set(2));
* apply migrate_pages(2) to arbitrary processes and allow processes to be migrated to arbitrary nodes;
* apply move_pages(2) to arbitrary processes;
* use the MPOL_MF_MOVE_ALL flag with mbind(2) and move_pages(2).

Documentation

http://man7.org/linux/man-pages/man7/capabilities.7.html
https://training.play-with-docker.com/security-capabilities/
https://github.com/docker/labs/tree/master/security/capabilities#docker_cap
https://docs.docker.com/v17.09/engine/security/security/#linux-kernel-capabilities
https://github.com/moby/moby/blob/master/oci/defaults.go#L14-L30

Plus sur les capabilities :
https://training.play-with-docker.com/security-capabilities
https://github.com/docker/labs/tree/master/security/capabilities#step-3-testing-docker-capabilities
https://github.com/docker/labs/tree/master/security/capabilities#step-4-extra-for-experts

> Partager <