-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
(SIMP-6366) Configure Bolt module ssh (#186)
Add a `simplib__sshd_config` fact that collects relevant bits of the SSH configuration and can be easily extended over time to return additional configuration items. SIMP-6366 #comment Create sshd_config fact for simp_bolt
- Loading branch information
1 parent
662c6d0
commit 5e24a5d
Showing
3 changed files
with
328 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# _Description_ | ||
# | ||
# Return values from the /etc/ssh/sshd_conf file | ||
# | ||
Facter.add('simplib__sshd_config') do | ||
confine { File.exist?('/etc/ssh/sshd_config') && File.readable?('/etc/ssh/sshd_config')} | ||
|
||
setcode do | ||
|
||
# Items that we wish to pull from the configuration | ||
# | ||
# Format: | ||
# Key => Default Value | ||
selected_settings = { | ||
'AuthorizedKeysFile' => '.ssh/authorized_keys' | ||
} | ||
|
||
sshd = Facter::Util::Resolution.which('sshd') | ||
if sshd | ||
full_version = Facter::Core::Execution.execute("#{sshd} --help 2>&1", :on_fail => :failed) | ||
|
||
unless full_version == :failed | ||
sshd_config ||= {} | ||
|
||
full_version = full_version.lines.grep(/^\s*OpenSSH_\d/).first | ||
|
||
if full_version | ||
sshd_config['version'] = full_version.split(/,|\s/).first.split('_').last | ||
sshd_config['full_version'] = full_version | ||
end | ||
end | ||
end | ||
|
||
sshd_disk_config = File.read('/etc/ssh/sshd_config') | ||
|
||
match_section = nil | ||
sshd_disk_config.lines do |line| | ||
line.strip! | ||
|
||
next if line.empty? | ||
next if line[0].chr == '#' | ||
|
||
if config_parts = line.match(/^(?:(?<key>.+?))\s+(?<value>.+)\s*$/) | ||
if config_parts[:key] == 'Match' | ||
match_section = line | ||
next | ||
end | ||
|
||
next unless selected_settings.keys.include?(config_parts[:key]) | ||
|
||
if match_section | ||
sshd_config ||= {} | ||
sshd_config[match_section] ||= {} | ||
|
||
if sshd_config[match_section][config_parts[:key]] | ||
sshd_config[match_section][config_parts[:key]] = Array(sshd_config[match_section][config_parts[:key]]) | ||
sshd_config[match_section][config_parts[:key]] << config_parts[:value] | ||
else | ||
sshd_config[match_section][config_parts[:key]] = config_parts[:value] | ||
end | ||
else | ||
sshd_config ||= {} | ||
|
||
if sshd_config[config_parts[:key]] | ||
sshd_config[config_parts[:key]] = Array(sshd_config[config_parts[:key]]) | ||
sshd_config[config_parts[:key]] << config_parts[:value] | ||
else | ||
sshd_config[config_parts[:key]] = config_parts[:value] | ||
end | ||
end | ||
end | ||
end | ||
|
||
if sshd_config | ||
# Add in any defaults that we missed | ||
# This should *not* be a deep_merge! | ||
selected_settings.merge(sshd_config) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,245 @@ | ||
require 'spec_helper' | ||
|
||
describe "simplib__sshd_config" do | ||
|
||
before :each do | ||
Facter.clear | ||
|
||
Facter::Util::Resolution.expects(:which).with('sshd').returns('/usr/bin/sshd') | ||
Facter::Core::Execution.expects(:execute).with('/usr/bin/sshd --help 2>&1', :on_fail => :failed).returns(openssh_version['full_version']) | ||
|
||
File.expects(:exist?).with('/etc/ssh/sshd_config').returns(true) | ||
File.expects(:readable?).with('/etc/ssh/sshd_config').returns(true) | ||
File.expects(:read).with('/etc/ssh/sshd_config').returns(sshd_config_content) | ||
|
||
# This resets the stubbing code in Mocha to ensure that the code does not | ||
# try to catch any other calls to the stubbed methods above. | ||
# | ||
# This is not documented well and is almost always what you want in | ||
# Puppet testing | ||
|
||
File.stubs(:exist?).with(Not(equals('/etc/ssh/sshd_config'))) | ||
File.stubs(:readable?).with(Not(equals('/etc/ssh/sshd_config'))) | ||
File.stubs(:read).with(Not(equals('/etc/ssh/sshd_config'))) | ||
end | ||
|
||
let(:openssh_version) {{ | ||
'full_version' => 'OpenSSH_7.9p1, OpenSSL 1.1.1a FIPS 20 Nov 2018', | ||
'version' => '7.9p1' | ||
}} | ||
|
||
context 'with a simp /etc/ssh/sshd_config' do | ||
let(:sshd_config_content) { <<-EOM | ||
#Brief chunk of file | ||
Port 22 | ||
ListenAddress 0.0.0.0 | ||
#ListenAddress :: | ||
#PubkeyAuthentication yes | ||
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 | ||
# but this is overridden so installations will only check .ssh/authorized_keys | ||
AuthorizedKeysFile /etc/ssh/local_keys/%u | ||
#AuthorizedPrincipalsFile none | ||
#AuthorizedKeysCommand none | ||
AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys | ||
#AuthorizedKeysCommandUser nobody | ||
AuthorizedKeysCommandUser nobody | ||
# Even inline comments! | ||
# And indented comments | ||
EOM | ||
} | ||
it { | ||
expect(Facter.fact('simplib__sshd_config').value).to eq(openssh_version.merge({"AuthorizedKeysFile"=>"/etc/ssh/local_keys/%u"})) | ||
} | ||
end | ||
|
||
context 'with a default /etc/ssh/sshd_config' do | ||
let(:sshd_config_content) { <<-EOM | ||
#Brief chunk of file | ||
#Port 22 | ||
#AddressFamily any | ||
#ListenAddress 0.0.0.0 | ||
#ListenAddress :: | ||
#PubkeyAuthentication yes | ||
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 | ||
# but this is overridden so installations will only check .ssh/authorized_keys | ||
AuthorizedKeysFile .ssh/authorized_keys | ||
#AuthorizedPrincipalsFile none | ||
#AuthorizedKeysCommand none | ||
#AuthorizedKeysCommandUser nobody | ||
# Even inline comments! | ||
# And indented comments | ||
EOM | ||
} | ||
|
||
it { | ||
expect(Facter.fact(:simplib__sshd_config).value).to eq(openssh_version.merge({ 'AuthorizedKeysFile' => '.ssh/authorized_keys' })) | ||
} | ||
|
||
context 'when the SSH daemon does not return a version string' do | ||
let(:openssh_version) {{ | ||
'full_version' => :failed, | ||
'version' => nil | ||
}} | ||
|
||
it { | ||
expect(Facter.fact(:simplib__sshd_config).value).to eq({ 'AuthorizedKeysFile' => '.ssh/authorized_keys' }) | ||
} | ||
end | ||
|
||
context 'when the SSH daemon does not return a valid version string' do | ||
let(:openssh_version) {{ | ||
'full_version' => 'OpenSSH_is amazing', | ||
'version' => nil | ||
}} | ||
|
||
it { | ||
expect(Facter.fact(:simplib__sshd_config).value).to eq({ 'AuthorizedKeysFile' => '.ssh/authorized_keys' }) | ||
} | ||
end | ||
end | ||
|
||
context 'with a commented values /etc/ssh/sshd_config' do | ||
let(:sshd_config_content) { <<-EOM | ||
#Brief chunk of file | ||
#Port 22 | ||
#AddressFamily any | ||
#ListenAddress 0.0.0.0 | ||
#ListenAddress :: | ||
#PubkeyAuthentication yes | ||
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 | ||
# but this is overridden so installations will only check .ssh/authorized_keys | ||
#AuthorizedKeysFile /etc/ssh/local_keys/%u | ||
#AuthorizedPrincipalsFile none | ||
#AuthorizedKeysCommand none | ||
#AuthorizedKeysCommandUser nobody | ||
EOM | ||
} | ||
|
||
it { | ||
expect(Facter.fact(:simplib__sshd_config).value).to eq(openssh_version.merge({ 'AuthorizedKeysFile' => '.ssh/authorized_keys' })) | ||
} | ||
end | ||
|
||
context 'with empty /etc/ssh/sshd_config' do | ||
let(:sshd_config_content) {''} | ||
|
||
it { | ||
expect(Facter.fact(:simplib__sshd_config).value).to eq(openssh_version.merge({ 'AuthorizedKeysFile' => '.ssh/authorized_keys' })) | ||
} | ||
end | ||
|
||
context 'with multiple matching entries' do | ||
let(:sshd_config_content) { <<-EOM | ||
#Brief chunk of file | ||
#Port 22 | ||
#AddressFamily any | ||
#ListenAddress 0.0.0.0 | ||
#ListenAddress :: | ||
#PubkeyAuthentication yes | ||
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 | ||
# but this is overridden so installations will only check .ssh/authorized_keys | ||
AuthorizedKeysFile /etc/ssh/local_keys/%u | ||
AuthorizedKeysFile /foo/bar/baz | ||
#AuthorizedPrincipalsFile none | ||
#AuthorizedKeysCommand none | ||
#AuthorizedKeysCommandUser nobody | ||
EOM | ||
} | ||
|
||
it { | ||
expect(Facter.fact(:simplib__sshd_config).value).to eq(openssh_version.merge( | ||
{ 'AuthorizedKeysFile' => ['/etc/ssh/local_keys/%u', '/foo/bar/baz'] } | ||
)) | ||
} | ||
end | ||
|
||
context 'with multiple entries in a Match block' do | ||
let(:sshd_config_content) { <<-EOM | ||
#Brief chunk of file | ||
#Port 22 | ||
#AddressFamily any | ||
#ListenAddress 0.0.0.0 | ||
#ListenAddress :: | ||
#PubkeyAuthentication yes | ||
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 | ||
# but this is overridden so installations will only check .ssh/authorized_keys | ||
Match user foo | ||
AuthorizedKeysFile /etc/ssh/local_keys/%u | ||
AuthorizedKeysFile /foo/bar/baz | ||
#AuthorizedPrincipalsFile none | ||
#AuthorizedKeysCommand none | ||
#AuthorizedKeysCommandUser nobody | ||
EOM | ||
} | ||
|
||
it { | ||
expect(Facter.fact(:simplib__sshd_config).value).to eq(openssh_version.merge( | ||
{ | ||
'AuthorizedKeysFile' => '.ssh/authorized_keys', | ||
'Match user foo' => { | ||
'AuthorizedKeysFile' => [ '/etc/ssh/local_keys/%u', '/foo/bar/baz'] | ||
} | ||
} | ||
)) | ||
} | ||
end | ||
|
||
context 'with global and Match block entries' do | ||
let(:sshd_config_content) { <<-EOM | ||
#Brief chunk of file | ||
#Port 22 | ||
#AddressFamily any | ||
#ListenAddress 0.0.0.0 | ||
#ListenAddress :: | ||
#PubkeyAuthentication yes | ||
AuthorizedKeysFile /global/time | ||
# The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2 | ||
# but this is overridden so installations will only check .ssh/authorized_keys | ||
Match user foo | ||
AuthorizedKeysFile /etc/ssh/local_keys/%u | ||
AuthorizedKeysFile /foo/bar/baz | ||
#AuthorizedPrincipalsFile none | ||
#AuthorizedKeysCommand none | ||
#AuthorizedKeysCommandUser nobody | ||
EOM | ||
} | ||
|
||
it { | ||
expect(Facter.fact(:simplib__sshd_config).value).to eq(openssh_version.merge( | ||
{ | ||
'AuthorizedKeysFile' => '/global/time', | ||
'Match user foo' => { | ||
'AuthorizedKeysFile' => [ '/etc/ssh/local_keys/%u', '/foo/bar/baz'] | ||
} | ||
} | ||
)) | ||
} | ||
end | ||
end |