diff --git a/desktop/l/below.nix b/desktop/l/below.nix new file mode 100644 index 0000000..36da9cc --- /dev/null +++ b/desktop/l/below.nix @@ -0,0 +1,25 @@ +# +# below.nix +# +# systemctl status below +# +{ config, pkgs, ... }: +{ + # https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/monitoring/below.nix + services.below = { + enable = true; + + # Enable all collection options + collect = { + diskStats = true; # Enable disk_stat collection (default: true) + ioStats = true; # Enable io.stat collection for cgroups + exitStats = true; # Enable eBPF-based exitstats (default: true) + }; + + # Enable data compression to save storage space + compression.enable = true; + + # Retain data for 7 days (604800 seconds = 7 * 24 * 3600) + retention.time = 604800; + }; +} \ No newline at end of file diff --git a/desktop/l/configuration.nix b/desktop/l/configuration.nix index d3f4617..c386483 100644 --- a/desktop/l/configuration.nix +++ b/desktop/l/configuration.nix @@ -49,6 +49,7 @@ ./nginx.nix ./ollama-service.nix ./fan2go.nix + ./below.nix ]; boot = { @@ -188,12 +189,22 @@ }; services.openssh.enable = true; - programs.ssh.extraConfig = '' - Host hp4.home - PubkeyAcceptedKeyTypes ssh-ed25519 - ServerAliveInterval 60 - IPQoS throughput - ''; + # programs.ssh.extraConfig = '' + # Host hp4.home + # PubkeyAcceptedKeyTypes ssh-ed25519 + # ServerAliveInterval 60 + # #IPQoS throughput + + # # Optimizations for nfbQotom SSH sessions + # # Reduce GPU rendering load in terminals with these settings + # Host nfbQotom 172.16.40.184 172.16.40.185 + # ControlMaster auto + # ControlPath ~/.ssh/master-%r@%h:%p + # ControlPersist 10m + # ServerAliveInterval 30 + # ServerAliveCountMax 3 + # Compression no + # ''; services.lldpd.enable = true; services.timesyncd.enable = true; diff --git a/desktop/l/flake.lock b/desktop/l/flake.lock index 0ea27f1..dc447ec 100644 --- a/desktop/l/flake.lock +++ b/desktop/l/flake.lock @@ -7,11 +7,11 @@ ] }, "locked": { - "lastModified": 1761750844, - "narHash": "sha256-ab6kNHAEP/oWz8qdblnDw7TIwetr4GnmnDyvya0aw/k=", + "lastModified": 1762223116, + "narHash": "sha256-glW1JJ/REWUcEIAKg62sKUQRlFBY00QNnBCQHh4XNOA=", "owner": "nix-community", "repo": "home-manager", - "rev": "b8082c6803353456d45e6a8c0d4b36ad33fb7d6a", + "rev": "1342b821db15b6c79731310ba787d152cd60e74b", "type": "github" }, "original": { @@ -22,11 +22,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1761373498, - "narHash": "sha256-Q/uhWNvd7V7k1H1ZPMy/vkx3F8C13ZcdrKjO7Jv7v0c=", + "lastModified": 1762111121, + "narHash": "sha256-4vhDuZ7OZaZmKKrnDpxLZZpGIJvAeMtK6FKLJYUtAdw=", "owner": "nixos", "repo": "nixpkgs", - "rev": "6a08e6bb4e46ff7fcbb53d409b253f6bad8a28ce", + "rev": "b3d51a0365f6695e7dd5cdf3e180604530ed33b4", "type": "github" }, "original": { diff --git a/desktop/l/grafana.nix b/desktop/l/grafana.nix index 471b71d..3f4c88d 100644 --- a/desktop/l/grafana.nix +++ b/desktop/l/grafana.nix @@ -7,9 +7,11 @@ services.grafana = { enable = true; settings = { + security.admin_password = "admin"; # this is my local only instance + users.password_hint = "admin"; server = { # Listening Address - http_addr = "0.0.0.0"; + http_addr = "127.0.0.1"; # and Port http_port = 3000; # Grafana needs to know on which domain and URL it's running diff --git a/desktop/l/home.nix b/desktop/l/home.nix index 5223710..0d96962 100644 --- a/desktop/l/home.nix +++ b/desktop/l/home.nix @@ -15,15 +15,17 @@ # https://ghostty.zerebos.com/app/import-export # no scorllback limit # https://github.com/ghostty-org/ghostty/issues/111 - xdg.configFile."ghostty/config.toml".text = '' - term = xterm-256color - scrollback-limit = 10000001 - image-storage-limit = 320000001 - clipboard-write = allow - window-subtitle = working-directory - background-opacity = 0.91 - background-blur = 20 - ''; + # xdg.configFile."ghostty/config.toml".text = '' + # term = xterm-256color + # scrollback-limit = 10000001 + # image-storage-limit = 320000001 + # clipboard-write = allow + # window-subtitle = working-directory + # background-opacity = 0.91 + # # Reduced blur from 20 to 5 for better SSH/remote terminal performance + # # GPU-accelerated blur can cause lag with rapid terminal output over SSH + # background-blur = 5 + # ''; home = { username = "das"; @@ -460,10 +462,10 @@ (flameshot.override { enableWlrSupport = true; }) # Custom onnxruntime package with ROCm support - onnxruntime + # onnxruntime # Standard Python onnxruntime module (should work with custom C++ library) - python313Packages.onnxruntime + # python313Packages.onnxruntime ]; # vscode @@ -500,7 +502,7 @@ jnoortheen.nix-ide rust-lang.rust-analyzer bazelbuild.vscode-bazel - continue.continue + #continue.continue # stopped working 2025/11/04 rooveterinaryinc.roo-cline waderyan.gitblame ]; diff --git a/desktop/l/nodeExporter.nix b/desktop/l/nodeExporter.nix index f26d49b..fa75582 100644 --- a/desktop/l/nodeExporter.nix +++ b/desktop/l/nodeExporter.nix @@ -10,7 +10,7 @@ enable = true; port = 19000; # https://github.com/NixOS/nixpkgs/blob/nixos-24.05/nixos/modules/services/monitoring/prometheus/exporters.nix - enabledCollectors = [ "systemd" ]; + enabledCollectors = [ "pressure" "diskstats" "filesystem" "meminfo" "vmstat" ]; # /nix/store/zgsw0yx18v10xa58psanfabmg95nl2bb-node_exporter-1.8.1/bin/node_exporter --help extraFlags = [ "--collector.ethtool" @@ -21,7 +21,9 @@ }; # https://search.nixos.org/options?channel=24.05&from=200&size=50&sort=relevance&type=packages&query=services.prometheus.exporters - services.prometheus.exporters.systemd.enable = true; - services.prometheus.exporters.smartctl.enable = true; - services.prometheus.exporters.process.enable = true; + services.prometheus.exporters = { + systemd.enable = true; + smartctl.enable = true; + process.enable = true; + }; } \ No newline at end of file diff --git a/desktop/l/prometheus.nix b/desktop/l/prometheus.nix index 24eabca..a6d99bf 100644 --- a/desktop/l/prometheus.nix +++ b/desktop/l/prometheus.nix @@ -7,6 +7,7 @@ services.prometheus = { enable = true; globalConfig.scrape_interval = "10s"; # "1m" + retentionTime = "90d"; scrapeConfigs = [ { job_name = "node"; @@ -14,51 +15,51 @@ targets = [ "localhost:${toString config.services.prometheus.exporters.node.port}" ]; }]; } - { - job_name = "xtcp"; - static_configs = [{ - targets = [ "localhost:9088" ]; - }]; - } - { - job_name = "hp1_xtcp"; - static_configs = [{ - targets = [ "hp1:9088" ]; - }]; - } - { - job_name = "clickhouse"; - static_configs = [{ - #targets = [ "localhost:9363" ]; - targets = [ "localhost:19363" ]; - }]; - } - { - job_name = "hp1"; - static_configs = [{ - targets = [ "hp1:${toString config.services.prometheus.exporters.node.port}" ]; - }]; - } - { - job_name = "hp1_clickhouse"; - static_configs = [{ - #targets = [ "localhost:9363" ]; - targets = [ "hp1:19363" ]; - }]; - } - { - job_name = "hp2"; - static_configs = [{ - targets = [ "hp2:${toString config.services.prometheus.exporters.node.port}" ]; - }]; - } - { - job_name = "hp2_clickhouse"; - static_configs = [{ - #targets = [ "localhost:9363" ]; - targets = [ "hp2:19363" ]; - }]; - } + # { + # job_name = "xtcp"; + # static_configs = [{ + # targets = [ "localhost:9088" ]; + # }]; + # } + # { + # job_name = "hp1_xtcp"; + # static_configs = [{ + # targets = [ "hp1:9088" ]; + # }]; + # } + # { + # job_name = "clickhouse"; + # static_configs = [{ + # #targets = [ "localhost:9363" ]; + # targets = [ "localhost:19363" ]; + # }]; + # } + # { + # job_name = "hp1"; + # static_configs = [{ + # targets = [ "hp1:${toString config.services.prometheus.exporters.node.port}" ]; + # }]; + # } + # { + # job_name = "hp1_clickhouse"; + # static_configs = [{ + # #targets = [ "localhost:9363" ]; + # targets = [ "hp1:19363" ]; + # }]; + # } + # { + # job_name = "hp2"; + # static_configs = [{ + # targets = [ "hp2:${toString config.services.prometheus.exporters.node.port}" ]; + # }]; + # } + # { + # job_name = "hp2_clickhouse"; + # static_configs = [{ + # #targets = [ "localhost:9363" ]; + # targets = [ "hp2:19363" ]; + # }]; + # } #{ # job_name = "chromebox1"; # static_configs = [{ diff --git a/desktop/l/systemPackages.nix b/desktop/l/systemPackages.nix index 97f88a2..40e8ac0 100644 --- a/desktop/l/systemPackages.nix +++ b/desktop/l/systemPackages.nix @@ -9,6 +9,7 @@ # $ nix search wget environment.systemPackages = with pkgs; [ # Basic system tools + sysstat psmisc vim curl diff --git a/qotom/nfb/SystemSecureAuthDesignDocument.md b/qotom/nfb/SystemSecureAuthDesignDocument.md new file mode 100644 index 0000000..464e4d3 --- /dev/null +++ b/qotom/nfb/SystemSecureAuthDesignDocument.md @@ -0,0 +1,706 @@ +# System Secure Auth Design Document + +This document outlines the design and implementation of the system secure authentication system. + +This will cover: +- ssh auth with google authenticator app on the phone +- freeradius authentication with google authenticator app on the phone + +The ssh is to protect the system at /home/das/nixos/qotom/nfb/. The same system will run the freeradius server, and then other routers will be configured to use freeradius for authentication. + +# Design overview + +## How Google Authenticator Works + +Google Authenticator implements the Time-based One-Time Password (TOTP) algorithm as specified in RFC 6238. The system works as follows: + +1. **Secret Key Generation**: When a user enrolls, a secret key is generated and shared between the server and the user's mobile device. + +2. **QR Code Setup**: The secret key is typically encoded in a QR code that the user scans with the Google Authenticator app (or any compatible TOTP app). + +3. **Token Generation**: The mobile app generates 6-digit codes that change every 30 seconds based on: + - The shared secret key + - The current Unix timestamp divided by 30 + - HMAC-SHA1 hashing algorithm + +4. **Authentication Process**: + - User enters username and password + - System prompts for the 6-digit TOTP code + - Server validates the code using the same algorithm + - Access is granted if the code matches (within a time window tolerance) + +5. **Time Synchronization**: Both the server and mobile device must have synchronized clocks (within ~30 seconds). The server validates codes for the current 30-second window and the previous/next window to account for slight time drift. + +## Libraries and Packages Used + +### For SSH Authentication: +- **`google-authenticator-libpam`**: PAM module that provides Google Authenticator support +- **`oath-toolkit`**: Optional command-line tools for managing OATH tokens +- **PAM (Pluggable Authentication Modules)**: Linux authentication framework + +### For FreeRADIUS Authentication: +- **`freeradius`**: RADIUS server implementation +- **`freeradius.pam`**: PAM module plugin for FreeRADIUS (rlm_pam) +- **`google-authenticator-libpam`**: Shared PAM module for TOTP validation + +## Authentication Flow + +### SSH Authentication Flow: +``` +User → SSH Client → SSH Server → PAM → Google Authenticator PAM Module → Validates TOTP Code +``` + +### FreeRADIUS Authentication Flow: +``` +Router → RADIUS Request → FreeRADIUS Server → rlm_pam → PAM → Google Authenticator PAM Module → Validates TOTP Code +``` + +# SSH Authentication Configuration with NixOS + +We will create a separate `.nix` file for SSH authentication: `services.ssh-google-auth.nix` + +## Configuration Components: + +1. **Enable Google Authenticator PAM module**: + - Ensure `google-authenticator-libpam` package is available + - Configure PAM to use the `pam_google_authenticator.so` module + +2. **SSH Configuration**: + - Enable `UsePAM = true` (already configured) + - Enable `KbdInteractiveAuthentication = true` (already configured) + - Set `ChallengeResponseAuthentication = true` (currently false) + - Configure PAM to require Google Authenticator after password authentication + +3. **PAM Configuration**: + - Modify `/etc/pam.d/sshd` to include Google Authenticator + - Use `auth required pam_google_authenticator.so` for 2FA enforcement + - Configure to allow fallback for users without TOTP setup (optional) + +4. **User Enrollment Process**: + - Users run `google-authenticator` command to generate secret + - QR code is displayed for scanning with mobile app + - Secret is stored in `~/.google_authenticator` + +## NixOS Module Structure: + +```nix +{ + security.pam.services.sshd.googleAuthenticator = { + enable = true; + # Optional: allow users without TOTP configured + # nullOk = true; + }; + + security.pam.services.sshd = { + # Configure PAM stack for SSH + # Password first, then TOTP + }; +} +``` + +# FreeRADIUS Authentication Configuration with NixOS + +We will create a separate `.nix` file for FreeRADIUS: `services.freeradius.nix` + +## Configuration Components: + +1. **FreeRADIUS Server Setup**: + - Enable FreeRADIUS service + - Configure listening IP/port (default: UDP 1812 for authentication, 1813 for accounting) + - Set shared secret for RADIUS clients (routers) + +2. **PAM Module Integration**: + - Configure `rlm_pam` module in FreeRADIUS + - Point to PAM service configuration that uses Google Authenticator + - Create `/etc/pam.d/radiusd` service file + +3. **RADIUS Clients Configuration**: + - Define authorized routers (NAS devices) + - Configure shared secrets per client + - Set IP addresses/networks for each client + +4. **User Database**: + - Use PAM for user authentication + - Users must exist in system (`/etc/passwd` or LDAP) + - TOTP secrets stored in `~/.google_authenticator` per user + +## NixOS Module Structure: + +```nix +{ + services.freeradius = { + enable = true; + # Configure clients (routers) + clients = { + "router1" = { + ipaddr = "192.168.1.1"; + secret = "..."; + }; + }; + # Configure authentication modules + extraModules = [ "pam" ]; + # Configure sites/default to use PAM + }; + + security.pam.services.radiusd = { + # Configure PAM for FreeRADIUS + googleAuthenticator.enable = true; + }; +} +``` + +# Testing Authentication + +## Testing SSH Authentication: + +1. **Initial Setup**: + ```bash + # On the server, as user 'das' + google-authenticator + # Follow prompts, scan QR code with phone app + ``` + +2. **Test SSH Login**: + ```bash + # From another machine + ssh das@nfbQotom + # Should prompt for password first, then TOTP code + ``` + +3. **Test with Public Key + TOTP** (if configured): + ```bash + ssh das@nfbQotom + # Should prompt for TOTP code even with key auth + ``` + +4. **Verify PAM Configuration**: + ```bash + # Check PAM config + cat /etc/pam.d/sshd + ``` + +## Testing FreeRADIUS: + +1. **Install RADIUS Client Tools**: + ```bash + nix-shell -p freeradius + ``` + +2. **Test Authentication**: + ```bash + # Test from server itself + radtest username password localhost:1812 0 testing123 + + # Should prompt or require TOTP code + # Use: radtest username "password:TOTPCODE" localhost:1812 0 testing123 + ``` + +3. **Monitor FreeRADIUS Logs**: + ```bash + journalctl -u freeradius -f + # Or check /var/log/freeradius/radius.log + ``` + +4. **Test from Router** (if router supports RADIUS testing): + - Configure router as RADIUS client + - Attempt login + - Verify authentication request appears in logs + +5. **Test TOTP Validation**: + ```bash + # Generate code manually + oathtool --totp -b $(cat ~/.google_authenticator | head -1) + + # Test with radtest + radtest das "password:123456" localhost:1812 0 secret + ``` + +# Router Configuration for FreeRADIUS + +## General Router Configuration Steps: + +1. **Obtain RADIUS Server Information**: + - Server IP: `172.16.40.185` (nfbQotom) + - Authentication Port: `1812` (UDP) + - Accounting Port: `1813` (UDP) + - Shared Secret: (configured in FreeRADIUS) + +2. **Router-Specific Configuration**: + + ### Cisco Router (IOS/IOS-XE): + ``` + aaa new-model + aaa authentication login default group radius local + radius server nfbQotom + address ipv4 172.16.40.185 auth-port 1812 acct-port 1813 + key + ``` + + ### Cisco ASA Firewall: + See `cisco-asa-radius-quick-reference.txt` for complete configuration. + ``` + ntp server 172.16.40.185 source management + aaa-server nfbQotom protocol radius + aaa-server nfbQotom (management) host 172.16.40.185 + key + authentication-port 1812 + accounting-port 1813 + aaa authentication ssh console nfbQotom LOCAL + ``` + + ### Juniper Router (JunOS): + ``` + [edit] + system { + authentication-order [ radius password ]; + radius-server { + 172.16.40.185 { + secret ""; + port 1812; + } + } + } + ``` + + ### pfSense/OPNsense: + - Navigate to System > User Manager > Authentication Servers + - Add RADIUS server + - Server IP: `172.16.40.185` + - Port: `1812` + - Shared Secret: (configured secret) + - Enable for login authentication + + ### VyOS: + ``` + set system radius-server 172.16.40.185 secret '' + set system login authentication-order radius + ``` + +3. **Time Synchronization (CRITICAL for TOTP)**: + - TOTP codes are time-based and require synchronized clocks + - Both router and RADIUS server must be within ~30 seconds of each other + - Configure router to sync time from nfbQotom NTP server (172.16.40.185) + - Verify time sync before testing RADIUS authentication + - For Cisco ASA: `ntp server 172.16.40.185 source management` + - Check sync status: `show ntp status` (ASA) or router equivalent + +4. **Authentication Method**: + - Most routers support password+TOTP via PAP (Password Authentication Protocol) + - Format: `password:TOTPCODE` or `passwordTOTPCODE` + - Some routers may require special formatting; check router documentation + - Cisco ASA may prompt for password and TOTP separately + +5. **Fallback Configuration**: + - Consider configuring local fallback for emergency access + - Example: `aaa authentication login default group radius local` + - Keep a local admin account for emergency access + +6. **Testing from Router**: + - Verify time synchronization first (see step 3) + - Attempt SSH/login with username + - Router sends RADIUS request to nfbQotom + - User enters password and TOTP code + - FreeRADIUS validates via PAM/Google Authenticator + - Router grants/denies access based on RADIUS response + +## Security Considerations: + +- Use strong shared secrets between routers and RADIUS server +- Consider IP-based restrictions in FreeRADIUS client configuration +- Monitor RADIUS authentication logs for suspicious activity +- Keep router firmware updated +- Use encrypted connections between routers and RADIUS server (if supported) + +# Router Accounting and Auditing + +## Overview + +Router accounting provides comprehensive auditing of user activity on routers. This enables tracking of: +- User logins and logouts +- Session duration +- Commands executed on routers +- Network activity +- Security events + +## Accounting Configuration + +Accounting has been enabled in the FreeRADIUS configuration using the following modules: + +### Detail Module + +The `detail` module writes detailed accounting records to disk. Configuration: +- **Log Location**: `/var/log/radius/radacct//detail-YYYYMMDD` +- **Format**: One directory per router IP address +- **Rotation**: One file per day (format: `detail-YYYYMMDD`) +- **Permissions**: 0600 (read/write for owner only) +- **Content**: Complete RADIUS accounting packets including timestamps, usernames, session information, and custom attributes + +**Example log structure:** +``` +/var/log/radius/radacct/ + ├── 192.168.1.1/ + │ ├── detail-20251031 + │ ├── detail-20251101 + │ └── ... + ├── 192.168.1.2/ + │ ├── detail-20251031 + │ └── ... + └── ... +``` + +### Unix Module + +The `unix` module provides Unix-style accounting logs similar to wtmp: +- **Log Location**: `/var/log/radius/radwtmp` +- **Format**: Binary format compatible with standard Unix accounting tools +- **Purpose**: Session tracking and user activity history +- **Compatibility**: Can be parsed with standard Unix tools if needed + +### Radutmp Module + +The `radutmp` module tracks active user sessions: +- **Location**: `/var/run/radiusd/radutmp` +- **Purpose**: Real-time session tracking - shows who is currently logged in +- **Format**: Binary session database +- **Usage**: Query active sessions, detect concurrent logins + +## Accounting Record Contents + +RADIUS accounting records include: +- **User identification**: Username, session ID +- **Network information**: Source IP (router), NAS identifier +- **Timing**: Login time, logout time, session duration +- **Service type**: SSH, console, etc. +- **RADIUS attributes**: All standard RADIUS accounting attributes +- **Custom attributes**: Router-specific information if provided + +## Accessing Accounting Records + +### Viewing Detail Logs: +```bash +# View today's accounting for a specific router +cat /var/log/radius/radacct/192.168.1.1/detail-$(date +%Y%m%d) + +# Search for specific user activity +grep "username" /var/log/radius/radacct/*/detail-* + +# View accounting for date range +ls -la /var/log/radius/radacct/192.168.1.1/ +``` + +### Querying Active Sessions: +```bash +# Use radwho (if available) or parse radutmp +cat /var/run/radiusd/radutmp +``` + +## Log Rotation + +FreeRADIUS creates new detail files daily automatically. For long-term retention: +- Consider implementing log rotation policy (keep N days/weeks) +- Archive old accounting records +- Monitor disk space usage +- Consider centralizing logs for analysis + +## Security and Privacy + +- Accounting logs contain sensitive information (usernames, IP addresses, session data) +- Logs are stored with restrictive permissions (0600) +- Only root and radius user can read logs +- Consider encrypting archived accounting logs +- Implement log retention policies per organizational requirements + +# FreeRADIUS systemd Security Hardening + +## Overview + +FreeRADIUS service should be hardened using systemd security features to reduce attack surface, limit resource usage, and improve overall security. This section documents the security design before implementation. + +## Current Security Analysis + +From `systemd-analyze security freeradius`, the current exposure level is **8.7 EXPOSED**, indicating significant room for improvement. + +## Security Design Goals + +1. **Resource Limits**: Constrain memory and CPU usage +2. **Process Isolation**: Limit access to system resources +3. **Network Security**: Restrict network access to only necessary operations +4. **File System Access**: Minimize file system access to required paths only +5. **Capability Restrictions**: Remove unnecessary Linux capabilities +6. **System Call Filtering**: Limit system calls to only those needed + +## Proposed Security Configuration + +### Resource Limits + +- **Memory**: Limit to 150MB (MemoryMax = 150M) +- **CPU**: Limit to 1 core (CPUQuota = 100%, CPUAffinity = single core) +- **File Descriptors**: Reasonable limit based on expected client count +- **Process Count**: Limit concurrent processes + +### Process Isolation + +- **User/Group**: Already running as `radius` user (✓) +- **PrivateTmp**: Enable to isolate temporary files +- **PrivateDevices**: Enable to restrict hardware device access +- **PrivateNetwork**: Consider - FreeRADIUS needs network access, so this may not be applicable +- **PrivateUsers**: Evaluate - FreeRADIUS may need user lookups for PAM +- **ProtectHome**: Enable (already set) +- **ProtectSystem**: Enable with appropriate level (full or strict) +- **ProtectHostname**: Enable +- **ProtectClock**: Enable +- **ProtectKernelTunables**: Enable +- **ProtectKernelModules**: Enable +- **ProtectKernelLogs**: Enable +- **ProtectControlGroups**: Enable +- **ProtectProc**: Set to "invisible" or "noaccess" +- **ProcSubset**: Set to "pid" + +### Network Security + +- **RestrictAddressFamilies**: Allow only AF_INET, AF_INET6, AF_UNIX, AF_NETLINK +- **IPAddressDeny**: Deny all by default, allow only necessary +- **RestrictNetworkInterfaces**: Consider restricting to specific interfaces + +### Capability Restrictions + +- **CapabilityBoundingSet**: Remove all capabilities except those absolutely necessary + - Keep: CAP_NET_BIND_SERVICE (to bind to ports < 1024) + - Remove: CAP_SYS_ADMIN, CAP_SYS_PTRACE, CAP_SYS_TIME, CAP_DAC_OVERRIDE, etc. +- **AmbientCapabilities**: None (already set) +- **NoNewPrivileges**: Enable + +### File System Access + +- **ReadWritePaths**: Only `/var/log/radius`, `/var/run/radiusd`, `/var/log/radius/radacct` +- **ReadOnlyPaths**: `/etc/raddb`, `/etc/passwd`, `/etc/group` (for PAM user lookups) +- **InaccessiblePaths**: Restrict access to unnecessary paths +- **RootDirectory** or **RootImage**: Consider if additional isolation is needed + +### System Call Filtering + +- **SystemCallFilter**: Use `@system-service` profile as base, with minimal exclusions +- **SystemCallArchitectures**: Restrict to x86-64 only + +### Other Security Settings + +- **LockPersonality**: Enable +- **RestrictNamespaces**: Enable for all namespace types +- **RestrictRealtime**: Enable +- **RestrictSUIDSGID**: Enable +- **RemoveIPC**: Enable +- **MemoryDenyWriteExecute**: Enable +- **UMask**: Set to 0077 for secure file creation + +### Security Trade-offs + +Some restrictions may conflict with FreeRADIUS functionality: + +1. **PrivateUsers**: May block PAM from accessing `/etc/passwd` - need to test +2. **ProtectSystem**: May need "full" instead of "strict" to allow log writing +3. **SystemCallFilter**: Must allow system calls needed for PAM, network operations, and file I/O +4. **ReadOnlyPaths**: Must include `/etc/passwd`, `/etc/group` for user lookups +5. **ReadWritePaths**: Must include log directories and runtime directories + +### Testing Requirements + +After applying security restrictions: +- Verify RADIUS authentication still works +- Verify PAM integration functions correctly +- Verify accounting logs are written properly +- Monitor for any permission errors +- Test with multiple concurrent connections + +## Reference Implementation + +See `atftpd.nix` for an example of comprehensive systemd security configuration with similar requirements (network service, user lookups, file operations). + +## Target Security Score + +Aim for security exposure level **≤ 3.0** (similar to atftpd which achieved 2.0), while maintaining full functionality. + +# Implementation Plan + +## Phase 1: SSH Google Authenticator Setup + +1. **Create SSH Google Authenticator Module** (`services.ssh-google-auth.nix`): + - Configure PAM to use Google Authenticator + - Update SSH settings if needed + - Test configuration before enforcing + +2. **User Enrollment**: + - Run `google-authenticator` for each user (das, nigel) + - Document backup codes + - Test SSH login with TOTP + +3. **Verification**: + - Verify SSH still works with TOTP + - Test with public key + TOTP combination + - Ensure fallback options work + +## Phase 2: FreeRADIUS Setup + +1. **Create FreeRADIUS Module** (`services.freeradius.nix`): + - Configure FreeRADIUS service + - Set up PAM integration + - Configure default site for PAM authentication + +2. **Initial Client Configuration**: + - Add at least one test router/client + - Configure shared secret + - Test connectivity + +3. **PAM Configuration for RADIUS**: + - Create PAM service for radiusd + - Integrate Google Authenticator + - Test authentication locally + +## Phase 3: Integration Testing + +1. **Local Testing**: + - Test FreeRADIUS authentication with radtest + - Verify TOTP codes work through RADIUS + - Check logs for errors + +2. **Router Integration**: + - Configure first router as RADIUS client + - Test login from router + - Verify TOTP prompt and validation + +3. **Multi-User Testing**: + - Test with multiple users + - Verify user isolation (one user's TOTP doesn't work for another) + +## Phase 4: Production Deployment + +1. **Configuration Hardening**: + - Review and tighten security settings + - Set appropriate firewall rules + - Configure log rotation + +2. **Documentation**: + - Document enrollment process + - Create runbook for common issues + - Document router configuration per router type + +3. **Rollout to Additional Routers**: + - Gradually add routers to RADIUS + - Monitor for issues + - Keep local fallback until stable + +## Phase 5: Monitoring and Maintenance + +1. **Logging Setup**: + - Configure centralized logging (if applicable) + - Set up alerts for authentication failures + - Monitor RADIUS performance + +2. **Backup and Recovery**: + - Backup user `.google_authenticator` files + - Document recovery procedures + - Test backup restoration + +3. **User Management**: + - Document user enrollment process + - Create procedures for user removal + - Handle lost/compromised devices + +## Files to Create: + +1. `qotom/nfb/services.ssh-google-auth.nix` - SSH TOTP configuration +2. `qotom/nfb/services.freeradius.nix` - FreeRADIUS configuration +3. Update `qotom/nfb/configuration.nix` to import new modules + +## Dependencies: + +- `google-authenticator-libpam` - PAM module for TOTP +- `freeradius` - RADIUS server +- `oath-toolkit` - Optional: CLI tools for token management + +## Testing Checklist: + +- [ ] SSH login with password + TOTP works +- [ ] SSH login with public key + TOTP works (if configured) +- [ ] FreeRADIUS service starts successfully +- [ ] radtest authentication works locally +- [ ] Router can authenticate via RADIUS +- [ ] Multiple users can authenticate independently +- [ ] Logs show successful authentication +- [ ] Invalid TOTP codes are rejected +- [ ] Time drift tolerance works (codes valid for ~90 seconds window) + +# Implementation Progress + +## Phase 1: SSH Google Authenticator Setup + +- [x] **Design Document Completed** - All sections filled in with technical details +- [x] **Create services.ssh-google-auth.nix** - NixOS module for SSH TOTP configuration ✅ +- [x] **Update services.ssh.nix** - Enable ChallengeResponseAuthentication ✅ +- [x] **Update configuration.nix** - Import new SSH auth module ✅ +- [ ] **Test NixOS Configuration** - Verify configuration compiles +- [ ] **User Enrollment** - Run `google-authenticator` for users +- [ ] **SSH Login Testing** - Verify password + TOTP works + +## Phase 2: FreeRADIUS Setup + +- [x] **Create services.freeradius.nix** - NixOS module for FreeRADIUS ✅ +- [x] **Configure PAM Integration** - Set up radiusd PAM service ✅ +- [x] **Configure RADIUS Clients** - Added Cisco ASA (172.16.40.30) client configuration ✅ +- [x] **Update configuration.nix** - Import FreeRADIUS module ✅ +- [x] **Fix Configuration Syntax** - Corrected to use environment.etc for config files ✅ +- [x] **Add radiusd.conf** - Created main FreeRADIUS configuration file ✅ +- [x] **Enable PAM Module** - Override package to include PAM support ✅ +- [x] **Simplify Site Configuration** - Removed EAP dependencies ✅ +- [x] **Enable Accounting Modules** - Added detail, unix, and radutmp for auditing ✅ +- [x] **Fix Deprecated Configuration** - Updated perm to permissions in radutmp ✅ +- [x] **Add Listen Sections** - Configured authentication and accounting ports ✅ +- [x] **Test FreeRADIUS Service** - Service starts successfully ✅ +- [x] **Apply Systemd Security Hardening** - Added comprehensive security restrictions ✅ +- [x] **Fix Directory Creation** - Added tmpfiles rules for required directories ✅ +- [x] **Fix Namespace Issues** - Corrected ReadOnlyPaths/InaccessiblePaths for proper isolation ✅ +- [x] **Create chrony.nix** - Configured NTP server for time synchronization ✅ +- [x] **Configure chronyd** - Enabled with security hardening, resource limits, and priority ✅ +- [x] **Verify Time Sync** - chronyd syncing with upstream NTP pool servers ✅ +- [x] **Configure Cisco ASA NTP** - ASA syncing time from nfbQotom (172.16.40.185) ✅ +- [x] **Verify Time Sync Accuracy** - ASA showing 2.49ms offset (acceptable for TOTP) ✅ +- [x] **Create ASA Configuration Files** - Created cisco-asa-radius-config.txt and quick reference ✅ +- [x] **Verify Security Score** - Security exposure level: 3.4 OK ✅ +- [x] **User Enrollment** - Google Authenticator configured for user 'das' ✅ +- [x] **Fix BlastRADIUS Warnings** - Updated localhost client to require Message-Authenticator ✅ +- [ ] **Configure Cisco ASA** - Apply RADIUS configuration to firewall +- [ ] **Test ASA RADIUS Authentication** - Verify authentication from Cisco ASA works + +## Phase 3: Integration Testing + +- [ ] **FreeRADIUS Authentication Testing** - Verify TOTP codes work via RADIUS +- [x] **Router Integration** - Cisco ASA configuration prepared (see cisco-asa-radius-quick-reference.txt) ✅ +- [ ] **Test ASA RADIUS Authentication** - Verify authentication from Cisco ASA firewall works +- [ ] **Password+TOTP Format Testing** - Verify correct format (password:TOTPCODE or separate prompts) +- [ ] **Multi-User Testing** - Test with multiple users (das, nigel) +- [ ] **Log Verification** - Check authentication logs and accounting records +- [ ] **Error Handling Testing** - Verify invalid TOTP codes are rejected properly + +## Phase 4: Production Deployment + +- [x] **Time Synchronization** - chronyd and ASA time sync configured and verified ✅ +- [x] **Firewall Rules** - UDP 123 (NTP) and UDP 1812/1813 (RADIUS) ports configured ✅ +- [ ] **Configuration Hardening** - Review security settings +- [ ] **Log Rotation** - Set up log management +- [ ] **Documentation** - Complete operational docs + +## Phase 5: Monitoring and Maintenance + +- [ ] **Logging Setup** - Configure centralized logging +- [ ] **Backup Procedures** - Backup TOTP secrets +- [ ] **User Management Procedures** - Document enrollment/removal + +## Files Status + +- [x] `SystemSecureAuthDesignDocument.md` - ✅ Completed +- [x] `services.ssh-google-auth.nix` - ✅ Created +- [x] `services.freeradius.nix` - ✅ Created +- [x] `services.ssh.nix` - ✅ Updated (ChallengeResponseAuthentication enabled) +- [x] `configuration.nix` - ✅ Updated (imports added) +- [x] `chrony.nix` - ✅ Created (NTP server with security hardening) +- [x] `cisco-asa-radius-config.txt` - ✅ Created (detailed ASA configuration guide) +- [x] `cisco-asa-radius-quick-reference.txt` - ✅ Created (quick reference for ASA commands) diff --git a/qotom/nfb/chrony.nix b/qotom/nfb/chrony.nix new file mode 100644 index 0000000..589cb8b --- /dev/null +++ b/qotom/nfb/chrony.nix @@ -0,0 +1,158 @@ +# +# qotom/nfb/chrony.nix +# +# Chrony NTP server configuration +# Syncs upstream to NTP pool and serves time to internal clients (e.g., Cisco ASA firewall) +# +# IMPORTANT: The NixOS chrony service module already defines comprehensive security features. +# Before adjusting this file, reference the upstream service module source: +# https://github.com/NixOS/nixpkgs/blob/nixos-unstable/nixos/modules/services/networking/ntp/chrony.nix +# +# The upstream module configures: +# - ProtectSystem, ProtectHome, ProtectProc, ProcSubset +# - ReadWritePaths, ReadOnlyPaths +# - RestrictAddressFamilies +# - CapabilityBoundingSet (includes CAP_SYS_TIME and other necessary capabilities) +# - DeviceAllow (includes RTC devices) +# - SystemCallFilter (but includes @privileged) +# - All other standard security restrictions +# +# This file only customizes: +# - Resource limits (MemoryHigh, MemoryMax, CPUQuota, TasksMax) +# - SystemCallFilter (to exclude @privileged for better security score) +# - UMask (more restrictive than default) +# +# sudo systemctl status chronyd +# chronyc tracking +# chronyc -n sources + +{ config, pkgs, lib, ... }: + +let + # Bind addresses for NTP server + # Bind to all interfaces to serve time to internal clients + # Alternatively, can bind to specific IP: [ "172.16.40.185" ] + bindAddresses = [ + "0.0.0.0" # IPv4 all interfaces + "::" # IPv6 all interfaces + ]; + + # Internal networks allowed to query this NTP server + # Allow the management network where the firewall is located + internalAllowFrom = [ + "172.16.40.0/24" # Management network (includes firewall at 172.16.40.30) + "127.0.0.0/8" # Localhost + "::1/128" # IPv6 localhost + ]; +in { + # Disable timesyncd as it conflicts with chrony + services.timesyncd.enable = false; + + # Enable chrony NTP server + services.chrony = { + enable = true; + + # Use public NTP servers as upstream sources + # North America NTP pool servers from https://www.ntppool.org/zone/north-america + # Big list of public NTP servers + # https://gist.github.com/mutin-sa/eea1c396b1e610a2da1e5550d94b0453 + servers = [ + "0.north-america.pool.ntp.org" + "1.north-america.pool.ntp.org" + "2.north-america.pool.ntp.org" + "3.north-america.pool.ntp.org" + "time.cloudflare.com" + "time.google.com" + "time.aws.com" + "time.facebook.com" + ]; + + # Use iburst for rapid polling on startup + serverOption = "iburst"; + + # Enable memory locking for better performance + enableMemoryLocking = true; + + # Enable RTC trimming for better timekeeping + enableRTCTrimming = true; + + # Allow large time steps on startup (useful for VMs or systems that may be offline) + initstepslew = { + enabled = true; + threshold = 1000; # 1000 seconds threshold + }; + + # Extra configuration for internal NTP server + extraConfig = '' + # Bind to specific interfaces for internal NTP service + ${lib.concatMapStringsSep "\n" (addr: "bindaddress ${addr}") bindAddresses} + + # Allow NTP queries from internal networks + ${lib.concatMapStringsSep "\n" (range: "allow ${range}") internalAllowFrom} + + # Serve time even if not synchronized (useful for internal networks) + local stratum 10 + + # Enable NTP server mode + port 123 + + # Client access restrictions + cmdallow 127.0.0.1 + cmdallow ::1 + + # Key configuration for authentication (if needed) + # keyfile /etc/chrony/chrony.keys + # generatecommandkey + ''; + }; + + # Systemd service configuration with resource limits and priority + # Note: Most security settings are already configured by the chrony service module + # We only override/add what we need to customize + # systemd-analyze security chronyd + systemd.services.chronyd = { + serviceConfig = { + # Resource limits (not set by default service, so no mkForce needed) + # Actual usage is ~9.5M, so set reasonable limits with headroom + MemoryHigh = "20M"; + MemoryMax = "30M"; + CPUQuota = "20%"; + TasksMax = 100; + + # Process priority - NTP services should respond quickly even under system pressure + # Lower nice value = higher priority (range: -20 to +19) + # -10 is a good balance for NTP: high enough priority to respond quickly, + # but not so high as to starve other important system services + # Note: Negative nice values may require CAP_SYS_NICE capability, but the default + # scheduling policy (CFS) with nice priority should be sufficient for NTP responsiveness + Nice = -10; + + # Override SystemCallFilter to exclude @privileged for better security score + # The default includes @privileged, we want to exclude it but keep necessary calls + SystemCallFilter = lib.mkForce [ + "~@cpu-emulation" + "~@debug" + "~@keyring" + "~@mount" + "~@obsolete" + "~@privileged" # Exclude privileged system calls (improves security score) + "~@resources" + "@clock" # Needed for time operations + "@setuid" # Needed for user switching + "capset" # Needed for capability management + "@chown" # Needed for file ownership changes + ]; + + # Override UMask for more restrictive permissions (default is "0027") + UMask = lib.mkForce "0077"; # Owner-only access + + # Note: All other security settings (ProtectSystem, ProtectHome, etc.) are already + # properly configured by the service module and don't need to be overridden + # The service module also creates the necessary tmpfiles rules for /var/lib/chrony + }; + }; + + # Firewall rules for NTP + networking.firewall.allowedUDPPorts = [ 123 ]; # NTP port +} + diff --git a/qotom/nfb/cisco-asa-radius-config.txt b/qotom/nfb/cisco-asa-radius-config.txt new file mode 100644 index 0000000..8d6ad0e --- /dev/null +++ b/qotom/nfb/cisco-asa-radius-config.txt @@ -0,0 +1,150 @@ +# Cisco ASA RADIUS Configuration for Google Authenticator +# +# This configuration enables RADIUS authentication on a Cisco ASA firewall +# to authenticate against FreeRADIUS server at 172.16.40.185 (nfbQotom) +# +# Prerequisites: +# - FreeRADIUS server configured at 172.16.40.185 +# - ASA can reach the RADIUS server (verified: ping successful) +# - Shared secret configured in FreeRADIUS clients.conf matches the secret below +# +# IMPORTANT: Change the shared secret to a strong, random value! +# The secret below matches what is configured in services.freeradius.nix +# Shared Secret: ASA-RADIUS-Secret-2025-Secure-Key-Please-Change-Me + +# ============================================ +# Configuration Steps: +# ============================================ + +# Step 0: Configure NTP (CRITICAL for TOTP to work correctly!) +# TOTP codes are time-based, so both the ASA and RADIUS server must have +# synchronized time. Configure the ASA to sync time from nfbQotom. +ntp server 172.16.40.185 source management + +# Step 1: Configure AAA model (required for RADIUS) +aaa-server nfbQotom protocol radius + +# Step 2: Configure RADIUS server group +aaa-server nfbQotom (management) host 172.16.40.185 + key ASA-RADIUS-Secret-2025-Secure-Key-Please-Change-Me + authentication-port 1812 + accounting-port 1813 + timeout 10 + retry 3 + +# Step 3: Configure AAA authentication for console/SSH/Telnet +# This will authenticate all management logins via RADIUS +aaa authentication ssh console nfbQotom LOCAL +aaa authentication telnet console nfbQotom LOCAL +aaa authentication serial console nfbQotom LOCAL + +# Step 4: Configure AAA authorization (optional but recommended) +# This allows RADIUS to send authorization attributes (privilege level, etc.) +aaa authorization exec console nfbQotom LOCAL + +# Step 5: Configure AAA accounting (optional but recommended for auditing) +# This logs all commands executed on the ASA +aaa accounting ssh console nfbQotom +aaa accounting telnet console nfbQotom +aaa accounting serial console nfbQotom + +# ============================================ +# Testing Commands: +# ============================================ + +# Test RADIUS connectivity: +test aaa-server authentication nfbQotom username das password code +# Example: +# test aaa-server authentication nfbQotom username das password MyPassword123 code 123456 + +# Verify NTP synchronization (CRITICAL for TOTP): +show ntp status +show ntp associations +# The ASA should show synchronization with nfbQotom (172.16.40.185) +# If not synchronized, TOTP codes will fail! + +# View AAA server status: +show aaa-server nfbQotom + +# View AAA server statistics: +show aaa-server nfbQotom statistics + +# View current AAA configuration: +show running-config aaa + +# View authentication sessions: +show uauth + +# ============================================ +# Authentication Flow: +# ============================================ +# +# 1. User attempts to SSH/Telnet to ASA +# 2. ASA prompts for username +# 3. User enters username (e.g., "das") +# 4. ASA prompts for password +# 5. User enters: password:TOTPCODE (e.g., "MyPassword123:123456") +# OR just the password if the ASA supports separate prompts +# 6. ASA sends RADIUS Access-Request to 172.16.40.185:1812 +# 7. FreeRADIUS validates via PAM (password + TOTP) +# 8. FreeRADIUS returns Access-Accept or Access-Reject +# 9. ASA grants or denies access +# +# Note: Some ASA versions may require the password and TOTP code to be +# entered separately. Test both formats: +# - Combined: password:TOTPCODE +# - Separate prompts (if supported) + +# ============================================ +# Troubleshooting: +# ============================================ + +# Enable debug logging for AAA: +debug aaa authentication 255 +debug aaa authorization 255 +debug aaa accounting 255 +debug radius 255 + +# View debug output: +# Look for RADIUS requests and responses in the ASA logs + +# Common issues: +# 1. "Server not responding" - Check network connectivity and firewall rules +# 2. "Authentication failed" - Verify shared secret matches on both sides +# 3. "Invalid password" - Check password format (may need password:TOTPCODE) +# 4. "User not found" - Ensure user exists in /etc/passwd on FreeRADIUS server +# 5. "TOTP code invalid" - MOST COMMON: Verify time sync between ASA and RADIUS server +# - Run "show ntp status" on ASA to verify time sync +# - Ensure both systems are within ~30 seconds of each other +# - Check code validity window (usually 30-90 seconds) +# - Verify chronyd is running on nfbQotom and serving time correctly + +# ============================================ +# Security Notes: +# ============================================ +# +# - LOCAL fallback: The "LOCAL" keyword provides fallback to local users +# Remove "LOCAL" from commands above to require RADIUS-only authentication +# (but keep a local admin account for emergency access!) +# +# - Shared Secret: Use a strong, random secret (at least 16 characters) +# Change the default secret before deploying! +# +# - Timeout/Retry: Adjust timeout and retry values based on network latency +# +# - Accounting: Enables auditing of all commands executed on the ASA +# Review accounting logs regularly for security monitoring + +# ============================================ +# Example Session: +# ============================================ +# +# $ ssh admin@172.16.40.30 +# Username: das +# Password: MyPassword123:123456 +# (If prompted separately) +# Password: MyPassword123 +# Enter passcode: 123456 +# +# ciscoasa> + diff --git a/qotom/nfb/cisco-asa-radius-quick-reference.txt b/qotom/nfb/cisco-asa-radius-quick-reference.txt new file mode 100644 index 0000000..b83b27b --- /dev/null +++ b/qotom/nfb/cisco-asa-radius-quick-reference.txt @@ -0,0 +1,36 @@ +# Cisco ASA RADIUS Configuration - Quick Reference +# +# Copy and paste these commands into your ASA terminal + +# Configure NTP to sync time from nfbQotom (IMPORTANT for TOTP to work!) +ntp server 172.16.40.185 source management + +# Configure AAA server +aaa-server nfbQotom protocol radius +aaa-server nfbQotom (management) host 172.16.40.185 + key ASA-RADIUS-Secret-2025-Secure-Key-Please-Change-Me + authentication-port 1812 + accounting-port 1813 + timeout 10 + retry 3 + +# Enable RADIUS authentication +aaa authentication ssh console nfbQotom LOCAL +aaa authentication telnet console nfbQotom LOCAL +aaa authentication serial console nfbQotom LOCAL + +# Optional: Enable accounting (for auditing) +aaa accounting ssh console nfbQotom +aaa accounting telnet console nfbQotom +aaa accounting serial console nfbQotom + +# Test the configuration (replace username, password, and TOTP code): +# test aaa-server authentication nfbQotom username das password MyPassword123 code 123456 + +# Verify NTP sync status: +# show ntp status +# show ntp associations + +# Save configuration: +write memory + diff --git a/qotom/nfb/configuration.nix b/qotom/nfb/configuration.nix index 83d40e3..60e14f7 100644 --- a/qotom/nfb/configuration.nix +++ b/qotom/nfb/configuration.nix @@ -23,6 +23,8 @@ ./nginx.nix ./services.ssh.nix + ./services.ssh-google-auth.nix + ./services.freeradius.nix ./smokeping.nix ./pdns-recursor.nix @@ -31,6 +33,8 @@ ./network.nix ./serial-tty.nix + + ./chrony.nix ]; boot = { @@ -60,7 +64,7 @@ # networking.networkmanager.enable = true; # Disabled - using systemd-networkd instead services.lldpd.enable = true; - services.timesyncd.enable = true; + # timesyncd is disabled in chrony.nix to avoid conflicts services.fstrim.enable = true; time.timeZone = "America/Los_Angeles"; diff --git a/qotom/nfb/services.freeradius.nix b/qotom/nfb/services.freeradius.nix new file mode 100644 index 0000000..e57dfb7 --- /dev/null +++ b/qotom/nfb/services.freeradius.nix @@ -0,0 +1,463 @@ +# +# nixos/qotom/nfb/services.freeradius.nix +# +# FreeRADIUS server configuration with PAM authentication using Google Authenticator +# This module configures FreeRADIUS to authenticate users via PAM, which uses Google Authenticator +# +# References: +# - https://nixos.wiki/wiki/FreeRADIUS +# - https://freeradius.org/documentation/ +# - https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/networking/freeradius.nix +# +# Note: The NixOS FreeRADIUS module only provides basic service setup. +# Configuration files must be written to /etc/raddb manually using environment.etc + +{ config, pkgs, lib, ... }: + +let + # Configuration directory for FreeRADIUS + raddbDir = "/etc/raddb"; + + # Default site configuration - define once, use in both places + # Ultra-minimal configuration for PAM-based authentication + # Only PAM module - simplest possible configuration + defaultSiteConfig = '' + # Default site configuration for FreeRADIUS + # Uses PAM for authentication with Google Authenticator + # Minimal configuration - only PAM authentication + + # Listen on authentication port (UDP 1812) + listen { + type = auth + ipaddr = * + port = 0 + } + + # Listen on accounting port (UDP 1813) + listen { + type = acct + ipaddr = * + port = 0 + } + + server default { + # Authorization (user lookup and Auth-Type setting) + # PAM module can't be used here - need to set Auth-Type + authorize { + # Set Auth-Type to PAP for PAM authentication + update control { + Auth-Type := PAP + } + } + + # Authentication - use PAM here + authenticate { + Auth-Type PAP { + pam + } + Auth-Type CHAP { + pam + } + Auth-Type MS-CHAP { + pam + } + } + + # Pre-proxy authorization + pre-proxy { + } + + # Post-proxy authorization + post-proxy { + } + + # Pre-accounting - prepare accounting records + preacct { + # Pre-process accounting packets + } + + # Accounting - log accounting records for auditing + # This provides auditing of commands run on routers + accounting { + # Write detailed accounting records to file + detail + # Write to Unix-style log (wtmp-like) + unix + # Write session records + radutmp + } + + # Session management - track user sessions + session { + radutmp + } + + # Post-authentication - process after authentication + post-auth { + # Reject handling if needed + Post-Auth-Type REJECT { + # Filter attributes for reject messages + } + } + } + ''; +in +{ + # Enable FreeRADIUS service + services.freeradius = { + enable = true; + # Use default configDir (/etc/raddb) + configDir = raddbDir; + # Override package to be minimal - only PAM support, disable all optional modules + # This reduces memory usage, attack surface, and build time + package = (pkgs.freeradius.override { + withLdap = false; + withSqlite = false; + withMysql = false; + withPostgresql = false; + withRedis = false; + withRest = false; + withJson = false; + withYubikey = false; + withMemcached = false; + withCollectd = false; + }).overrideAttrs (oldAttrs: { + buildInputs = (oldAttrs.buildInputs or []) ++ [ + pkgs.linux-pam + ]; + }); + }; + + # Write FreeRADIUS configuration files + environment.etc = { + # Clients configuration - defines routers that can authenticate against this server + "raddb/clients.conf".text = '' + # FreeRADIUS clients configuration + # Each router needs a shared secret configured here and on the router + + # Localhost client for testing + # Note: require_message_authenticator = yes is recommended for BlastRADIUS protection + # However, radtest from command line may not always include Message-Authenticator + client localhost { + ipaddr = 127.0.0.1 + secret = testing123 + require_message_authenticator = yes + nas_type = other + } + + # Cisco ASA Firewall (172.16.40.30) + # Management interface: Management1/1 + client ciscoasa { + ipaddr = 172.16.40.30 + secret = ASA-RADIUS-Secret-2025-Secure-Key-Please-Change-Me + require_message_authenticator = yes + nas_type = cisco + } + + # Example router clients - uncomment and configure as needed + # client router1 { + # ipaddr = 192.168.1.1 + # secret = changeme-strong-secret-here + # require_message_authenticator = yes + # nas_type = other + # } + # + # client router2 { + # ipaddr = 192.168.1.2 + # secret = another-strong-secret + # require_message_authenticator = yes + # nas_type = other + # } + ''; + + # Main radiusd.conf - minimal configuration + # Based on FreeRADIUS package defaults, adapted for NixOS + "raddb/radiusd.conf".text = '' + # FreeRADIUS main configuration file + # Minimal configuration for PAM-based authentication + + # Package paths - use config.services.freeradius.package + prefix = ${config.services.freeradius.package} + exec_prefix = ''${prefix} + sysconfdir = /etc + localstatedir = /var + sbindir = ''${prefix}/bin + logdir = ''${localstatedir}/log/radius + raddbdir = ${raddbDir} + radacctdir = ''${logdir}/radacct + run_dir = ''${localstatedir}/run/radiusd + db_dir = ''${raddbdir} + libdir = ''${prefix}/lib + + # Server name + name = radiusd + + # Config directories + confdir = ''${raddbdir} + modconfdir = ''${confdir}/mods-config + certdir = ''${confdir}/certs + cadir = ''${confdir}/certs + + # PID file + pidfile = ''${run_dir}/''${name}.pid + + # Request handling + max_request_time = 30 + cleanup_delay = 5 + max_requests = 1024 + hostname_lookups = no + + # Note: user, group, and allow_core_dumps are deprecated in FreeRADIUS 3.2.7 + # They are now handled by systemd service configuration + + # Logging + log { + destination = files + colourise = yes + file = ''${logdir}/radius.log + syslog_facility = daemon + stripped_names = no + auth = yes # Enable authentication logging for debugging + auth_badpass = yes # Log bad passwords for debugging + auth_goodpass = yes # Log good passwords for debugging + msg_denied = "You are already logged in - access denied" + } + + # Checkrad program + checkrad = ''${sbindir}/checkrad + + # Security settings (allow_core_dumps removed - deprecated in 3.2.7) + security { + max_attributes = 200 + reject_delay = 1 + status_server = yes + require_message_authenticator = auto + limit_proxy_state = auto + } + + # Proxy requests + proxy_requests = yes + + # Thread pool + thread pool { + start_servers = 5 + max_servers = 32 + min_spare_servers = 3 + max_spare_servers = 10 + max_requests_per_server = 0 + auto_limit_acct = no + } + + # Modules - include module configurations + modules { + $INCLUDE ''${confdir}/mods-enabled/ + } + + # Instantiate modules + instantiate { + } + + # Policy + policy { + } + + # Include configuration files + $INCLUDE ''${confdir}/clients.conf + $INCLUDE ''${confdir}/sites-enabled/ + ''; + + # PAM module configuration - write directly to mods-enabled + # FreeRADIUS loads modules from mods-enabled directory + "raddb/mods-enabled/pam".text = '' + # PAM module configuration for FreeRADIUS + # This uses the radiusd PAM service (defined in security.pam.services.radiusd) + pam { + pam_auth = radiusd + } + ''; + + # Detail module - detailed accounting logs + "raddb/mods-enabled/detail".text = '' + # Detailed accounting logging + # Logs to /var/log/radius/radacct/*/detail-YYYYMMDD files + # One file per router IP address, one file per day + detail { + filename = ''${radacctdir}/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d + permissions = 0600 + dirperm = 0755 + locking = no + log_packet_header = no + log_request_authenticator = no + } + ''; + + # Unix module - Unix-style accounting (like wtmp) + "raddb/mods-enabled/unix".text = '' + # Unix-style accounting (wtmp-like logs) + unix { + radwtmp = ''${logdir}/radwtmp + } + ''; + + # Radutmp module - session tracking + "raddb/mods-enabled/radutmp".text = '' + # Session tracking for accounting + radutmp { + filename = ''${run_dir}/radutmp + username = %{User-Name} + case_sensitive = yes + check_with_nas = yes + permissions = 0600 + caller_id = yes + } + ''; + + # Site configuration - available version (for reference) + "raddb/sites-available/default".text = defaultSiteConfig; + + # Enable default site - write directly to sites-enabled + # FreeRADIUS loads sites from sites-enabled directory + "raddb/sites-enabled/default".text = defaultSiteConfig; + }; + + # Configure PAM for FreeRADIUS (radiusd service) + # This PAM service will use Google Authenticator for TOTP validation + security.pam.services.radiusd = { + # Enable Google Authenticator for RADIUS authentication + googleAuthenticator = { + enable = true; + # Allow users without TOTP configured (set to false to require TOTP) + # nullOk = false; + }; + }; + + # Create necessary directories for FreeRADIUS before service starts + # systemd needs these directories to exist before bind-mounting them in the namespace + systemd.tmpfiles.rules = [ + # Create log directory + "d /var/log/radius 0750 radius radius -" + # Create accounting directory + "d /var/log/radius/radacct 0750 radius radius -" + # Create runtime directory + "d /var/run/radiusd 0750 radius radius -" + ]; + + # Security hardening for FreeRADIUS service + # systemd-analyze security freeradius.service + # Target: Reduce exposure level from 8.7 to ≤ 3.0 + # Note: Default service only sets: User, ProtectSystem, ProtectHome, Restart, RestartSec, LogsDirectory + # Only use lib.mkForce for attributes already set by the default service + systemd.services.freeradius = { + serviceConfig = { + # User/Group already set by services.freeradius (radius:radius) + + # Resource limits (not set by default service, so no mkForce needed) + MemoryMax = "150M"; + MemoryHigh = "120M"; + CPUQuota = "100%"; + LimitNOFILE = 1024; + LimitNPROC = 200; + + # Security restrictions - process isolation (not set by default, so no mkForce) + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + ProtectKernelLogs = true; + ProtectClock = true; + ProtectHostname = true; + RestrictNamespaces = true; + RestrictRealtime = true; + MemoryDenyWriteExecute = true; + LockPersonality = true; + PrivateDevices = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + + # Additional security restrictions (not set by default, so no mkForce) + NoNewPrivileges = true; + RestrictSUIDSGID = true; + PrivateTmp = true; + PrivateUsers = false; # Must be false: FreeRADIUS needs access to /etc/passwd and /etc/group for PAM user lookups + RemoveIPC = true; + + # System call architecture restriction (not set by default, so no mkForce) + SystemCallArchitectures = "x86-64"; + + # System call filtering (not set by default, so no mkForce) + # Note: Excluding @privileged or @resources causes FreeRADIUS/PAM to crash + # PAM authentication requires various system calls that are part of these groups + # We keep @system-service which includes necessary calls for network and file operations + SystemCallFilter = [ + "@system-service" + "~@mount" + "~@debug" + "~@module" + "~@reboot" + "~@swap" + "~@obsolete" + ]; + + # Restrict address families (not set by default, so no mkForce) + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + + # Device access (minimal) + # /dev/null: rw for stdout/stderr redirection + # /dev/zero: r only (read zeros for memory initialization, no need to write) + # /dev/urandom and /dev/random: r only for random number generation + DeviceAllow = [ + "/dev/null rw" + "/dev/zero r" + "/dev/urandom r" + "/dev/random r" + ]; + + # Capabilities (not set by default, so no mkForce) + CapabilityBoundingSet = [ ]; + AmbientCapabilities = [ ]; + + # File permissions (not set by default, so no mkForce) + UMask = "0077"; + + # File system restrictions + # ProtectSystem and ProtectHome are already set by default service, so use mkForce + ProtectSystem = lib.mkForce "full"; + ProtectHome = lib.mkForce true; + + # ReadOnlyPaths: Configuration, system files, and Nix store needed for operation + # /etc/raddb: FreeRADIUS configuration + # /etc: Required for PAM user/group lookups (passwd, group, nsswitch.conf, etc.) + # /nix: Required for accessing Nix store executables and scripts + ReadOnlyPaths = [ "/etc/raddb" "/etc" "/nix" ]; + + # ReadWritePaths: Logs, runtime, and accounting directories + # /var/log/radius: Main log directory + # /var/log/radius/radacct: Accounting records (one subdirectory per router IP) + # /var/run/radiusd: Runtime files (PID, radutmp, etc.) + # /var/run/nscd: Name service cache daemon socket (for user lookups) + ReadWritePaths = [ + "/var/log/radius" + "/var/log/radius/radacct" + "/var/run/radiusd" + "/var/run/nscd" + ]; + + # InaccessiblePaths: Block access to unnecessary paths + # Note: /nix is in ReadOnlyPaths for script execution + # Note: /dev is controlled via DeviceAllow, so don't put it in InaccessiblePaths + InaccessiblePaths = [ "/proc" "/sys" "/boot" "/root" "/home" ]; + }; + }; + + # Open firewall ports for FreeRADIUS + # UDP 1812: Authentication + # UDP 1813: Accounting + networking.firewall.allowedUDPPorts = [ 1812 1813 ]; + + # Ensure required packages are available + environment.systemPackages = with pkgs; [ + freeradius # Includes radtest for testing + google-authenticator # For user enrollment + oath-toolkit # CLI tools for token management + ]; +} + diff --git a/qotom/nfb/services.ssh-google-auth.nix b/qotom/nfb/services.ssh-google-auth.nix new file mode 100644 index 0000000..19d3d2f --- /dev/null +++ b/qotom/nfb/services.ssh-google-auth.nix @@ -0,0 +1,44 @@ +# +# nixos/qotom/nfb/services.ssh-google-auth.nix +# +# SSH authentication with Google Authenticator (TOTP) two-factor authentication +# This module configures PAM to use Google Authenticator for SSH logins +# +# References: +# - https://nixos.wiki/wiki/Google_Authenticator +# - https://github.com/google/google-authenticator-libpam +# - https://nixos.org/manual/nixos/stable/index.html#module-security-pam + +{ config, pkgs, ... }: + +{ + # Ensure google-authenticator-libpam package is available + environment.systemPackages = with pkgs; [ + google-authenticator + oath-toolkit # Optional: CLI tools for managing OATH tokens + ]; + + # Configure PAM for SSH to use Google Authenticator + security.pam.services.sshd = { + # Enable Google Authenticator for SSH + googleAuthenticator = { + enable = true; + # Allow users without TOTP configured (set to false to require TOTP for all users) + # nullOk = false; + # Show secret in QR code + # secret = ""; # Per-user secrets stored in ~/.google_authenticator + }; + + # Configure PAM authentication stack + # Order: password first, then TOTP + # The googleAuthenticator option automatically adds the PAM module + # but we can customize the text prompt + # text = "Verification code: "; + }; + + # Note: The SSH configuration in services.ssh.nix must have: + # - UsePAM = true (already set) + # - KbdInteractiveAuthentication = true (already set) + # - ChallengeResponseAuthentication = true (needs to be enabled) +} + diff --git a/qotom/nfb/services.ssh.nix b/qotom/nfb/services.ssh.nix index 9b482b5..094deea 100644 --- a/qotom/nfb/services.ssh.nix +++ b/qotom/nfb/services.ssh.nix @@ -44,9 +44,18 @@ KbdInteractiveAuthentication = true; PermitRootLogin = "prohibit-password"; #PasswordAuthentication = false; - ChallengeResponseAuthentication = false; + ChallengeResponseAuthentication = true; # Required for Google Authenticator TOTP #X11Forwarding = false; #GatewayPorts = "no"; + + # Performance optimizations - reduce delays and improve prompt responsiveness + UseDns = false; # Disable DNS reverse lookups to speed up connections + GSSAPIAuthentication = false; # Disable GSSAPI to prevent authentication delays + UseLogin = false; # Use sshd's built-in login instead of /bin/login + + # Terminal initialization + PrintMotd = false; # Disable motd to speed up login (can be re-enabled if desired) + PrintLastLog = true; # Keep last login message }; }; diff --git a/qotom/nfb/test-terminal-ssh.sh b/qotom/nfb/test-terminal-ssh.sh new file mode 100644 index 0000000..36f0d9f --- /dev/null +++ b/qotom/nfb/test-terminal-ssh.sh @@ -0,0 +1,81 @@ +#!/usr/bin/env bash +# Terminal and SSH Diagnostic Script +# Run this on your client machine (l) + +set -e + +echo "=== Terminal Diagnostic Tests ===" +echo + +# Test 1: Terminal Info +echo "1. Terminal Information:" +echo " TERM=$TERM" +echo " COLORTERM=${COLORTERM:-not set}" +echo " TERM_PROGRAM=${TERM_PROGRAM:-not set}" +echo " Terminal: $(tput longname 2>/dev/null || echo 'unknown')" +echo + +# Test 2: Local Terminal Rendering Speed +echo "2. Testing local terminal rendering:" +echo -n " Immediate output test... " +sleep 0.1 +echo "✓ Pass" +echo + +# Test 3: SSH Connection Timing (without TTY) +echo "3. Testing SSH connection speed (no TTY):" +time ssh -o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=no \ + 172.16.40.185 'echo "Connection test"' 2>&1 | grep -v "^Warning:" || true +echo + +# Test 4: SSH Connection Timing (with TTY) +echo "4. Testing SSH connection speed (with TTY):" +time ssh -tt 172.16.40.185 'echo "TTY test"; exit' 2>&1 | head -3 +echo + +# Test 5: Test prompt delay +echo "5. Testing SSH prompt delay:" +echo " Connecting and measuring time to prompt..." +( + timeout 10 ssh -o ConnectTimeout=5 172.16.40.185 <<'REMOTE' + echo "Remote shell started" + sleep 0.5 + echo "Ready" +REMOTE +) 2>&1 | while IFS= read -r line; do + echo " [$(date +%H:%M:%S.%N | cut -b1-12)] $line" +done +echo + +# Test 6: Terminal Control Sequences +echo "6. Testing terminal control sequences:" +printf " \033[2J\033[H" # Clear screen +printf " \033[32mGreen text test\033[0m\n" +echo " If colors work above, terminal control sequences are OK" +echo + +# Test 7: Check for buffering issues +echo "7. Testing output buffering:" +echo -n " Line 1 (no newline)... " +sleep 0.2 +echo "Line 2 (with newline)" +echo + +# Test 8: SSH multiplexing status +echo "8. SSH Multiplexing Status:" +if [ -S ~/.ssh/master-das@172.16.40.185:22 ]; then + echo " Master socket exists: ~/.ssh/master-das@172.16.40.185:22" + ls -lh ~/.ssh/master-das@172.16.40.185:22 2>/dev/null || echo " (socket exists but may be stale)" +else + echo " No master socket found (multiplexing not active)" +fi +echo + +echo "=== Diagnostic Complete ===" +echo +echo "Recommendations:" +echo " - If Test 4 is slow (>2 seconds), the issue is server-side" +echo " - If Tests 3-4 are fast but interactive SSH is slow, it's terminal buffering" +echo " - Try different terminals: xterm, alacritty, kitty, gnome-terminal" +echo " - For Ghostty specifically, try: ssh -o RequestTTY=force ..." +