Showing with 99 additions and 3 deletions.
  1. +2 −2 Gemfile
  2. +10 −0 README.md
  3. +14 −0 manifests/init.pp
  4. +1 −1 metadata.json
  5. +69 −0 spec/classes/init_spec.rb
  6. +3 −0 templates/ssh_config.erb
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ end

gem 'metadata-json-lint'
gem 'puppetlabs_spec_helper', '>= 0.1.0'
gem 'puppet-lint', '>= 1.0.0'
gem 'facter', '>= 1.7.0'
gem 'rspec-puppet', '~> 2.0'
gem 'rspec-puppet'
gem 'puppet-lint', :git => 'https://github.com/rodjek/puppet-lint.git'
gem 'puppet-lint-absolute_classname-check'
gem 'puppet-lint-alias-check'
gem 'puppet-lint-empty_string-check'
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,16 @@ This module sets this option to 'yes' on Linux and undef on Solaris.

- *Default*: 'USE_DEFAULTS'

ssh_config_use_roaming
----------------------
String to enable or disable UseRoaming in client configuration ssh_config.
Valid values are 'yes', 'no' and 'unset'. Using 'unset' will not use (print)
this configuration parameter at all. Default is set to 'no' on Linux and
'unset' on Solaris. If you have OpenSSH >= version 5.4, this should be set to
'no' to mitigate CVE-2016-0777 and CVE-2016-0778.

- *Default*: 'USE_DEFAULTS'

sshd_client_alive_interval
--------------------------
ClientAliveInterval in sshd_config.
Expand Down
14 changes: 14 additions & 0 deletions manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
$ssh_config_sendenv_xmodifiers = false,
$ssh_config_ciphers = undef,
$ssh_config_macs = undef,
$ssh_config_use_roaming = 'USE_DEFAULTS',
$ssh_config_template = 'ssh/ssh_config.erb',
$ssh_sendenv = 'USE_DEFAULTS',
$ssh_gssapiauthentication = 'yes',
Expand Down Expand Up @@ -107,6 +108,7 @@
$default_ssh_package_source = undef
$default_ssh_package_adminfile = undef
$default_ssh_sendenv = true
$default_ssh_config_use_roaming = 'no'
$default_sshd_config_subsystem_sftp = '/usr/libexec/openssh/sftp-server'
$default_sshd_config_mode = '0600'
$default_sshd_config_use_dns = 'yes'
Expand All @@ -127,6 +129,7 @@
$default_ssh_package_source = undef
$default_ssh_package_adminfile = undef
$default_ssh_sendenv = true
$default_ssh_config_use_roaming = 'no'
$default_ssh_config_forward_x11_trusted = 'yes'
$default_sshd_config_mode = '0600'
$default_sshd_config_use_dns = 'yes'
Expand Down Expand Up @@ -164,6 +167,7 @@
$default_ssh_package_source = undef
$default_ssh_package_adminfile = undef
$default_ssh_sendenv = true
$default_ssh_config_use_roaming = 'no'
$default_sshd_config_subsystem_sftp = '/usr/lib/openssh/sftp-server'
$default_sshd_config_mode = '0600'
$default_sshd_config_use_dns = 'yes'
Expand All @@ -181,6 +185,7 @@
$default_ssh_config_hash_known_hosts = undef
$default_ssh_sendenv = false
$default_ssh_config_forward_x11_trusted = undef
$default_ssh_config_use_roaming = 'unset'
$default_sshd_config_subsystem_sftp = '/usr/lib/ssh/sftp-server'
$default_sshd_config_mode = '0644'
$default_sshd_config_use_dns = undef
Expand Down Expand Up @@ -337,6 +342,12 @@
$sshd_gssapicleanupcredentials_real = $sshd_gssapicleanupcredentials
}

if $ssh_config_use_roaming == 'USE_DEFAULTS' {
$ssh_config_use_roaming_real = $default_ssh_config_use_roaming
} else {
$ssh_config_use_roaming_real = $ssh_config_use_roaming
}

if $ssh_sendenv == 'USE_DEFAULTS' {
$ssh_sendenv_real = $default_ssh_sendenv
} else {
Expand Down Expand Up @@ -433,6 +444,9 @@
if $sshd_config_serverkeybits_real != undef {
if is_integer($sshd_config_serverkeybits_real) == false { fail("ssh::sshd_config_serverkeybits must be an integer and is set to <${sshd_config_serverkeybits}>.") }
}
if $ssh_config_use_roaming_real != undef {
validate_re($ssh_config_use_roaming_real, '^(yes|no|unset)$', "ssh::ssh_config_use_roaming may be either 'yes', 'no' or 'unset' and is set to <${$ssh_config_use_roaming}>.")
}
if is_integer($sshd_client_alive_interval) == false { fail("ssh::sshd_client_alive_interval must be an integer and is set to <${sshd_client_alive_interval}>.") }
if is_integer($sshd_client_alive_count_max) == false { fail("ssh::sshd_client_alive_count_max must be an integer and is set to <${sshd_client_alive_count_max}>.") }

Expand Down
2 changes: 1 addition & 1 deletion metadata.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ghoneycutt-ssh",
"version": "3.33.1",
"version": "3.34.0",
"author": "ghoneycutt",
"summary": "Manages SSH",
"license": "Apache-2.0",
Expand Down
69 changes: 69 additions & 0 deletions spec/classes/init_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@

it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) }
it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) }

it {
Expand Down Expand Up @@ -204,6 +205,7 @@

it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) }
it { should contain_file('ssh_config').without_content(/^\s*UseRoaming/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*SendEnv L.*$/) }
it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) }
Expand Down Expand Up @@ -326,6 +328,7 @@

it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) }
it { should contain_file('ssh_config').without_content(/^\s*UseRoaming/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*SendEnv L.*$/) }
it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) }
Expand Down Expand Up @@ -446,6 +449,7 @@

it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) }
it { should contain_file('ssh_config').without_content(/^\s*UseRoaming/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*SendEnv L.*$/) }
it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) }
Expand Down Expand Up @@ -567,6 +571,7 @@

it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) }
it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) }
it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) }
it { should contain_file('ssh_config').without_content(/^\s*MACs/) }
Expand Down Expand Up @@ -695,6 +700,7 @@

it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) }
it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) }
it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) }
it { should contain_file('ssh_config').without_content(/^\s*MACs/) }
Expand Down Expand Up @@ -825,6 +831,7 @@

it { should contain_file('ssh_config').without_content(/^\s*ForwardAgent$/) }
it { should contain_file('ssh_config').without_content(/^\s*ForwardX11$/) }
it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) }
it { should contain_file('ssh_config').without_content(/^\s*ServerAliveInterval$/) }
it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) }
it { should contain_file('ssh_config').without_content(/^\s*MACs/) }
Expand Down Expand Up @@ -953,6 +960,7 @@

it { should_not contain_file('ssh_config').with_content(/^\s*ForwardAgent$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ForwardX11$/) }
it { should contain_file('ssh_config').with_content(/^\s*UseRoaming no$/) }
it { should_not contain_file('ssh_config').with_content(/^\s*ServerAliveInterval$/) }
it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) }
it { should contain_file('ssh_config').without_content(/^\s*MACs/) }
Expand Down Expand Up @@ -1062,6 +1070,7 @@
:ssh_config_hash_known_hosts => 'yes',
:ssh_config_forward_agent => 'yes',
:ssh_config_forward_x11 => 'yes',
:ssh_config_use_roaming => 'yes',
:ssh_config_server_alive_interval => '300',
:ssh_config_sendenv_xmodifiers => true,
:ssh_config_ciphers => [ 'aes128-cbc',
Expand Down Expand Up @@ -1099,6 +1108,7 @@
it { should contain_file('ssh_config').with_content(/^ ForwardAgent yes$/) }
it { should contain_file('ssh_config').with_content(/^ ForwardX11 yes$/) }
it { should contain_file('ssh_config').with_content(/^\s*GSSAPIAuthentication yes$/) }
it { should contain_file('ssh_config').with_content(/^\s*UseRoaming yes$/) }
it { should contain_file('ssh_config').with_content(/^ ServerAliveInterval 300$/) }
it { should contain_file('ssh_config').with_content(/^ SendEnv XMODIFIERS$/) }
it { should contain_file('ssh_config').with_content(/^\s*Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc$/) }
Expand Down Expand Up @@ -3440,4 +3450,63 @@
end
end
end

describe 'with parameter ssh_config_use_roaming' do
let(:facts) { { :osfamily => 'RedHat' } }

['yes','no','unset'].each do |value|
context "set to valid value #{value}" do
let(:params) { { :ssh_config_use_roaming => value } }
if value == 'unset'
it { should contain_file('ssh_config').without_content(/^\s*UseRoaming/) }
else
it { should contain_file('ssh_config').with_content(/^\s*UseRoaming #{value}$/) }
end
end
end
end

describe 'variable type and content validations' do
# set needed custom facts and variables
let(:facts) do
{
:osfamily => 'RedHat',
}
end
let(:mandatory_params) do
{
#:param => 'value',
}
end

validations = {
'regex (yes|no|unset)' => {
:name => %w(ssh_config_use_roaming),
:valid => ['yes', 'no', 'unset'],
:invalid => ['string', %w(array), { 'ha' => 'sh' }, 3, 2.42, true, false, nil],
:message => 'may be either \'yes\', \'no\' or \'unset\'',
},
}

validations.sort.each do |type, var|
var[:name].each do |var_name|
var[:params] = {} if var[:params].nil?
var[:valid].each do |valid|
context "when #{var_name} (#{type}) is set to valid #{valid} (as #{valid.class})" do
let(:params) { [mandatory_params, var[:params], { :"#{var_name}" => valid, }].reduce(:merge) }
it { should compile }
end
end

var[:invalid].each do |invalid|
context "when #{var_name} (#{type}) is set to invalid #{invalid} (as #{invalid.class})" do
let(:params) { [mandatory_params, var[:params], { :"#{var_name}" => invalid, }].reduce(:merge) }
it 'should fail' do
expect { should contain_class(subject) }.to raise_error(Puppet::Error, /#{var[:message]}/)
end
end
end
end # var[:name].each
end # validations.sort.each
end # describe 'variable type and content validations'
end
3 changes: 3 additions & 0 deletions templates/ssh_config.erb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ GSSAPIDelegateCredentials <%= @ssh_gssapidelegatecredentials %>
<% if @ssh_config_forward_x11 != nil -%>
ForwardX11 <%= @ssh_config_forward_x11 %>
<% end -%>
<% if (@ssh_config_use_roaming_real == 'yes') or (@ssh_config_use_roaming_real == 'no') -%>
UseRoaming <%= @ssh_config_use_roaming_real %>
<% end -%>
<% if @ssh_config_server_alive_interval != nil -%>
ServerAliveInterval <%= @ssh_config_server_alive_interval %>
<% end -%>
Expand Down