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>
130 lines
4.1 KiB
Nix
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";
|
|
};
|
|
};
|
|
} |