feat: hardening nixos desktops (#160)

* feat: hardening nixos desktops

* refactor: move hardening to the root folder

* feat: add nixpaks into nixpkgs via overlays

* feat: nixpak - add netease music

* docs: hardening

* fix: nvidia

* fix: disable apparmor & hardening profile to avoid neovim being killed

* fix: firefox cursor & fonts
This commit is contained in:
Ryan Yin
2024-09-05 23:59:39 +08:00
committed by GitHub
parent 773688a9e5
commit df9ca7aefa
21 changed files with 626 additions and 13 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ result/
.DS_Store
.pre-commit-config.yaml
logs/
core*

69
flake.lock generated
View File

@@ -264,6 +264,27 @@
"type": "github"
}
},
"flake-parts_4": {
"inputs": {
"nixpkgs-lib": [
"nixpak",
"nixpkgs"
]
},
"locked": {
"lastModified": 1722555600,
"narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "8471fe90ad337a8074e957b69ca4d0089218391d",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems_2"
@@ -382,6 +403,31 @@
"type": "github"
}
},
"hercules-ci-effects": {
"inputs": {
"flake-parts": [
"nixpak",
"flake-parts"
],
"nixpkgs": [
"nixpak",
"nixpkgs"
]
},
"locked": {
"lastModified": 1719226092,
"narHash": "sha256-YNkUMcCUCpnULp40g+svYsaH1RbSEj6s4WdZY/SHe38=",
"owner": "hercules-ci",
"repo": "hercules-ci-effects",
"rev": "11e4b8dc112e2f485d7c97e1cee77f9958f498f5",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "hercules-ci-effects",
"type": "github"
}
},
"home-manager": {
"inputs": {
"nixpkgs": [
@@ -576,6 +622,28 @@
"type": "github"
}
},
"nixpak": {
"inputs": {
"flake-parts": "flake-parts_4",
"hercules-ci-effects": "hercules-ci-effects",
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1724898170,
"narHash": "sha256-/QslnBDv9+dnBCkAd4tto7sZck2CUeCIHtnpzRmZ+Lo=",
"owner": "nixpak",
"repo": "nixpak",
"rev": "02d04e4ac37fd71f117aaaf367d5c41fad14d29b",
"type": "github"
},
"original": {
"owner": "nixpak",
"repo": "nixpak",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1723221148,
@@ -882,6 +950,7 @@
"nix-gaming": "nix-gaming",
"nixos-generators": "nixos-generators",
"nixos-hardware": "nixos-hardware",
"nixpak": "nixpak",
"nixpkgs": "nixpkgs_2",
"nixpkgs-darwin": "nixpkgs-darwin",
"nixpkgs-stable": "nixpkgs-stable_2",

View File

@@ -106,6 +106,11 @@
inputs.nixpkgs.follows = "nixpkgs";
};
nixpak = {
url = "github:nixpak/nixpak";
inputs.nixpkgs.follows = "nixpkgs";
};
######################## Some non-flake repositories #########################################
# doom-emacs is a configuration framework for GNU Emacs.

70
hardening/README.md Normal file
View File

@@ -0,0 +1,70 @@
# Linux Hardening
## Goal
- **System Level**: Protect critical files from being accessed by untrusted applications.
1. Such as browser cookies, SSH keys, etc.
- **Per-App Level**: Prevent untrusted applications(such as closed-source apps) from:
1. Accessing files they shouldn't.
- Such as a malicious application accessing your browser's cookies, SSH Keys, etc.
1. Accessing the network when they don't need to.
1. Accessing hardware devices they don't need.
## Kernel Hardening
- NixOS Kernel Config:
https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/os-specific/linux/kernel/hardened/config.nix
## System Hardening
- NixOS Profile:
https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/profiles/hardened.nix
- Apparmor: [roddhjav/apparmor.d)](https://github.com/roddhjav/apparmor.d)
- https://gitlab.com/apparmor/apparmor/-/wikis/Documentation
- AppArmor.d is a set of over 1500 AppArmor profiles whose aim is to confine most Linux based
applications and processes.
- Nix Package:
[roddhjav-apparmor-rules](https://github.com/NixOS/nixpkgs/blob/nixos-unstable/pkgs/by-name/ro/roddhjav-apparmor-rules/package.nix#L33)
- https://github.com/NixOS/nixpkgs/issues/331645
- SELinux: too complex, not recommended for personal use.
## Application Sandboxing
- [Firejail](https://github.com/netblue30/firejail/tree/master/etc): A SUID security sandbox with
hundreds of security profiles for many common applications in the default installation.
- https://wiki.nixos.org/wiki/Firejail
- Firejail needs SUID to work, which is considered a security risk -
[Does firejail improve the security of my system?](https://github.com/netblue30/firejail/discussions/4601)
- [Bubblewrap](https://github.com/containers/bubblewrap):
[nixpak](https://github.com/nixpak/nixpak), more secure than firejail, but no batteries included.
- NixOS's FHSEnv is implemented using bubblewrap by default.
- [Systemd/Hardening](https://wiki.nixos.org/wiki/Systemd/Hardening): Systemd also provides some
sandboxing features.
## NOTE
**Running untrusted code is never safe, kernel hardening & sandboxing cannot change this**.
If you want to run untrusted code, please use a VM & an isolated network environment, which will
provide a much higher level of security.
## References
- [Harden your NixOS workstation - dataswamp](https://dataswamp.org/~solene/2022-01-13-nixos-hardened.html)
- [Linux Insecurities - Madaidans](https://madaidans-insecurities.github.io/linux.html)
- [Sandboxing all programs by default - NixOS Discourse](https://discourse.nixos.org/t/sandboxing-all-programs-by-default/7792)
- [在 Firejail 中运行 Steam](https://imbearchild.cyou/archives/2021/11/steam-in-firejail/)
- [Firejail - Arch Linux Wiki](https://wiki.archlinux.org/title/Firejail)
- nixpak configs:
- https://github.com/pokon548/OysterOS/tree/b97604d89953373d6316286b96f6a964af2c398d/desktop/application
- https://github.com/segment-tree/my-nixos/tree/ceb6041f73bd9edcb78a8818b27a28f7c629193b/hm/me/apps/nixpak
- https://github.com/Keksgesicht/nixos-config/tree/91cc77d8d6b598da7c4dbed143e0009c2dea6940/packages/nixpak
- https://github.com/bluskript/nix-config/blob/7ecb6a7254c1ac4969072f4c4febdc19f8b83b30/pkgs/nixpak/default.nix
- firejail configs:
- https://github.com/stelcodes/nixos-config/blob/f8967c82a5e5f3d128eb1aaf7498b5f918f719ec/packages/overlay.nix#L261
- apparmor configs:
- https://github.com/sukhmancs/nixos-configs/blob/7fcf737c506ad843113cd5b94796b49d4d4dfad2/modules/shared/security/apparmor/default.nix#L8
- https://github.com/zramctl/dotfiles/blob/4fe177f6984154960942bb47d5a375098ec6ed6a/modules/nixos/security/apparmor.nix#L4
- Others:
- Directly via `buildFHSUserEnvBubblewrap`:
https://github.com/xddxdd/nur-packages/blob/master/pkgs/uncategorized/wechat-uos/default.nix

View File

@@ -0,0 +1,58 @@
{
config,
pkgs,
...
}: {
services.dbus.apparmor = "enabled";
security.apparmor = {
enable = true;
# kill process that are not confined but have apparmor profiles enabled
killUnconfinedConfinables = true;
packages = with pkgs; [
apparmor-utils
apparmor-profiles
];
# apparmor policies
policies = {
"default_deny" = {
enforce = false;
enable = false;
profile = ''
profile default_deny /** { }
'';
};
"sudo" = {
enforce = false;
enable = false;
profile = ''
${pkgs.sudo}/bin/sudo {
file /** rwlkUx,
}
'';
};
"nix" = {
enforce = false;
enable = false;
profile = ''
${config.nix.package}/bin/nix {
unconfined,
}
'';
};
};
};
environment.systemPackages = with pkgs; [
apparmor-bin-utils
apparmor-profiles
apparmor-parser
libapparmor
apparmor-kernel-patches
apparmor-pam
apparmor-utils
];
}

View File

@@ -0,0 +1,75 @@
{pkgs, ...}: let
firejailWrapper = import ./firejailWrapper.nix pkgs;
in {
programs.firejail.enable = true;
# Add firejailed Apps into nixsuper, and reference them in home-manager or other nixos modules
nixpkgs.overlays = [
(_: super: {
firejailed = {
steam = firejailWrapper {
name = "steam-firejailed";
executable = "${super.steam}/bin/steam";
profile = "${super.firejail}/etc/firejail/steam.profile";
};
steam-run = firejailWrapper {
name = "steam-run-firejailed";
executable = "${super.steam}/bin/steam-run";
profile = "${super.firejail}/etc/firejail/steam.profile";
};
# firefox = firejailWrapper {
# name = "firefox-firejailed";
# executable = "${super.lib.getBin super.firefox-wayland}/bin/firefox";
# profile = "${super.firejail}/etc/firejail/firefox.profile";
# };
# chromium = firejailWrapper {
# name = "chromium-firejailed";
# executable = "${super.lib.getBin super.ungoogled-chromium}/bin/chromium";
# profile = "${super.firejail}/etc/firejail/chromium.profile";
# };
mpv = firejailWrapper {
executable = "${super.lib.getBin super.mpv}/bin/mpv";
profile = "${super.firejail}/etc/firejail/mpv.profile";
};
imv = firejailWrapper {
executable = "${super.lib.getBin super.imv}/bin/imv";
profile = "${super.firejail}/etc/firejail/imv.profile";
};
zathura = firejailWrapper {
executable = "${super.lib.getBin super.zathura}/bin/zathura";
profile = "${super.firejail}/etc/firejail/zathura.profile";
};
discord = firejailWrapper {
executable = "${super.lib.getBin super.discord}/bin/discord";
profile = "${super.firejail}/etc/firejail/discord.profile";
};
slack = firejailWrapper {
executable = "${super.lib.getBin super.slack}/bin/slack";
profile = "${super.firejail}/etc/firejail/slack.profile";
};
telegram-desktop = firejailWrapper {
executable = "${super.lib.getBin super.tdesktop}/bin/telegram-desktop";
profile = "${super.firejail}/etc/firejail/telegram-desktop.profile";
};
brave = firejailWrapper {
executable = "${super.lib.getBin super.brave}/bin/brave";
profile = "${super.firejail}/etc/firejail/brave.profile";
};
qutebrowser = firejailWrapper {
executable = "${super.lib.getBin super.qutebrowser}/bin/qutebrowser";
profile = "${super.firejail}/etc/firejail/qutebrowser.profile";
};
thunar = firejailWrapper {
executable = "${super.lib.getBin super.xfce.thunar}/bin/thunar";
profile = "${super.firejail}/etc/firejail/thunar.profile";
};
vscodium = firejailWrapper {
executable = "${super.lib.getBin super.vscodium}/bin/vscodium";
profile = "${super.firejail}/etc/firejail/vscodium.profile";
};
};
})
];
}

View File

@@ -0,0 +1,35 @@
# https://www.reddit.com/r/NixOS/comments/1b56jdx/simple_nix_function_for_wrapping_executables_with/
pkgs: {
name ? "firejail-wrapper",
executable,
desktop ? null,
profile ? null,
extraArgs ? [],
}:
pkgs.runCommand name
{
preferLocalBuild = true;
allowSubstitutes = false;
meta.priority = -1; # take precedence over non-firejailed versions
}
(
let
firejailArgs = pkgs.lib.concatStringsSep " " (
extraArgs ++ (pkgs.lib.optional (profile != null) "--profile=${toString profile}")
);
in
''
command_path="$out/bin/$(basename ${executable})-jailed"
mkdir -p $out/bin
mkdir -p $out/share/applications
cat <<'_EOF' >"$command_path"
#! ${pkgs.runtimeShell} -e
exec /run/wrappers/bin/firejail ${firejailArgs} -- ${toString executable} "\$@"
_EOF
chmod 0755 "$command_path"
''
+ pkgs.lib.optionalString (desktop != null) ''
substitute ${desktop} $out/share/applications/$(basename ${desktop}) \
--replace ${executable} "$command_path"
''
)

View File

@@ -0,0 +1,30 @@
{
pkgs,
nixpak,
...
}: let
callArgs = {
mkNixPak = nixpak.lib.nixpak {
inherit (pkgs) lib;
inherit pkgs;
};
safeBind = sloth: realdir: mapdir: [
(sloth.mkdir (sloth.concat' sloth.appDataDir realdir))
(sloth.concat' sloth.homeDir mapdir)
];
};
wrapper = _pkgs: path: (_pkgs.callPackage path callArgs).config.script;
in {
# Add nixpaked Apps into nixpkgs, and reference them in home-manager or other nixos modules
nixpkgs.overlays = [
(_: super: {
nixpaks = {
qq = wrapper super ./qq.nix;
qq-desktop-item = super.callPackage ./qq-desktop-item.nix {};
firefox = wrapper super ./firefox.nix;
firefox-desktop-item = super.callPackage ./firefox-desktop-item.nix {};
};
})
];
}

View File

@@ -0,0 +1,11 @@
{makeDesktopItem}:
makeDesktopItem {
name = "firefox";
desktopName = "firefox";
exec = "firefox %U";
terminal = false;
icon = "firefox";
type = "Application";
categories = ["Network"];
comment = "firefox boxed";
}

View File

@@ -0,0 +1,75 @@
# Refer:
# - Flatpak manifest's docs:
# - https://docs.flatpak.org/en/latest/manifests.html
# - https://docs.flatpak.org/en/latest/sandbox-permissions.html
# - Firefox's flatpak manifest: https://hg.mozilla.org/mozilla-central/file/tip/taskcluster/docker/firefox-flatpak/runme.sh#l151
{
lib,
pkgs,
mkNixPak,
...
}:
mkNixPak {
config = {
config,
sloth,
...
}: {
app = {
package = pkgs.firefox-wayland;
binPath = "bin/firefox";
};
flatpak.appId = "org.mozilla.firefox";
imports = [
./modules/gui-base.nix
./modules/network.nix
];
# list all dbus services:
# ls -al /run/current-system/sw/share/dbus-1/services/
# ls -al /etc/profiles/per-user/ryan/share/dbus-1/services/
dbus.policies = {
"org.mozilla.firefox.*" = "own"; # firefox
"org.mozilla.firefox_beta.*" = "own"; # firefox beta
"org.mpris.MediaPlayer2.firefox.*" = "own";
"org.freedesktop.NetworkManager" = "talk";
};
bubblewrap = {
bind.rw = [
(sloth.concat' sloth.homeDir "/.mozilla")
(sloth.concat' sloth.homeDir "/Downloads")
# ================ for externsions ===============================
# required by https://github.com/browserpass/browserpass-extension
(sloth.concat' sloth.homeDir "/.local/share/password-store") # pass
];
bind.ro = [
# To actually make Firefox run
"/sys/bus/pci"
["${config.app.package}/lib/firefox" "/app/etc/firefox"]
# Unsure
(sloth.concat' sloth.xdgConfigHome "/dconf")
];
sockets = {
x11 = false;
wayland = true;
pipewire = true;
};
bind.dev = [
"/dev/shm" # Shared Memory
# seems required when using nvidia as primary gpu
"/dev/nvidia0"
"/dev/nvidia-uvm"
"/dev/nvidia-modeset"
];
tmpfs = [
"/tmp"
];
};
};
}

View File

@@ -0,0 +1,84 @@
# https://github.com/nixpak/pkgs/blob/master/pkgs/modules/gui-base.nix
{
config,
lib,
pkgs,
sloth,
...
}: let
envSuffix = envKey: suffix: sloth.concat' (sloth.env envKey) suffix;
# cursor & icon's theme should be the same as the host's one.
cursorTheme = pkgs.bibata-cursors;
iconTheme = pkgs.papirus-icon-theme;
in {
config = {
dbus.policies = {
"${config.flatpak.appId}" = "own";
"org.freedesktop.DBus" = "talk";
"org.gtk.vfs.*" = "talk";
"org.gtk.vfs" = "talk";
"ca.desrt.dconf" = "talk";
"org.freedesktop.portal.*" = "talk";
"org.a11y.Bus" = "talk";
};
# https://github.com/nixpak/nixpak/blob/master/modules/gpu.nix
# 1. bind readonly - /run/opengl-driver
# 2. bind device - /dev/dri
gpu = {
enable = lib.mkDefault true;
provider = "nixos";
bundlePackage = pkgs.mesa.drivers; # for amd & intel
};
# https://github.com/nixpak/nixpak/blob/master/modules/gui/fonts.nix
# it works not well, bind system's /etc/fonts directly instead
fonts.enable = true;
fonts.fonts = config.fonts.packages;
# https://github.com/nixpak/nixpak/blob/master/modules/locale.nix
locale.enable = true;
bubblewrap = {
network = lib.mkDefault false;
bind.rw = [
[
(envSuffix "HOME" "/.var/app/${config.flatpak.appId}/cache")
sloth.xdgCacheHome
]
(sloth.concat' sloth.xdgCacheHome "/fontconfig")
(sloth.concat' sloth.xdgCacheHome "/mesa_shader_cache")
(sloth.concat [
(sloth.env "XDG_RUNTIME_DIR")
"/"
(sloth.envOr "WAYLAND_DISPLAY" "no")
])
(envSuffix "XDG_RUNTIME_DIR" "/at-spi/bus")
(envSuffix "XDG_RUNTIME_DIR" "/gvfsd")
(envSuffix "XDG_RUNTIME_DIR" "/pulse")
"/run/dbus"
];
bind.ro = [
(envSuffix "XDG_RUNTIME_DIR" "/doc")
(sloth.concat' sloth.xdgConfigHome "/gtk-2.0")
(sloth.concat' sloth.xdgConfigHome "/gtk-3.0")
(sloth.concat' sloth.xdgConfigHome "/gtk-4.0")
(sloth.concat' sloth.xdgConfigHome "/fontconfig")
"/etc/fonts" # for fontconfig
"/etc/machine-id"
"/etc/localtime"
];
env = {
XDG_DATA_DIRS = lib.mkForce (lib.makeSearchPath "share" [
iconTheme
cursorTheme
pkgs.shared-mime-info
]);
XCURSOR_PATH = lib.mkForce (lib.concatStringsSep ":" [
"${cursorTheme}/share/icons"
"${cursorTheme}/share/pixmaps"
]);
};
};
};
}

View File

@@ -0,0 +1,8 @@
# https://github.com/nixpak/pkgs/blob/master/pkgs/modules/network.nix
{
etc.sslCertificates.enable = true;
bubblewrap = {
bind.ro = ["/etc/resolv.conf"];
network = true;
};
}

View File

@@ -0,0 +1,15 @@
{
makeDesktopItem,
qq,
}:
makeDesktopItem {
name = "qq";
desktopName = "QQ";
exec = "qq %U";
terminal = false;
# icon = "qq";
icon = "${qq}/share/icons/hicolor/512x512/apps/qq.png";
type = "Application";
categories = ["Network"];
comment = "QQ boxed";
}

59
hardening/nixpaks/qq.nix Normal file
View File

@@ -0,0 +1,59 @@
# Refer:
# - Flatpak manifest's docs:
# - https://docs.flatpak.org/en/latest/manifests.html
# - https://docs.flatpak.org/en/latest/sandbox-permissions.html
# - QQ's flatpak manifest: https://github.com/flathub/com.qq.QQ/blob/master/com.qq.QQ.yaml
{
lib,
pkgs,
mkNixPak,
...
}:
mkNixPak {
config = {sloth, ...}: {
app = {
package = pkgs.qq.override {
# fix fcitx5 input method
commandLineArgs = lib.concatStringsSep " " ["--enable-wayland-ime"];
};
binPath = "bin/qq";
};
flatpak.appId = "com.tencent.qq";
imports = [
./modules/gui-base.nix
./modules/network.nix
];
# list all dbus services:
# ls -al /run/current-system/sw/share/dbus-1/services/
# ls -al /etc/profiles/per-user/ryan/share/dbus-1/services/
dbus.policies = {
"org.gnome.Shell.Screencast" = "talk";
"org.freedesktop.Notifications" = "talk";
"org.kde.StatusNotifierWatcher" = "talk";
};
bubblewrap = {
bind.rw = [
(sloth.concat [sloth.xdgConfigHome "/QQ"])
(sloth.mkdir (sloth.concat [sloth.xdgDownloadDir "/QQ"]))
];
sockets = {
x11 = false;
wayland = true;
pipewire = true;
};
bind.dev = [
"/dev/shm" # Shared Memory
# seems required when using nvidia as primary gpu
"/dev/nvidia0"
"/dev/nvidia-uvm"
"/dev/nvidia-modeset"
];
tmpfs = [
"/tmp"
];
};
};
}

View File

@@ -0,0 +1,9 @@
{modulesPath, ...}: {
imports = [
(modulesPath + "/profiles/hardened.nix")
];
# disable coredump that could be exploited later
# and also slow down the system when something crash
systemd.coredump.enable = false;
}

View File

@@ -4,7 +4,7 @@
...
}: {
home.packages = with pkgs; [
# nix-gaming.packages.${pkgs.system}.osu-lazer-bin
# nix-gaming.packages.${pkgs.system}.osu-laser-bin
gamescope # SteamOS session compositing window manager
prismlauncher # A free, open source launcher for Minecraft
winetricks # A script to install DLLs needed to work around problems in Wine

View File

@@ -12,7 +12,6 @@
# instant messaging
telegram-desktop
discord
pkgs-unstable.qq # https://github.com/NixOS/nixpkgs/tree/master/pkgs/applications/networking/instant-messengers/qq
# remote desktop(rdp connect)
remmina
@@ -21,6 +20,10 @@
# misc
flameshot
ventoy # multi-boot usb creator
# my custom hardened packages
pkgs.nixpaks.qq
pkgs.nixpaks.qq-desktop-item
];
# GitHub CLI tool

View File

@@ -21,6 +21,12 @@
''
+ (builtins.readFile "${nur-ryan4yin.packages.${pkgs.system}.catppuccin-foot}/catppuccin-mocha.conf");
home.packages = [
pkgs.firefox-wayland
# pkgs.nixpaks.firefox
# pkgs.nixpaks.firefox-desktop-item
];
programs = {
# a wayland only terminal emulator
foot = {
@@ -54,12 +60,6 @@
];
};
firefox = {
enable = true;
enableGnomeExtensions = false;
package = pkgs.firefox-wayland; # firefox with wayland support
};
vscode = {
enable = true;
# let vscode sync and update its configuration & extensions across devices, using github account.

View File

@@ -1,7 +1,3 @@
{
mylib,
lib,
...
}: {
{mylib, ...}: {
imports = mylib.scanPaths ./.;
}

View File

@@ -0,0 +1,6 @@
{
nixpkgs.config.permittedInsecurePackages = [
# required by wechat-uos:
# "openssl-1.1.1w"
];
}

View File

@@ -19,6 +19,10 @@
"modules/nixos/desktop.nix"
# host specific
"hosts/idols-${name}"
# nixos hardening
# "hardening/profiles/default.nix"
"hardening/nixpaks"
# "hardening/apparmor"
];
home-modules = map mylib.relativeToRoot [
# common