Skip to content

File tree

5 files changed

+66
-0
lines changed

5 files changed

+66
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ override['ssh-hardening']['ssh']['server']['listen_to'] = node['ipaddress']
4646
* `['ssh-hardening']['ssh']['client']['remote_hosts']` - `[]` - one or more hosts, to which ssh-client can connect to.
4747
* `['ssh-hardening']['ssh']['client']['password_authentication']` - `false`. Set to `true` if password authentication should be enabled.
4848
* `['ssh-hardening']['ssh']['client']['roaming']` - `false`. Set to `true` if experimental client roaming should be enabled. This is known to cause potential issues with secrets being disclosed to malicious servers and defaults to being disabled.
49+
* `['ssh-hardening']['ssh']['server']['dh_min_prime_size']` - `2048` - Minimal acceptable prime length in bits in `/etc/ssh/moduli`. Primes below this number will get removed. (See [this](https://entropux.net/article/openssh-moduli/) for more information and background)
4950
* `['ssh-hardening']['ssh']['server']['listen_to']` `#override attribute#` - one or more ip addresses, to which ssh-server should listen to. Default is to listen on all interfaces. It should be configured for security reasons!
5051
* `['ssh-hardening']['ssh']['server']['allow_root_with_key']` - `false` to disable root login altogether. Set to `true` to allow root to login via key-based mechanism
5152
* `['ssh-hardening']['ssh']['server']['allow_tcp_forwarding']` - `false`. Set to `true` to allow TCP Forwarding

attributes/default.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
default['ssh-hardening']['ssh']['server']['cbc_required'] = false
7171
default['ssh-hardening']['ssh']['server']['weak_hmac'] = false
7272
default['ssh-hardening']['ssh']['server']['weak_kex'] = false
73+
default['ssh-hardening']['ssh']['server']['dh_min_prime_size'] = 2048
7374
default['ssh-hardening']['ssh']['server']['host_key_files'] = ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_dsa_key', '/etc/ssh/ssh_host_ecdsa_key']
7475
default['ssh-hardening']['ssh']['server']['client_alive_interval'] = 600 # 10min
7576
default['ssh-hardening']['ssh']['server']['client_alive_count'] = 3 # ~> 3 x interval

recipes/server.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
['0.0.0.0']
3131
end
3232

33+
# some internal definitions
34+
dh_moduli_file = '/etc/ssh/moduli'
35+
3336
# installs package name
3437
package 'openssh-server' do
3538
package_name node['ssh-hardening']['sshserver']['package']
@@ -73,6 +76,36 @@
7376
end
7477
end
7578

79+
# handle Diffie-Hellman moduli
80+
# remove all small primes
81+
# https://stribika.github.io/2015/01/04/secure-secure-shell.html
82+
dh_min_prime_size = node['ssh-hardening']['ssh']['server']['dh_min_prime_size'].to_i - 1 # 4096 is 4095 in the moduli file
83+
ruby_block 'remove small primes from DH moduli' do # ~FC014
84+
block do
85+
tmp_file = "#{dh_moduli_file}.tmp"
86+
::File.open(tmp_file, 'w') do |new_file|
87+
::File.readlines(dh_moduli_file).each do |line|
88+
unless line_match = line.match(/^(\d+ ){4}(\d+) \d+ \h+$/) # rubocop:disable Lint/AssignmentInCondition
89+
# some line without expected data structure, e.g. comment line
90+
# write it and go to the next data
91+
new_file.write(line)
92+
next
93+
end
94+
95+
# lets compare the bits and do not write the lines with small bit size
96+
bits = line_match[2]
97+
new_file.write(line) unless bits.to_i < dh_min_prime_size
98+
end
99+
end
100+
101+
# we use cp&rm to preserve the permissions of existing file
102+
FileUtils.cp(tmp_file, dh_moduli_file)
103+
FileUtils.rm(tmp_file)
104+
end
105+
not_if "test $(awk '$5 < #{dh_min_prime_size} && $5 ~ /^[0-9]+$/ { print $5 }' #{dh_moduli_file} | uniq | wc -c) -eq 0"
106+
notifies :restart, 'service[sshd]'
107+
end
108+
76109
# defines the sshd service
77110
service 'sshd' do
78111
# use upstart for ubuntu, otherwise chef uses init

spec/recipes/default_spec.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323
ChefSpec::ServerRunner.new.converge(described_recipe)
2424
end
2525

26+
before do
27+
stub_command("test $(awk '$5 < 2047 && $5 ~ /^[0-9]+$/ { print $5 }' /etc/ssh/moduli | uniq | wc -c) -eq 0").and_return(true)
28+
end
29+
2630
# check that the recipes are executed
2731
it 'includes server recipe' do
2832
expect(chef_run).to include_recipe('ssh-hardening::server')

spec/recipes/server_spec.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@
2121
describe 'ssh-hardening::server' do
2222
let(:helper_lib) { DevSec::Ssh }
2323
let(:ssh_config_file) { '/etc/ssh/sshd_config' }
24+
let(:dh_primes_ok) { true }
2425

2526
# converge
2627
cached(:chef_run) do
2728
ChefSpec::ServerRunner.new.converge(described_recipe)
2829
end
2930

31+
before do
32+
stub_command("test $(awk '$5 < 2047 && $5 ~ /^[0-9]+$/ { print $5 }' /etc/ssh/moduli | uniq | wc -c) -eq 0").and_return(dh_primes_ok)
33+
end
34+
3035
it 'installs openssh-server' do
3136
expect(chef_run).to install_package('openssh-server')
3237
end
@@ -327,6 +332,28 @@
327332
end
328333
end
329334

335+
describe 'DH primes handling' do
336+
let(:chef_run) do
337+
ChefSpec::ServerRunner.new.converge(described_recipe)
338+
end
339+
340+
context 'when there are no small primes' do
341+
let(:dh_primes_ok) { true }
342+
343+
it 'should not remove small primes from DH moduli' do
344+
expect(chef_run).not_to run_ruby_block('remove small primes from DH moduli')
345+
end
346+
end
347+
348+
context 'when there are small primes present' do
349+
let(:dh_primes_ok) { false }
350+
351+
it 'should invoke small primes from DH module' do
352+
expect(chef_run).to run_ruby_block('remove small primes from DH moduli')
353+
end
354+
end
355+
end
356+
330357
describe 'debian banner' do
331358
cached(:chef_run) do
332359
ChefSpec::ServerRunner.new(platform: 'ubuntu', version: '16.04').converge(described_recipe)

0 commit comments

Comments
 (0)