From b476a3f72541de5df770b34a7d2b109731753631 Mon Sep 17 00:00:00 2001 From: Phil Friderici Date: Thu, 23 Feb 2017 14:44:46 +0100 Subject: [PATCH] Enhance compatibility with Solaris Some OpenSSH parameters are not compatible with Solaris SSH. They do break if they are included into the configuration file(s). This patch does not include them by default on Solaris anymore. Changed parameters: sshd_config_tcp_keepalive (TCPKeepAlive in sshd_config) sshd_config_permittunnel (PermitTunnel in sshd_config) sshd_config_maxsessions (MaxSessions in sshd_config) ssh_config_hash_known_hosts (HashKnownHosts in ssh_config) --- README.md | 34 +++++++++++++----- manifests/init.pp | 55 +++++++++++++++++++--------- spec/classes/init_spec.rb | 60 ++++++++++++++++++++++++------- spec/fixtures/sshd_config_solaris | 2 -- templates/sshd_config.erb | 12 ++++--- 5 files changed, 121 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 1a13b86..160668a 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,14 @@ only), 1.9.3, 2.0.0, 2.1.0 and 2.3.1 (Puppet v4 only). * Solaris 10 * Solaris 11 +If you use the Sun Solaris SSH, please keep in mind that not all parameters can be used. + +Unsupported parameters for ssh_config: +AddressFamily, Tunnel, TunnelDevice, PermitLocalCommand, HashKnownHosts + +Unsupported parameters for sshd_config: +KerberosOrLocalPasswd, KerberosTicketCleanup, KerberosGetAFSToken, TCPKeepAlive, ShowPatchLevel, MaxSessions, PermitTunnel + === # Parameters @@ -63,6 +71,8 @@ Note that existing names and addresses in known hosts files will not be converte but may be manually hashed using ssh-keygen. Use of this option may break facilities such as tab-completion that rely on being able to read unhashed host names from ~/.ssh/known_hosts. +A value of 'unset' will not add this parameter to the configuration file. + - *Default*: 'USE_DEFAULTS' ssh_config_path @@ -451,22 +461,29 @@ are sent, death of the connection or crash of one of the machines will be proper However, this means that connections will die if the route is down temporarily, and some people find it annoying. On the other hand, if TCP keepalives are not sent, sessions may hang indefinitely on the server, leaving ``ghost'' users and consuming server resources. -The default is ``yes'' (to send TCP keepalive messages), and the server will notice if the -network goes down or the client host crashes. This avoids infinitely hanging sessions. +A value of 'unset' will not add this parameter to the configuration file. -- *Default*: 'yes' +On Linux the default is set to ``yes'' (to send TCP keepalive messages), and the server will +notice if the network goes down or the client host crashes. This avoids infinitely hanging +sessions. +On Solaris the default is to not add this parameter to the configuration file. + +- *Default*: undef sshd_config_permittunnel ----------------------- PermitTunnel in sshd_config. -Specifies whether tun(4) device forwarding is allowed. The argument must be -'yes', 'point-to-point' (layer 3), 'ethernet' (layer 2), or 'no'. -Specifying 'yes' permits both 'point-to-point' and 'ethernet'. The -default is 'no'. +Specifies whether tun(4) device forwarding is allowed. The argument must be 'yes', +'point-to-point' (layer 3), 'ethernet' (layer 2), 'no', or 'unset' (parameter not used). +Specifying 'yes' permits both 'point-to-point' and 'ethernet'. Independent of this setting, the permissions of the selected tun(4) device must allow access to the user. +A value of 'unset' will not add this parameter to the configuration file. -- *Default*: 'no' +On Linux the default is set to ``no''. +On Solaris the default is to not add this parameter to the configuration file. + +- *Default*: undef sshd_config_ciphers ------------------- @@ -519,6 +536,7 @@ Specifies the maximum number of concurrent unauthenticated connections to the SS sshd_config_maxsessions ----------------------- Specifies the maximum number of open sessions permitted per network connection. +A value of 'unset' or undef will not add this parameter to the configuration file. - *Default*: undef diff --git a/manifests/init.pp b/manifests/init.pp index 809e911..a10df3f 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -109,8 +109,8 @@ class ssh ( $keys = undef, $manage_root_ssh_config = false, $root_ssh_config_content = "# This file is being maintained by Puppet.\n# DO NOT EDIT\n", - $sshd_config_tcp_keepalive = 'yes', - $sshd_config_permittunnel = 'no', + $sshd_config_tcp_keepalive = undef, + $sshd_config_permittunnel = undef, ) { case $::osfamily { @@ -136,6 +136,8 @@ class ssh ( $default_sshd_config_serverkeybits = '1024' $default_sshd_config_hostkey = [ '/etc/ssh/ssh_host_rsa_key' ] $default_sshd_addressfamily = 'any' + $default_sshd_config_tcp_keepalive = 'yes' + $default_sshd_config_permittunnel = 'no' } 'Suse': { $default_packages = 'openssh' @@ -157,6 +159,8 @@ class ssh ( $default_sshd_config_serverkeybits = '1024' $default_sshd_config_hostkey = [ '/etc/ssh/ssh_host_rsa_key' ] $default_sshd_addressfamily = 'any' + $default_sshd_config_tcp_keepalive = 'yes' + $default_sshd_config_permittunnel = 'no' case $::architecture { 'x86_64': { if ($::operatingsystem == 'SLES') and ($::operatingsystemrelease =~ /^12\./) { @@ -207,6 +211,8 @@ class ssh ( $default_service_hasstatus = true $default_sshd_config_serverkeybits = '1024' $default_sshd_addressfamily = 'any' + $default_sshd_config_tcp_keepalive = 'yes' + $default_sshd_config_permittunnel = 'no' } 'Solaris': { $default_ssh_config_hash_known_hosts = undef @@ -225,6 +231,8 @@ class ssh ( $default_ssh_package_adminfile = undef $default_sshd_config_hostkey = [ '/etc/ssh/ssh_host_rsa_key' ] $default_sshd_addressfamily = undef + $default_sshd_config_tcp_keepalive = undef + $default_sshd_config_permittunnel = undef case $::kernelrelease { '5.11': { $default_packages = ['network/ssh', @@ -285,10 +293,10 @@ class ssh ( $packages_real = $packages } - if $ssh_config_hash_known_hosts == 'USE_DEFAULTS' { - $ssh_config_hash_known_hosts_real = $default_ssh_config_hash_known_hosts - } else { - $ssh_config_hash_known_hosts_real = $ssh_config_hash_known_hosts + case $ssh_config_hash_known_hosts { + 'unset': { $ssh_config_hash_known_hosts_real = undef } + 'USE_DEFAULTS': { $ssh_config_hash_known_hosts_real = $default_ssh_config_hash_known_hosts } + default: { $ssh_config_hash_known_hosts_real = $ssh_config_hash_known_hosts } } if $service_name == 'USE_DEFAULTS' { @@ -459,6 +467,23 @@ class ssh ( $sshd_addressfamily_real = $sshd_addressfamily } + case $sshd_config_maxsessions { + 'unset', undef: { $sshd_config_maxsessions_integer = undef } + default: { $sshd_config_maxsessions_integer = floor($sshd_config_maxsessions) } + } + + case $sshd_config_tcp_keepalive { + 'unset': { $sshd_config_tcp_keepalive_real = undef } + undef: { $sshd_config_tcp_keepalive_real = $default_sshd_config_tcp_keepalive } + default: { $sshd_config_tcp_keepalive_real = $sshd_config_tcp_keepalive } + } + + case $sshd_config_permittunnel { + 'unset': { $sshd_config_permittunnel_real = undef } + undef: { $sshd_config_permittunnel_real = $default_sshd_config_permittunnel } + default: { $sshd_config_permittunnel_real = $sshd_config_permittunnel } + } + # validate params if $ssh_config_ciphers != undef { validate_array($ssh_config_ciphers) @@ -485,7 +510,7 @@ class ssh ( } if $ssh_config_hash_known_hosts_real != undef { - validate_re($ssh_config_hash_known_hosts_real, '^(yes|no)$', "ssh::ssh_config_hash_known_hosts may be either 'yes' or 'no' and is set to <${ssh_config_hash_known_hosts_real}>.") + validate_re($ssh_config_hash_known_hosts_real, '^(yes|no)$', "ssh::ssh_config_hash_known_hosts may be either 'yes', 'no' or 'unset' and is set to <${ssh_config_hash_known_hosts_real}>.") } if $sshd_config_permitemptypasswords != undef { validate_re($sshd_config_permitemptypasswords, '^(yes|no)$', "ssh::sshd_config_permitemptypasswords may be either 'yes' or 'no' and is set to <${sshd_config_permitemptypasswords}>.") @@ -582,13 +607,6 @@ class ssh ( "ssh::sshd_config_maxstartups may be either an integer or three integers separated with colons, such as 10:30:100. Detected value is <${sshd_config_maxstartups}>.") } - if $sshd_config_maxsessions != undef { - $is_int_sshd_config_maxsessions = is_integer($sshd_config_maxsessions) - if $is_int_sshd_config_maxsessions == false { - fail("sshd_config_maxsessions must be an integer. Detected value is ${sshd_config_maxsessions}.") - } - } - if $sshd_config_chrootdirectory != undef { validate_absolute_path($sshd_config_chrootdirectory) } @@ -781,9 +799,14 @@ class ssh ( validate_array($sshd_config_allowgroups_real) } - validate_re($sshd_config_tcp_keepalive, '^(yes|no)$', "ssh::sshd_config_tcp_keepalive may be either 'yes' or 'no' and is set to <${sshd_config_tcp_keepalive}>.") - validate_re($sshd_config_permittunnel, '^(yes|no|point-to-point|ethernet)$', "ssh::sshd_config_permittunnel may be either 'yes', 'point-to-point', 'ethernet' or 'no' and is set to <${sshd_config_permittunnel}>.") + if $sshd_config_tcp_keepalive_real != undef { + validate_re($sshd_config_tcp_keepalive_real, '^(yes|no)$', "ssh::sshd_config_tcp_keepalive may be either 'yes', 'no' or 'unset' and is set to <${sshd_config_tcp_keepalive_real}>.") + } + + if $sshd_config_permittunnel_real != undef { + validate_re($sshd_config_permittunnel_real, '^(yes|no|point-to-point|ethernet|unset)$', "ssh::sshd_config_permittunnel may be either 'yes', 'point-to-point', 'ethernet', 'no' or 'unset' and is set to <${sshd_config_permittunnel_real}>.") + } package { $packages_real: ensure => installed, diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index bb28fe4..a6f305e 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -806,13 +806,27 @@ describe 'ssh' do end end - context 'with ssh_config_hash_known_hosts set to invalid value on valid osfamily' do - let(:params) { { :ssh_config_hash_known_hosts => 'invalid' } } + describe 'with ssh_config_hash_known_hosts param' do + ['yes','no','unset'].each do |value| + context "set to #{value}" do + let (:params) { { :ssh_config_hash_known_hosts => value } } - it 'should fail' do - expect { - should contain_class('ssh') - }.to raise_error(Puppet::Error,/ssh::ssh_config_hash_known_hosts may be either \'yes\' or \'no\' and is set to \./) + if value == 'unset' + it { should contain_file('ssh_config').without_content(/^\s*HashKnownHosts/) } + else + it { should contain_file('ssh_config').with_content(/^\s*HashKnownHosts #{value}$/) } + end + end + end + + context 'when set to an invalid value' do + let (:params) { { :ssh_config_hash_known_hosts => 'invalid' } } + + it 'should fail' do + expect { + should contain_class('ssh') + }.to raise_error(Puppet::Error,/ssh::ssh_config_hash_known_hosts may be either \'yes\', \'no\' or \'unset\' and is set to \./) + end end end @@ -971,11 +985,15 @@ describe 'ssh' do end describe 'sshd_config_permittunnel param' do - ['yes','point-to-point','ethernet','no'].each do |value| + ['yes','point-to-point','ethernet','no','unset'].each do |value| context "set to #{value}" do let (:params) { { :sshd_config_permittunnel => value } } - it { should contain_file('sshd_config').with_content(/^PermitTunnel #{value}$/) } + if value == 'unset' + it { should contain_file('sshd_config').without_content(/^\s*PermitTunnel/) } + else + it { should contain_file('sshd_config').with_content(/^PermitTunnel #{value}$/) } + end end end @@ -985,7 +1003,7 @@ describe 'ssh' do it 'should fail' do expect { should contain_class('ssh') - }.to raise_error(Puppet::Error,/ssh::sshd_config_permittunnel may be either \'yes\', \'point-to-point\', \'ethernet\' or \'no\' and is set to \./) + }.to raise_error(Puppet::Error,/ssh::sshd_config_permittunnel may be either \'yes\', \'point-to-point\', \'ethernet\', \'no\' or \'unset\' and is set to \./) end end end @@ -1812,6 +1830,12 @@ describe 'ssh' do it { should contain_file('sshd_config').with_content(/^MaxSessions 10$/) } end + context 'as a valid string ' do + let(:params) { { :sshd_config_maxsessions => 'unset' } } + + it { should contain_file('sshd_config').without_content(/^\s*MaxSessions/) } + end + context 'as an invalid type' do let(:params) { { :sshd_config_maxsessions => 'BOGUS' } } @@ -2267,13 +2291,25 @@ describe 'ssh' do end describe 'sshd_config_tcp_keepalive param' do - context 'when set to invalid' do - let(:params) { { :sshd_config_tcp_keepalive => 'invalid' } } + ['yes','no','unset'].each do |value| + context "set to #{value}" do + let (:params) { { :sshd_config_tcp_keepalive => value } } + + if value == 'unset' + it { should contain_file('sshd_config').without_content(/^\s*TCPKeepAlive/) } + else + it { should contain_file('sshd_config').with_content(/^TCPKeepAlive #{value}$/) } + end + end + end + + context 'when set to an invalid value' do + let (:params) { { :sshd_config_tcp_keepalive => 'invalid' } } it 'should fail' do expect { should contain_class('ssh') - }.to raise_error(Puppet::Error,/ssh::sshd_config_tcp_keepalive may be either \'yes\' or \'no\' and is set to \./) + }.to raise_error(Puppet::Error,/ssh::sshd_config_tcp_keepalive may be either \'yes\', \'no\' or \'unset\' and is set to \./) end end end diff --git a/spec/fixtures/sshd_config_solaris b/spec/fixtures/sshd_config_solaris index d9c4b60..653deb5 100644 --- a/spec/fixtures/sshd_config_solaris +++ b/spec/fixtures/sshd_config_solaris @@ -101,7 +101,6 @@ X11UseLocalhost yes PrintMotd yes #PrintLastLog yes #TCPKeepAlive yes -TCPKeepAlive yes #UseLogin no #UsePrivilegeSeparation yes #PermitUserEnvironment no @@ -115,7 +114,6 @@ ClientAliveCountMax 3 #MaxSessions 10 #PermitTunnel no -PermitTunnel no #ChrootDirectory none # no default banner path diff --git a/templates/sshd_config.erb b/templates/sshd_config.erb index 89752a1..51c3196 100644 --- a/templates/sshd_config.erb +++ b/templates/sshd_config.erb @@ -166,7 +166,9 @@ X11UseLocalhost <%= @sshd_x11_use_localhost %> PrintMotd <%= @sshd_config_print_motd %> #PrintLastLog yes #TCPKeepAlive yes -TCPKeepAlive <%= @sshd_config_tcp_keepalive %> +<% if @sshd_config_tcp_keepalive_real != nil -%> +TCPKeepAlive <%= @sshd_config_tcp_keepalive_real %> +<% end -%> #UseLogin no #UsePrivilegeSeparation yes #PermitUserEnvironment no @@ -188,14 +190,16 @@ MaxStartups <%= @sshd_config_maxstartups %> <% else -%> #MaxStartups 10:30:100 <% end -%> -<% if @sshd_config_maxsessions -%> -MaxSessions <%= @sshd_config_maxsessions %> +<% if @sshd_config_maxsessions_integer != nil -%> +MaxSessions <%= @sshd_config_maxsessions_integer %> <% else -%> #MaxSessions 10 <% end -%> #PermitTunnel no -PermitTunnel <%= @sshd_config_permittunnel %> +<% if @sshd_config_permittunnel_real != nil -%> +PermitTunnel <%= @sshd_config_permittunnel_real %> +<% end -%> <% if @sshd_config_chrootdirectory -%> ChrootDirectory <%= @sshd_config_chrootdirectory %> <% else -%>