diff --git a/README.md b/README.md index 0edb4e9..29cc0e5 100644 --- a/README.md +++ b/README.md @@ -365,6 +365,18 @@ Array of users for the AllowUsers setting in sshd_config. - *Default*: undef +sshd_config_maxstartups +----------------------- +Specifies the maximum number of concurrent unauthenticated connections to the SSH daemon. + +- *Default*: undef + +sshd_config_maxsessions +----------------------- +Specifies the maximum number of open sessions permitted per network connection. + +- *Default*: undef + keys ---- Hash of keys for user's ~/.ssh/authorized_keys diff --git a/manifests/init.pp b/manifests/init.pp index da08605..aee55c3 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -47,6 +47,8 @@ class ssh ( $sshd_config_denygroups = undef, $sshd_config_allowusers = undef, $sshd_config_allowgroups = undef, + $sshd_config_maxstartups = undef, + $sshd_config_maxsessions = undef, $sshd_banner_content = undef, $sshd_banner_owner = 'root', $sshd_banner_group = 'root', @@ -434,6 +436,17 @@ class ssh ( validate_string($sshd_config_authkey_location) } + if $sshd_config_maxstartups != undef { + validate_string($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_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}>.") } diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index eebd65d..9eb5050 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -86,6 +86,8 @@ describe 'ssh' do it { should_not contain_file('sshd_config').with_content(/^\s*GSSAPIKeyExchange no$/) } it { should_not contain_file('sshd_config').with_content(/^AuthorizedKeysFile/) } it { should_not contain_file('sshd_config').with_content(/^StrictModes/) } + it { should_not contain_file('sshd_config').with_content(/^MaxStartups/) } + it { should_not contain_file('sshd_config').with_content(/^MaxSessions/) } it { should contain_file('sshd_config').with_content(/^AcceptEnv L.*$/) } it { should contain_file('sshd_config').without_content(/^\s*Ciphers/) } it { should contain_file('sshd_config').without_content(/^\s*MACs/) } @@ -205,6 +207,8 @@ describe 'ssh' do it { should_not contain_file('sshd_config').with_content(/^\s*AcceptEnv L.*$/) } it { should_not contain_file('sshd_config').with_content(/^AuthorizedKeysFile/) } it { should_not contain_file('sshd_config').with_content(/^StrictModes/) } + it { should_not contain_file('sshd_config').with_content(/^MaxStartups/) } + it { should_not contain_file('sshd_config').with_content(/^MaxSessions/) } it { should contain_file('sshd_config').with_content(/^ServerKeyBits 768$/) } it { should contain_file('sshd_config').without_content(/^\s*Ciphers/) } it { should contain_file('sshd_config').without_content(/^\s*MACs/) } @@ -307,6 +311,8 @@ describe 'ssh' do it { should_not contain_file('sshd_config').with_content(/^\s*AcceptEnv L.*$/) } it { should_not contain_file('sshd_config').with_content(/^AuthorizedKeysFile/) } it { should_not contain_file('sshd_config').with_content(/^StrictModes/) } + it { should_not contain_file('sshd_config').with_content(/^MaxStartups/) } + it { should_not contain_file('sshd_config').with_content(/^MaxSessions/) } it { should contain_file('sshd_config').with_content(/^ServerKeyBits 768$/) } it { should contain_file('sshd_config').without_content(/^\s*Ciphers/) } it { should contain_file('sshd_config').without_content(/^\s*MACs/) } @@ -408,6 +414,8 @@ describe 'ssh' do it { should_not contain_file('sshd_config').with_content(/^\s*AcceptEnv L.*$/) } it { should_not contain_file('sshd_config').with_content(/^AuthorizedKeysFile/) } it { should_not contain_file('sshd_config').with_content(/^StrictModes/) } + it { should_not contain_file('sshd_config').with_content(/^MaxStartups/) } + it { should_not contain_file('sshd_config').with_content(/^MaxSessions/) } it { should contain_file('sshd_config').with_content(/^ServerKeyBits 768$/) } it { should contain_file('sshd_config').without_content(/^\s*Ciphers/) } it { should contain_file('sshd_config').without_content(/^\s*MACs/) } @@ -517,6 +525,8 @@ describe 'ssh' do it { should contain_file('sshd_config').with_content(/^AcceptEnv L.*$/) } it { should_not contain_file('sshd_config').with_content(/^AuthorizedKeysFile/) } it { should_not contain_file('sshd_config').with_content(/^StrictModes/) } + it { should_not contain_file('sshd_config').with_content(/^MaxStartups/) } + it { should_not contain_file('sshd_config').with_content(/^MaxSessions/) } it { should contain_file('ssh_config').without_content(/^\s*Ciphers/) } it { should contain_file('ssh_config').without_content(/^\s*MACs/) } it { should contain_file('ssh_config').without_content(/^\s*DenyUsers/) } @@ -625,6 +635,8 @@ describe 'ssh' do it { should contain_file('sshd_config').with_content(/^AcceptEnv L.*$/) } it { should_not contain_file('sshd_config').with_content(/^AuthorizedKeysFile/) } it { should_not contain_file('sshd_config').with_content(/^StrictModes/) } + it { should_not contain_file('sshd_config').with_content(/^MaxStartups/) } + it { should_not contain_file('sshd_config').with_content(/^MaxSessions/) } it { should contain_file('sshd_config').without_content(/^\s*Ciphers/) } it { should contain_file('sshd_config').without_content(/^\s*MACs/) } it { should contain_file('sshd_config').without_content(/^\s*DenyUsers/) } @@ -733,6 +745,8 @@ describe 'ssh' do it { should contain_file('sshd_config').with_content(/^AcceptEnv L.*$/) } it { should_not contain_file('sshd_config').with_content(/^AuthorizedKeysFile/) } it { should_not contain_file('sshd_config').with_content(/^StrictModes/) } + it { should_not contain_file('sshd_config').with_content(/^MaxStartups/) } + it { should_not contain_file('sshd_config').with_content(/^MaxSessions/) } it { should contain_file('sshd_config').without_content(/^\s*Ciphers/) } it { should contain_file('sshd_config').without_content(/^\s*MACs/) } it { should contain_file('sshd_config').without_content(/^\s*DenyUsers/) } @@ -935,6 +949,8 @@ describe 'ssh' do it { should contain_file('sshd_config').with_content(/^HostKey \/etc\/ssh\/ssh_host_rsa_key/) } it { should contain_file('sshd_config').with_content(/^HostKey \/etc\/ssh\/ssh_host_dsa_key/) } it { should contain_file('sshd_config').with_content(/^StrictModes yes$/) } + it { should_not contain_file('sshd_config').with_content(/^MaxStartups/) } + it { should_not contain_file('sshd_config').with_content(/^MaxSessions/) } it { should contain_file('sshd_config').with_content(/^\s*Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc$/) } it { should contain_file('sshd_config').with_content(/^\s*MACs hmac-md5-etm@openssh.com,hmac-sha1-etm@openssh.com$/) } it { should contain_file('sshd_config').with_content(/^\s*DenyUsers root lusers$/) } @@ -2219,6 +2235,60 @@ describe 'ssh' do end end + describe 'with parameter sshd_config_maxstartups specified' do + context 'as a valid string' do + let(:params) { { :sshd_config_maxstartups => '10:30:100' } } + let(:facts) do + { :fqdn => 'monkey.example.com', + :osfamily => 'RedHat', + :sshrsakey => 'AAAAB3NzaC1yc2EAAAABIwAAAQEArGElx46pD6NNnlxVaTbp0ZJMgBKCmbTCT3RaeCk0ZUJtQ8wkcwTtqIXmmiuFsynUT0DFSd8UIodnBOPqitimmooAVAiAi30TtJVzADfPScMiUnBJKZajIBkEMkwUcqsfh630jyBvLPE/kyQcxbEeGtbu1DG3monkeymanOBW1AKc5o+cJLXcInLnbowMG7NXzujT3BRYn/9s5vtT1V9cuZJs4XLRXQ50NluxJI7sVfRPVvQI9EMbTS4AFBXUej3yfgaLSV+nPZC/lmJ2gR4t/tKvMFF9m16f8IcZKK7o0rK7v81G/tREbOT5YhcKLK+0wBfR6RsmHzwy4EddZloyLQ==' + } + end + it { should contain_file('sshd_config').with_content(/^MaxStartups 10:30:100$/) } + end + + context 'as an invalid type' do + let(:params) { { :sshd_config_maxstartups => true } } + let(:facts) do + { :fqdn => 'monkey.example.com', + :osfamily => 'RedHat', + :sshrsakey => 'AAAAB3NzaC1yc2EAAAABIwAAAQEArGElx46pD6NNnlxVaTbp0ZJMgBKCmbTCT3RaeCk0ZUJtQ8wkcwTtqIXmmiuFsynUT0DFSd8UIodnBOPqitimmooAVAiAi30TtJVzADfPScMiUnBJKZajIBkEMkwUcqsfh630jyBvLPE/kyQcxbEeGtbu1DG3monkeymanOBW1AKc5o+cJLXcInLnbowMG7NXzujT3BRYn/9s5vtT1V9cuZJs4XLRXQ50NluxJI7sVfRPVvQI9EMbTS4AFBXUej3yfgaLSV+nPZC/lmJ2gR4t/tKvMFF9m16f8IcZKK7o0rK7v81G/tREbOT5YhcKLK+0wBfR6RsmHzwy4EddZloyLQ==' + } + end + it 'should fail' do + expect { should raise_error(Puppet::Error) } + end + end + end + +#MAX + describe 'with parameter sshd_config_maxsessions specified' do + context 'as a valid integer' do + let(:params) { { :sshd_config_maxsessions => 10 } } + let(:facts) do + { :fqdn => 'monkey.example.com', + :osfamily => 'RedHat', + :sshrsakey => 'AAAAB3NzaC1yc2EAAAABIwAAAQEArGElx46pD6NNnlxVaTbp0ZJMgBKCmbTCT3RaeCk0ZUJtQ8wkcwTtqIXmmiuFsynUT0DFSd8UIodnBOPqitimmooAVAiAi30TtJVzADfPScMiUnBJKZajIBkEMkwUcqsfh630jyBvLPE/kyQcxbEeGtbu1DG3monkeymanOBW1AKc5o+cJLXcInLnbowMG7NXzujT3BRYn/9s5vtT1V9cuZJs4XLRXQ50NluxJI7sVfRPVvQI9EMbTS4AFBXUej3yfgaLSV+nPZC/lmJ2gR4t/tKvMFF9m16f8IcZKK7o0rK7v81G/tREbOT5YhcKLK+0wBfR6RsmHzwy4EddZloyLQ==' + } + end + it { should contain_file('sshd_config').with_content(/^MaxSessions 10$/) } + end + + context 'as an invalid type' do + let(:params) { { :sshd_config_maxsessions => 'BOGUS' } } + let(:facts) do + { :fqdn => 'monkey.example.com', + :osfamily => 'RedHat', + :sshrsakey => 'AAAAB3NzaC1yc2EAAAABIwAAAQEArGElx46pD6NNnlxVaTbp0ZJMgBKCmbTCT3RaeCk0ZUJtQ8wkcwTtqIXmmiuFsynUT0DFSd8UIodnBOPqitimmooAVAiAi30TtJVzADfPScMiUnBJKZajIBkEMkwUcqsfh630jyBvLPE/kyQcxbEeGtbu1DG3monkeymanOBW1AKc5o+cJLXcInLnbowMG7NXzujT3BRYn/9s5vtT1V9cuZJs4XLRXQ50NluxJI7sVfRPVvQI9EMbTS4AFBXUej3yfgaLSV+nPZC/lmJ2gR4t/tKvMFF9m16f8IcZKK7o0rK7v81G/tREbOT5YhcKLK+0wBfR6RsmHzwy4EddZloyLQ==' + } + end + it 'should fail' do + expect { should raise_error(Puppet::Error) } + end + end + end +#MAX + describe 'with parameter sshd_acceptenv specified' do ['true',true].each do |value| context "as #{value}" do diff --git a/templates/sshd_config.erb b/templates/sshd_config.erb index 7e04039..fac430d 100644 --- a/templates/sshd_config.erb +++ b/templates/sshd_config.erb @@ -154,7 +154,18 @@ ClientAliveCountMax <%= @sshd_client_alive_count_max %> UseDNS <%= @sshd_config_use_dns_real %> <% end -%> #PidFile /var/run/sshd.pid -#MaxStartups 10 +<% if @sshd_config_maxstartups %> +MaxStartups <%= sshd_config_maxstartups %> +<% else %> +#MaxStartups 10:30:100 +<% end %> +<% if @sshd_config_maxsessions %> +MaxSessions <%= sshd_config_maxsessions %> +<% else %> +#MaxSessions 10 +<% end %> + + #PermitTunnel no #ChrootDirectory none