ops-jrz1/modules/security/ssh-hardening.nix
Dan bcfdf962f3 Disable security modules pending fixes, patch ssh-hardening
ssh-hardening.nix had fatal bugs:
- UsePAM=false breaks NixOS SSH auth
- Protocol=2 deprecated, crashes modern sshd
- AllowUsers defaulted to ["admin"], locks out all users

Partial fixes applied but module still unsafe to enable.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 17:09:07 -08:00

130 lines
4.1 KiB
Nix

# SSH hardening configuration for production security
{ config, lib, ... }:
with lib;
{
options.security.ssh-hardening = {
enable = mkEnableOption "SSH security hardening";
level = mkOption {
type = types.enum [ "development" "production" "paranoid" ];
default = "production";
description = "Security level for SSH configuration";
};
allowUsers = mkOption {
type = types.listOf types.str;
default = [ ];
description = "Users allowed to SSH (empty = allow all authenticated users)";
};
maxAuthTries = mkOption {
type = types.int;
default = 3;
description = "Maximum authentication attempts";
};
maxSessions = mkOption {
type = types.int;
default = 10;
description = "Maximum concurrent sessions";
};
};
config = mkIf config.security.ssh-hardening.enable {
services.openssh = {
enable = true;
settings = {
# Authentication settings
PermitRootLogin = if config.security.ssh-hardening.level == "development"
then "prohibit-password"
else "no";
PasswordAuthentication = false;
KbdInteractiveAuthentication = false;
ChallengeResponseAuthentication = false;
# Security settings
PermitEmptyPasswords = false;
# UsePAM must stay true - NixOS SSH auth requires PAM
X11Forwarding = false;
AllowAgentForwarding = config.security.ssh-hardening.level == "development";
AllowTcpForwarding = config.security.ssh-hardening.level != "paranoid";
GatewayPorts = "no";
# User restrictions (only set if explicitly configured)
AllowUsers = mkIf (config.security.ssh-hardening.allowUsers != [])
config.security.ssh-hardening.allowUsers;
# Logging
LogLevel = if config.security.ssh-hardening.level == "paranoid" then "VERBOSE" else "INFO";
# Timing settings
LoginGraceTime = 30;
ClientAliveInterval = 300;
ClientAliveCountMax = 2;
TCPKeepAlive = false;
# Crypto settings for security
Ciphers = [
"chacha20-poly1305@openssh.com"
"aes256-gcm@openssh.com"
"aes128-gcm@openssh.com"
"aes256-ctr"
"aes192-ctr"
"aes128-ctr"
];
Macs = [
"hmac-sha2-256-etm@openssh.com"
"hmac-sha2-512-etm@openssh.com"
"hmac-sha2-256"
"hmac-sha2-512"
];
KexAlgorithms = [
"curve25519-sha256@libssh.org"
"diffie-hellman-group16-sha512"
"diffie-hellman-group18-sha512"
"diffie-hellman-group14-sha256"
];
};
extraConfig = ''
# Rate limiting
MaxAuthTries ${toString config.security.ssh-hardening.maxAuthTries}
MaxSessions ${toString config.security.ssh-hardening.maxSessions}
MaxStartups 10:30:60
# Banner
${optionalString (config.security.ssh-hardening.level != "development") ''
Banner /etc/ssh/banner
''}
# Additional security
${optionalString (config.security.ssh-hardening.level == "paranoid") ''
StrictModes yes
IgnoreRhosts yes
HostbasedAuthentication no
PermitUserEnvironment no
Compression delayed
''}
'';
};
# Create SSH banner for non-development environments
environment.etc."ssh/banner" = mkIf (config.security.ssh-hardening.level != "development") {
text = ''
################################################################################
# NOTICE #
# #
# This system is for authorized users only. All activity may be monitored #
# and recorded. Unauthorized access is prohibited. #
# #
################################################################################
'';
mode = "0644";
};
};
}