Skip to content

Commit eaf6c11

Browse files
authored
Merge pull request #173 from bdwyertech/extras
Add Support for Extra Configuration Options
2 parents d4dc236 + 925f81e commit eaf6c11

File tree

6 files changed

+148
-49
lines changed

6 files changed

+148
-49
lines changed

README.md

+21
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']['client']['extras']` - `{}`. Add extra configuration options, see [below](#extra-configuration-options) for details
4950
* `['ssh-hardening']['ssh']['server']['host_key_files']` - `nil` to calculate best hostkey configuration based on server version, otherwise specify an array with file paths (e.g. `/etc/ssh/ssh_host_rsa_key`)
5051
* `['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)
5152
* `['ssh-hardening']['ssh']['server']['dh_build_primes']` - `false` - If own primes should be built. This rebuild happens only once and takes a lot of time (~ 1.5 - 2h on the modern hardware for 4096 length).
@@ -76,6 +77,8 @@ override['ssh-hardening']['ssh']['server']['listen_to'] = node['ipaddress']
7677
* `['ssh-hardening']['ssh']['server']['sftp']['group']` - `sftponly`. Sets the `Match Group` option of SFTP to allow SFTP only for dedicated users
7778
* `['ssh-hardening']['ssh']['server']['sftp']['chroot']` - `/home/%u`. Sets the directory where the SFTP user should be chrooted
7879

80+
* `['ssh-hardening']['ssh']['server']['extras']` - `{}`. Add extra configuration options, see [below](#extra-configuration-options) for details
81+
7982

8083
## Usage
8184

@@ -124,6 +127,24 @@ Configure attributes:
124127

125128
This will enable the SFTP Server and chroot every user in the `sftpusers` group to the `/home/sftp/%u` directory.
126129

130+
## Extra Configuration Options
131+
Extra configuration options can be appended to the client or server configuration files. This can be used to override statically set values, or add configuration options not otherwise available via attributes.
132+
133+
The syntax is as follows:
134+
```
135+
# => Extra Server Configuration
136+
default['ssh-hardening']['ssh']['server']['extras'].tap do |extra|
137+
extra['#Some Comment'] = 'Heres the Comment'
138+
extra['AuthenticationMethods'] = 'publickey,keyboard-interactive'
139+
end
140+
141+
# => Extra Client Configuration
142+
default['ssh-hardening']['ssh']['client']['extras'].tap do |extra|
143+
extra['PermitLocalCommand'] = 'no'
144+
extra['Tunnel'] = 'no'
145+
end
146+
```
147+
127148
## Local Testing
128149

129150
For local testing you can use vagrant and Virtualbox of VMWare to run tests locally. You will have to install Virtualbox and Vagrant on your system. See [Vagrant Downloads](http://downloads.vagrantup.com/) for a vagrant package suitable for your system. For all our tests we use `test-kitchen`. If you are not familiar with `test-kitchen` please have a look at [their guide](http://kitchen.ci/docs/getting-started). We are writing our test with [InSpec](https://github.com/chef/inspec).

attributes/default.rb

+59-49
Original file line numberDiff line numberDiff line change
@@ -52,55 +52,65 @@
5252
default['ssh-hardening']['ssh']['ports'] = [22]
5353

5454
# ssh client
55-
default['ssh-hardening']['ssh']['client']['mac'] = nil # nil = calculate best combination for client
56-
default['ssh-hardening']['ssh']['client']['kex'] = nil # nil = calculate best combination for client
57-
default['ssh-hardening']['ssh']['client']['cipher'] = nil # nil = calculate best combination for client
58-
default['ssh-hardening']['ssh']['client']['cbc_required'] = false
59-
default['ssh-hardening']['ssh']['client']['weak_hmac'] = false
60-
default['ssh-hardening']['ssh']['client']['weak_kex'] = false
61-
default['ssh-hardening']['ssh']['client']['remote_hosts'] = []
62-
default['ssh-hardening']['ssh']['client']['password_authentication'] = false # ssh
63-
# http://undeadly.org/cgi?action=article&sid=20160114142733
64-
default['ssh-hardening']['ssh']['client']['roaming'] = false
65-
default['ssh-hardening']['ssh']['client']['send_env'] = ['LANG', 'LC_*', 'LANGUAGE']
55+
default['ssh-hardening']['ssh']['client'].tap do |client|
56+
client['mac'] = nil # nil = calculate best combination for client
57+
client['kex'] = nil # nil = calculate best combination for client
58+
client['cipher'] = nil # nil = calculate best combination for client
59+
client['cbc_required'] = false
60+
client['weak_hmac'] = false
61+
client['weak_kex'] = false
62+
client['remote_hosts'] = []
63+
client['password_authentication'] = false # ssh
64+
# http://undeadly.org/cgi?action=article&sid=20160114142733
65+
client['roaming'] = false
66+
client['send_env'] = ['LANG', 'LC_*', 'LANGUAGE']
67+
68+
# extra client configuration options
69+
client['extras'] = {}
70+
end
6671

6772
# sshd
68-
default['ssh-hardening']['ssh']['server']['kex'] = nil # nil = calculate best combination for server version
69-
default['ssh-hardening']['ssh']['server']['cipher'] = nil # nil = calculate best combination for server version
70-
default['ssh-hardening']['ssh']['server']['mac'] = nil # nil = calculate best combination for server version
71-
default['ssh-hardening']['ssh']['server']['cbc_required'] = false
72-
default['ssh-hardening']['ssh']['server']['weak_hmac'] = false
73-
default['ssh-hardening']['ssh']['server']['weak_kex'] = false
74-
default['ssh-hardening']['ssh']['server']['dh_min_prime_size'] = 2048
75-
default['ssh-hardening']['ssh']['server']['dh_build_primes'] = false
76-
default['ssh-hardening']['ssh']['server']['dh_build_primes_size'] = 4096
77-
default['ssh-hardening']['ssh']['server']['host_key_files'] = nil
78-
default['ssh-hardening']['ssh']['server']['client_alive_interval'] = 600 # 10min
79-
default['ssh-hardening']['ssh']['server']['client_alive_count'] = 3 # ~> 3 x interval
80-
default['ssh-hardening']['ssh']['server']['allow_root_with_key'] = false
81-
default['ssh-hardening']['ssh']['server']['allow_tcp_forwarding'] = false
82-
default['ssh-hardening']['ssh']['server']['allow_agent_forwarding'] = false
83-
default['ssh-hardening']['ssh']['server']['allow_x11_forwarding'] = false
84-
default['ssh-hardening']['ssh']['server']['use_pam'] = true
85-
default['ssh-hardening']['ssh']['server']['challenge_response_authentication'] = false
86-
default['ssh-hardening']['ssh']['server']['deny_users'] = []
87-
default['ssh-hardening']['ssh']['server']['allow_users'] = []
88-
default['ssh-hardening']['ssh']['server']['deny_groups'] = []
89-
default['ssh-hardening']['ssh']['server']['allow_groups'] = []
90-
default['ssh-hardening']['ssh']['server']['print_motd'] = false
91-
default['ssh-hardening']['ssh']['server']['print_last_log'] = false
92-
default['ssh-hardening']['ssh']['server']['banner'] = nil # set this to nil to disable banner or provide a path like '/etc/issue.net'
93-
default['ssh-hardening']['ssh']['server']['os_banner'] = false # (Debian OS family)
94-
default['ssh-hardening']['ssh']['server']['use_dns'] = nil # set this to nil to let us use the default OpenSSH in case it's not set by the user
95-
default['ssh-hardening']['ssh']['server']['use_privilege_separation'] = nil # set this to nil to let us detect the attribute based on the node platform
96-
default['ssh-hardening']['ssh']['server']['login_grace_time'] = '30s'
97-
default['ssh-hardening']['ssh']['server']['max_auth_tries'] = 2
98-
default['ssh-hardening']['ssh']['server']['max_sessions'] = 10
99-
default['ssh-hardening']['ssh']['server']['password_authentication'] = false
100-
default['ssh-hardening']['ssh']['server']['log_level'] = 'verbose'
101-
default['ssh-hardening']['ssh']['server']['accept_env'] = ['LANG', 'LC_*', 'LANGUAGE']
73+
default['ssh-hardening']['ssh']['server'].tap do |server| # rubocop: disable BlockLength
74+
server['kex'] = nil # nil = calculate best combination for server version
75+
server['cipher'] = nil # nil = calculate best combination for server version
76+
server['mac'] = nil # nil = calculate best combination for server version
77+
server['cbc_required'] = false
78+
server['weak_hmac'] = false
79+
server['weak_kex'] = false
80+
server['dh_min_prime_size'] = 2048
81+
server['dh_build_primes'] = false
82+
server['dh_build_primes_size'] = 4096
83+
server['host_key_files'] = nil
84+
server['client_alive_interval'] = 600 # 10min
85+
server['client_alive_count'] = 3 # ~> 3 x interval
86+
server['allow_root_with_key'] = false
87+
server['allow_tcp_forwarding'] = false
88+
server['allow_agent_forwarding'] = false
89+
server['allow_x11_forwarding'] = false
90+
server['use_pam'] = true
91+
server['challenge_response_authentication'] = false
92+
server['deny_users'] = []
93+
server['allow_users'] = []
94+
server['deny_groups'] = []
95+
server['allow_groups'] = []
96+
server['print_motd'] = false
97+
server['print_last_log'] = false
98+
server['banner'] = nil # set this to nil to disable banner or provide a path like '/etc/issue.net'
99+
server['os_banner'] = false # (Debian OS family)
100+
server['use_dns'] = nil # set this to nil to let us use the default OpenSSH in case it's not set by the user
101+
server['use_privilege_separation'] = nil # set this to nil to let us detect the attribute based on the node platform
102+
server['login_grace_time'] = '30s'
103+
server['max_auth_tries'] = 2
104+
server['max_sessions'] = 10
105+
server['password_authentication'] = false
106+
server['log_level'] = 'verbose'
107+
server['accept_env'] = ['LANG', 'LC_*', 'LANGUAGE']
102108

103-
# sshd sftp options
104-
default['ssh-hardening']['ssh']['server']['sftp']['enable'] = false
105-
default['ssh-hardening']['ssh']['server']['sftp']['group'] = 'sftponly'
106-
default['ssh-hardening']['ssh']['server']['sftp']['chroot'] = '/home/%u'
109+
# extra server configuration options
110+
server['extras'] = {}
111+
112+
# sshd sftp options
113+
server['sftp']['enable'] = false
114+
server['sftp']['group'] = 'sftponly'
115+
server['sftp']['chroot'] = '/home/%u'
116+
end

spec/recipes/client_spec.rb

+27
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,33 @@
191191
end
192192
end
193193

194+
describe 'extra configuration values' do
195+
context 'without custom extra config value' do
196+
cached(:chef_run) do
197+
ChefSpec::ServerRunner.new.converge(described_recipe)
198+
end
199+
200+
it 'does not have any extra config options' do
201+
expect(chef_run).to render_file('/etc/ssh/ssh_config')
202+
expect(chef_run).not_to render_file('/etc/ssh/ssh_config').
203+
with_content(/^# Extra Configuration Options/)
204+
end
205+
end
206+
207+
context 'with custom extra config value' do
208+
cached(:chef_run) do
209+
ChefSpec::ServerRunner.new do |node|
210+
node.normal['ssh-hardening']['ssh']['client']['extras']['#ExtraConfig'] = 'Value'
211+
end.converge(described_recipe)
212+
end
213+
214+
it 'uses the extra config attributes' do
215+
expect(chef_run).to render_file('/etc/ssh/ssh_config').with_content(/^# Extra Configuration Options/)
216+
expect(chef_run).to render_file('/etc/ssh/ssh_config').with_content(/^#ExtraConfig Value/)
217+
end
218+
end
219+
end
220+
194221
context 'chef-solo' do
195222
cached(:chef_run) do
196223
ChefSpec::SoloRunner.new.converge(described_recipe)

spec/recipes/server_spec.rb

+27
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,33 @@
403403
end
404404
end
405405

406+
describe 'extra configuration values' do
407+
context 'without custom extra config value' do
408+
cached(:chef_run) do
409+
ChefSpec::ServerRunner.new.converge(described_recipe)
410+
end
411+
412+
it 'does not have any extra config options' do
413+
expect(chef_run).to render_file('/etc/ssh/sshd_config')
414+
expect(chef_run).not_to render_file('/etc/ssh/sshd_config').
415+
with_content(/^# Extra Configuration Options/)
416+
end
417+
end
418+
419+
context 'with custom extra config value' do
420+
cached(:chef_run) do
421+
ChefSpec::ServerRunner.new do |node|
422+
node.normal['ssh-hardening']['ssh']['server']['extras']['#ExtraConfig'] = 'Value'
423+
end.converge(described_recipe)
424+
end
425+
426+
it 'uses the extra config attributes' do
427+
expect(chef_run).to render_file('/etc/ssh/sshd_config').with_content(/^# Extra Configuration Options/)
428+
expect(chef_run).to render_file('/etc/ssh/sshd_config').with_content(/^#ExtraConfig Value/)
429+
end
430+
end
431+
end
432+
406433
it 'disables the challenge response authentication' do
407434
expect(chef_run).to render_file('/etc/ssh/sshd_config').
408435
with_content(/ChallengeResponseAuthentication no/)

templates/default/openssh.conf.erb

+7
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,10 @@ UseRoaming <%= @node['ssh-hardening']['ssh']['client']['roaming'] ? 'yes' : 'no'
117117
# Send locale environment variables
118118
SendEnv <%= @node['ssh-hardening']['ssh']['client']['send_env'].join(' ') %>
119119
<% end %>
120+
121+
<%- unless @node['ssh-hardening']['ssh']['client']['extras'].empty? %>
122+
# Extra Configuration Options
123+
<%- @node['ssh-hardening']['ssh']['client']['extras'].each do |key, value| %>
124+
<%= key %> <%= value %>
125+
<% end -%>
126+
<% end -%>

templates/default/opensshd.conf.erb

+7
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,10 @@ X11Forwarding no
229229
#PermitRootLogin no
230230
#X11Forwarding no
231231
<% end %>
232+
233+
<%- unless @node['ssh-hardening']['ssh']['server']['extras'].empty? %>
234+
# Extra Configuration Options
235+
<%- @node['ssh-hardening']['ssh']['server']['extras'].each do |key, value| %>
236+
<%= key %> <%= value %>
237+
<% end -%>
238+
<% end -%>

0 commit comments

Comments
 (0)