Showing with 204 additions and 2 deletions.
  1. +22 −0 README.md
  2. +1 −1 lib/facter/ssh.rb
  3. +14 −0 manifests/init.pp
  4. +1 −1 metadata.json
  5. +115 −0 spec/classes/init_spec.rb
  6. +41 −0 spec/unit/facter/ssh_spec.rb
  7. +10 −0 templates/ssh_config.erb
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,28 @@ in ssh_config.

- *Default*: undef

ssh_hostbasedauthentication
-------------------------
String for HostbasedAuthentication option in ssh_config. Valid values are 'yes' and 'no'.

- *Default*: undef


ssh_strict_host_key_checking
-----------------------------
*string* For StrictHostKeyChecking setting in ssh_config. Valid values are
'yes', 'no' or 'ask'.

- *Default*: undef

ssh_enable_ssh_keysign
-----------------------------
*string* For EnableSSHKeysign setting in ssh_config. Valid values are
'yes' and 'no' or to leave undef which will ensure the setting is not present
in ssh_config.

- *Default*: undef

sshd_addressfamily
----------------
Specifies the value of the AddressFamily setting in sshd_config. Valid values are 'any', 'inet' (IPv4 only), 'inet6' (IPv6 only) and undef. A value of undef will ensure that AddressFamily is not in the configuration.
Expand Down
2 changes: 1 addition & 1 deletion lib/facter/ssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
setcode do
ssh_version = Facter.value(:ssh_version)
if ssh_version
ssh_version.match(/\d+\.\d+/)[0]
ssh_version.match(/(\d+\.\d+\.\d+|\d+\.\d+)/)[0]
end
end
end
14 changes: 14 additions & 0 deletions manifests/init.pp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
$ssh_config_forward_agent = undef,
$ssh_config_server_alive_interval = undef,
$ssh_config_sendenv_xmodifiers = false,
$ssh_hostbasedauthentication = undef,
$ssh_strict_host_key_checking = undef,
$ssh_config_ciphers = undef,
$ssh_config_macs = undef,
$ssh_config_use_roaming = 'USE_DEFAULTS',
Expand All @@ -45,6 +47,7 @@
$sshd_config_banner = 'none',
$sshd_config_ciphers = undef,
$sshd_config_macs = undef,
$ssh_enable_ssh_keysign = undef,
$sshd_config_allowgroups = [],
$sshd_config_allowusers = [],
$sshd_config_denygroups = [],
Expand Down Expand Up @@ -488,6 +491,14 @@
validate_re($sshd_gssapicleanupcredentials_real, '^(yes|no)$', "ssh::sshd_gssapicleanupcredentials may be either 'yes' or 'no' and is set to <${sshd_gssapicleanupcredentials_real}>.")
}

if $ssh_strict_host_key_checking != undef {
validate_re($ssh_strict_host_key_checking, '^(yes|no|ask)$', "ssh::ssh_strict_host_key_checking may be 'yes', 'no' or 'ask' and is set to <${ssh_strict_host_key_checking}>.")
}

if $ssh_enable_ssh_keysign != undef {
validate_re($ssh_enable_ssh_keysign, '^(yes|no)$', "ssh::ssh_enable_ssh_keysign may be either 'yes' or 'no' and is set to <${ssh_enable_ssh_keysign}>.")
}

if $sshd_config_authkey_location != undef {
validate_string($sshd_config_authkey_location)
}
Expand Down Expand Up @@ -527,6 +538,9 @@
if $sshd_config_strictmodes != undef {
validate_re($sshd_config_strictmodes, '^(yes|no)$', "ssh::sshd_config_strictmodes may be either 'yes' or 'no' and is set to <${sshd_config_strictmodes}>.")
}
if $ssh_hostbasedauthentication != undef {
validate_re($ssh_hostbasedauthentication, '^(yes|no)$', "ssh::ssh_hostbasedauthentication may be either 'yes' or 'no' and is set to <${ssh_hostbasedauthentication}>.")
}

validate_re($sshd_hostbasedauthentication, '^(yes|no)$', "ssh::sshd_hostbasedauthentication may be either 'yes' or 'no' and is set to <${sshd_hostbasedauthentication}>.")

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.36.0",
"version": "3.37.0",
"author": "ghoneycutt",
"summary": "Manages SSH",
"license": "Apache-2.0",
Expand Down
115 changes: 115 additions & 0 deletions spec/classes/init_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
'Suse-10-x86_64' => {
:architecture => 'x86_64',
:osfamily => 'Suse',
:operatingsystem => 'SLED',
:operatingsystemrelease => '10.4',
:ssh_version => 'OpenSSH_5.1p1',
:ssh_version_numeric => '5.1',
Expand All @@ -100,6 +101,7 @@
'Suse-11-x86_64' => {
:architecture => 'x86_64',
:osfamily => 'Suse',
:operatingsystem => 'SLED',
:operatingsystemrelease => '11.4',
:ssh_version => 'OpenSSH_6.6.1p1',
:ssh_version_numeric => '6.6',
Expand All @@ -126,6 +128,7 @@
'Suse-12-x86_64' => {
:architecture => 'x86_64',
:osfamily => 'Suse',
:operatingsystem => 'SLED',
:operatingsystemrelease => '12.0',
:ssh_version => 'OpenSSH_6.6.1p1',
:ssh_version_numeric => '6.6',
Expand Down Expand Up @@ -316,6 +319,9 @@
'hmac-sha1-etm@openssh.com',
],
:ssh_config_global_known_hosts_file => '/etc/ssh/ssh_known_hosts2',
:ssh_hostbasedauthentication => 'yes',
:ssh_strict_host_key_checking => 'ask',
:ssh_enable_ssh_keysign => 'yes',
}
end

Expand Down Expand Up @@ -345,6 +351,9 @@
it { should contain_file('ssh_config').with_content(/^\s*Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc$/) }
it { should contain_file('ssh_config').with_content(/^\s*MACs hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com$/) }
it { should contain_file('ssh_config').with_content(/^\s*GlobalKnownHostsFile \/etc\/ssh\/ssh_known_hosts2$/) }
it { should contain_file('ssh_config').with_content(/^\s*HostbasedAuthentication yes$/) }
it { should contain_file('ssh_config').with_content(/^\s*StrictHostKeyChecking ask$/) }
it { should contain_file('ssh_config').with_content(/^\s*EnableSSHKeysign yes$/) }
end

context 'with params used in sshd_config set on valid osfamily' do
Expand Down Expand Up @@ -1465,6 +1474,7 @@
default_facts.merge(
{
:osfamily => 'Suse',
:operatingsystem => 'SLED',
:fqdn => 'notinhiera.example.com',
:lsbmajdistrelease => '11',
:architecture => 'x86_64',
Expand Down Expand Up @@ -1736,6 +1746,111 @@
end
end

describe 'with parameter ssh_hostbasedauthentication' do
let :facts do
default_facts.merge(
{
}
)
end

['yes','no'].each do |value|
context "specified as valid #{value} (as #{value.class})" do
let(:params) { { :ssh_hostbasedauthentication => value } }

it { should contain_file('ssh_config').with_content(/^\s*HostbasedAuthentication #{value}$/) }
end
end

['YES',true,2.42,['array'],a = { 'ha' => 'sh' }].each do |value|
context "specified as invalid value #{value} (as #{value.class})" do
let(:params) { { :ssh_hostbasedauthentication => value } }

if value.is_a?(Array)
value = value.join
elsif value.is_a?(Hash)
value = '{ha => sh}'
end

it 'should fail' do
expect {
should contain_class('ssh')
}.to raise_error(Puppet::Error,/ssh::ssh_hostbasedauthentication may be either 'yes' or 'no' and is set to <#{Regexp.escape(value.to_s)}>\./)
end
end
end
end

describe 'with parameter ssh_strict_host_key_checking' do
let :facts do
default_facts.merge(
{
}
)
end

['yes','no', 'ask'].each do |value|
context "specified as valid #{value} (as #{value.class})" do
let(:params) { { :ssh_strict_host_key_checking => value } }

it { should contain_file('ssh_config').with_content(/^\s*StrictHostKeyChecking #{value}$/) }
end
end

['YES',true,2.42,['array'],a = { 'ha' => 'sh' }].each do |value|
context "specified as invalid value #{value} (as #{value.class})" do
let(:params) { { :ssh_strict_host_key_checking => value } }

if value.is_a?(Array)
value = value.join
elsif value.is_a?(Hash)
value = '{ha => sh}'
end

it 'should fail' do
expect {
should contain_class('ssh')
}.to raise_error(Puppet::Error,/ssh::ssh_strict_host_key_checking may be 'yes', 'no' or 'ask' and is set to <#{Regexp.escape(value.to_s)}>\./)
end
end
end
end

describe 'with parameter ssh_enable_ssh_keysign' do
let :facts do
default_facts.merge(
{
}
)
end

['yes','no'].each do |value|
context "specified as valid #{value} (as #{value.class})" do
let(:params) { { :ssh_enable_ssh_keysign => value } }

it { should contain_file('ssh_config').with_content(/^\s*EnableSSHKeysign #{value}$/) }
end
end

['YES',true,2.42,['array'],a = { 'ha' => 'sh' }].each do |value|
context "specified as invalid value #{value} (as #{value.class})" do
let(:params) { { :ssh_enable_ssh_keysign => value } }

if value.is_a?(Array)
value = value.join
elsif value.is_a?(Hash)
value = '{ha => sh}'
end

it 'should fail' do
expect {
should contain_class('ssh')
}.to raise_error(Puppet::Error,/ssh::ssh_enable_ssh_keysign may be either 'yes' or 'no' and is set to <#{Regexp.escape(value.to_s)}>\./)
end
end
end
end

describe 'with parameter sshd_gssapiauthentication' do
let :facts do
default_facts.merge(
Expand Down
41 changes: 41 additions & 0 deletions spec/unit/facter/ssh_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'spec_helper'

describe 'Facter::Util::Fact' do

version_matrix = {
'OpenSSH_5.1p1, OpenSSL 0.9.8a 11 Oct 2005' => { :ssh_version => 'OpenSSH_5.1p1', :ssh_version_numeric => '5.1' }, # SLES 10.4 i586
'OpenSSH_5.1p1, OpenSSL 0.9.8j-fips 07 Jan 2009' => { :ssh_version => 'OpenSSH_5.1p1', :ssh_version_numeric => '5.1' }, # SLES 11.2 x86_64
'OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013' => { :ssh_version => 'OpenSSH_5.3p1', :ssh_version_numeric => '5.3' }, # CentOS 6.5 / RedHat 6.7 x86_64
'OpenSSH_6.2p2, OpenSSL 0.9.8j-fips 07 Jan 2009' => { :ssh_version => 'OpenSSH_6.2p2', :ssh_version_numeric => '6.2' },
'OpenSSH_6.6.1p1, OpenSSL 0.9.8j-fips 07 Jan 2009' => { :ssh_version => 'OpenSSH_6.6.1p1', :ssh_version_numeric => '6.6.1' }, # SLES 11.4 x86_64
'Sun_SSH_1.1, SSH protocols 1.5/2.0, OpenSSL 0x0090700f' => { :ssh_version => 'Sun_SSH_1.1', :ssh_version_numeric => '1.1' }, # Solaris 9 SPARC
'Sun_SSH_1.1.5, SSH protocols 1.5/2.0, OpenSSL 0x0090704f' => { :ssh_version => 'Sun_SSH_1.1.5', :ssh_version_numeric => '1.1.5' }, # Solaris 10 SPARC
'broken string' => { :ssh_version => 'broken', :ssh_version_numeric => nil },
}

describe 'ssh_version' do
version_matrix.sort.each do |ssh_version_string, result|
context "with <#{ssh_version_string}>" do
before do
Facter.clear
# Stub exec for older Facter Otherwise this spec will fail with
# unexpected invocation: Facter::Util::Resolution.exec('uname -s')
Facter::Util::Resolution.stubs(:exec)
Facter::Util::Resolution.stubs(:exec).with('ssh -V 2>&1').returns("#{ssh_version_string}")
end

context "ssh_version should return <#{result[:ssh_version]}>" do
it do
expect(Facter.fact(:ssh_version).value).to eq(result[:ssh_version])
end
end

context "ssh_version_numeric should return <#{result[:ssh_version_numeric]}>" do
it do
expect(Facter.fact(:ssh_version_numeric).value).to eq(result[:ssh_version_numeric])
end
end
end
end
end
end
10 changes: 10 additions & 0 deletions templates/ssh_config.erb
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,17 @@
PasswordAuthentication yes
PubkeyAuthentication yes
# HostbasedAuthentication no
<% if @ssh_hostbasedauthentication -%>
HostbasedAuthentication <%= @ssh_hostbasedauthentication %>
<% end -%>
# BatchMode no
# CheckHostIP yes
# AddressFamily any
# ConnectTimeout 0
# StrictHostKeyChecking ask
<% if @ssh_strict_host_key_checking -%>
StrictHostKeyChecking <%= @ssh_strict_host_key_checking %>
<% end -%>
# IdentityFile ~/.ssh/identity
IdentityFile ~/.ssh/id_rsa
IdentityFile ~/.ssh/id_dsa
Expand Down Expand Up @@ -90,3 +96,7 @@ GSSAPIDelegateCredentials <%= @ssh_gssapidelegatecredentials %>
<% if @ssh_config_macs -%>
MACs <%= @ssh_config_macs.join(',') %>
<% end -%>
<% if not @ssh_enable_ssh_keysign.nil? -%>
# EnableSSHKeysign no
EnableSSHKeysign <%= @ssh_enable_ssh_keysign %>
<% end -%>