feat(modules): system services, security, polkit and apparmor
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
620af4f502
commit
1d90e18860
2 changed files with 957 additions and 0 deletions
552
modules/security.nix
Normal file
552
modules/security.nix
Normal file
|
|
@ -0,0 +1,552 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
# Omnixient Security Configuration
|
||||||
|
# Fingerprint, FIDO2, and system hardening features
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (lib)
|
||||||
|
mkIf
|
||||||
|
mkEnableOption
|
||||||
|
mkOption
|
||||||
|
mkMerge
|
||||||
|
mkDefault
|
||||||
|
mkBefore
|
||||||
|
mkAfter
|
||||||
|
types
|
||||||
|
;
|
||||||
|
cfg = config.omni.security;
|
||||||
|
omni = config.omni.lib;
|
||||||
|
|
||||||
|
# Hardware detection helpers
|
||||||
|
hasFingerprintReader = ''
|
||||||
|
${pkgs.usbutils}/bin/lsusb | grep -i -E "(fingerprint|synaptics|goodix|elan|validity)" > /dev/null
|
||||||
|
'';
|
||||||
|
|
||||||
|
hasFido2Device = ''
|
||||||
|
${pkgs.libfido2}/bin/fido2-token -L 2>/dev/null | grep -q "dev:"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Security management scripts
|
||||||
|
securityScripts = [
|
||||||
|
# Fingerprint management
|
||||||
|
(omni.makeScript "omni-fingerprint" "Manage fingerprint authentication" ''
|
||||||
|
case "$1" in
|
||||||
|
"setup"|"enroll")
|
||||||
|
echo "🔐 Omnixient Fingerprint Setup"
|
||||||
|
echo "═══════════════════════════"
|
||||||
|
|
||||||
|
# Check for fingerprint hardware
|
||||||
|
if ! (${hasFingerprintReader}); then
|
||||||
|
echo "❌ No fingerprint reader detected!"
|
||||||
|
echo " Supported devices: Synaptics, Goodix, Elan, Validity sensors"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ Fingerprint reader detected"
|
||||||
|
|
||||||
|
# Check if fprintd service is running
|
||||||
|
if ! systemctl is-active fprintd >/dev/null 2>&1; then
|
||||||
|
echo "🔄 Starting fingerprint service..."
|
||||||
|
sudo systemctl start fprintd
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "👆 Please follow the prompts to enroll your fingerprint"
|
||||||
|
echo " You'll need to scan your finger multiple times"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Enroll fingerprint
|
||||||
|
${pkgs.fprintd}/bin/fprintd-enroll "$USER"
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "✅ Fingerprint enrolled successfully!"
|
||||||
|
echo "💡 You can now use your fingerprint for:"
|
||||||
|
echo " - sudo commands"
|
||||||
|
echo " - System authentication dialogs"
|
||||||
|
echo " - Screen unlock (if supported)"
|
||||||
|
else
|
||||||
|
echo "❌ Fingerprint enrollment failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"test"|"verify")
|
||||||
|
echo "🔐 Testing fingerprint authentication..."
|
||||||
|
|
||||||
|
if ! (${hasFingerprintReader}); then
|
||||||
|
echo "❌ No fingerprint reader detected!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "👆 Please scan your enrolled finger"
|
||||||
|
${pkgs.fprintd}/bin/fprintd-verify "$USER"
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "✅ Fingerprint verification successful!"
|
||||||
|
else
|
||||||
|
echo "❌ Fingerprint verification failed"
|
||||||
|
echo "💡 Try: omni-fingerprint setup"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"remove"|"delete")
|
||||||
|
echo "🗑️ Removing fingerprint data..."
|
||||||
|
${pkgs.fprintd}/bin/fprintd-delete "$USER"
|
||||||
|
echo "✅ Fingerprint data removed"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"list")
|
||||||
|
echo "📋 Enrolled fingerprints:"
|
||||||
|
${pkgs.fprintd}/bin/fprintd-list "$USER" 2>/dev/null || echo " No fingerprints enrolled"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "🔐 Omnixient Fingerprint Management"
|
||||||
|
echo
|
||||||
|
echo "Usage: omni-fingerprint <command>"
|
||||||
|
echo
|
||||||
|
echo "Commands:"
|
||||||
|
echo " setup, enroll - Enroll a new fingerprint"
|
||||||
|
echo " test, verify - Test fingerprint authentication"
|
||||||
|
echo " remove, delete - Remove enrolled fingerprints"
|
||||||
|
echo " list - List enrolled fingerprints"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Show hardware status
|
||||||
|
if (${hasFingerprintReader}); then
|
||||||
|
echo "Hardware: ✅ Fingerprint reader detected"
|
||||||
|
else
|
||||||
|
echo "Hardware: ❌ No fingerprint reader found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show service status
|
||||||
|
if systemctl is-active fprintd >/dev/null 2>&1; then
|
||||||
|
echo "Service: ✅ fprintd running"
|
||||||
|
else
|
||||||
|
echo "Service: ❌ fprintd not running"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'')
|
||||||
|
|
||||||
|
# FIDO2 management
|
||||||
|
(omni.makeScript "omni-fido2" "Manage FIDO2/WebAuthn authentication" ''
|
||||||
|
case "$1" in
|
||||||
|
"setup"|"register")
|
||||||
|
echo "🔑 Omnixient FIDO2 Setup"
|
||||||
|
echo "═══════════════════"
|
||||||
|
|
||||||
|
# Check for FIDO2 hardware
|
||||||
|
if ! (${hasFido2Device}); then
|
||||||
|
echo "❌ No FIDO2 device detected!"
|
||||||
|
echo " Please insert a FIDO2 security key (YubiKey, etc.)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✅ FIDO2 device detected:"
|
||||||
|
${pkgs.libfido2}/bin/fido2-token -L
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Register device
|
||||||
|
echo "🔑 Please touch your security key when prompted..."
|
||||||
|
output=$(${pkgs.pam_u2f}/bin/pamu2fcfg -u "$USER")
|
||||||
|
|
||||||
|
if [ $? -eq 0 ] && [ -n "$output" ]; then
|
||||||
|
# Save to system configuration
|
||||||
|
echo "$output" | sudo tee -a /etc/fido2/fido2 >/dev/null
|
||||||
|
|
||||||
|
echo "✅ FIDO2 device registered successfully!"
|
||||||
|
echo "💡 You can now use your security key for:"
|
||||||
|
echo " - sudo commands"
|
||||||
|
echo " - System authentication dialogs"
|
||||||
|
echo " - Screen unlock"
|
||||||
|
else
|
||||||
|
echo "❌ FIDO2 device registration failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"test")
|
||||||
|
echo "🔑 Testing FIDO2 authentication..."
|
||||||
|
|
||||||
|
if [ ! -s /etc/fido2/fido2 ]; then
|
||||||
|
echo "❌ No FIDO2 devices registered"
|
||||||
|
echo "💡 Try: omni-fido2 setup"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🔑 Please touch your security key..."
|
||||||
|
# Test by trying to authenticate with PAM
|
||||||
|
echo "Authentication test complete"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"list")
|
||||||
|
echo "📋 Registered FIDO2 devices:"
|
||||||
|
if [ -f /etc/fido2/fido2 ]; then
|
||||||
|
cat /etc/fido2/fido2 | while read -r line; do
|
||||||
|
if [ -n "$line" ]; then
|
||||||
|
echo " Device: ''${line%%:*}"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
else
|
||||||
|
echo " No devices registered"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"remove")
|
||||||
|
echo "🗑️ Removing FIDO2 configuration..."
|
||||||
|
sudo rm -f /etc/fido2/fido2
|
||||||
|
sudo touch /etc/fido2/fido2
|
||||||
|
echo "✅ All FIDO2 devices removed"
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "🔑 Omnixient FIDO2 Management"
|
||||||
|
echo
|
||||||
|
echo "Usage: omni-fido2 <command>"
|
||||||
|
echo
|
||||||
|
echo "Commands:"
|
||||||
|
echo " setup, register - Register a new FIDO2 device"
|
||||||
|
echo " test - Test FIDO2 authentication"
|
||||||
|
echo " list - List registered devices"
|
||||||
|
echo " remove - Remove all registered devices"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Show hardware status
|
||||||
|
if (${hasFido2Device}); then
|
||||||
|
echo "Hardware: ✅ FIDO2 device detected"
|
||||||
|
else
|
||||||
|
echo "Hardware: ❌ No FIDO2 device found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show configuration status
|
||||||
|
if [ -s /etc/fido2/fido2 ]; then
|
||||||
|
echo "Config: ✅ Devices registered"
|
||||||
|
else
|
||||||
|
echo "Config: ❌ No devices registered"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'')
|
||||||
|
|
||||||
|
# Security status and management
|
||||||
|
(omni.makeScript "omni-security" "Security status and management" ''
|
||||||
|
case "$1" in
|
||||||
|
"status")
|
||||||
|
echo "🔒 Omnixient Security Status"
|
||||||
|
echo "═══════════════════════"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Hardware detection
|
||||||
|
echo "🔧 Hardware:"
|
||||||
|
if (${hasFingerprintReader}); then
|
||||||
|
echo " ✅ Fingerprint reader detected"
|
||||||
|
else
|
||||||
|
echo " ❌ No fingerprint reader"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if (${hasFido2Device}); then
|
||||||
|
echo " ✅ FIDO2 device detected"
|
||||||
|
else
|
||||||
|
echo " ❌ No FIDO2 device"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Services
|
||||||
|
echo "🛡️ Services:"
|
||||||
|
printf " fprintd: "
|
||||||
|
if systemctl is-active fprintd >/dev/null 2>&1; then
|
||||||
|
echo "✅ running"
|
||||||
|
else
|
||||||
|
echo "❌ stopped"
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf " firewall: "
|
||||||
|
if systemctl is-active ufw >/dev/null 2>&1; then
|
||||||
|
echo "✅ active"
|
||||||
|
else
|
||||||
|
echo "❌ inactive"
|
||||||
|
fi
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
echo "⚙️ Configuration:"
|
||||||
|
if [ -s /etc/fido2/fido2 ]; then
|
||||||
|
device_count=$(wc -l < /etc/fido2/fido2)
|
||||||
|
echo " FIDO2: ✅ $device_count device(s) registered"
|
||||||
|
else
|
||||||
|
echo " FIDO2: ❌ no devices registered"
|
||||||
|
fi
|
||||||
|
|
||||||
|
fingerprint_count=$(${pkgs.fprintd}/bin/fprintd-list "$USER" 2>/dev/null | wc -l || echo "0")
|
||||||
|
if [ "$fingerprint_count" -gt 0 ]; then
|
||||||
|
echo " Fingerprint: ✅ enrolled"
|
||||||
|
else
|
||||||
|
echo " Fingerprint: ❌ not enrolled"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
|
"reset-lockout")
|
||||||
|
echo "🔓 Resetting account lockout..."
|
||||||
|
sudo ${pkgs.util-linux}/bin/faillock --user "$USER" --reset
|
||||||
|
echo "✅ Account lockout reset"
|
||||||
|
;;
|
||||||
|
|
||||||
|
"firewall")
|
||||||
|
echo "🛡️ Firewall status:"
|
||||||
|
sudo ufw status verbose
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "🔒 Omnixient Security Management"
|
||||||
|
echo
|
||||||
|
echo "Usage: omni-security <command>"
|
||||||
|
echo
|
||||||
|
echo "Commands:"
|
||||||
|
echo " status - Show security status"
|
||||||
|
echo " reset-lockout - Reset failed login attempts"
|
||||||
|
echo " firewall - Show firewall status"
|
||||||
|
echo
|
||||||
|
echo "Related commands:"
|
||||||
|
echo " omni-fingerprint - Manage fingerprint authentication"
|
||||||
|
echo " omni-fido2 - Manage FIDO2 authentication"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
'')
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.omni.security = {
|
||||||
|
enable = mkEnableOption "Omnixient security features";
|
||||||
|
|
||||||
|
fingerprint = {
|
||||||
|
enable = mkEnableOption "fingerprint authentication";
|
||||||
|
autoDetect = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Automatically detect and enable fingerprint readers";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fido2 = {
|
||||||
|
enable = mkEnableOption "FIDO2/WebAuthn authentication";
|
||||||
|
autoDetect = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Automatically detect and enable FIDO2 devices";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemHardening = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable system security hardening";
|
||||||
|
};
|
||||||
|
|
||||||
|
faillock = {
|
||||||
|
enable = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = "Enable account lockout protection";
|
||||||
|
};
|
||||||
|
denyAttempts = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 10;
|
||||||
|
description = "Number of failed attempts before lockout";
|
||||||
|
};
|
||||||
|
unlockTime = mkOption {
|
||||||
|
type = types.int;
|
||||||
|
default = 120;
|
||||||
|
description = "Lockout duration in seconds";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf (cfg.enable or true) {
|
||||||
|
# Security packages and management scripts (consolidated)
|
||||||
|
environment.systemPackages =
|
||||||
|
(with pkgs; [
|
||||||
|
# Fingerprint authentication
|
||||||
|
fprintd
|
||||||
|
|
||||||
|
# FIDO2/WebAuthn
|
||||||
|
libfido2
|
||||||
|
pam_u2f
|
||||||
|
|
||||||
|
# Security utilities
|
||||||
|
usbutils
|
||||||
|
pciutils
|
||||||
|
])
|
||||||
|
++ [
|
||||||
|
# Security management scripts defined below
|
||||||
|
]
|
||||||
|
++ securityScripts;
|
||||||
|
|
||||||
|
# Fingerprint authentication configuration
|
||||||
|
services.fprintd = mkIf (cfg.fingerprint.enable or cfg.fingerprint.autoDetect) {
|
||||||
|
enable = true;
|
||||||
|
package = pkgs.fprintd;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Security configuration (consolidated)
|
||||||
|
security = {
|
||||||
|
# Sudo security configuration
|
||||||
|
sudo = mkMerge [
|
||||||
|
(mkIf cfg.systemHardening.enable {
|
||||||
|
enable = true;
|
||||||
|
wheelNeedsPassword = true;
|
||||||
|
execWheelOnly = true;
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# Polkit security configuration
|
||||||
|
polkit = mkIf cfg.systemHardening.enable {
|
||||||
|
enable = true;
|
||||||
|
extraConfig = ''
|
||||||
|
polkit.addRule(function(action, subject) {
|
||||||
|
if (subject.isInGroup("wheel") &&
|
||||||
|
(action.id == "org.freedesktop.systemd1.manage-units" ||
|
||||||
|
action.id == "org.freedesktop.NetworkManager.settings.modify.system")) {
|
||||||
|
return polkit.Result.YES;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# PAM configuration for authentication methods
|
||||||
|
pam = {
|
||||||
|
# Login limits for account lockout protection
|
||||||
|
loginLimits = mkIf cfg.systemHardening.faillock.enable [
|
||||||
|
{
|
||||||
|
domain = "*";
|
||||||
|
type = "hard";
|
||||||
|
item = "core";
|
||||||
|
value = "0";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
# PAM services configuration
|
||||||
|
services = {
|
||||||
|
# Sudo configuration
|
||||||
|
sudo = mkMerge [
|
||||||
|
(mkIf (cfg.fingerprint.enable or cfg.fingerprint.autoDetect) {
|
||||||
|
fprintAuth = true;
|
||||||
|
})
|
||||||
|
(mkIf cfg.fido2.enable {
|
||||||
|
text = mkBefore ''
|
||||||
|
auth sufficient pam_u2f.so cue authfile=/etc/fido2/fido2
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# Polkit configuration
|
||||||
|
polkit-1 = mkMerge [
|
||||||
|
(mkIf (cfg.fingerprint.enable or cfg.fingerprint.autoDetect) {
|
||||||
|
fprintAuth = true;
|
||||||
|
text = ''
|
||||||
|
auth sufficient pam_fprintd.so
|
||||||
|
auth include system-auth
|
||||||
|
account include system-auth
|
||||||
|
password include system-auth
|
||||||
|
session include system-auth
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
(mkIf cfg.fido2.enable {
|
||||||
|
text = mkBefore ''
|
||||||
|
auth sufficient pam_u2f.so cue authfile=/etc/fido2/fido2
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
# Login configuration
|
||||||
|
login = mkIf (cfg.fingerprint.enable or cfg.fingerprint.autoDetect) {
|
||||||
|
fprintAuth = mkDefault true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Screen lock configuration
|
||||||
|
hyprlock = mkIf (config.omni.desktop.enable or false) (mkMerge [
|
||||||
|
(mkIf (cfg.fingerprint.enable or cfg.fingerprint.autoDetect) {
|
||||||
|
fprintAuth = true;
|
||||||
|
text = ''
|
||||||
|
auth sufficient pam_fprintd.so
|
||||||
|
auth include system-auth
|
||||||
|
account include system-auth
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
(mkIf cfg.fido2.enable {
|
||||||
|
text = mkBefore ''
|
||||||
|
auth sufficient pam_u2f.so cue authfile=/etc/fido2/fido2
|
||||||
|
'';
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
# Faillock configuration for system-auth
|
||||||
|
system-auth = mkIf cfg.systemHardening.faillock.enable {
|
||||||
|
text = mkAfter ''
|
||||||
|
auth required pam_faillock.so preauth
|
||||||
|
auth required pam_faillock.so authfail deny=${toString cfg.systemHardening.faillock.denyAttempts} unlock_time=${toString cfg.systemHardening.faillock.unlockTime}
|
||||||
|
account required pam_faillock.so
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Firewall configuration
|
||||||
|
networking.firewall = mkIf cfg.systemHardening.enable {
|
||||||
|
enable = true;
|
||||||
|
|
||||||
|
# Essential services (NixOS firewall denies by default)
|
||||||
|
allowedTCPPorts = [ 22 ]; # SSH
|
||||||
|
allowedUDPPorts = [ 53317 ]; # LocalSend
|
||||||
|
allowedTCPPortRanges = [
|
||||||
|
{
|
||||||
|
from = 53317;
|
||||||
|
to = 53317;
|
||||||
|
} # LocalSend TCP
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Create FIDO2 configuration directory
|
||||||
|
system.activationScripts.fido2Setup = mkIf cfg.fido2.enable ''
|
||||||
|
mkdir -p /etc/fido2
|
||||||
|
chmod 755 /etc/fido2
|
||||||
|
|
||||||
|
# Create empty fido2 config file if it doesn't exist
|
||||||
|
if [ ! -f /etc/fido2/fido2 ]; then
|
||||||
|
touch /etc/fido2/fido2
|
||||||
|
chmod 644 /etc/fido2/fido2
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Security management scripts are now defined in the let block above
|
||||||
|
|
||||||
|
# Add to main menu integration
|
||||||
|
home-manager.users.${config.omni.user} = {
|
||||||
|
programs.bash.shellAliases = {
|
||||||
|
fingerprint = "omni-fingerprint";
|
||||||
|
fido2 = "omni-fido2";
|
||||||
|
security = "omni-security";
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.zsh.shellAliases = {
|
||||||
|
fingerprint = "omni-fingerprint";
|
||||||
|
fido2 = "omni-fido2";
|
||||||
|
security = "omni-security";
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.fish.shellAliases = {
|
||||||
|
fingerprint = "omni-fingerprint";
|
||||||
|
fido2 = "omni-fido2";
|
||||||
|
security = "omni-security";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
405
modules/services.nix
Normal file
405
modules/services.nix
Normal file
|
|
@ -0,0 +1,405 @@
|
||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.omni;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# XDG portal config is in modules/desktop/hyprland.nix
|
||||||
|
|
||||||
|
# Tuigreet display manager
|
||||||
|
# Write HM's generated Hyprland config to /etc so it's available before HM activation
|
||||||
|
environment.etc."hypr/hyprland.conf" = lib.mkIf (config.programs.hyprland.enable or false) {
|
||||||
|
source = config.home-manager.users.${cfg.user}.xdg.configFile."hypr/hyprland.conf".source;
|
||||||
|
};
|
||||||
|
|
||||||
|
services.greetd = {
|
||||||
|
enable = true;
|
||||||
|
settings.default_session.command =
|
||||||
|
let
|
||||||
|
hyprland-session = pkgs.writeShellScript "hyprland-session" ''
|
||||||
|
export HOME="''${HOME:-/home/$(whoami)}"
|
||||||
|
mkdir -p "$HOME/.config/hypr"
|
||||||
|
cp -f /etc/hypr/hyprland.conf "$HOME/.config/hypr/hyprland.conf" 2>/dev/null || true
|
||||||
|
exec start-hyprland
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
"${pkgs.tuigreet}/bin/tuigreet --time --cmd ${hyprland-session}";
|
||||||
|
};
|
||||||
|
|
||||||
|
# System services configuration
|
||||||
|
services = {
|
||||||
|
# Display server
|
||||||
|
xserver = {
|
||||||
|
enable = true;
|
||||||
|
excludePackages = [ pkgs.xterm ];
|
||||||
|
|
||||||
|
xkb = {
|
||||||
|
layout = "us";
|
||||||
|
variant = "";
|
||||||
|
options = "caps:escape,compose:ralt";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Display Manager (disabled - using greetd instead)
|
||||||
|
displayManager.gdm.enable = false;
|
||||||
|
|
||||||
|
# Touchpad support
|
||||||
|
libinput = {
|
||||||
|
enable = true;
|
||||||
|
touchpad = {
|
||||||
|
naturalScrolling = true;
|
||||||
|
tapping = true;
|
||||||
|
clickMethod = "clickfinger";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Printing support
|
||||||
|
printing = {
|
||||||
|
enable = true;
|
||||||
|
drivers = with pkgs; [
|
||||||
|
gutenprint
|
||||||
|
gutenprintBin
|
||||||
|
hplip
|
||||||
|
epson-escpr
|
||||||
|
epson-escpr2
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Sound — disable PulseAudio in favor of PipeWire
|
||||||
|
pulseaudio.enable = false;
|
||||||
|
pipewire = {
|
||||||
|
enable = true;
|
||||||
|
alsa = {
|
||||||
|
enable = true;
|
||||||
|
support32Bit = true;
|
||||||
|
};
|
||||||
|
pulse.enable = true;
|
||||||
|
jack.enable = true;
|
||||||
|
wireplumber = {
|
||||||
|
enable = true;
|
||||||
|
# Workaround: libldac-dec decoder init crashes (LDACBT_ERR_FATAL) on
|
||||||
|
# PipeWire 1.6.2, causing silent audio failure with no fallback.
|
||||||
|
# Remove once nixpkgs#502690 lands in our channel.
|
||||||
|
extraConfig."bluetooth" = {
|
||||||
|
"monitor.bluez.properties" = {
|
||||||
|
"bluez5.codecs" = [
|
||||||
|
"sbc"
|
||||||
|
"sbc_xq"
|
||||||
|
"aac"
|
||||||
|
"aptx"
|
||||||
|
"aptx_hd"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Network
|
||||||
|
resolved = {
|
||||||
|
enable = true;
|
||||||
|
settings.Resolve = {
|
||||||
|
DNSSEC = "true";
|
||||||
|
Domains = [ "~." ];
|
||||||
|
FallbackDNS = [
|
||||||
|
"1.1.1.1"
|
||||||
|
"8.8.8.8"
|
||||||
|
"1.0.0.1"
|
||||||
|
"8.8.4.4"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Bluetooth
|
||||||
|
blueman.enable = true;
|
||||||
|
|
||||||
|
# Power management
|
||||||
|
power-profiles-daemon.enable = true;
|
||||||
|
thermald.enable = true;
|
||||||
|
upower = {
|
||||||
|
enable = true;
|
||||||
|
percentageLow = 15;
|
||||||
|
percentageCritical = 5;
|
||||||
|
percentageAction = 3;
|
||||||
|
};
|
||||||
|
|
||||||
|
# System monitoring
|
||||||
|
smartd = {
|
||||||
|
enable = true;
|
||||||
|
autodetect = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# File indexing and search
|
||||||
|
locate = {
|
||||||
|
enable = true;
|
||||||
|
interval = "daily";
|
||||||
|
package = pkgs.plocate;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Backup service (optional)
|
||||||
|
restic = {
|
||||||
|
backups = {
|
||||||
|
# Example backup configuration
|
||||||
|
# home = {
|
||||||
|
# paths = [ "/home/${cfg.user}" ];
|
||||||
|
# repository = "/backup/restic";
|
||||||
|
# passwordFile = "/etc/restic/password";
|
||||||
|
# timerConfig = {
|
||||||
|
# OnCalendar = "daily";
|
||||||
|
# Persistent = true;
|
||||||
|
# };
|
||||||
|
# pruneOpts = [
|
||||||
|
# "--keep-daily 7"
|
||||||
|
# "--keep-weekly 4"
|
||||||
|
# "--keep-monthly 12"
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# SSH daemon
|
||||||
|
openssh = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
PermitRootLogin = "no";
|
||||||
|
PasswordAuthentication = false;
|
||||||
|
KbdInteractiveAuthentication = false;
|
||||||
|
X11Forwarding = false;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Firewall
|
||||||
|
fail2ban = {
|
||||||
|
enable = true;
|
||||||
|
maxretry = 3;
|
||||||
|
bantime = "1h";
|
||||||
|
bantime-increment.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# System maintenance
|
||||||
|
fstrim = {
|
||||||
|
enable = true;
|
||||||
|
interval = "weekly";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Scheduled tasks
|
||||||
|
cron = {
|
||||||
|
enable = true;
|
||||||
|
systemCronJobs = [
|
||||||
|
# Example: Update system database daily
|
||||||
|
# "0 3 * * * root ${pkgs.nix-index}/bin/nix-index"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Syncthing for file synchronization
|
||||||
|
syncthing = {
|
||||||
|
enable = false; # Set to true to enable
|
||||||
|
user = cfg.user;
|
||||||
|
dataDir = "/home/${cfg.user}/Documents";
|
||||||
|
configDir = "/home/${cfg.user}/.config/syncthing";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Tailscale VPN
|
||||||
|
tailscale = {
|
||||||
|
enable = false; # Set to true to enable
|
||||||
|
useRoutingFeatures = "client";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Flatpak support
|
||||||
|
flatpak.enable = config.xdg.portal.enable;
|
||||||
|
|
||||||
|
# GVFS for mounting and trash support
|
||||||
|
gvfs.enable = true;
|
||||||
|
|
||||||
|
# Thumbnail generation
|
||||||
|
tumbler.enable = true;
|
||||||
|
|
||||||
|
# Notification daemon is handled by mako in Hyprland config
|
||||||
|
|
||||||
|
# System daemons
|
||||||
|
dbus = {
|
||||||
|
enable = true;
|
||||||
|
packages = with pkgs; [ dconf ];
|
||||||
|
};
|
||||||
|
|
||||||
|
# Secret storage for Electron apps (Signal, Ferdium, etc.)
|
||||||
|
gnome.gnome-keyring.enable = true;
|
||||||
|
|
||||||
|
# Avahi for network discovery
|
||||||
|
avahi = {
|
||||||
|
enable = true;
|
||||||
|
nssmdns4 = true;
|
||||||
|
publish = {
|
||||||
|
enable = true;
|
||||||
|
addresses = true;
|
||||||
|
domain = true;
|
||||||
|
workstation = true;
|
||||||
|
userServices = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# ACPI daemon for power management
|
||||||
|
acpid.enable = true;
|
||||||
|
|
||||||
|
# Firmware updates via LVFS
|
||||||
|
fwupd.enable = true;
|
||||||
|
|
||||||
|
# Automatic upgrades (disabled by default)
|
||||||
|
# system.autoUpgrade = {
|
||||||
|
# enable = true;
|
||||||
|
# allowReboot = false;
|
||||||
|
# dates = "04:00";
|
||||||
|
# flake = "/etc/nixos#omni";
|
||||||
|
# };
|
||||||
|
|
||||||
|
# Earlyoom - out of memory killer
|
||||||
|
earlyoom = {
|
||||||
|
enable = true;
|
||||||
|
freeMemThreshold = 5;
|
||||||
|
freeSwapThreshold = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Logrotate
|
||||||
|
logrotate = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
"/var/log/omni/*.log" = {
|
||||||
|
frequency = "weekly";
|
||||||
|
rotate = 4;
|
||||||
|
compress = true;
|
||||||
|
delaycompress = true;
|
||||||
|
notifempty = true;
|
||||||
|
create = "644 root root";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Systemd services
|
||||||
|
systemd = {
|
||||||
|
# User session environment.
|
||||||
|
# systemd.user.extraConfig was removed upstream; the [Manager] section is
|
||||||
|
# now expressed via the structured systemd.user.settings.Manager attrset.
|
||||||
|
user.settings.Manager.DefaultEnvironment = ''"PATH=/run/wrappers/bin:/home/${cfg.user}/.nix-profile/bin:/etc/profiles/per-user/${cfg.user}/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin"'';
|
||||||
|
|
||||||
|
# Automatic cleanup
|
||||||
|
timers.clear-tmp = {
|
||||||
|
description = "Clear /tmp weekly";
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
timerConfig = {
|
||||||
|
OnCalendar = "weekly";
|
||||||
|
Persistent = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.clear-tmp = {
|
||||||
|
description = "Clear /tmp directory";
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
ExecStart = "${pkgs.coreutils}/bin/find /tmp -type f -atime +7 -delete";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Custom Omarchy services
|
||||||
|
services.omni-init = {
|
||||||
|
description = "Omarchy initialization service";
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [ "network.target" ];
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "oneshot";
|
||||||
|
RemainAfterExit = true;
|
||||||
|
ExecStart = pkgs.writeShellScript "omni-init" ''
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
echo "Initializing Omarchy..."
|
||||||
|
|
||||||
|
# Create necessary directories
|
||||||
|
mkdir -p /var/log/omni
|
||||||
|
mkdir -p /var/lib/omni
|
||||||
|
mkdir -p /etc/omni
|
||||||
|
|
||||||
|
# Set up initial configuration
|
||||||
|
if [ ! -f /etc/omni/initialized ]; then
|
||||||
|
echo "$(date): Omnixient initialized" > /etc/omni/initialized
|
||||||
|
echo "Welcome to Omarchy!" > /etc/motd
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Unlock gnome-keyring on login
|
||||||
|
security.pam.services.greetd.enableGnomeKeyring = true;
|
||||||
|
|
||||||
|
# Signal Messenger uses its own self-signed root CA for certificate pinning.
|
||||||
|
# Add it to the system trust store so Electron/curl can connect.
|
||||||
|
security.pki.certificates = [
|
||||||
|
''
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
9qfgAJizyy3kqM4lOwBH
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
''
|
||||||
|
];
|
||||||
|
|
||||||
|
# Security policies
|
||||||
|
security = {
|
||||||
|
# Required for PipeWire real-time scheduling
|
||||||
|
rtkit.enable = true;
|
||||||
|
|
||||||
|
polkit = {
|
||||||
|
enable = true;
|
||||||
|
extraConfig = ''
|
||||||
|
/* Allow members of wheel group to manage systemd services without password */
|
||||||
|
polkit.addRule(function(action, subject) {
|
||||||
|
if (action.id == "org.freedesktop.systemd1.manage-units" &&
|
||||||
|
subject.isInGroup("wheel")) {
|
||||||
|
return polkit.Result.YES;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
# AppArmor
|
||||||
|
apparmor = {
|
||||||
|
enable = true;
|
||||||
|
packages = with pkgs; [
|
||||||
|
apparmor-utils
|
||||||
|
apparmor-profiles
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue