# Socle commun à toutes les machines de la flotte (repo public) : compte # système, réseau/durcissement, bureau Cinnamon/Firefox. Un seul fichier # plutôt que plusieurs petits (base/desktop/accounts) -- chaque option # n'a qu'un seul endroit où la chercher. { pkgs, lib, ... }: let # PREMIER ESSAI FAUX (corrigé ici) : Cinnamon ne suit PAS le mécanisme # GNOME standard (gnome-background-properties via XDG_DATA_DIRS). # Vérifié dans le vrai source du sélecteur, cs_backgrounds.py # (linuxmint/cinnamon, module cinnamon-settings) : # `properties_dir = "/usr/share/cinnamon-background-properties"`, un # chemin ABSOLU EN DUR, jamais résolu via XDG_DATA_DIRS -- même en # mettant le bon XML au bon endroit dans le store, Cinnamon ne # regarde jamais là. mint-artwork (déjà installé par défaut avec # Cinnamon) ne fournit de toute façon aucun XML de ce genre -- ses # images sont sur le disque mais invisibles dans le sélecteur. # # Solution : générer le XML nous-mêmes (à partir de ce que # mint-artwork contient réellement, pas une liste en dur -- chemin # confirmé dans nixpkgs/pkgs/by-name/mi/mint-artwork/package.nix qui # sed-remplace littéralement usr/share/backgrounds/linuxmint/*.jpg), # PUIS forcer /usr/share/cinnamon-background-properties à pointer # dessus via systemd-tmpfiles (seul moyen d'atteindre un chemin en # dur sur un système qui n'a pas de /usr/share FHS classique). cinnamonDefaultWallpapers = pkgs.runCommand "cinnamon-default-wallpapers-properties" { } '' mkdir -p $out/share/cinnamon-background-properties { echo '' echo '' echo '' for f in ${pkgs.mint-artwork}/share/backgrounds/linuxmint/*.jpg \ ${pkgs.mint-artwork}/share/backgrounds/linuxmint/*.png \ ${./wallpaper/Nix/13977413.png}; do [ -e "$f" ] || continue name=$(basename "$f") echo " " echo " $name" echo " $f" echo " zoom" echo " " done echo '' } > $out/share/cinnamon-background-properties/nixos-fleet-defaults.xml ''; in { imports = [ ../../modules/anssi ]; # L+ crée aussi les dossiers parents manquants (/usr, /usr/share, # confirmé dans la doc systemd-tmpfiles.d) -- pas besoin de les créer # à la main. Réappliqué à chaque nixos-rebuild switch (pas seulement # au boot), donc pas besoin de reboot pour que ça prenne effet. # # Symlink un FICHIER précis dans le dossier, pas le dossier entier : # /usr/share/cinnamon-background-properties reste alors un vrai # dossier (auto-créé par L+) où d'autres XML peuvent être ajoutés à # côté (ex: hosts/oreo/configuration.nix côté nixos_users) sans # conflit -- symlinker le dossier entier depuis deux endroits # différents écraserait l'un des deux. systemd.tmpfiles.rules = [ "L+ /usr/share/cinnamon-background-properties/common-defaults.xml - - - - ${cinnamonDefaultWallpapers}/share/cinnamon-background-properties/nixos-fleet-defaults.xml" ]; # Nom uniforme, pas d'identification individuelle pour l'instant (voir # README). À revoir via le numéro de série DMI si le besoin apparaît. networking.hostName = "Nixos_Fleet"; networking.networkmanager.enable = true; # Couverture matérielle maximale (wifi/Bluetooth/PCI) sur un parc # hétérogène inconnu à l'avance. Inclut enableRedistributableFirmware. hardware.enableAllFirmware = lib.mkDefault true; # Durcissement ANSSI (modules/anssi/, vendored depuis SécurixOS). # level "intermediary" : couvre déjà tout ce qui était réglé à la main # sur le profil oreo (R9/R11/R12/R14). category "client" : postes de # travail, pas des serveurs. # # R12 force net.ipv4.ip_forward = 0 : sans impact sur des postes # clients. Ne pas importer ce module sur pxe-server/configuration.nix # (a besoin du forwarding inverse). security.anssi = { enable = true; level = "intermediary"; category = "client"; # R8 (mitigations CPU) coupe l'hyperthreading via "mds=full,nosmt" : # trop coûteux sur le matériel bas de gamme du parc. Désactivé via # exception plutôt que contourné en silence ; réappliqué ci-dessous # sans le "nosmt". exceptions.R8.rationale = "SMT conservé : impact perf trop lourd sur le parc (matériel bas de gamme, parfois 4 Go de RAM). Mitigations réappliquées ci-dessous sans 'nosmt'."; }; # R8 (modules/anssi/kernel-options.nix), sauf mds=full,nosmt -> mds=full. boot.kernelParams = [ "l1tf=full,force" "page_poison=on" "pti=on" "slab_nomerge=yes" "slub_debug=FZP" "spec_store_bypass_disable=seccomp" "spectre_v2=on" "mds=full" # sans ",nosmt" : hyperthreading conservé "mce=0" "page_alloc.shuffle=1" "rng_core.default_quality=500" ]; # Pas couvert par le module ANSSI (R45 en exception : AppArmor # partiellement supporté sur NixOS). systemd.coredump.enable = false; security.apparmor.packages = [ pkgs.apparmor-profiles ]; security.apparmor.enableCache = true; # Bluetooth (même config que le profil oreo) : pas d'allumage auto au # boot, blueman pour la gestion depuis Cinnamon. hardware.bluetooth = { enable = true; powerOnBoot = false; }; services.blueman.enable = true; time.timeZone = "Europe/Paris"; i18n.defaultLocale = "fr_FR.UTF-8"; i18n.extraLocaleSettings = { LC_ADDRESS = "fr_FR.UTF-8"; LC_IDENTIFICATION = "fr_FR.UTF-8"; LC_MEASUREMENT = "fr_FR.UTF-8"; LC_MONETARY = "fr_FR.UTF-8"; LC_NAME = "fr_FR.UTF-8"; LC_NUMERIC = "fr_FR.UTF-8"; LC_PAPER = "fr_FR.UTF-8"; LC_TELEPHONE = "fr_FR.UTF-8"; LC_TIME = "fr_FR.UTF-8"; }; services.xserver.xkb = { layout = "fr"; variant = ""; }; boot.loader.systemd-boot.enable = true; boot.loader.efi.canTouchEfiVariables = true; boot.loader.systemd-boot.configurationLimit = 10; services.openssh.enable = true; networking.firewall.enable = true; # Swap compressé en RAM : couvre le bas du parc (4 Go, desktop complet). zramSwap = { enable = true; memoryPercent = 50; }; nix.settings.experimental-features = [ "nix-command" "flakes" ]; nixpkgs.config.allowUnfree = true; nix.gc = { automatic = true; dates = "weekly"; options = "--delete-older-than 30d"; }; # Convergence automatique depuis le repo public, sans netrc. Cadence # weekly (même format que oreo, plutôt que daily). persistent = true # (déjà la valeur par défaut de ce module -- explicité ici) : si la # machine est éteinte au moment prévu, la maj se lance dès le # prochain démarrage plutôt que d'attendre la semaine suivante. system.autoUpgrade = { enable = true; persistent = true; dates = "weekly"; flake = "git+https://gitea.miniclic.net/Damien/Nixos_Fleet.git#usagers"; }; # Compte admin de la flotte : root, mot de passe "nixos" STABLE (pas # d'expiration forcée) -- machines génériques/partagées, un mot de # passe connu et constant sur tout le parc est voulu pour # l'administration courante. `initialPassword` n'est appliqué qu'à la # création du compte : un rebuild/auto-upgrade ultérieur ne le réécrit # jamais, mais on ne force pas non plus de changement -- "nixos" doit # rester valide indéfiniment sur la flotte. Login root direct autorisé # en local (console/tty) ; SSH reste sur le défaut NixOS (clé # uniquement), ce mot de passe n'ouvre pas la porte à distance. users.mutableUsers = true; users.users.root.initialPassword = "nixos"; # --- Bureau Cinnamon + Firefox -------------------------------------- services.xserver.enable = true; services.xserver.displayManager.lightdm.enable = true; services.xserver.displayManager.lightdm.background = "/etc/nixos/hosts/common/wallpaper/Nix/13977413.png"; services.xserver.desktopManager.cinnamon.enable = true; services.accounts-daemon.enable = true; environment.cinnamon.excludePackages = with pkgs; [ celluloid warpinator ]; # Fond d'écran par défaut (logo NixOS, pas la galerie perso de # nixos_cinnamon). Suppose la config installée sur /etc/nixos (voir # installer/install.sh). Réglé par utilisateur via home-manager # (dconf.settings) plutôt que la base dconf système + activation # script à la main qu'on avait avant -- home-manager génère le bon # fichier et lance `dconf load` lui-même dans le bon contexte # utilisateur, plus besoin de gérer ça nous-mêmes. home-manager.useGlobalPkgs = true; # partage le pkgs du système, pas de deuxième évaluation (RAM) home-manager.backupFileExtension = "hm-backup"; # évite un échec si un fichier existe déjà (migration) home-manager.users.usagers = { ... }: { home.stateVersion = "26.05"; dconf.settings."org/cinnamon/desktop/background".picture-uri = "file:///etc/nixos/hosts/common/wallpaper/Nix/13977413.png"; }; # Reprend la config Firefox d'oreo (nixos_users/hosts/oreo/configuration.nix) # -- c'est elle qui tue la page d'accueil/configuration au premier # lancement (aboutwelcome, newtabpage...) et bloque les pubs/contenu # sponsorisé bien plus largement que l'ancienne version ici (qui ne # coupait que le strict showSponsored). Deux choses changées par # rapport à oreo, volontairement : SearXNG (perso, privé) remplacé par # DuckDuckGo (public, intégré à Firefox) ; ExtensionSettings réduit à # uBlock Origin + Privacy Badger (oreo en a une quinzaine, trop pour # un poste générique de flotte). programs.firefox = { enable = true; languagePacks = [ "fr" ]; preferences = { "browser.startup.homepage" = "https://duckduckgo.com"; "privacy.resistFingerprinting" = true; "network.trr.mode" = 3; "network.trr.uri" = "https://dns.quad9.net/dns-query"; "network.trr.fallback-resolver" = "https://mozilla.cloudflare-dns.com/dns-query"; "browser.newtabpage.enabled" = false; "browser.newtabpage.activity-stream.enabled" = false; "browser.startup.page" = 1; # Page de configuration/bienvenue au premier lancement -- désactivée. "browser.aboutwelcome.enabled" = false; "browser.newtabpage.pinned" = "[]"; "browser.newtabpage.section.discovery" = false; "places.history.enabled" = false; "privacy.clearOnShutdown.history" = true; "privacy.clearOnShutdown.cache" = true; "privacy.clearOnShutdown.downloads" = true; "privacy.clearOnShutdown.cookies" = false; "privacy.clearOnShutdown.sessions" = false; "privacy.clearOnShutdown.formdata" = false; "privacy.clearOnShutdown.offlineApps" = true; # Onglets verticaux à gauche par défaut "sidebar.revamp" = true; "sidebar.verticalTabs" = true; # Virer "Recent browsing" (Firefox View) "browser.tabs.firefox-view" = false; "browser.tabs.firefox-view-next" = false; # Virer "List all tabs" (bouton chevron dropdown) "browser.tabs.tabmanager.enabled" = true; # Virer suggestions de recherche (y compris tendances) "browser.search.suggest.enabled" = false; "browser.urlbar.suggest.searches" = false; "browser.urlbar.suggest.trending" = false; "browser.newtabpage.activity-stream.showSponsored" = false; # HTTPS obligatoire en permanence "dom.security.https_only_mode" = true; "dom.security.https_only_mode_ever_enabled" = true; # Désactiver WebRTC (fuite d'IP réelle même via VPN) "media.peerconnection.enabled" = false; # Désactiver la géolocalisation "geo.enabled" = false; # Désactiver DRM (Widevine) "media.eme.enabled" = false; # Désactiver le prefetching (DNS/liens) — fuite d'intention de navigation "network.dns.disablePrefetch" = true; "network.prefetch-next" = false; "network.predictor.enabled" = false; "network.http.speculative-parallel-limit" = 0; # Désactiver Safe Browsing distant (envoie des hachages d'URL à Google) "browser.safebrowsing.malware.enabled" = false; "browser.safebrowsing.phishing.enabled" = false; # Désactiver la détection de portail captif (requête réseau vers Mozilla) "network.captive-portal-service.enabled" = false; "network.connectivity-service.enabled" = false; # Isolation par premier-parti (empêche le cross-site tracking via cache/cookies) "privacy.firstparty.isolate" = true; # Désactiver WebGL (vecteur de fingerprinting majeur) "webgl.disabled" = true; # Désactiver l'API batterie (fingerprinting) "dom.battery.enabled" = false; # Bloquer l'autoplay média "media.autoplay.default" = 5; # Référent minimal envoyé aux sites "network.http.referer.XOriginPolicy" = 2; # Do Not Track : plus d'UI depuis les versions récentes de Firefox, # mais le pref existe encore et envoie bien l'en-tête DNT=1. "privacy.donottrackheader.enabled" = true; }; policies = { DisableFirefoxStudies = true; DisableFirefoxAccounts = false; DisableFirefoxScreenshots = true; DisableForgetButton = true; DisableMasterPasswordCreation = true; DisableProfileImport = true; DisableProfileRefresh = true; DisableSetDesktopBackground = true; DisablePocket = true; DisableTelemetry = true; DisableFormHistory = true; DisablePasswordReveal = true; SanitizeOnShutdown = false; GenerativeAI.Enable = false; FirefoxSuggest = { WebSuggestions = false; SponsoredSuggestions = false; ImproveSuggest = false; }; FirefoxHome = { SponsoredTopSites = false; SponsoredPocket = false; TopSites = false; Highlights = false; Pocket = false; Snippets = false; Locked = true; }; UserMessaging = { WhatsNew = false; MoreFromMozilla = false; }; EnableTrackingProtection = { Value = true; Locked = true; Cryptomining = true; Fingerprinting = true; }; BlockAboutConfig = false; BlockAboutProfiles = false; BlockAboutSupport = false; DontCheckDefaultBrowser = true; HardwareAcceleration = true; OfferToSaveLogins = false; DefaultDownloadDirectory = "$HOME/Downloads"; PromptForDownloadLocation = true; DisplayBookmarksToolbar = "never"; Preferences = { "privacy.globalprivacycontrol.enabled" = { Value = true; Status = "locked"; }; "privacy.globalprivacycontrol.functionality.enabled" = { Value = true; Status = "locked"; }; }; # DuckDuckGo est un moteur intégré à Firefox, pas besoin de l'Add. Homepage = { URL = "https://duckduckgo.com"; Locked = true; StartPage = "homepage"; }; SearchEngines = { Default = "DuckDuckGo"; PreventInstalls = true; }; "browser.aboutConfig.showWarning" = { Value = false; Status = "locked"; }; NewTabPage = false; ExtensionSettings = { "uBlock0@raymondhill.net" = { install_url = "https://addons.mozilla.org/firefox/downloads/latest/ublock-origin/latest.xpi"; installation_mode = "force_installed"; }; "jid1-MnnxcxisBPnSXQ@jetpack" = { install_url = "https://addons.mozilla.org/firefox/downloads/latest/privacy-badger17/latest.xpi"; installation_mode = "force_installed"; }; }; }; }; environment.systemPackages = with pkgs; [ cinnamonDefaultWallpapers git curl wget htop nixfmt # === Office/Notes === libreoffice pdfarranger simple-scan # === System tools === btop unzip screenfetch tmux fwupd fwupd-efi ncdu gdu hplip gutenprint cups inxi ntfs3g # === Communication/Media === thunderbird ffmpeg vlc mpv strawberry ]; # Flatpak services.flatpak.enable = true; xdg.portal.enable = true; xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; systemd.services.flatpak-repo = { wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; path = [ pkgs.flatpak ]; script = '' flatpak remote-add --if-not-exists flathub \ https://dl.flathub.org/repo/flathub.flatpakrepo ''; }; systemd.services.flatpak-install = { wantedBy = [ "multi-user.target" ]; after = [ "flatpak-repo.service" "network-online.target" ]; wants = [ "network-online.target" ]; requires = [ "flatpak-repo.service" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; }; path = [ pkgs.flatpak ]; script = '' flatpak install -y flathub \ net.waterfox.waterfox \ eu.betterbird.Betterbird ''; }; systemd.services.flatpak-update = { wantedBy = [ "multi-user.target" ]; path = [ pkgs.flatpak ]; script = '' flatpak update -y ''; }; programs.appimage = { enable = true; binfmt = true; }; system.stateVersion = "26.05"; }