
Outil de sécurité piloté par eBPF pour verrouiller et auditer les machines Linux. Restreint les fonctionnalités du noyau, bloque l'exécution sans fichier, protège la mémoire et durcit les conteneurs et les appareils IoT via des profils déclaratifs.

bpflock - Sécurité pilotée par eBPF pour verrouiller et auditer les machines Linux.
Remarque : bpflock est actuellement en phase expérimentale, il peut casser, les options et la sémantique de sécurité peuvent changer, certains programmes BPF seront mis à jour pour utiliser la bibliothèque ebpf de Cilium.
bpflock utilise eBPF pour renforcer la sécurité Linux. En restreignant l'accès à une large gamme de fonctionnalités Linux, bpflock est capable de réduire la surface d'attaque et de bloquer certaines techniques d'attaque bien connues.
Seuls les programmes comme les gestionnaires de conteneurs, systemd et autres conteneurs/programmes qui s'exécutent dans les espaces de noms pid et réseau de l'hôte sont autorisés à accéder à l'ensemble des fonctionnalités Linux ; les conteneurs et applications qui s'exécutent dans leur propre espace de noms seront restreints.
Si les programmes bpf de bpflock s'exécutent sous le profil restricted, alors tous les programmes/conteneurs, y compris les privilégiés, verront leur accès refusé.
bpflock protège les machines Linux en tirant parti de multiples fonctionnalités de sécurité, notamment Linux Security Modules + BPF.
Notes sur l'architecture et la conception de la sécurité :
bpflock offre plusieurs protections de sécurité qui peuvent être classées comme suit :
Protections du système de fichiers
Protections réseau
bpflock garde une sémantique de sécurité simple. Il prend en charge trois profils globaux pour couvrir largement le spectre de sécurité et restreindre l'accès à des fonctionnalités Linux spécifiques.
profile : c'est le profil global qui peut être appliqué par programme bpf, il prend l'une des valeurs suivantes :
allow|none|privileged : ils sont identiques, ils définissent le profil le moins sécurisé. Dans ce profil, l'accès est journalisé et autorisé pour tous les processus. Utile pour enregistrer les événements de sécurité.baseline : profil restrictif où l'accès est refusé pour tous les processus, sauf pour les applications privilégiées et les conteneurs qui s'exécutent dans les espaces de noms de l'hôte, ou les profils autorisés par cgroup dans la carte bpf bpflock_cgroupmap.restricted : profil fortement restrictif où l'accès est refusé pour tous les processus.Opérations/commandes autorisées ou bloquées :
Sous les profils allow|privileged ou baseline, une liste de commandes autorisées ou bloquées peut être spécifiée et sera appliquée.
--protection-allow : liste d'opérations autorisées séparées par des virgules. Valide sous le profil baseline, utile pour les applications très spécifiques qui effectuent des opérations privilégiées. Cela réduit l'utilisation du profil ; ainsi, au lieu d'utiliser le profil , on peut spécifier le profil et ajouter un ensemble de commandes autorisées pour offrir une définition au cas par cas pour ces applications.Pour des exemples de sécurité bpf, consultez les exemples de configuration bpflock
bpflock nécessite ce qui suit :
Version du noyau Linux >= 5.13 avec la configuration suivante :
CONFIG_BPF_SYSCALL=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_INFO_BTF=y
CONFIG_KPROBES=y
CONFIG_LSM="...,bpf"
CONFIG_BPF_LSM=y
Évidemment un noyau avec BTF activé.
Si votre noyau a été compilé avec CONFIG_BPF_LSM=y, vérifiez dans /boot/config-* pour confirmer, mais si lors de l'exécution de bpflock il échoue avec :
must have a kernel with 'CONFIG_BPF_LSM=y' 'CONFIG_LSM=\"...,bpf\"'"
Alors pour activer BPF LSM, par exemple sur Ubuntu :
/etc/default/grub en tant que privilégié bien sûr.GRUB_CMDLINE_LINUX et enregistrez.
"lsm=lockdown,capability,yama,apparmor,bpf"
GRUB_CMDLINE_LINUX="lsm=lockdown,capability,yama,apparmor,bpf"
sudo update-grub2
Pour exécuter avec le profil allow ou privileged par défaut (le moins sécurisé) :
docker run --name bpflock -it --rm --cgroupns=host \
--pid=host --privileged \
-v /sys/kernel/:/sys/kernel/ \
-v /sys/fs/bpf:/sys/fs/bpf linuxlock/bpflock
Pour journaliser et restreindre l'exécution binaire sans fichier, exécutez avec :
docker run --name bpflock -it --rm --cgroupns=host --pid=host --privileged \
-e "BPFLOCK_FILELESSLOCK_PROFILE=restricted" \
-v /sys/kernel/:/sys/kernel/ \
-v /sys/fs/bpf:/sys/fs/bpf linuxlock/bpflock
Lors de l'exécution sous le profil restricted, les logs du conteneur afficheront :
time="2022-02-04T14:54:33Z" level=info msg="event=syscall_execve tgid=1833 pid=1833 ppid=1671 uid=1000 cgroupid=8821 comm=loader pcomm=bash filename=./loader retval=0" bpfprog=execsnoop subsys=bpf
time="2022-02-04T14:54:33Z" level=info msg="event=lsm_bprm_creds_from_file tgid=1833 pid=1833 ppid=1671 uid=1000 cgroupid=8821 comm=loader pcomm=bash filename=memfd:memfd-test retval=-1 reason=denied (restricted)" bpfprog=filelesslock subsys=bpf
time="2022-02-04T14:54:33Z" level=info msg="event=syscall_execve tgid=1833 pid=1833 ppid=0 uid=1000 cgroupid=8821 comm= pcomm= filename=/proc/self/fd/3 retval=-1" bpfprog=execsnoop subsys=bpf
Exécuter sous le profil restricted peut casser des choses, c'est pourquoi le profil par défaut est allow.
Pour appliquer la protection des modules du noyau,
exécutez avec la variable d'environnement BPFLOCK_KMODLOCK_PROFILE=baseline ou BPFLOCK_KMODLOCK_PROFILE=restricted :
docker run --name bpflock -it --rm --cgroupns=host --pid=host --privileged \
-e "BPFLOCK_KMODLOCK_PROFILE=restricted" \
-v /sys/kernel/:/sys/kernel/ \
-v /sys/fs/bpf:/sys/fs/bpf linuxlock/bpflock
Exemple :
$ sudo unshare -p -n -f
# modprobe xfs
modprobe: ERROR: could not insert 'xfs': Operation not permitted
time="2022-02-07T06:50:25+01:00" level=info msg="event=syscall_execve tgid=52323 pid=52323 ppid=52288 uid=0 cgroupid=7014 comm=modprobe pcomm=bash filename=/usr/sbin/modprobe retval=0" bpfprog=execsnoop subsys=bpf
time="2022-02-07T06:50:25+01:00" level=info msg="event=lsm_kernel_read_file operation=loading module tgid=52323 pid=52323 ppid=52288 uid=0 cgroupid=7014 comm=modprobe pcomm=bash filename=xfs.ko retval=-1 reason=denied (restricted)" bpfprog=kmodlock subsys=bpf
Pour appliquer le verrouillage de l'image du noyau, exécutez avec la variable d'environnement BPFLOCK_KIMGLOCK_PROFILE=baseline :
docker run --name bpflock -it --rm --cgroupns=host --pid=host --privileged \
-e "BPFLOCK_KIMGLOCK_PROFILE=baseline" \
-v /sys/kernel/:/sys/kernel/ \
-v /sys/fs/bpf:/sys/fs/bpf linuxlock/bpflock
$ sudo unshare -f -p -n bash
# head -c 1 /dev/mem
head: cannot open '/dev/mem' for reading: Operation not permitted
time="2022-02-07T06:57:22+01:00" level=info msg="event=syscall_execve tgid=52428 pid=52428 ppid=52288 uid=0 cgroupid=7014 comm=head pcomm=bash filename=/usr/bin/head retval=0" bpfprog=execsnoop subsys=bpf
time="2022-02-07T06:57:22+01:00" level=info msg="event=lsm_locked_down operation=/dev/mem,kmem,port tgid=52428 pid=52428 ppid=52288 uid=0 cgroupid=7014 comm=head pcomm=bash retval=-1 reason=denied (baseline)" bpfprog=kimglock subsys=bpf
Pour appliquer la restriction bpf, exécutez avec la variable d'environnement BPFLOCK_BPFRESTRICT_PROFILE=baseline ou BPFLOCK_BPFRESTRICT_PROFILE=restricted :
docker run --name bpflock -it --rm --cgroupns=host --pid=host --privileged \
-e "BPFLOCK_BPFRESTRICT_PROFILE=baseline" \
-v /sys/kernel/:/sys/kernel/ \
-v /sys/fs/bpf:/sys/fs/bpf linuxlock/bpflock
Exemple exécuté dans un espace de noms pid et réseau différent et utilisant bpftool :
$ sudo unshare -f -p -n bash
# bpftool prog
Error: can't get next program: Operation not permitted
time="2022-02-04T15:40:56Z" level=info msg="event=lsm_bpf tgid=2378 pid=2378 ppid=2364 uid=0 cgroupid=9458 comm=bpftool pcomm=bash filename= retval=-1 reason=baseline" bpfprog=bpfrestrict subsys=bpf
time="2022-02-04T15:40:56Z" level=info msg="event=lsm_bpf tgid=2378 pid=2378 ppid=2364 uid=0 cgroupid=9458 comm=bpftool pcomm=bash filename= retval=-1 reason=baseline" bpfprog=bpfrestrict subsys=bpf
Exécution avec le profil -e "BPFLOCK_BPFRESTRICT_PROFILE=restricted" refusera bpf pour tout le monde :
time="2022-02-04T15:44:13Z" level=info msg="event=syscall_execve tgid=2500 pid=2500 ppid=2499 uid=0 cgroupid=9458 comm=bpftool pcomm=sudo filename=./tools/amd64/bpftool retval=0" bpfprog=execsnoop subsys=bpf
time="2022-02-04T15:44:13Z" level=info msg="event=lsm_bpf tgid=2500 pid=2500 ppid=2499 uid=0 cgroupid=9458 comm=bpftool pcomm=sudo filename= retval=-1 reason=denied (restricted)" bpfprog=bpfrestrict subsys=bpf
time="2022-02-04T15:44:13Z" level=info msg="event=lsm_bpf tgid=2500 pid=2500 ppid=2499 uid=0 cgroupid=9458 comm=bpftool pcomm=sudo filename= retval=-1 reason=denied (restricted)" bpfprog=bpfrestrict subsys=bpf
Passer une configuration sous forme de montages liés peut être réalisé en utilisant la commande suivante.
En supposant que bpflock.yaml et les profils bpf.d se trouvent dans le répertoire courant à l'intérieur du répertoire bpflock, alors on peut simplement utiliser :
ls bpflock/
bpf.d bpflock.d bpflock.yaml
docker run --name bpflock -it --rm --cgroupns=host --pid=host --privileged \
-v $(pwd)/bpflock/:/etc/bpflock \
-v /sys/kernel/:/sys/kernel/ \
-v /sys/fs/bpf:/sys/fs/bpf linuxlock/bpflock
Le passage de variables d'environnement peut également se faire avec des fichiers en utilisant --env-file. Tous les paramètres peuvent être passés sous forme de variables d'environnement en utilisant le format BPFLOCK_$NOM_VARIABLE=VALEUR.
Exemple d'exécution avec des variables d'environnement dans un fichier :
docker run --name bpflock -it --rm --cgroupns=host --pid=host --privileged \
--env-file bpflock.env.list \
-v /sys/kernel/:/sys/kernel/ \
-v /sys/fs/bpf:/sys/fs/bpf linuxlock/bpflock
Les fichiers de documentation se trouvent ici.
bpflock utilise docker BuildKit pour construire et Golang pour effectuer certaines vérifications et exécuter des tests. bpflock est construit à l'intérieur d'un conteneur Ubuntu qui télécharge le package golang standard.
Exécutez ce qui suit pour construire le conteneur docker bpflock :
git submodule update --init --recursive
make
Les programmes Bpf sont construits en utilisant libbpf. L'image docker utilisée est Ubuntu.
Si vous souhaitez construire uniquement les programmes bpf directement sans utiliser docker, alors sur Ubuntu :
sudo apt install -y pkg-config bison binutils-dev build-essential \
flex libc6-dev clang-12 libllvm12 llvm-12-dev libclang-12-dev \
zlib1g-dev libelf-dev libfl-dev gcc-multilib zlib1g-dev \
libcap-dev libiberty-dev libbfd-dev
Puis exécutez :
make bpf-programs
Dans ce cas, les programmes générés se trouveront dans le répertoire ./bpf/build/...
bpflock utilise beaucoup de ressources, y compris du code source provenant des projets Cilium et bcc.
Les composants espace utilisateur de bpflock sont sous licence Apache License, Version 2.0. Le code BPF, là où cela est indiqué, est sous licence General Public License, Version 2.0.
allow | privilegedprivilegedbaseline--protection-block : liste d'opérations bloquées séparées par des virgules. Valide sous les profils allow|privileged et baseline, permet de restreindre l'accès à certaines fonctionnalités sans utiliser le profil complet restricted qui pourrait casser certaines applications spécifiques. Utiliser les profils baseline ou privileged ouvre l'accès à la plupart des fonctionnalités Linux, mais avec l'option --protection-block, une partie de cet accès peut être bloquée.