Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch UsePAM default to yes #157

Merged
merged 3 commits into from
Jan 12, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions .kitchen.vagrant.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ platforms:
- name: ubuntu-14.04
- name: ubuntu-16.04
- name: centos-6.8
- name: centos-7.2
- name: centos-7.3
- name: debian-7.11
- name: debian-8.6
- name: fedora-23
- name: fedora-24
- name: fedora-25
- name: opensuse-leap-42.1
- name: opensuse-13.2

Expand All @@ -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-24
- fedora-25
driver:
provision: true
vagrantfiles:
- test/fixtures/vagrantfiles/enforce_selinux.rb
run_list:
- recipe[ssh-hardening]
attributes:
ssh-hardening:
ssh:
server:
use_pam: false
verifier:
inspec_tests:
- https://github.com/dev-sec/tests-ssh-hardening
- test/integration/without-pam
9 changes: 4 additions & 5 deletions .kitchen.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,15 @@ platforms:
- RUN /usr/bin/apt-get update
- RUN /usr/bin/apt-get install -y procps
pid_one_command: /bin/systemd
- name: fedora-23
- name: fedora-24
driver:
image: fedora:23
image: fedora:24
pid_one_command: /usr/lib/systemd/systemd
# Chef needs yum package for now: https://github.com/chef/chef/issues/3201
intermediate_instructions:
- RUN dnf install -y yum
- name: fedora-24
- name: fedora-25
driver:
image: fedora:24
image: fedora:25
pid_one_command: /usr/lib/systemd/systemd
intermediate_instructions:
- RUN dnf install -y yum
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This cookbook provides secure ssh-client and ssh-server configurations. This coo
- RHEL 6, 7
- CentOS 6, 7
- Oracle Linux 6, 7
- Fedora 23, 24
- Fedora 24, 25
- OpenSuse Leap 42.1
- OpenSuse 13.2

Expand Down 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 };
38 changes: 38 additions & 0 deletions recipes/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,44 @@
package_name node['ssh-hardening']['sshserver']['package']
end

# Handle addional SELinux policy on RHEL/Fedora for different UsePAM options
if %w(fedora rhel).include?(node['platform_family'])
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')

package 'policycoreutils-python'
# on fedora we need an addtional package for semodule_package
package 'policycoreutils-python-utils' if node['platform_family'] == 'fedora'

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
120 changes: 120 additions & 0 deletions spec/recipes/server_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,122 @@
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')
expect(chef_run).not_to install_package('policycoreutils-python')
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

it 'should install selinux tools' do
expect(chef_run).to install_package('policycoreutils-python')
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 +351,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