Skip to content

Commit

Permalink
Switch UsePAM default to yes
Browse files Browse the repository at this point in the history
and install SELinux policy on RHEL if UsePAM is set to no

Basiclly its a port from ansible to chef of the following change in
ansible-ssh-hardening:
dev-sec/ansible-ssh-hardening@c4482cb
  • Loading branch information
artem-sidorenko committed Jan 5, 2017
1 parent 996232c commit e3267a7
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 3 deletions.
21 changes: 21 additions & 0 deletions .kitchen.vagrant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,24 @@ suites:
verifier:
inspec_tests:
- https://github.com/dev-sec/tests-ssh-hardening
- name: rhel-with-disabled-pam
includes:
- centos-6.8
- centos-7.3
- fedora-23
- fedora-24
driver:
provision: true
vagrantfiles:
- test/fixtures/vagrantfiles/enforce_selinux.rb
run_list:
- recipe[ssh-hardening]
attributes:
ssh-hardening:
ssh:
server:
use_pam: true
verifier:
inspec_tests:
- https://github.com/dev-sec/tests-ssh-hardening
- test/integration/without-pam
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ override['ssh-hardening']['ssh']['server']['listen_to'] = node['ipaddress']
* `['ssh-hardening']['ssh']['server']['allow_tcp_forwarding']` - `false`. Set to `true` to allow TCP Forwarding
* `['ssh-hardening']['ssh']['server']['allow_agent_forwarding']` - `false`. Set to `true` to allow Agent Forwarding
* `['ssh-hardening']['ssh']['server']['allow_x11_forwarding']` - `false`. Set to `true` to allow X11 Forwarding
* `['ssh-hardening']['ssh']['server']['use_pam']` - `false`. Set to `true` to enable the pam authentication of sshd
* `['ssh-hardening']['ssh']['server']['use_pam']` - `true`. Set to `false` to disable the pam authentication of sshd
* `['ssh-hardening']['ssh']['server']['challenge_response_authentication']` - `false`. Set to `true` to enable challenge response authentication.
* `['ssh-hardening']['ssh']['server']['deny_users']` - `[]` to configure `DenyUsers`, if specified login is disallowed for user names that match one of the patterns.
* `['ssh-hardening']['ssh']['server']['allow_users']` - `[]` to configure `AllowUsers`, if specified, login is allowed only for user names that match one of the patterns.
Expand Down
2 changes: 1 addition & 1 deletion attributes/default.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
default['ssh-hardening']['ssh']['server']['allow_tcp_forwarding'] = false
default['ssh-hardening']['ssh']['server']['allow_agent_forwarding'] = false
default['ssh-hardening']['ssh']['server']['allow_x11_forwarding'] = false
default['ssh-hardening']['ssh']['server']['use_pam'] = false
default['ssh-hardening']['ssh']['server']['use_pam'] = true
default['ssh-hardening']['ssh']['server']['challenge_response_authentication'] = false
default['ssh-hardening']['ssh']['server']['deny_users'] = []
default['ssh-hardening']['ssh']['server']['allow_users'] = []
Expand Down
10 changes: 10 additions & 0 deletions files/default/ssh_password.te
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module ssh_password 1.0;

require {
type sshd_t;
type shadow_t;
class file { read open };
}

#============= sshd_t ==============
allow sshd_t shadow_t:file { read open };
34 changes: 34 additions & 0 deletions recipes/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,40 @@
package_name node['ssh-hardening']['sshserver']['package']
end

# Handle addional SELinux policy on RHEL for different UsePAM options
if node['platform_family'] == 'rhel'
policy_dir = ::File.join(Chef::Config[:file_cache_path], cookbook_name.to_s)
policy_file = ::File.join(policy_dir, 'ssh_password.te')
module_file = ::File.join(policy_dir, 'ssh_password.mod')
package_file = ::File.join(policy_dir, 'ssh_password.pp')

if node['ssh-hardening']['ssh']['server']['use_pam']
# UsePAM yes: disable and remove the additional SELinux policy

execute 'remove selinux policy' do
command 'semodule -r ssh_password'
only_if 'getenforce | grep -vq Disabled && semodule -l | grep -q ssh_password'
end
else
# UsePAM no: enable and install the additional SELinux policy

directory policy_dir

cookbook_file policy_file do
source 'ssh_password.te'
end

bash 'build selinux package and install it' do
code <<-EOC
checkmodule -M -m -o #{module_file} #{policy_file}
semodule_package -o #{package_file} -m #{module_file}
semodule -i #{package_file}
EOC
not_if 'getenforce | grep -q Disabled || semodule -l | grep -q ssh_password'
end
end
end

# defines the sshd service
service 'sshd' do
# use upstart for ubuntu, otherwise chef uses init
Expand Down
115 changes: 115 additions & 0 deletions spec/recipes/server_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,117 @@
end
end

it 'should set UsePAM to yes per default' do
expect(chef_run).to render_file('/etc/ssh/sshd_config').with_content('UsePAM yes')
end

describe 'UsePAM option' do
let(:use_pam) { true }

let(:chef_run) do
ChefSpec::ServerRunner.new(platform: platform, version: version) do |node|
node.normal['ssh-hardening']['ssh']['server']['use_pam'] = use_pam
end.converge(described_recipe)
end

context 'when running on Ubuntu' do
let(:platform) { 'ubuntu' }
let(:version) { '16.04' }

it 'does not invoke any SELinux resources' do
expect(chef_run).not_to create_directory('/tmp/ssh-hardening-file-cache/ssh-hardening')
expect(chef_run).not_to render_file('/tmp/ssh-hardening-file-cache/ssh-hardening/ssh_password.te')
expect(chef_run).not_to run_execute('remove selinux policy')
expect(chef_run).not_to run_bash('build selinux package and install it')
end

context 'when use_pam is set to true' do
let(:use_pam) { true }

it 'should set UsePAM to yes' do
expect(chef_run).to render_file('/etc/ssh/sshd_config').with_content('UsePAM yes')
end
end

context 'when use_pam is set to false' do
let(:use_pam) { false }

it 'should set UsePAM to no' do
expect(chef_run).to render_file('/etc/ssh/sshd_config').with_content('UsePAM no')
end
end
end

context 'when running on CentOS' do
let(:platform) { 'centos' }
let(:version) { '7.2.1511' }

let(:selinux_disabled_or_policy_removed) { false }
let(:selinux_enabled_and_policy_installed) { false }

before do
stub_command('getenforce | grep -vq Disabled && semodule -l | grep -q ssh_password').and_return(selinux_enabled_and_policy_installed)
stub_command('getenforce | grep -q Disabled || semodule -l | grep -q ssh_password').and_return(selinux_disabled_or_policy_removed)
end

context 'when use_pam is set to true' do
let(:use_pam) { true }

it 'should set UsePAM to yes' do
expect(chef_run).to render_file('/etc/ssh/sshd_config').with_content('UsePAM yes')
end

context 'when selinux is disabled or policy is removed' do
let(:selinux_enabled_and_policy_installed) { false }

it 'should not invoke the policy removal' do
expect(chef_run).not_to run_execute('remove selinux policy')
end
end

context 'when selinux is enabled and policy is present' do
let(:selinux_enabled_and_policy_installed) { true }

it 'should invoke the policy removal' do
expect(chef_run).to run_execute('remove selinux policy')
end
end
end

context 'when use_pam is set to false' do
let(:use_pam) { false }

it 'should set UsePAM to no' do
expect(chef_run).to render_file('/etc/ssh/sshd_config').with_content('UsePAM no')
end

it 'should create cache directory for policy files' do
expect(chef_run).to create_directory('/tmp/ssh-hardening-file-cache/ssh-hardening')
end

it 'should create selinux source policy file' do
expect(chef_run).to render_file('/tmp/ssh-hardening-file-cache/ssh-hardening/ssh_password.te')
end

context 'when selinux is disabled or policy is installed' do
let(:selinux_disabled_or_policy_removed) { true }

it 'should not install the policy' do
expect(chef_run).not_to run_bash('build selinux package and install it')
end
end

context 'when selinux is enabled and policy is not installed' do
let(:selinux_disabled_or_policy_removed) { false }

it 'should install the policy' do
expect(chef_run).to run_bash('build selinux package and install it')
end
end
end
end
end

describe 'debian banner' do
cached(:chef_run) do
ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '16.04').converge(described_recipe)
Expand All @@ -235,6 +346,10 @@
end

context 'with centos as platform' do
before do
stub_command('getenforce | grep -vq Disabled && semodule -l | grep -q ssh_password').and_return(true)
end

cached(:chef_run) do
ChefSpec::ServerRunner.new(platform: 'centos', version: '7.2.1511') do |node|
node.normal['ssh-hardening']['ssh']['server']['os_banner'] = true
Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
# OS and version for mocking of ohai data, needed by chefspec
config.platform = 'ubuntu'
config.version = '16.04'
config.file_cache_path = '/tmp/ssh-hardening-file-cache'
end

require_relative '../libraries/devsec_ssh'
Expand Down
1 change: 0 additions & 1 deletion templates/default/opensshd.conf.erb
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ KerberosTicketCleanup yes
GSSAPIAuthentication no
GSSAPICleanupCredentials yes

# In case you don't use PAM (`UsePAM no`), you can alternatively restrict users and groups here. For key-based authentication this is not necessary, since all keys must be explicitely enabled.
<% unless @node['ssh-hardening']['ssh']['server']['deny_users'].empty? %>
DenyUsers <%= @node['ssh-hardening']['ssh']['server']['deny_users'].join(' ') %>
<% else %>
Expand Down
6 changes: 6 additions & 0 deletions test/fixtures/vagrantfiles/enforce_selinux.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Vagrant.configure(2) do |config|
config.vm.provision 'shell', inline: <<-SHELL
yum -y update selinux-* # there are sometimes issues because of old selinux policy in the box
setenforce 1
SHELL
end
11 changes: 11 additions & 0 deletions test/integration/without-pam/ssh_password_selinux_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
describe command('getenforce') do
its(:exit_status) { should eq 0 }
its(:stdout) { should include 'Enforcing' }
its(:stderr) { should eq '' }
end

describe command('semodule -l | grep "ssh_password"') do
its(:exit_status) { should eq 0 }
its(:stdout) { should include 'ssh_password' }
its(:stderr) { should eq '' }
end

0 comments on commit e3267a7

Please sign in to comment.