Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Qu’est-ce que Sécurix ?

Un système d’exploitation développé à la DINUM, principalement pour un usage interne, pour construire des environnements de poste de travail déclaratifs, reproductibles et sécurisés par défaut. Basé sur NixOS, il permet d’écrire la configuration sous forme de code pour définir les utilisateurs, programmes, services, configurations, et plus encore.

Note

Ce projet est en alpha, aucun support n’est proposé pour l’heure.

Objectifs

SécurixOS est une distribution NixOS développée par la DINUM pour équiper des ordinateurs sécurisés pour l’administration système, la bureautique et le développement afin de traiter des informations Non Protégées dans un premier temps puis éventuellement des informations Diffusion Restreinte.

Il constitue un modèle de PC sécurisé conçu pour permettre des accès à la production et d’autres usages critiques en garantissant un niveau de sécurité variable selon la configuration employée.

Grâce à NixOS, ce modèle est ré-instantiable pour des cas d’usages variables : poste multi-agent, poste multi-niveaux, poste en intranet seulement, etc. avec des équipes différentes, des souches de VPN différents.

Construit selon les recommandations de l’ANSSI : https://cyber.gouv.fr/publications/recommandations-relatives-ladministration-securisee-des-si.

Licences

Sécurix est distribué en majeure partie sous licence MIT. Voir le dossier LICENSES pour plus de détails. Le projet utilise REUSE pour annoter les licences utilisés. Voir aussi Comment contribuer.

Initialisation

Contexte

Le projet SécurixOS est un projet de kit de fabrication de poste de travail, qu’ils soient d’administration ou qu’ils soient de bureautique et tout ce qu’il y a entre les deux en matière de nuance de postes de travail, e.g. poste métier spécialisé, poste durci nomade, etc.

Le projet met à contribution le projet NixOS qui est lui-même un kit de fabrication de distributions Linux héritant des concepts de Nix [1] et le spécialise à des fins de fabrication de postes de travail géré de façon organisationnel.

Le projet SécurixOS n’adresse pas les besoins de postes de travail dans les milieux BYOD (“Bring Your Own Device”), il n’adresse que les postes maîtrisés sous le contrôle d’une entité centralisée au sein d’une organisation. Il est bien sûr possible d’avoir la gestion de plusieurs souches SécurixOS sous différentes branches au sein d’une même organisation, si cela est nécessaire.

Puisque SécurixOS est un kit de fabrication, il ne donne pas accès à des artéfacts d’installation « sur étagère » comme les distributions Linux classiques, il n’est donc pas possible de télécharger un ISO de SécurixOS pour l’essayer car il faudrait fabriquer une organisation factice et avoir une infrastructure de postes de travail de démonstration.

Néanmoins, le projet SécurixOS propose des dépôts de code à titre d’exemple pour voir une façon d’intégrer le kit SécurixOS pour pouvoir obtenir des artéfacts en tout genre: ISOs, systèmes à copier sur le disque, images de machines virtuelles, etc.

Le projet SécurixOS fait l’hypothèse que les personnes qui vont s’en emparer disposent déjà d’une compréhension de l’écosystème Nix ou NixOS, il n’est pas conseillé d’utiliser SécurixOS sans compétences Nix au sein de son organisation.

La distinction entre securix et securix-$org ou bureautix-$org

Dans le projet SécurixOS, nous conseillons de garder une référence vers le projet open source et de mettre en commun les efforts dans le commun numérique lorsque votre besoin pourrait bénéficier à tout le monde. Lorsque votre besoin est très spécifique à votre organisation ou en expérimentation, il est préférable de le garder pour vous et de le maturer. En plus, le projet SécurixOS propose plein de mécanismes permettant de contrôler les politiques appliqués pour générer les postes de travail de votre organisation. Ces informations doivent être stockés dans un dépôt de code, nous les appelons les dépôts securix-$org (si vous utilisez une variante poste d’administration) ou bureautix-$org (si vous utilisez une variante bureautique), on y trouve :

  • vos personnalisations spécifiques à votre organisation
  • vos expérimentations
  • vos inventaires statiques
  • vos éléments de configuration VPNs
  • vos éléments de configuration de proxy
graph TD
    A[securix<br/>open-source<br/>cloud-gouv/securix] --> B[securix-$org<br/>dépôt orga<br/>custom + inventaire + VPN/proxy]
    A --> C[bureautix-$org<br/>dépôt orga bureautique]
    B -.-> D[securix-acme<br/>ex. acme]
    C -.-> E[bureautix-acme<br/>ex. acme]
    D & E --> F[postes déployés]

Par exemple, si votre organisation acme décide de déployer un poste d’administration et un poste de bureautique (deux populations, parfois qui se recoupent) sous la gestion de deux divisions différentes, vous pouvez construire alors securix-acme et bureautix-acme et ils feront tous les deux référence au projet open source https://github.com/cloud-gouv/securix. Il est bien entendu possible de faire un miroir de ce projet sur votre forge et de dépendre de la version en miroir.

Ainsi, pour la montée de version, il existe deux composants majeurs à gérer :

  • NixOS & nixpkgs qui fait l’objet d’une mise à jour tous les 6 mois si vous suivez les versions stables ou toutes les semaines si vous suivez les versions continues
  • SécurixOS qui fait l’objet d’un développement au fil de l’eau et maintient les composants de sécurité qui ne sont pas dans nixpkgs, e.g. lanzaboote pour Secure Boot ou disko pour le partitionnement du disque.

Préparer le dépôt securix-$org ou bureautix-$org

Nous prendrons l’exemple de l’organisation acme, pour préparer le dépôt securix-acme, il y a deux possibilités :

  • Créer sa hiérarchie et sa structure de toute pièce si on comprend bien les APIs fournies par le projet SécurixOS pour l’instantiation, il est aussi tout à fait possible de consommer les modules utiles directement et d’ignorer toutes les abstractions du projet
  • Suivre un template d’exemple comme bureautix-example

Nous proposons d’expliquer comment travailler avec le second pour le reste de ce guide.

Forker bureautix-example

https://github.com/cloud-gouv/bureautix-example se trouve un exemple factice d’application du kit du projet SécurixOS.

Pour s’en emparer, il est possible de le forker directement sur GitHub puis de le rendre privé (mais attention, ça laisse des traces du côté de la base de données GitHub), ou bien de le cloner puis de le repousser vers un nouveau dépôt indépendant qui est privé dès le départ.

La structure du dépôt se décompose ainsi :

bureautix-example/
├── common/                         # Configurations partagées (toutes machines)
│   ├── admins.nix                  # Administrateurs système via FIDO2
│   ├── filesystems.nix             # Choix du modèle de partition
│   ├── pam_u2f.nix                 # Authentification YubiKey/U2F
│   ├── printing.nix                # Drivers d'impression
│   └── tools.nix                   # Outils communs (curl, vim, htop...)
│
├── defaults/                       # Profils matériels
│   └── x280.nix                    # ThinkPad X280 (modèle de référence)
│
├── developer/                      # Profil développeur
│   └── virtualisation.nix          # Docker, KVM, libvirtd
│
├── inventory/                      # Inventaire statique
│   ├── machines/
│   │   └── PC140V35.nix            # Configuration d'une machine spécifique
│   └── users/
│       ├── alice.nix               # Comptes utilisateurs (exemples)
│       ├── bob.nix
│       └── heloise.nix
│
├── netboot/                        # Démarrage réseau PXE
│   ├── Caddyfile                   # Serveur web Caddy
│   └── shell.nix                   # Environnement netboot
│
├── npins/                          # Épinglage des dépendances
│   └── sources.json                # Versions figées des sources
│
├── pkgs/                           # Paquets Nix spécifiques à Sécurix
│   └── nixos-installer/
│       └── installer.py            # Script d'installation NixOS
│
├── workflows/                      # CI/CD pour GitHub
│   ├── build-toplevels.nix         # Construction des configurations
│   └── pre-commit.nix              # Contrôle de la qualité
│
├── default.nix                     # Point d'entrée principal Nix
├── shell.nix                       # Environnement de développement
├── treefmt.toml                    # Formatage automatique
├── README.md                       # Documentation en anglais
└── README.fr.md                    # Documentation en français

Gérer l’inventaire statique : ajout et suppressions

Le projet SécurixOS ne supporte officiellement pour le moment que les inventaires statiques qui conviennent aux environnements jusqu’à 300 utilisateurs. Au delà, il est possible d’utiliser des inventaires statiques mais il convient de mettre en place des techniques de gestion à l’échelle, i.e. générer l’inventaire statique depuis une base de données ITSM, de fractionner les repertoires d’inventaires par rapport à des préfixes distinguants pour éviter d’avoir trop de fichiers dans le même repertoire et ainsi de suite.

Le projet SécurixOS prévoit de supporter les inventaires dynamiques reposant sur LDAP ou OIDC, ce qui éliminerait le besoin de prédéclarer les utilisateurs dans Git.

Comment ajouter une nouvelle machine ?

Pour ajouter une nouvelle machine, il suffit d’ajouter un nouveau fichier .nix avec le nom de son identifiant (e.g. numéro de série, asset tag, numéro d’inventaire interne) avec le contenu suivant :

{
  securix.self.mainDisk = "/dev/nvme0n1"; # Si c'est un disque NVMe, sinon /dev/sda si c'est un disque sur le bus SATA.
  securix.self.machine = {
    hardwareSKU = "x280"; # Le SKU pour le profil matériel, ici: X280.
    serialNumber = "PC140V35"; # Le numéro de série, d'asset tag ou d'inventaire interne du système, il est utilisé pour construire le nom d'hôte de la machine.

    users = [
      "heloise" # Les utilisateurs qui seront provisionnés sur cette machine. Il faut qu'ils existent au préalable.
    ];
  };
}

Comment ajouter une nouvelle personne ?

Pour ajouter une nouvelle personne, il suffit d’ajouter un nouveau fichier .nix avec son identifiant utilisateur (prénom, prénom puis nom, etc.) :

{ pkgs, ... }:
{
  securix.self.user = {
    email = "heloise@example.com"; # Adresse email
    username = "heloise"; # Nom d'utilisateur
    # Clefs Universal 2 Factor (U2F), e.g. clefs FIDO2 comme les Yubikeys
    # Généré via pamu2cfg
    u2f_keys = [
      "..."
    ];
    defaultLoginShell = pkgs.zsh; # Optionnellement, shell pour l'utilisateur
  };
}

⚠️ Attention, ces fichiers Nix ne vivent pas dans un module NixOS pour les développeurs qui connaissent bien NixOS, ceci est une limitation documentée par https://github.com/cloud-gouv/securix/issues/196 que nous souhaitons lever.

L’ensemble des options configurables sur un utilisateur sont disponibles à https://github.com/cloud-gouv/securix/blob/main/modules/self.nix#L74-L140.

Déclarer outils et programmes

La déclaration d’outils ou de programme se fait en utilisant les options NixOS classiques, e.g. environment.systemPackages.

Déclarer un outil pour l’ensemble des utilisateurs du poste

Dans le fichier common/tools.nix, il est possible d’ajouter un paquet pour tout le monde.

Déclarer un outil pour un sous-ensemble des utilisateurs du poste

Dans le fichier common/tools.nix, il est possible d’ajouter un paquet conditionnellement relatif à quel est le poste ou l’utilisateur en inspectant config.securix.self.user ou config.securix.self.machine.

Déclarer un outil pour une personne

Dans le fichier d’inventaire, il est possible d’ajouter environment.systemPackages sur une machine ou sur une personne.

Options de déploiement

La plupart de ces méthodes sont des idées d’architecture, l’implémentation par défaut est la première.

Bureautix implémente la plupart des suivantes.

1. Installateur USB pour chaque système

Cette méthode consiste à créer un installateur USB distinct pour chaque système. Chaque clé contient les fichiers d’installation adaptés à la configuration spécifique du système.

Lorsque l’utilisateur démarre depuis cette clé, l’installateur installe directement une closure NixOS spécifique après l’invocation de autoinstall-terminal.

Cette méthode est pratique lorsque vous avez peu de systèmes et pas d’infrastructure, c’est la méthode par défaut.

2. Installateur USB générique « masse »

L’installateur USB « masse » est conçu pour simplifier le déploiement de plusieurs systèmes. Il contient une liste de systèmes pré-configurés, chacun indexé par son numéro de série. Au démarrage, le système vérifie son numéro de série et sélectionne automatiquement la configuration appropriée. Vous pouvez ainsi avoir un seul installateur USB pour plusieurs systèmes.

Cette méthode est pratique pour installer en masse plusieurs systèmes en série. Elle nécessite une grosse clé USB si les systèmes ont beaucoup de personnalisations distinctes conduisant à de grosses closures.

Cette méthode est implémentée comme exemple dans Bureautix.

3. Installateur USB générique en ligne

L’installateur USB générique en ligne fonctionne comme l’installateur masse, mais se connecte à un site externe pendant l’installation. Au démarrage, le système envoie son numéro de série au site, qui redirige vers une closure NixOS adaptée à ce numéro.

Le site cible doit agir comme un cache Nix, une fois la redirection effectuée, Nix copie la closure en mémoire.

Cette méthode est pratique lorsque les configurations sont toutes construites en CI et poussées vers un cache accessible dans l’environnement de l’installateur. La clé USB peut être gravée une fois et reste relativement à jour tant que le partitionnement ou les fonctions de boot spéciales ne changent pas.

Cette méthode peut être implémentée à partir d’un exemple dans Bureautix en ajoutant d’autres closures.

4. Installation par netboot

L’installation par netboot est une solution légère où l’installateur est envoyé via PXE au lieu d’une clé USB physique. Au démarrage, le système récupère l’installateur par le réseau (HTTP ou TFTP) et télécharge les fichiers nécessaires. Cela permet d’installer sans support physique.

Cette méthode est pratique pour les cycles de développement, le déploiement de masse sur site et même en ligne si votre OEM supporte le HTTP boot et que vous avez un mécanisme d’authentification du système d’origine.

Cette méthode est implémentée comme exemple dans Bureautix.

Un cache pour vos pipelines CI/CD (internes)

Ce document décrit comment configurer un cache binaire Nix dans un pipeline CI/CD pour réutiliser les résultats de compilation entre les exécutions et les machines. Utiliser un cache réduit drastiquement les temps de compilation et la charge sur votre CI lors de la construction d’artefacts Sécurix (ISOs, configurations système, etc.).

Les exemples sont volontairement agnostiques de la CI. Quand un outillage spécifique à GitHub Actions est mentionné, nous expliquons comment le remplacer dans d’autres CI.

Flux haut niveau du pipeline

Un pipeline CI utilisant un cache Nix suit généralement ces étapes :

  1. Cloner le dépôt
  2. Installer Nix (Sécurix est développé et testé avec https://lix.systems/)
  3. Configurer l’accès au cache (substituters + identifiants)
  4. Lancer nix-build, nix develop ou nix build
  5. Envoyer les résultats vers le cache

Chacune de ces étapes est décrite ci-dessous.

Note : le garbage collection n’est pas couvert ici. Après un certain temps, votre cache S3 accumulera des chemins Nix inutiles. Vous pouvez lancer un pipeline planifié pour expirer les objets selon la date ou leur vivacité avec des outils S3 standards.

Étape 1 : Cloner le dépôt

Votre CI doit récupérer le code source avant de lancer les commandes Nix.

Aucune configuration spécifique à Nix n’est requise ici.

Étape 2 : Installer Nix

Un interpréteur Nix doit être installé sur le runner CI.

Prérequis

  • Linux ou macOS
  • Accès root ou sudo (sauf Nix en mode utilisateur, non recommandé)

Options d’installation génériques

Vous pouvez installer Lix avec (exemple Linux) :

curl -L https://install.lix.systems/lix/lix-installer-x86_64-linux | sh

Après installation, vérifiez :

nix --version

Remarques

Beaucoup de CI proposent des workflows réutilisables pour installer Nix. Ils :

  • préconfigurent nix.conf pour les entrées nixpkgs
  • injectent les jetons de forge (GitHub, GitLab, etc.) pour éviter les limites d’API
  • activent des fonctionnalités optionnelles comme l’accélération KVM

Si vous utilisez GitHub Actions, nous recommandons https://github.com/samueldr/lix-gha-installer-action, rapide, léger et facile à auditer. Sa logique est portable vers d’autres CI.

Étape 3 : Configurer le cache binaire

C’est l’étape la plus importante, et souvent la plus complexe.

Configurer les substituters

Un substituter indique à Nix où télécharger les artefacts cachés.

Exemple :

s3://oss-securix

Avec paramètres additionnels :

  • endpoint : endpoint S3 compatible
  • region : région du stockage objet
  • compression : format de compression. Nous recommandons zstd plutôt que xz : zstd offre une compression/décompression bien plus rapide pour un compromis taille raisonnable.
  • parallel-compression : optimisation vitesse pour xz ou zstd

Ces réglages peuvent être appliqués via :

  • nix.conf
  • variables d’environnement
  • drapeaux CLI

Exemple nix.conf :

substituters = https://cache.nixos.org s3://oss-securix?endpoint=https://s3.gra.io.cloud.ovh.net&region=gra
trusted-public-keys = oss-securix-1:PUBLIC_KEY_HERE

Étape 4 : Configurer les secrets

Pour envoyer des artefacts vers le cache, Nix doit signer et avoir l’accès en écriture au stockage S3.

Secrets requis

Stockez en secrets CI :

  • Clé privée de signature Nix : générable via nix key generate-secret
  • Access key du stockage objet
  • Secret key du stockage objet

Si votre projet accepte des PR non fiables, séparez les caches :

  • Cache CI non fiable : builds déclenchés par PR/forks
  • Cache CD fiable : builds après merge/approbation

Cela évite que du code non revu pollue les caches fiables.

Déclarer les secrets en CI

La plupart des CI supportent les secrets masqués, préférez ce mécanisme à un autre pouvant exposer les identifiants.

La clé de signature est typiquement référencée dans nix.conf :

secret-key-files = /path/to/signing-key

Étape 5 : Activer l’envoi vers le cache

Pour que les résultats soient envoyés :

  • Le cache doit être listé comme substituter
  • La clé de signature doit être disponible
  • Le job CI doit avoir l’accès en écriture au stockage objet
  • Une partie de votre workflow doit envoyer les chemins

Pour ce dernier point, plusieurs solutions :

  • Utiliser un post-build-hook pour envoyer immédiatement. Cela garantit que tous les chemins touchés sont envoyés, y compris ceux copiés depuis https://cache.nixos.org.
  • envoyer manuellement avec nix copy $built_path s3://your-bucket?endpoint=... à la fin
  • lancer un daemon observant le filesystem et copiant les chemins au fil de la construction

Étape 6 : Lancer la compilation

Une fois tout configuré, lancez comme d’habitude :

nix-build -A tests

Considérations de sécurité

  • Ne jamais committer de clé privée
  • Limiter les identifiants au minimum requis (lecture/écriture)
  • Utiliser des caches séparés pour builds fiables/non fiables si nécessaire
  • Restreindre qui peut envoyer vers le cache
  • Supprimer l’accès direct à la clé de signature et aux identifiants S3 est possible via un service intermédiaire comme Attic.

Profils matériels

L’équipe SécurixOS maintient un ensemble de profils matériels dans le répertoire hardware. Ces profils matériels ont été testés manuellement et sont utilisés en environnement réel.

Warning

Actuellement, l’équipe n’accepte pas les contributions matérielles de la communauté qu’elle ne peut pas tester et valider en continu.

Cependant, si votre matériel n’est pas pris en charge, vous pouvez toujours l’utiliser dans SécurixOS en créant et en important votre propre module dans votre configuration, comme pris en charge par la fonctionnalité de types d’options extensibles de NixOS. Un fichier de module matériel SécurixOS votre-materiel.nix ressemble à :

{ pkgs, lib, config, ...}:
{
  options.securix.self.machine.hardwareSKU = mkOption {
    type = lib.types.enum ["votre-nom-materiel"];
  }
  config = lib.mkIf (config.securix.self.machine.hardwareSKU == "votre-nom-materiel") {
    # La configuration NixOS de votre matériel qui peut être générée par nixos-generate-config
  }
}

Dans votre configuration SécurixOS, vous pouvez ensuite importer ce fichier et activer votre configuration matérielle :

{
  imports = [ ./votre-materiel.nix ];
  config = {
    securix.self.machine.hardwareSKU = "votre-nom-materiel";
  }
}

Comment contribuer

Contribuer au projet

Les contributions sont ouvertes au projet, il est recommandé d’avoir une expertise NixOS pour en faciliter l’intégration. Consultez les tickets ouverts et le guide de contribution pour participer. Vous pouvez ouvrir des tickets pour proposer des fonctionnalités et discuter de l’architecture. Les PR générées par IA sans relecture ni test seront fermées, les contributions par le même auteur pourront être bloquées par la suite.

Ce README est en français mais le reste du code, les issues et les PR sont en anglais.

Compiler la documentation

Pour compiler et afficher la documentation :

nix-build -A docs.all
xdg-open ./result/index.html
# ou
xdg-open ./result/en/index.html  # version anglaise
xdg-open ./result/fr/index.html  # version française

Comment tester mes changements dans une machine virtuelle ?

Comment tester mes changements sur une machine physique ?

Ressources

  • nix.dev un bon point de départ pour l’écosystème Nix/Lix et NixOS
  • Manuels
  • le wiki officiel contient des astuces sur des sujets pointus, mais de qualité et fraîcheur très variables