Aller au contenu principal
Version: 1.0.0

bitenforcer

bitenforcer lit une politique de durcissement déclarative et répond complètement à une seule question :

« Si j'appliquais ceci à cette machine, qu'est-ce qui changerait exactement — et quel effet cela pourrait-il avoir sur mon accès ? »

Version0.1.0-ga, commit 4c6ce93, compilée avec go1.25.12
PlateformesLinux amd64/arm64 uniquement — macOS et Windows ne sont pas publiés, et pourquoi
Chaîne d'approvisionnementCompilation reproductible, SBOM CycloneDX, signature cosign, attestation du SBOM, SHA256SUMS signé
FormeOutil en ligne de commande à exécution unique. Pas de démon, pas de télémétrie, pas de battement de cœur
La v1 ne modifie aucun hôte

bitenforcer v1 livre validate et apply --dry-run. Il planifie chaque changement, valide le contenu qu'il écrirait, exécute ses garde-fous anti-verrouillage — puis s'arrête. Il n'écrit pas sur l'hôte, et aucune option ne l'y contraint.

C'est une décision de périmètre délibérée : ce n'est ni un bogue, ni une panne, ni un réglage qui vous manquerait. Pourquoi mérite dix minutes de votre temps avant de planifier un déploiement.

Les garde-fous eux-mêmes, et l'exposé complet des raisons pour lesquelles l'application est hors périmètre, se trouvent sur Les garde-fous, et pourquoi la v1 n'applique rien.

Ce qu'il fait​

Pointez-le sur une politique YAML :

bitenforcer validate --config policy.yaml # is the policy well-formed?
bitenforcer apply --config policy.yaml --dry-run # what would it do to THIS host?

Le contrôle préalable nomme chaque fichier qu'il écrirait et les octets qu'il y écrirait, chaque unité systemd qu'il activerait, désactiverait, masquerait ou dans laquelle il déposerait un fragment de durcissement, chaque règle de pare-feu, chaque sysctl, chaque compte et chaque permission — dans l'ordre où ils seraient appliqués.

Là où un vrai validateur existe, le contenu candidat y est passé :

ArtefactValidateur
sshd_configsshd -t -f <candidate>
sudoersvisudo -c
jeu de règles nftablesnft -c -f <candidate>
jeu de règles iptablesiptables-restore --test

Ainsi, « cette politique produit un sshd_config que sshd rejettera » est détecté avant que quiconque en porte la responsabilité — et non à 3 h du matin quand le démon refuse de redémarrer.

Parallèlement, les garde-fous anti-verrouillage rapportent ce que votre politique ferait à votre propre accès, mesuré par rapport à la session dans laquelle vous êtes réellement en train de travailler.

Ce qu'il ne fera pas, c'est deviner. Un module dont les prérequis sont absents produit une erreur au lieu de supposer. Une session qui ne peut pas être mesurée est rapportée comme non mesurée, jamais comme « personne n'est en danger ». Un validateur qui ne peut pas s'exécuter indique NOT VALIDATED fichier par fichier, avec la raison, plutôt que de laisser croire que le contenu a été vérifié.

Sortie réelle d'un contrôle préalable​

Il s'agit d'une exécution réelle du binaire 0.1.0-ga livré, contre le modèle standard, sur un hôte Ubuntu ordinaire, en tant qu'utilisateur non root. Seule l'adresse IP de l'opérateur a été remplacée par une adresse de documentation, et un très long bloc d'erreur nft a été abrégé.

$ bitenforcer generate --template standard --output-file policy.yaml
Example configuration written to policy.yaml

$ bitenforcer validate --config policy.yaml
Configuration 'standard-hardening' is valid.
Environment : staging
Compliance : [CIS-L1]
A valid policy is not a safe one: run `bitenforcer apply --dry-run` to see what it
would change and which guards fire.
(FR) Politique valide. Une politique valide n'est pas pour autant sûre : utilisez
`apply --dry-run`.

$ bitenforcer apply --config policy.yaml --dry-run

=== PRE-FLIGHT: every change this run would make ===
operator "ubuntu" is on an SSH session whose peer socket was NOT measured
(SSH_CONNECTION/SSH_CLIENT in this process's environment (an inherited, settable
environment variable -- a hint, NOT a measured socket)); any address in the
environment is a hint, not evidence

NOT EXAMINED on this host (the rest of the pre-flight below is unaffected):
selinux: SELinux prerequisites check failed: SELinux tools not found
(getenforce not in PATH)
These modules were SKIPPED, not found compliant — this run says nothing
about whether the host matches that part of the policy.
(FR) Modules NON EXAMINÉS sur cet hôte : ignorés, et non déclarés conformes.
1. [command] users /etc/passwd
chmod 0644 /etc/passwd
2. [command] users /etc/passwd
chown root:root /etc/passwd
3. [command] users /etc/shadow
chmod 0640 /etc/shadow
4. [command] users /etc/shadow
chown root:root /etc/shadow
5. [command] users /etc/group
chmod 0644 /etc/group
6. [command] users /etc/group
chown root:root /etc/group
7. [command] users /etc/gshadow
chmod 0640 /etc/gshadow
8. [command] users /etc/gshadow
chown root:root /etc/gshadow
9. [file-write] ssh /etc/ssh/sshd_config
1194 bytes, mode 0600, validated with sshd -t -f <candidate>; NOT VALIDATED in
this dry run (the validator could not be run in this context: sshd -t needs root
to read the host keys (sshd: no hostkeys available -- exiting.)) — re-run the
dry run as root to validate
10. [file-write] firewall /etc/nftables.conf
566 bytes, mode 0600, validated with nft -c -f <candidate>; NOT VALIDATED in
this dry run (nft -c needs root […]) — re-run the dry run as root to validate
11. [file-write] kernel /etc/sysctl.d/99-bitenforcer.conf
672 bytes, mode 0644, validated with sysctl key syntax check
12. [command] kernel /etc/sysctl.d/99-bitenforcer.conf
sysctl -p /etc/sysctl.d/99-bitenforcer.conf

=== PRE-FLIGHT ADVISORIES (the guards; they did NOT block this run) ===
These are the lockout guards. They are advisory: they report the shapes they
recognise, and seven independent reviewers each found one they did not — which is
why this release does not apply anything. Treat a finding as a reason to change the
policy, never as the full list of ways it could strand you. Re-run with
--guards=blocking to have findings exit non-zero, e.g. to gate a policy in CI.
1. [kernel-remote-access-loss] this run would set net.ipv4.conf.all.rp_filter=1,
which drops any packet whose reply route does not leave by the interface it
arrived on
evidence: bitenforcer measures the interface carrying your session (eth0)
but not this host's routing table, so it cannot show that the route back
to 198.51.100.24 leaves by that same interface. On a host with two
uplinks, a VPN, or asymmetric routing, strict reverse-path filtering
drops your session and every future connection from that address
remedy: run `ip route get 198.51.100.24` and confirm it leaves by eth0;
if it does, say so for this one parameter, and keep a second session
open while you apply
override: re-run with --acknowledge kernel-remote-access-loss (this guard only)
2. [kernel-remote-access-loss] this run would set net.ipv4.ip_forward=0, and
bitenforcer cannot establish whether this host routes the network your session
arrives through
…

DRY RUN: nothing above was applied and this host was not changed.
This is the only mode bitenforcer v1 runs in; enforcement is not part of this release.
(FR) SIMULATION : rien n'a été appliqué et cet hôte n'a pas été modifié.

Trois éléments de cette sortie constituent tout le produit :

  1. NOT EXAMINED est une réponse, pas une omission. L'outillage SELinux est absent d'une Ubuntu standard : le module selinux est donc rapporté comme ignoré, et explicitement non déclaré conforme, et le reste du contrôle préalable se poursuit. Une exécution qui ne dit rien d'un contrôle est très différente d'une exécution qui déclare ce contrôle satisfaisant.
  2. NOT VALIDATED nomme la raison, fichier par fichier. sshd -t a besoin des droits root pour lire les clés d'hôte : en tant qu'utilisateur ordinaire, l'outil vous dit donc que le contenu n'a pas été vérifié et ce qu'il faut faire pour y remédier — au lieu de laisser croire discrètement qu'il l'a été.
  3. Le constat d'un garde-fou apporte une preuve, une remédiation et une dérogation propre à ce garde-fou. Il ne dit pas « risqué ». Il dit quel paramètre, ce qu'il a mesuré, ce qu'il n'a pas pu mesurer, et la commande exacte à exécuter pour trancher la question.

Ce que cela vous apporte aujourd'hui​

Il est facile de lire « n'applique pas les changements » comme « ne fait rien ». Voici ce qu'un outil limité au contrôle préalable vous apporte réellement :

  • Un artefact pour votre fenêtre de changement. Joignez la sortie du contrôle préalable à la demande de changement. Chaque fichier, unité, règle et sysctl, dans l'ordre, avec les octets.
  • Un verrou en CI. --guards=blocking fait échouer le pipeline lorsqu'un socle couperait l'accès, avant qu'il n'atteigne un hôte.
  • La détection précoce d'un contenu de politique invalide. sshd -t et nft -c sont exécutés contre le contenu candidat : une politique qui produit une configuration inanalysable est donc détectée dès la revue.
  • Une dérive sur laquelle agir, sans danger. Lancez la simulation sur tout un parc et lisez ce que chaque hôte rapporte comme devant changer — sans aucune possibilité de modifier quoi que ce soit par accident.
  • Une carte de couverture honnête. NOT EXAMINED vous dit là où l'outil n'a rien à dire, pour que vous ne preniez pas le silence pour de la conformité.

La politique en tant que code​

bitenforcer generate --template standard --output-file policy.yaml

Modèles : minimal, standard, strict. Ce sont des points de départ figés, à éditer — ils ne lisent pas l'hôte et ne dérivent aucune posture de la machine sur laquelle vous les avez exécutés. Les politiques générées font un aller-retour complet : redonnez la sortie à validate et elle passe.

validate va plus loin qu'une vérification de schéma : une politique qui définit une clé que rien n'implémente est refusée au chargement, nommément, avec l'énoncé de ce qui ne se produira pas. Un réglage qui est analysé mais inerte est précisément le défaut que ces produits ont passé un mois à retirer d'eux-mêmes.

Une politique valide n'est pas une politique sûre

validate lit le fichier de politique et rien d'autre — il ne regarde pas cet hôte. Exécutez bitenforcer apply --config <file> --dry-run pour savoir ce qu'elle changerait ici.

Plateformes​

0.1.0-ga publie deux binaires signés, et l'écart est délibéré :

PlateformePubliéePourquoi
Linux amd64Oui
Linux arm64Oui
macOS amd64/arm64NonRetenue — voir ci-dessous
Windows amd64NonRetenue — voir ci-dessous

bitenforcer est réservé à Linux parce que tout son sujet est Linux. Chaque module qu'il planifie porte sur un mécanisme Linux : jeux de règles iptables/nftables, clés sysctl sous /proc/sys, unités systemd, SELinux et AppArmor, ainsi que /etc/passwd, /etc/shadow, /etc/gshadow et sudoers avec leurs modes et propriétaires POSIX. Il en va de même pour les validateurs auxquels il soumet le contenu candidat — sshd -t, visudo -c, nft -c, iptables-restore --test.

Une compilation macOS ou Windows fonctionnerait. C'est précisément le problème : elle démarrerait, accepterait une politique et produirait un contrôle préalable dans lequel chaque module serait NOT EXAMINED — un rapport qui ressemble à une exécution réussie et ne dit rien de l'hôte. Puisque cet outil existe pour vous dire ce qu'un changement ferait avant que vous ne le fassiez, un binaire dont la sortie honnête est « je n'ai rien à dire sur cette machine » est pire que pas de binaire du tout. Il n'est pas publié, afin que personne ne le prenne pour une couverture.

Si vous avez besoin de la posture de durcissement d'un hôte macOS, c'est le collecteur posture de bitcollector, qui est livré sur macOS et rapporte, contrôle par contrôle, s'il a été observé, non observé, ou non pris en charge par l'agent là-bas.

Étapes suivantes​

Cette page vous a-t-elle été utile ?