diff --git a/.fixtures.yml b/.fixtures.yml new file mode 100644 index 00000000..5eec1869 --- /dev/null +++ b/.fixtures.yml @@ -0,0 +1,5 @@ +fixtures: + repositories: + stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib" + symlinks: + ssh: "#{source_dir}" diff --git a/.gemfile b/.gemfile new file mode 100644 index 00000000..30601444 --- /dev/null +++ b/.gemfile @@ -0,0 +1,9 @@ +source 'https://rubygems.org' + +puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 3.3'] +gem 'puppet', puppetversion +gem 'puppetlabs_spec_helper', '>= 0.1.0', :require => false +gem 'puppet-lint', '>= 0.3.2' +gem 'facter', '>= 1.7.0', "< 1.8.0" + +# vim:ft=ruby diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..873111c1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,38 @@ +--- +branches: + only: + - master +language: ruby +bundler_args: --without development +script: 'bundle exec rake validate && bundle exec rake lint && SPEC_OPTS="--format documentation" bundle exec rake spec' +after_success: + - git clone -q git://github.com/puppetlabs/ghpublisher.git .forge-releng + - .forge-releng/publish +rvm: + - 1.8.7 + - 1.9.3 +env: + matrix: + - PUPPET_GEM_VERSION="~> 2.7.0" + - PUPPET_GEM_VERSION="~> 3.0.0" + - PUPPET_GEM_VERSION="~> 3.1.0" + - PUPPET_GEM_VERSION="~> 3.2.0" + - PUPPET_GEM_VERSION="~> 3.3.0" + - PUPPET_GEM_VERSION="~> 3.4.0" + global: + - PUBLISHER_LOGIN=saz + - secure: |- + bMAcMOMNUgKl7mVDNc47HwT7A8s3SvVRgy4Gu49XbyQ4C/pQ/TCSVlhyvNS7AHAA5BoZcypC + 23f69ykM4qVFGKDEi+oy6rfWXq8WVgyqA9r30Gcg95Plna5fRt/8lmbfBpa+DLRuUYhbzOXg + RuXT20V+nQOHDfp7fuC0EBQxIfM= +matrix: + include: + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 3.2.0" + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 3.3.0" + - rvm: 1.8.7 + env: PUPPET_GEM_VERSION="~> 2.6.0" +notifications: + email: false +gemfile: .gemfile diff --git a/Modulefile b/Modulefile index 9268adbf..90291201 100644 --- a/Modulefile +++ b/Modulefile @@ -1,5 +1,5 @@ name 'saz-ssh' -version '2.0.0' +version '2.3.3' source 'git://github.com/saz/puppet-ssh.git' author 'saz' license 'Apache License, Version 2.0' diff --git a/README.markdown b/README.markdown index 13125dad..509bfbb3 100644 --- a/README.markdown +++ b/README.markdown @@ -1,4 +1,4 @@ -# SSH Client and Server Puppet Module +# puppet-ssh [![Build Status](https://secure.travis-ci.org/saz/puppet-ssh.png)](http://travis-ci.org/saz/puppet-ssh) Manage SSH client and server via Puppet @@ -79,7 +79,8 @@ or ``` ### Server only -Host keys will be collected for client distribution +Host keys will be collected for client distribution unless + storeconfigs_enabled => false ``` include ssh::server @@ -89,6 +90,7 @@ or ``` class { 'ssh::server': + storeconfigs_enabled => false, options => { 'Match User www-data' => { 'ChrootDirectory' => '%h', diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..0a28d845 --- /dev/null +++ b/Rakefile @@ -0,0 +1,18 @@ +require 'rubygems' +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] + +desc "Run puppet in noop mode and check for syntax errors." +task :validate do + Dir['manifests/**/*.pp'].each do |manifest| + sh "puppet parser validate --noop #{manifest}" + end + Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file| + sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/ + end + Dir['templates/**/*.erb'].each do |template| + sh "erb -P -x -T '-' #{template} | ruby -c" + end +end diff --git a/manifests/client.pp b/manifests/client.pp index 1a18d1bd..7cd2458f 100644 --- a/manifests/client.pp +++ b/manifests/client.pp @@ -1,4 +1,5 @@ class ssh::client( + $ensure = present, $options = {} ) inherits ssh::params { $merged_options = merge($ssh::params::ssh_default_options, $options) diff --git a/manifests/client/config.pp b/manifests/client/config.pp index 608fd8cb..2658ac02 100644 --- a/manifests/client/config.pp +++ b/manifests/client/config.pp @@ -1,4 +1,4 @@ -class ssh::client::config { +class ssh::client::config { file { $ssh::params::ssh_config: ensure => present, owner => 0, diff --git a/manifests/client/install.pp b/manifests/client/install.pp index 008a040b..86771d77 100644 --- a/manifests/client/install.pp +++ b/manifests/client/install.pp @@ -1,7 +1,9 @@ class ssh::client::install { - if !defined(Package[$ssh::params::client_package_name]) { - package { $ssh::params::client_package_name: - ensure => present, + if $ssh::params::client_package_name { + if !defined(Package[$ssh::params::client_package_name]) { + package { $ssh::params::client_package_name: + ensure => $ssh::client::ensure, + } } } } diff --git a/manifests/params.pp b/manifests/params.pp index 6ad2c8e0..df5ff3ac 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -8,6 +8,7 @@ $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'ssh' + $sftp_server_path = '/usr/lib/openssh/sftp-server' } redhat: { $server_package_name = 'openssh-server' @@ -17,6 +18,16 @@ $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'sshd' + $sftp_server_path = '/usr/lib/openssh/sftp-server' + } + freebsd: { + $server_package_name = undef + $client_package_name = undef + $sshd_config = '/etc/ssh/sshd_config' + $ssh_config = '/etc/ssh/ssh_config' + $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' + $service_name = 'sshd' + $sftp_server_path = '/usr/lib/openssh/sftp-server' } default: { case $::operatingsystem { @@ -28,6 +39,7 @@ $ssh_config = '/etc/ssh/ssh_config' $ssh_known_hosts = '/etc/ssh/ssh_known_hosts' $service_name = 'sshd' + $sftp_server_path = '/usr/lib/misc/sftp-server' } default: { fail("Unsupported platform: ${::osfamily}/${::operatingsystem}") @@ -41,7 +53,7 @@ 'X11Forwarding' => 'yes', 'PrintMotd' => 'no', 'AcceptEnv' => 'LANG LC_*', - 'Subsystem' => 'sftp /usr/lib/openssh/sftp-server', + 'Subsystem' => "sftp ${sftp_server_path}", 'UsePAM' => 'yes', } @@ -49,7 +61,6 @@ 'Host *' => { 'SendEnv' => 'LANG LC_*', 'HashKnownHosts' => 'yes', - 'GSSAPIAuthentication' => 'yes', }, } } diff --git a/manifests/server.pp b/manifests/server.pp index 65ca278a..9f1fb7f9 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -1,4 +1,6 @@ class ssh::server( + $ensure = present, + $storeconfigs_enabled = true, $options = {} ) inherits ssh::params { $merged_options = merge($ssh::params::sshd_default_options, $options) @@ -6,17 +8,29 @@ include ssh::server::install include ssh::server::config include ssh::server::service - include ssh::hostkeys - include ssh::knownhosts anchor { 'ssh::server::start': } anchor { 'ssh::server::end': } - Anchor['ssh::server::start'] -> - Class['ssh::server::install'] -> - Class['ssh::server::config'] ~> - Class['ssh::server::service'] -> - Class['ssh::hostkeys'] -> - Class['ssh::knownhosts'] -> - Anchor['ssh::server::end'] + # Provide option to *not* use storeconfigs/puppetdb, which means not managing + # hostkeys and knownhosts + if ($storeconfigs_enabled) { + include ssh::hostkeys + include ssh::knownhosts + + Anchor['ssh::server::start'] -> + Class['ssh::server::install'] -> + Class['ssh::server::config'] ~> + Class['ssh::server::service'] -> + Class['ssh::hostkeys'] -> + Class['ssh::knownhosts'] -> + Anchor['ssh::server::end'] + } + else { + Anchor['ssh::server::start'] -> + Class['ssh::server::install'] -> + Class['ssh::server::config'] ~> + Class['ssh::server::service'] -> + Anchor['ssh::server::end'] + } } diff --git a/manifests/server/host_key.pp b/manifests/server/host_key.pp index b8e22151..a8960684 100644 --- a/manifests/server/host_key.pp +++ b/manifests/server/host_key.pp @@ -36,10 +36,10 @@ $private_key_content = '', ) { if $public_key_source == '' and $public_key_content == '' { - fail("You must provide either public_key_source or public_key_content parameter") + fail('You must provide either public_key_source or public_key_content parameter') } if $private_key_source == '' and $private_key_content == '' { - fail("You must provide either private_key_source or private_key_content parameter") + fail('You must provide either private_key_source or private_key_content parameter') } $manage_pub_key_content = $public_key_source ? { diff --git a/manifests/server/install.pp b/manifests/server/install.pp index e2d6669e..58b5ca1d 100644 --- a/manifests/server/install.pp +++ b/manifests/server/install.pp @@ -1,8 +1,10 @@ class ssh::server::install { include ssh::params - if !defined(Package[$ssh::params::server_package_name]) { - package { $ssh::params::server_package_name: - ensure => present, + if $ssh::params::server_package_name { + if !defined(Package[$ssh::params::server_package_name]) { + package { $ssh::params::server_package_name: + ensure => $ssh::server::ensure, + } } } } diff --git a/manifests/site.pp b/manifests/site.pp new file mode 100644 index 00000000..e69de29b diff --git a/spec/classes/client_spec.rb b/spec/classes/client_spec.rb new file mode 100644 index 00000000..cabe803d --- /dev/null +++ b/spec/classes/client_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe 'ssh::client', :type => 'class' do + context "On Debian with no other parameters" do + let :facts do + { + :osfamily => 'Debian', + :interfaces => 'eth0', + :ipaddress_eth0 => '192.168.1.1' + } + end + it { + should contain_package('openssh-client').with(:ensure => 'present') + } + end + context "On Debian with custom ensure" do + let :facts do + { + :osfamily => 'Debian', + :interfaces => 'eth0', + :ipaddress_eth0 => '192.168.1.1' + } + end + let :params do + { + :ensure => 'latest' + } + end + it { + should contain_package('openssh-client').with(:ensure => 'latest') + } + end +end diff --git a/spec/classes/server_spec.rb b/spec/classes/server_spec.rb new file mode 100644 index 00000000..6c62c9c4 --- /dev/null +++ b/spec/classes/server_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' +describe 'ssh::server' do + let :default_params do + { + :ensure => 'present', + :storeconfigs_enabled => true, + :options => {} + } + end + + [ {}, + { + :ensure => 'latest', + :storeconfigs_enabled => true, + :options => {} + }, + { + :ensure => 'present', + :storeconfigs_enabled => false, + :options => {} + } + ].each do |param_set| + describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do + let :param_hash do + default_params.merge(param_set) + end + + let :params do + param_set + end + + ['Debian'].each do |osfamily| + let :facts do + { + :osfamily => osfamily, + :interfaces => 'eth0', + :ipaddress_eth0 => '192.168.1.1' + } + end + + describe "on supported osfamily: #{osfamily}" do + it { should contain_class('ssh::params') } + it { should contain_package('openssh-server').with_ensure(param_hash[:ensure]) } + + it { should contain_file('/etc/ssh/sshd_config').with( + 'owner' => 0, + 'group' => 0 + )} + + it { should contain_service('ssh').with( + 'ensure' => 'running', + 'enable' => true, + 'hasrestart' => true, + 'hasstatus' => true + )} + + it 'should compile the template based on the class parameters' do + content = param_value( + subject, + 'file', + '/etc/ssh/sshd_config', + 'content' + ) + expected_lines = [ + 'ChallengeResponseAuthentication no', + 'X11Forwarding yes', + 'PrintMotd no', + 'AcceptEnv LANG LC_*', + 'Subsystem sftp /usr/lib/openssh/sftp-server', + 'UsePAM yes' + ] + (content.split("\n") & expected_lines).should =~ expected_lines + end + end + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a4aeeae2..6e1d9681 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,18 +1,2 @@ -require 'pathname' -dir = Pathname.new(__FILE__).parent -$LOAD_PATH.unshift(dir, dir + 'lib', dir + '../lib') - -require 'mocha' -require 'puppet' -gem 'rspec', '=1.2.9' -require 'spec/autorun' - -Spec::Runner.configure do |config| - config.mock_with :mocha -end - -# We need this because the RAL uses 'should' as a method. This -# allows us the same behaviour but with a different method name. -class Object - alias :must :should -end +require 'rspec-puppet' +require 'puppetlabs_spec_helper/module_spec_helper' diff --git a/templates/sshd_config.erb b/templates/sshd_config.erb index b1adfbee..d7ed11a7 100644 --- a/templates/sshd_config.erb +++ b/templates/sshd_config.erb @@ -1,6 +1,6 @@ # File is managed by Puppet -<%- scope.lookupvar('ssh::server::merged_options').sort.each do |k, v| -%> +<%- scope.lookupvar('ssh::server::merged_options').sort_by{ |sk| (sk.to_s.downcase.include? "match") ? "zzz" + sk.to_s : sk.to_s }.each do |k, v| -%> <%- if v.is_a?(Hash) -%> <%= k %> <%- v.sort.each do |key, value| -%> diff --git a/tests/init.pp b/tests/init.pp index 13a46380..6687c2c7 100644 --- a/tests/init.pp +++ b/tests/init.pp @@ -1 +1 @@ -include ssh +class { '::ssh::server': } diff --git a/tests/server.pp b/tests/server.pp new file mode 100644 index 00000000..112640ec --- /dev/null +++ b/tests/server.pp @@ -0,0 +1 @@ +include ssh::server