Skip to content
This repository was archived by the owner on Dec 26, 2020. It is now read-only.
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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ script:
- 'docker run --detach --volume="${PWD}":/etc/ansible/roles/ansible-ssh-hardening:ro ${run_opts} rndmh3ro/docker-${distro}-ansible:${version} "${init}" > "${container_id}"'

# Test role.
- 'docker exec "$(cat ${container_id})" ansible-playbook /etc/ansible/roles/ansible-ssh-hardening/default_custom.yml'
- 'docker exec "$(cat ${container_id})" ansible-playbook /etc/ansible/roles/ansible-ssh-hardening/default.yml'

# Verify role
Expand Down
47 changes: 1 addition & 46 deletions default.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
- name: wrapper playbook for kitchen testing "ansible-ssh-hardening" with custom settings
- name: wrapper playbook for kitchen testing "ansible-ssh-hardening" with default settings
hosts: localhost
pre_tasks:
- package: name="{{item}}" state=installed
Expand All @@ -19,48 +19,3 @@

roles:
- ansible-ssh-hardening
vars:
network_ipv6_enable: true
ssh_allow_root_with_key: true
ssh_allow_tcp_forwarding: true
ssh_gateway_ports: true
ssh_allow_agent_forwarding: true
ssh_server_permit_environment_vars: ['PWD','HTTP_PROXY']
ssh_client_alive_interval: 100
ssh_client_alive_count: 10
ssh_client_password_login: true
ssh_client_cbc_required: true
ssh_client_weak_kex: true
ssh_challengeresponseauthentication: true
ssh_compression: true
ssh_allow_users: 'root kitchen vagrant'
ssh_allow_groups: 'root kitchen vagrant'
ssh_deny_users: 'foo bar'
ssh_deny_groups: 'foo bar'
ssh_authorized_keys_file: '/etc/ssh/authorized_keys/%u'
ssh_max_auth_retries: 10
ssh_permit_tunnel: true
ssh_print_motd: true
ssh_print_last_log: true
ssh_banner: true
ssh_server_password_login: true
ssh_server_weak_hmac: true
sftp_enabled: true
ssh_server_match_group:
- group: 'root'
rules: 'AllowTcpForwarding yes'
ssh_server_match_user:
- user: 'root'
rules: 'AllowTcpForwarding yes'
ssh_remote_hosts:
- names: ['example.com', 'example2.com']
options: ['Port 2222', 'ForwardAgent yes']
- names: ['example3.com']
options: ['StrictHostKeyChecking no']
ssh_use_dns: true
ssh_use_pam: true

- name: wrapper playbook for kitchen testing "ansible-ssh-hardening" with default settings
hosts: localhost
roles:
- ansible-ssh-hardening
62 changes: 62 additions & 0 deletions default_custom.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
- name: wrapper playbook for kitchen testing "ansible-ssh-hardening" with custom settings
hosts: localhost
pre_tasks:
- package: name="{{item}}" state=installed
with_items:
- "openssh-clients"
- "openssh-server"
ignore_errors: true
- apt: name="{{item}}" state=installed update_cache=true
with_items:
- "openssh-client"
- "openssh-server"
ignore_errors: true
- file: path="/var/run/sshd" state=directory
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please always use YAML syntax.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix this in a separate PR where I'll change it everywhere.

- name: create ssh host keys
command: "ssh-keygen -A"
when: not ((ansible_os_family in ['Oracle Linux', 'RedHat']) and ansible_distribution_major_version < '7')

roles:
- ansible-ssh-hardening
vars:
network_ipv6_enable: true
ssh_allow_root_with_key: true
ssh_allow_tcp_forwarding: true
ssh_gateway_ports: true
ssh_allow_agent_forwarding: true
ssh_server_permit_environment_vars: ['PWD','HTTP_PROXY']
ssh_client_alive_interval: 100
ssh_client_alive_count: 10
ssh_client_password_login: true
ssh_client_cbc_required: true
ssh_client_weak_kex: true
ssh_challengeresponseauthentication: true
ssh_compression: true
ssh_allow_users: 'root kitchen vagrant'
ssh_allow_groups: 'root kitchen vagrant'
ssh_deny_users: 'foo bar'
ssh_deny_groups: 'foo bar'
ssh_authorized_keys_file: '/etc/ssh/authorized_keys/%u'
ssh_max_auth_retries: 10
ssh_permit_tunnel: true
ssh_print_motd: true
ssh_print_last_log: true
ssh_banner: true
ssh_server_password_login: true
ssh_server_weak_hmac: true
sftp_enabled: true
ssh_server_enabled: false
ssh_server_match_group:
- group: 'root'
rules: 'AllowTcpForwarding yes'
ssh_server_match_user:
- user: 'root'
rules: 'AllowTcpForwarding yes'
ssh_remote_hosts:
- names: ['example.com', 'example2.com']
options: ['Port 2222', 'ForwardAgent yes']
- names: ['example3.com']
options: ['StrictHostKeyChecking no']
ssh_use_dns: true
ssh_use_pam: true
13 changes: 11 additions & 2 deletions defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ ssh_server_permit_environment_vars: false
ssh_ps53: 'yes'
ssh_ps59: 'sandbox'

ssh_macs: []
ssh_ciphers: []
ssh_kex: []

ssh_macs_53_default:
- hmac-ripemd160
- hmac-sha1
Expand All @@ -138,11 +142,16 @@ ssh_macs_59_weak: "{{ ssh_macs_59_default + ['hmac-sha1'] }}"
ssh_macs_66_default:
- hmac-sha2-512-etm@openssh.com
- hmac-sha2-256-etm@openssh.com
- hmac-ripemd160-etm@openssh.com
- umac-128-etm@openssh.com
- hmac-sha2-512
- hmac-sha2-256
- hmac-ripemd160

ssh_macs_76_default:
- hmac-sha2-512-etm@openssh.com
- hmac-sha2-256-etm@openssh.com
- umac-128-etm@openssh.com
- hmac-sha2-512
- hmac-sha2-256

ssh_macs_66_weak: "{{ ssh_macs_66_default + ['hmac-sha1'] }}"

Expand Down
98 changes: 98 additions & 0 deletions tasks/crypto.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---

- name: set hostkeys according to openssh-version
set_fact:
ssh_host_key_files: ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_ecdsa_key', '/etc/ssh/ssh_host_ed25519_key']
when: sshd_version.stdout >= '6.3' and not ssh_host_key_files

- name: set hostkeys according to openssh-version
set_fact:
ssh_host_key_files: ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_ecdsa_key']
when: sshd_version.stdout >= '6.0' and not ssh_host_key_files

- name: set hostkeys according to openssh-version
set_fact:
ssh_host_key_files: ['/etc/ssh/ssh_host_rsa_key']
when: sshd_version.stdout >= '5.3' and not ssh_host_key_files
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would do that using one set_fact or even better in the defaults file. Something like:

ssh_host_key_files: '{{ ['/etc/ssh/ssh_host_rsa_key'] if sshd_version.stdout >= '6.0' else ... }}'

This way, the whole file can be reduced to Jinja2 templating in defaults/main.yml. This also helps with performance :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried and did not find a proper solution with the correct syntax.

                       "[/etc/ssh/ssh_host_rsa_key, /etc/ssh/ssh_host_ecdsa_key]" if sshd_version.stdout >= 6.0 else \  }}
                       "[/etc/ssh/ssh_host_rsa_key, /etc/ssh/ssh_host_ecdsa_key, /etc/ssh/ssh_host_ed25519_key]" if sshd_version.stdout >= 6.3 }}'```

This and variations of it do not work. They always give some error like:
```       fatal: [localhost]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{ssh_host_key_files}}): __init__() takes at least 3 arguments (2 given)"}


###

- name: set weak macs according to openssh-version if openssh >= 7.6
set_fact:
ssh_macs: "{{ssh_macs_76_default}}"
when: sshd_version.stdout >= '7.6' and not ssh_macs

- name: set weak macs according to openssh-version if openssh >= 6.6
set_fact:
ssh_macs: "{{ssh_macs_66_weak}}"
when: sshd_version.stdout >= '6.6' and ssh_server_weak_hmac and not ssh_macs

- name: set macs according to openssh-version if openssh >= 6.6
set_fact:
ssh_macs: "{{ssh_macs_66_default}}"
when: sshd_version.stdout >= '6.6' and not ssh_macs

- name: set weak macs according to openssh-version
set_fact:
ssh_macs: "{{ssh_macs_59_weak}}"
when: sshd_version.stdout >= '5.9' and ssh_server_weak_hmac and not ssh_macs

- name: set macs according to openssh-version
set_fact:
ssh_macs: "{{ssh_macs_59_default}}"
when: sshd_version.stdout >= '5.9' and not ssh_macs

- name: set macs according to openssh-version
set_fact:
ssh_macs: "{{ssh_macs_53_default}}"
when: sshd_version.stdout >= '5.3' and not ssh_macs

- name: set macs according to openssh-version
set_fact:
ssh_macs: "{{ssh_macs_53_default}}"
when: sshd_version.stdout >= '5.3' and not ssh_macs

###

- name: set weak ciphers according to openssh-version if openssh >= 6.6
set_fact:
ssh_ciphers: "{{ssh_ciphers_66_weak}}"
when: sshd_version.stdout >= '6.6' and ssh_server_cbc_required and not ssh_ciphers

- name: set ciphers according to openssh-version if openssh >= 6.6
set_fact:
ssh_ciphers: "{{ssh_ciphers_66_default}}"
when: sshd_version.stdout >= '6.6' and not ssh_ciphers

- name: set weak ciphers according to openssh-version
set_fact:
ssh_ciphers: "{{ssh_ciphers_53_weak}}"
when: sshd_version.stdout >= '5.3' and ssh_server_cbc_required and not ssh_ciphers

- name: set ciphers according to openssh-version
set_fact:
ssh_ciphers: "{{ssh_ciphers_53_default}}"
when: sshd_version.stdout >= '5.3' and not ssh_ciphers

###

- name: set weak kex according to openssh-version if openssh >= 6.6
set_fact:
ssh_kex: "{{ssh_kex_66_weak}}"
when: sshd_version.stdout >= '6.6' and ssh_server_weak_hmac and not ssh_kex

- name: set kex according to openssh-version if openssh >= 6.6
set_fact:
ssh_kex: "{{ssh_kex_66_default}}"
when: sshd_version.stdout >= '6.6' and not ssh_kex

- name: set weak kex according to openssh-version
set_fact:
ssh_kex: "{{ssh_kex_59_weak}}"
when: sshd_version.stdout >= '5.9' and ssh_server_weak_hmac and not ssh_kex

- name: set kex according to openssh-version
set_fact:
ssh_kex: "{{ssh_kex_59_default}}"
when: sshd_version.stdout >= '5.9' and not ssh_kex

15 changes: 1 addition & 14 deletions tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,7 @@
register: sshd_version
check_mode: no

- name: set hostkeys according to openssh-version
set_fact:
ssh_host_key_files: ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_ecdsa_key', '/etc/ssh/ssh_host_ed25519_key']
when: sshd_version.stdout >= '6.3' and not ssh_host_key_files

- name: set hostkeys according to openssh-version
set_fact:
ssh_host_key_files: ['/etc/ssh/ssh_host_rsa_key', '/etc/ssh/ssh_host_ecdsa_key']
when: sshd_version.stdout >= '6.0' and not ssh_host_key_files

- name: set hostkeys according to openssh-version
set_fact:
ssh_host_key_files: ['/etc/ssh/ssh_host_rsa_key']
when: sshd_version.stdout >= '5.3' and not ssh_host_key_files
- include: crypto.yml

- name: create revoked_keys and set permissions to root/600
template: src='revoked_keys.j2' dest='/etc/ssh/revoked_keys' mode=0600 owner="{{ ssh_owner }}" group="{{ ssh_group }}"
Expand Down
54 changes: 10 additions & 44 deletions templates/openssh.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -45,68 +45,34 @@ CheckHostIP yes
# Always ask before adding keys to the `known_hosts` file. Do not set to `yes`.
StrictHostKeyChecking ask


# **Ciphers** -- If your clients don't support CTR (eg older versions), cbc will be added
# CBC: is true if you want to connect with OpenSSL-base libraries
# eg ruby Net::SSH::Transport::CipherFactory requires cbc-versions of the given openssh ciphers to work
# -- see: (http://net-ssh.github.com/net-ssh/classes/Net/SSH/Transport/CipherFactory.html)
#
{% if ssh_client_cbc_required -%}
{% if (ansible_distribution == 'Ubuntu' and ansible_distribution_version >= '14.04') or (ansible_distribution == 'Debian' and ansible_distribution_version >= '8') or (ansible_os_family in ['Oracle Linux', 'RedHat'] and ansible_distribution_major_version >= '7') or (ansible_distribution == 'FreeBSD' and ansible_distribution_version >= '11') -%}
Ciphers {{ ssh_ciphers_66_weak | join(',') }}
{% else -%}
Ciphers {{ ssh_ciphers_53_weak | join(',') }}
{% endif %}
{% else -%}
{% if (ansible_distribution == 'Ubuntu' and ansible_distribution_version >= '14.04') or (ansible_distribution == 'Debian' and ansible_distribution_version >= '8') or (ansible_os_family in ['Oracle Linux', 'RedHat'] and ansible_distribution_major_version >= '7') or (ansible_distribution == 'FreeBSD' and ansible_distribution_version >= '11') -%}
Ciphers {{ ssh_ciphers_66_default | join(',') }}
{% else -%}
Ciphers {{ ssh_ciphers_53_default | join(',') }}
{% endif %}
{% endif %}

{# This outputs "Ciphers <list-of-ciphers>" if ssh_ciphers is defined or "#Ciphers" if ssh_ciphers is undefined #}
{{ "Ciphers "+ssh_ciphers| join(',') if ssh_ciphers else "Ciphers"|comment }}

# **Hash algorithms** -- Make sure not to use SHA1 for hashing, unless it is really necessary.
# Weak HMAC is sometimes required if older package versions are used
# eg Ruby's Net::SSH at around 2.2.* doesn't support sha2 for hmac, so this will have to be set true in this case.
#
{% if ssh_client_weak_hmac -%}
{% if (ansible_distribution == 'Ubuntu' and ansible_distribution_version >= '14.04') or (ansible_distribution == 'Debian' and ansible_distribution_version >= '8') or (ansible_os_family in ['Oracle Linux', 'RedHat'] and ansible_distribution_major_version >= '7') or (ansible_distribution == 'FreeBSD' and ansible_distribution_version >= '11') -%}
MACs {{ ssh_macs_66_weak | join(',') }}
{% elif ansible_os_family in ['Oracle Linux', 'RedHat'] and ansible_distribution_major_version <= '6' -%}
MACs {{ ssh_macs_53_default | join(',') }}
{% endif %}
{% else -%}
{% if (ansible_distribution == 'Ubuntu' and ansible_distribution_version >= '14.04') or (ansible_distribution == 'Debian' and ansible_distribution_version >= '8') or (ansible_os_family in ['Oracle Linux', 'RedHat'] and ansible_distribution_major_version >= '7') or (ansible_distribution == 'FreeBSD' and ansible_distribution_version >= '11') -%}
MACs {{ ssh_macs_66_default | join(',') }}
{% elif ansible_os_family in ['Oracle Linux', 'RedHat'] and ansible_distribution_major_version <= '6' -%}
MACs {{ ssh_macs_53_default | join(',') }}
{% else -%}
MACs {{ ssh_macs_59_default | join(',') }}
{% endif %}
{% endif %}

{# This outputs "MACs <list-of-macs>" if ssh_macs is defined or "#MACs" if ssh_macs is undefined #}
{{ "MACs "+ssh_macs| join(',') if ssh_macs else "MACs"|comment }}

# Alternative setting, if OpenSSH version is below v5.9
#MACs hmac-ripemd160

# **Key Exchange Algorithms** -- Make sure not to use SHA1 for kex, unless it is really necessary
# Weak kex is sometimes required if older package versions are used
# eg ruby's Net::SSH at around 2.2.* doesn't support sha2 for kex, so this will have to be set true in this case.
#
{% if (ansible_distribution == 'Ubuntu' and ansible_distribution_version >= '14.04') or (ansible_distribution == 'Debian' and ansible_distribution_version >= '8') or (ansible_os_family in ['Oracle Linux', 'RedHat'] and ansible_distribution_major_version >= '7') or (ansible_distribution == 'FreeBSD' and ansible_distribution_version >= '11') -%}
{% if ssh_client_weak_kex -%}
KexAlgorithms {{ ssh_kex_66_weak | join(',') }}
{% else -%}
KexAlgorithms {{ ssh_kex_66_default | join(',') }}
{% endif %}
{% else -%}
{% if ansible_os_family in ['Oracle Linux', 'RedHat'] and ansible_distribution_major_version <= '6' -%}
#KexAlgorithms
{% elif ssh_client_weak_kex -%}
KexAlgorithms {{ ssh_kex_59_weak | join(',') }}
{% else -%}
KexAlgorithms {{ ssh_kex_59_default | join(',') }}
{% endif %}
{% endif %}
# based on: https://bettercrypto.org/static/applied-crypto-hardening.pdf

{# This outputs "KexAlgorithms <list-of-algos>" if ssh_kex is defined or "#KexAlgorithms" if ssh_kex is undefined #}
{{ "KexAlgorithms "+ssh_kex| join(',') if ssh_kex else "KexAlgorithms"|comment }}

# Disable agent forwarding, since local agent could be accessed through forwarded connection.
ForwardAgent no
Expand Down
Loading