diff --git a/attributes/default.rb b/attributes/default.rb index c8d8e38..c4da0d4 100644 --- a/attributes/default.rb +++ b/attributes/default.rb @@ -46,55 +46,57 @@ default['ssh-hardening']['sshserver']['service_name'] = 'ssh' end +# sshd + ssh client +default['ssh-hardening']['network']['ipv6']['enable'] = false default['ssh-hardening']['config_disclaimer'] = '**Note:** This file was automatically created by Hardening Framework (dev-sec.io) configuration. If you use its automated setup, do not edit this file directly, but adjust the automation instead.' -default['ssh-hardening']['network']['ipv6']['enable'] = false # sshd + ssh -default['ssh-hardening']['ssh']['server']['kex'] = nil # nil = calculate best combination for server version +default['ssh-hardening']['ssh']['ports'] = [22] + +# ssh client default['ssh-hardening']['ssh']['client']['mac'] = nil # nil = calculate best combination for client -default['ssh-hardening']['ssh']['server']['cipher'] = nil # nil = calculate best combination for server version default['ssh-hardening']['ssh']['client']['kex'] = nil # nil = calculate best combination for client -default['ssh-hardening']['ssh']['server']['mac'] = nil # nil = calculate best combination for server version default['ssh-hardening']['ssh']['client']['cipher'] = nil # nil = calculate best combination for client -default['ssh-hardening']['ssh']['client']['cbc_required'] = false # ssh -default['ssh-hardening']['ssh']['server']['cbc_required'] = false # sshd -default['ssh-hardening']['ssh']['client']['weak_hmac'] = false # ssh -default['ssh-hardening']['ssh']['server']['weak_hmac'] = false # sshd -default['ssh-hardening']['ssh']['client']['weak_kex'] = false # ssh -default['ssh-hardening']['ssh']['server']['weak_kex'] = false # sshd -default['ssh-hardening']['ssh']['ports'] = [22] # sshd + ssh -default['ssh-hardening']['ssh']['listen_to'] = ['0.0.0.0'] # sshd -default['ssh-hardening']['ssh']['host_key_files'] = ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_dsa_key', '/etc/ssh/ssh_host_ecdsa_key'] # sshd -default['ssh-hardening']['ssh']['client_alive_interval'] = 600 # sshd, 10min -default['ssh-hardening']['ssh']['client_alive_count'] = 3 # sshd, ~> 3 x interval -default['ssh-hardening']['ssh']['remote_hosts'] = [] # ssh -default['ssh-hardening']['ssh']['allow_root_with_key'] = false # sshd -default['ssh-hardening']['ssh']['allow_tcp_forwarding'] = false # sshd -default['ssh-hardening']['ssh']['allow_agent_forwarding'] = false # sshd -default['ssh-hardening']['ssh']['allow_x11_forwarding'] = false # sshd -default['ssh-hardening']['ssh']['use_pam'] = false # sshd -default['ssh-hardening']['ssh']['challenge_response_authentication'] = false # sshd -default['ssh-hardening']['ssh']['deny_users'] = [] # sshd -default['ssh-hardening']['ssh']['allow_users'] = [] # sshd -default['ssh-hardening']['ssh']['deny_groups'] = [] # sshd -default['ssh-hardening']['ssh']['allow_groups'] = [] # sshd -default['ssh-hardening']['ssh']['print_motd'] = false # sshd -default['ssh-hardening']['ssh']['print_last_log'] = false # sshd -# set this to nil to disable banner or provide a path like '/etc/issue.net' -default['ssh-hardening']['ssh']['banner'] = nil # sshd -default['ssh-hardening']['ssh']['os_banner'] = false # sshd (Debian OS family) +default['ssh-hardening']['ssh']['client']['cbc_required'] = false +default['ssh-hardening']['ssh']['client']['weak_hmac'] = false +default['ssh-hardening']['ssh']['client']['weak_kex'] = false -# set this to nil to let us use the default OpenSSH in case it's not set by the user -default['ssh-hardening']['ssh']['use_dns'] = nil # sshd -# set this to nil to let us detect the attribute based on the node platform -default['ssh-hardening']['ssh']['use_privilege_separation'] = nil -default['ssh-hardening']['ssh']['login_grace_time'] = '30s' # sshd -default['ssh-hardening']['ssh']['max_auth_tries'] = 2 # sshd -default['ssh-hardening']['ssh']['max_sessions'] = 10 # sshd +default['ssh-hardening']['ssh']['client']['remote_hosts'] = [] default['ssh-hardening']['ssh']['client']['password_authentication'] = false # ssh -default['ssh-hardening']['ssh']['server']['password_authentication'] = false # sshd # http://undeadly.org/cgi?action=article&sid=20160114142733 default['ssh-hardening']['ssh']['client']['roaming'] = false -# Define SFTP options -default['ssh-hardening']['ssh']['sftp']['enable'] = false -default['ssh-hardening']['ssh']['sftp']['group'] = 'sftponly' -default['ssh-hardening']['ssh']['sftp']['chroot'] = '/home/%u' +# sshd +default['ssh-hardening']['ssh']['server']['kex'] = nil # nil = calculate best combination for server version +default['ssh-hardening']['ssh']['server']['cipher'] = nil # nil = calculate best combination for server version +default['ssh-hardening']['ssh']['server']['mac'] = nil # nil = calculate best combination for server version +default['ssh-hardening']['ssh']['server']['cbc_required'] = false +default['ssh-hardening']['ssh']['server']['weak_hmac'] = false +default['ssh-hardening']['ssh']['server']['weak_kex'] = false +default['ssh-hardening']['ssh']['server']['listen_to'] = ['0.0.0.0'] +default['ssh-hardening']['ssh']['server']['host_key_files'] = ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_dsa_key', '/etc/ssh/ssh_host_ecdsa_key'] +default['ssh-hardening']['ssh']['server']['client_alive_interval'] = 600 # 10min +default['ssh-hardening']['ssh']['server']['client_alive_count'] = 3 # ~> 3 x interval + +default['ssh-hardening']['ssh']['server']['allow_root_with_key'] = false +default['ssh-hardening']['ssh']['server']['allow_tcp_forwarding'] = false +default['ssh-hardening']['ssh']['server']['allow_agent_forwarding'] = false +default['ssh-hardening']['ssh']['server']['allow_x11_forwarding'] = false +default['ssh-hardening']['ssh']['server']['use_pam'] = false +default['ssh-hardening']['ssh']['server']['challenge_response_authentication'] = false +default['ssh-hardening']['ssh']['server']['deny_users'] = [] +default['ssh-hardening']['ssh']['server']['allow_users'] = [] +default['ssh-hardening']['ssh']['server']['deny_groups'] = [] +default['ssh-hardening']['ssh']['server']['allow_groups'] = [] +default['ssh-hardening']['ssh']['server']['print_motd'] = false +default['ssh-hardening']['ssh']['server']['print_last_log'] = false +default['ssh-hardening']['ssh']['server']['banner'] = nil # set this to nil to disable banner or provide a path like '/etc/issue.net' +default['ssh-hardening']['ssh']['server']['os_banner'] = false # (Debian OS family) +default['ssh-hardening']['ssh']['server']['use_dns'] = nil # set this to nil to let us use the default OpenSSH in case it's not set by the user +default['ssh-hardening']['ssh']['server']['use_privilege_separation'] = nil # set this to nil to let us detect the attribute based on the node platform +default['ssh-hardening']['ssh']['server']['login_grace_time'] = '30s' +default['ssh-hardening']['ssh']['server']['max_auth_tries'] = 2 +default['ssh-hardening']['ssh']['server']['max_sessions'] = 10 +default['ssh-hardening']['ssh']['server']['password_authentication'] = false +# sshd sftp options +default['ssh-hardening']['ssh']['server']['sftp']['enable'] = false +default['ssh-hardening']['ssh']['server']['sftp']['group'] = 'sftponly' +default['ssh-hardening']['ssh']['server']['sftp']['chroot'] = '/home/%u' diff --git a/recipes/client.rb b/recipes/client.rb index b5ddc01..097db8e 100644 --- a/recipes/client.rb +++ b/recipes/client.rb @@ -38,7 +38,6 @@ variables( mac: node['ssh-hardening']['ssh']['client']['mac'] || DevSec::Ssh.get_client_macs(node['ssh-hardening']['ssh']['client']['weak_hmac']), kex: node['ssh-hardening']['ssh']['client']['kex'] || DevSec::Ssh.get_client_kexs(node['ssh-hardening']['ssh']['client']['weak_kex']), - cipher: node['ssh-hardening']['ssh']['client']['cipher'] || DevSec::Ssh.get_client_ciphers(node['ssh-hardening']['ssh']['client']['cbc_required']), - roaming: node['ssh-hardening']['ssh']['client']['roaming'] + cipher: node['ssh-hardening']['ssh']['client']['cipher'] || DevSec::Ssh.get_client_ciphers(node['ssh-hardening']['ssh']['client']['cbc_required']) ) end diff --git a/recipes/server.rb b/recipes/server.rb index 98895b9..fd0d243 100644 --- a/recipes/server.rb +++ b/recipes/server.rb @@ -69,11 +69,7 @@ mac: node['ssh-hardening']['ssh']['server']['mac'] || DevSec::Ssh.get_server_macs(node['ssh-hardening']['ssh']['server']['weak_hmac']), kex: node['ssh-hardening']['ssh']['server']['kex'] || DevSec::Ssh.get_server_kexs(node['ssh-hardening']['ssh']['server']['weak_kex']), cipher: node['ssh-hardening']['ssh']['server']['cipher'] || DevSec::Ssh.get_server_ciphers(node['ssh-hardening']['ssh']['server']['cbc_required']), - use_priv_sep: node['ssh-hardening']['ssh']['use_privilege_separation'] || DevSec::Ssh.get_server_privilege_separarion, - deny_users: node['ssh-hardening']['ssh']['deny_users'], - allow_users: node['ssh-hardening']['ssh']['allow_users'], - deny_groups: node['ssh-hardening']['ssh']['deny_groups'], - allow_groups: node['ssh-hardening']['ssh']['allow_groups'] + use_priv_sep: node['ssh-hardening']['ssh']['use_privilege_separation'] || DevSec::Ssh.get_server_privilege_separarion ) notifies :restart, 'service[sshd]' end diff --git a/spec/recipes/server_spec.rb b/spec/recipes/server_spec.rb index 092169b..ac08b8b 100644 --- a/spec/recipes/server_spec.rb +++ b/spec/recipes/server_spec.rb @@ -177,7 +177,7 @@ context 'with attribute deny_users' do cached(:chef_run) do ChefSpec::ServerRunner.new do |node| - node.normal['ssh-hardening']['ssh']['deny_users'] = %w(someuser) + node.normal['ssh-hardening']['ssh']['server']['deny_users'] = %w(someuser) end.converge(described_recipe) end @@ -190,7 +190,7 @@ context 'with attribute deny_users mutiple' do cached(:chef_run) do ChefSpec::ServerRunner.new do |node| - node.normal['ssh-hardening']['ssh']['deny_users'] = %w(someuser otheruser) + node.normal['ssh-hardening']['ssh']['server']['deny_users'] = %w(someuser otheruser) end.converge(described_recipe) end @@ -210,7 +210,7 @@ context 'with attribute use_dns set to false' do cached(:chef_run) do ChefSpec::ServerRunner.new do |node| - node.normal['ssh-hardening']['ssh']['use_dns'] = false + node.normal['ssh-hardening']['ssh']['server']['use_dns'] = false end.converge(described_recipe) end @@ -223,7 +223,7 @@ context 'with attribute use_dns set to true' do cached(:chef_run) do ChefSpec::ServerRunner.new do |node| - node.normal['ssh-hardening']['ssh']['use_dns'] = true + node.normal['ssh-hardening']['ssh']['server']['use_dns'] = true end.converge(described_recipe) end @@ -243,7 +243,7 @@ context 'with attribute ["sftp"]["enable"] set to true' do cached(:chef_run) do ChefSpec::ServerRunner.new do |node| - node.normal['ssh-hardening']['ssh']['sftp']['enable'] = true + node.normal['ssh-hardening']['ssh']['server']['sftp']['enable'] = true end.converge(described_recipe) end @@ -256,8 +256,8 @@ context 'with attribute ["sftp"]["enable"] set to true and ["sftp"]["group"] set to "testgroup"' do cached(:chef_run) do ChefSpec::ServerRunner.new do |node| - node.normal['ssh-hardening']['ssh']['sftp']['enable'] = true - node.normal['ssh-hardening']['ssh']['sftp']['group'] = 'testgroup' + node.normal['ssh-hardening']['ssh']['server']['sftp']['enable'] = true + node.normal['ssh-hardening']['ssh']['server']['sftp']['group'] = 'testgroup' end.converge(described_recipe) end @@ -270,8 +270,8 @@ context 'with attribute ["sftp"]["enable"] set to true and ["sftp"]["chroot"] set to "/export/home/%u"' do cached(:chef_run) do ChefSpec::ServerRunner.new do |node| - node.normal['ssh-hardening']['ssh']['sftp']['enable'] = true - node.normal['ssh-hardening']['ssh']['sftp']['chroot'] = 'test_home_dir' + node.normal['ssh-hardening']['ssh']['server']['sftp']['enable'] = true + node.normal['ssh-hardening']['ssh']['server']['sftp']['chroot'] = 'test_home_dir' end.converge(described_recipe) end diff --git a/templates/default/openssh.conf.erb b/templates/default/openssh.conf.erb index 5e6bf5f..49f6ebb 100644 --- a/templates/default/openssh.conf.erb +++ b/templates/default/openssh.conf.erb @@ -14,7 +14,7 @@ # Address family should always be limited to the active network configuration. AddressFamily <%= ((@node['ssh-hardening']['network']['ipv6']['enable']) ? "any" : "inet" ) %> -<% Array(@node['ssh-hardening']['ssh']['remote_hosts']).each do |host| %> +<% Array(@node['ssh-hardening']['ssh']['client']['remote_hosts']).each do |host| %> # Restrict the following configuration to be limited to this Host. Host <%= host %> <% end %> @@ -111,4 +111,4 @@ Compression yes #VisualHostKey yes # http://undeadly.org/cgi?action=article&sid=20160114142733 -UseRoaming <%= @roaming ? 'yes' : 'no' %> +UseRoaming <%= @node['ssh-hardening']['ssh']['client']['roaming'] ? 'yes' : 'no' %> diff --git a/templates/default/opensshd.conf.erb b/templates/default/opensshd.conf.erb index eb3c491..7211bc8 100644 --- a/templates/default/opensshd.conf.erb +++ b/templates/default/opensshd.conf.erb @@ -12,7 +12,7 @@ # =================== # Either disable or only allow root login via certificates. -<% if @node['ssh-hardening']['ssh']['allow_root_with_key'] %> +<% if @node['ssh-hardening']['ssh']['server']['allow_root_with_key'] %> PermitRootLogin without-password <% else %> PermitRootLogin no @@ -27,12 +27,12 @@ Port <%= ssh_port %> AddressFamily <%= ((@node['ssh-hardening']['network']['ipv6']['enable']) ? "any" : "inet" ) %> # Define which addresses sshd should listen to. Default to `0.0.0.0`, ie make sure you put your desired address in here, since otherwise sshd will listen to everyone. -<% Array(@node['ssh-hardening']['ssh']['listen_to']).each do |ssh_ip| %> +<% Array(@node['ssh-hardening']['ssh']['server']['listen_to']).each do |ssh_ip| %> ListenAddress <%= ssh_ip %> <% end %> # List HostKeys here. -<% Array(@node['ssh-hardening']['ssh']['host_key_files']).each do |host_key_file| %> +<% Array(@node['ssh-hardening']['ssh']['server']['host_key_files']).each do |host_key_file| %> HostKey <%= host_key_file %> # Req 20 <% end %> @@ -88,9 +88,9 @@ KexAlgorithms <%= @kex %> UseLogin no UsePrivilegeSeparation <%= @use_priv_sep %> PermitUserEnvironment no -LoginGraceTime <%= @node['ssh-hardening']['ssh']['login_grace_time'] %> -MaxAuthTries <%= @node['ssh-hardening']['ssh']['max_auth_tries'] %> -MaxSessions <%= @node['ssh-hardening']['ssh']['max_sessions'] %> +LoginGraceTime <%= @node['ssh-hardening']['ssh']['server']['login_grace_time'] %> +MaxAuthTries <%= @node['ssh-hardening']['ssh']['server']['max_auth_tries'] %> +MaxSessions <%= @node['ssh-hardening']['ssh']['server']['max_sessions'] %> MaxStartups 10:30:100 # Enable public key authentication @@ -102,12 +102,12 @@ IgnoreUserKnownHosts yes HostbasedAuthentication no # Enable PAM to enforce system wide rules -UsePAM <%= ((@node['ssh-hardening']['ssh']['use_pam']) ? "yes" : "no" ) %> +UsePAM <%= ((@node['ssh-hardening']['ssh']['server']['use_pam']) ? "yes" : "no" ) %> # Disable password-based authentication, it can allow for potentially easier brute-force attacks. <% passsword_auth = @node['ssh-hardening']['ssh']['server']['password_authentication'] || !!@node['ssh-hardening']['ssh']['password_authentication'] -%> PasswordAuthentication <%= (passsword_auth ? "yes" : "no" ) %> PermitEmptyPasswords no -ChallengeResponseAuthentication <%= (@node['ssh-hardening']['ssh']['challenge_response_authentication'] ? "yes" : "no" ) %> +ChallengeResponseAuthentication <%= (@node['ssh-hardening']['ssh']['server']['challenge_response_authentication'] ? "yes" : "no" ) %> # Only enable Kerberos authentication if it is configured. KerberosAuthentication no @@ -120,23 +120,23 @@ GSSAPIAuthentication no GSSAPICleanupCredentials yes # In case you don't use PAM (`UsePAM no`), you can alternatively restrict users and groups here. For key-based authentication this is not necessary, since all keys must be explicitely enabled. -<% unless @node['ssh-hardening']['ssh']['deny_users'].empty? %> -DenyUsers <%= @node['ssh-hardening']['ssh']['deny_users'].join(' ') %> +<% unless @node['ssh-hardening']['ssh']['server']['deny_users'].empty? %> +DenyUsers <%= @node['ssh-hardening']['ssh']['server']['deny_users'].join(' ') %> <% else %> #DenyUsers * <% end %> -<% unless @node['ssh-hardening']['ssh']['allow_users'].empty? %> -AllowUsers <%= @node['ssh-hardening']['ssh']['allow_users'].join(' ') %> +<% unless @node['ssh-hardening']['ssh']['server']['allow_users'].empty? %> +AllowUsers <%= @node['ssh-hardening']['ssh']['server']['allow_users'].join(' ') %> <% else %> #AllowUsers user1 <% end %> -<% unless @node['ssh-hardening']['ssh']['deny_groups'].empty? %> -DenyGroups <%= @node['ssh-hardening']['ssh']['deny_groups'].join(' ') %> +<% unless @node['ssh-hardening']['ssh']['server']['deny_groups'].empty? %> +DenyGroups <%= @node['ssh-hardening']['ssh']['server']['deny_groups'].join(' ') %> <% else %> #DenyGroups * <% end %> -<% unless @node['ssh-hardening']['ssh']['allow_groups'].empty? %> -AllowGroups <%= @node['ssh-hardening']['ssh']['allow_groups'].join(' ') %> +<% unless @node['ssh-hardening']['ssh']['server']['allow_groups'].empty? %> +AllowGroups <%= @node['ssh-hardening']['ssh']['server']['allow_groups'].join(' ') %> <% else %> #AllowGroups group1 <% end %> @@ -149,25 +149,25 @@ AllowGroups <%= @node['ssh-hardening']['ssh']['allow_groups'].join(' ') %> TCPKeepAlive no # Manage `ClientAlive..` signals via interval and maximum count. This will periodically check up to a `..CountMax` number of times within `..Interval` timeframe, and abort the connection once these fail. -ClientAliveInterval <%= @node['ssh-hardening']['ssh']['client_alive_interval'] %> -ClientAliveCountMax <%= @node['ssh-hardening']['ssh']['client_alive_count'] %> +ClientAliveInterval <%= @node['ssh-hardening']['ssh']['server']['client_alive_interval'] %> +ClientAliveCountMax <%= @node['ssh-hardening']['ssh']['server']['client_alive_count'] %> # Disable tunneling PermitTunnel no # Disable forwarding tcp connections. # no real advantage without denied shell access -AllowTcpForwarding <%= ((@node['ssh-hardening']['ssh']['allow_tcp_forwarding']) ? 'yes' : 'no' ) %> +AllowTcpForwarding <%= ((@node['ssh-hardening']['ssh']['server']['allow_tcp_forwarding']) ? 'yes' : 'no' ) %> # Disable agent formwarding, since local agent could be accessed through forwarded connection. # no real advantage without denied shell access -AllowAgentForwarding <%= ((@node['ssh-hardening']['ssh']['allow_agent_forwarding']) ? 'yes' : 'no' ) %> +AllowAgentForwarding <%= ((@node['ssh-hardening']['ssh']['server']['allow_agent_forwarding']) ? 'yes' : 'no' ) %> # Do not allow remote port forwardings to bind to non-loopback addresses. GatewayPorts no # Disable X11 forwarding, since local X11 display could be accessed through forwarded connection. -X11Forwarding <%= ((@node['ssh-hardening']['ssh']['allow_x11_forwarding']) ? 'yes' : 'no' ) %> +X11Forwarding <%= ((@node['ssh-hardening']['ssh']['server']['allow_x11_forwarding']) ? 'yes' : 'no' ) %> X11UseLocalhost yes @@ -175,35 +175,35 @@ X11UseLocalhost yes # =================== -PrintMotd <%= ((@node['ssh-hardening']['ssh']['print_motd']) ? 'yes' : 'no' ) %> -PrintLastLog <%= ((@node['ssh-hardening']['ssh']['print_last_log']) ? 'yes' : 'no' ) %> -Banner <%= @node['ssh-hardening']['ssh']['banner'] ? @node['ssh-hardening']['ssh']['banner'] : 'none' %> +PrintMotd <%= ((@node['ssh-hardening']['ssh']['server']['print_motd']) ? 'yes' : 'no' ) %> +PrintLastLog <%= ((@node['ssh-hardening']['ssh']['server']['print_last_log']) ? 'yes' : 'no' ) %> +Banner <%= @node['ssh-hardening']['ssh']['server']['banner'] ? @node['ssh-hardening']['ssh']['server']['banner'] : 'none' %> <% if @node['platform_family'] == 'debian' %> -DebianBanner <%= @node['ssh-hardening']['ssh']['os_banner'] ? 'yes' : 'no' %> +DebianBanner <%= @node['ssh-hardening']['ssh']['server']['os_banner'] ? 'yes' : 'no' %> <% end %> -<% if @node['ssh-hardening']['ssh']['use_dns'].nil? %> +<% if @node['ssh-hardening']['ssh']['server']['use_dns'].nil? %> # Since OpenSSH 6.8, this value defaults to 'no' #UseDNS no <% else %> -UseDNS <%= ((@node['ssh-hardening']['ssh']['use_dns']) ? 'yes' : 'no' ) %> +UseDNS <%= ((@node['ssh-hardening']['ssh']['server']['use_dns']) ? 'yes' : 'no' ) %> <% end %> #PidFile /var/run/sshd.pid #MaxStartups 10 #ChrootDirectory none #ChrootDirectory /home/%u -<% if @node['ssh-hardening']['ssh']['sftp']['enable'] %> +<% if @node['ssh-hardening']['ssh']['server']['sftp']['enable'] %> # Configuration, in case SFTP is used ## override default of no subsystems ## Subsystem sftp /opt/app/openssh5/libexec/sftp-server Subsystem sftp internal-sftp -l VERBOSE ## These lines must appear at the *end* of sshd_config -Match Group <%= @node['ssh-hardening']['ssh']['sftp']['group'] %> +Match Group <%= @node['ssh-hardening']['ssh']['server']['sftp']['group'] %> ForceCommand internal-sftp -l VERBOSE -ChrootDirectory <%= @node['ssh-hardening']['ssh']['sftp']['chroot'] %> +ChrootDirectory <%= @node['ssh-hardening']['ssh']['server']['sftp']['chroot'] %> AllowTcpForwarding no AllowAgentForwarding no PasswordAuthentication no