* linting

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* more linting

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* change line length issues

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* replace yes with true in tasks

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* use manual line-wrapping because ansible-lint does not support it correctly.

see https://github.com/ansible/ansible-lint/issues/2522

* use manual line-wrapping because ansible-lint does not support it correctly.

see https://github.com/ansible/ansible-lint/issues/2522

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* use manual line-wrapping because ansible-lint does not support it correctly.

see https://github.com/ansible/ansible-lint/issues/2522

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* add exception for task

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* remove trailing whitespace

* add back deleted params

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* add back deleted params

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>

* add back tasks

Signed-off-by: Sebastian Gumprich <sebastian.gumprich@t-systems.com>
This commit is contained in:
Sebastian Gumprich 2023-01-24 12:40:27 +01:00 committed by GitHub
parent a94168c84f
commit bb588bd777
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
74 changed files with 1095 additions and 1029 deletions

View file

@ -1,26 +0,0 @@
---
# Based on ansible-lint config
extends: default
rules:
braces:
max-spaces-inside: 1
level: error
brackets:
max-spaces-inside: 1
level: error
colons:
max-spaces-after: -1
level: error
commas:
max-spaces-after: -1
level: error
empty-lines:
max: 3
level: error
hyphens:
level: error
key-duplicates: enable
line-length: disable
new-lines:
type: unix

View file

@ -1,13 +1,14 @@
---
namespace: devsec
name: hardening
version: 8.4.0
readme: README.md
authors:
- dev-sec <hello@dev-sec.io>
description: 'This collection provides battle tested hardening for Linux, SSH, nginx, MySQL'
description: This collection provides battle tested hardening for Linux, SSH, nginx, MySQL
license:
- Apache-2.0
license_file: ''
license_file: ""
tags:
- devsec
- hardening
@ -23,13 +24,13 @@ tags:
- os_hardening
- ssh_hardening
dependencies:
ansible.posix: '>=1.0.0'
community.crypto: '>=1.0.0'
community.general: '>=1.0.0'
community.mysql: '>=1.3.0'
repository: 'https://github.com/dev-sec/ansible-collection-hardening/'
homepage: 'https://dev-sec.io/'
issues: 'https://github.com/dev-sec/ansible-collection-hardening/issues'
ansible.posix: ">=1.0.0"
community.crypto: ">=1.0.0"
community.general: ">=1.0.0"
community.mysql: ">=1.3.0"
repository: https://github.com/dev-sec/ansible-collection-hardening/
homepage: https://dev-sec.io/
issues: https://github.com/dev-sec/ansible-collection-hardening/issues
build_ignore:
- codecov.yml
- .github

View file

@ -1,2 +1,2 @@
---
requires_ansible: '>=2.9.10'
requires_ansible: ">=2.9.10"

View file

@ -7,9 +7,9 @@ mysql_daemon_enabled: true
mysql_hardening_restart_mysql: true
# general configuration
mysql_hardening_mysql_hardening_conf_file: '{{ mysql_hardening_mysql_confd_dir }}/hardening.cnf'
mysql_hardening_mysql_hardening_conf_file: "{{ mysql_hardening_mysql_confd_dir }}/hardening.cnf"
# You have to change this to your own strong enough mysql root password
mysql_root_password: '-----====>SetR00tPa$$wordH3r3!!!<====-----'
mysql_root_password: "-----====>SetR00tPa$$wordH3r3!!!<====-----"
# There .my.cnf with mysql root credentials will be installed
mysql_user_home: "{{ ansible_env.HOME }}"
@ -48,6 +48,6 @@ mysql_hardening_options:
automatic-sp-privileges: 0
# @see https://dev.mysql.com/doc/refman/5.7/en/server-options.html#option-mysqld-secure-file-priv
secure-file-priv: '/tmp'
secure-file-priv: /tmp
# @see https://dev.mysql.com/doc/refman/5.7/en/server-options.html#option_mysqld_user
user: '{{ mysql_hardening_user }}'
user: "{{ mysql_hardening_user }}"

View file

@ -1,7 +1,6 @@
---
- name: Restart mysql
service:
name: '{{ mysql_daemon }}'
ansible.builtin.service:
name: "{{ mysql_daemon }}"
state: restarted
when: mysql_hardening_restart_mysql | bool

View file

@ -1,10 +1,10 @@
---
galaxy_info:
author: "Sebastian Gumprich"
description: 'This Ansible playbook provides security configuration for mysql.'
author: Sebastian Gumprich
description: This Ansible playbook provides security configuration for mysql.
company: Hardening Framework Team
license: Apache License 2.0
min_ansible_version: '2.9.10'
min_ansible_version: 2.9.10
platforms:
- name: EL
versions:

View file

@ -1,64 +1,64 @@
---
- name: Protect my.cnf
file:
path: '{{ mysql_hardening_mysql_conf_file }}'
mode: '0640'
owner: '{{ mysql_cnf_owner }}'
group: '{{ mysql_cnf_group }}'
ansible.builtin.file:
path: "{{ mysql_hardening_mysql_conf_file }}"
mode: "0640"
owner: "{{ mysql_cnf_owner }}"
group: "{{ mysql_cnf_group }}"
follow: true
state: file
- name: Ensure permissions on mysql-datadir are correct
file:
path: '{{ item }}'
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: '{{ mysql_hardening_user }}'
group: '{{ mysql_hardening_user }}'
mode: '0750'
owner: "{{ mysql_hardening_user }}"
group: "{{ mysql_hardening_user }}"
mode: "0750"
when: item is defined and item != ""
loop:
- '{{ mysql_settings.settings.datadir }}'
- "{{ mysql_settings.settings.datadir }}"
- '{{ mysql_datadir | default("") }}'
- name: Ensure permissions on mysql-logfile are correct
file:
path: '{{ item }}'
ansible.builtin.file:
path: "{{ item }}"
state: file
owner: '{{ mysql_hardening_user }}'
group: '{{ mysql_hardening_group }}'
mode: '0640'
owner: "{{ mysql_hardening_user }}"
group: "{{ mysql_hardening_group }}"
mode: "0640"
when: item is defined and item != ""
loop:
- '{{ mysql_settings.settings.log_error }}'
- "{{ mysql_settings.settings.log_error }}"
- '{{ mysql_hardening_log_file | default("") }}'
- name: Check mysql configuration-directory exists and has right permissions
file:
path: '{{ mysql_hardening_mysql_confd_dir }}'
ansible.builtin.file:
path: "{{ mysql_hardening_mysql_confd_dir }}"
state: directory
owner: '{{ mysql_hardening_user }}'
group: '{{ mysql_hardening_group }}'
mode: '0750'
owner: "{{ mysql_hardening_user }}"
group: "{{ mysql_hardening_group }}"
mode: "0750"
- name: Check include-dir directive is present in my.cnf
lineinfile:
dest: '{{ mysql_hardening_mysql_conf_file }}'
line: '!includedir {{ mysql_hardening_mysql_confd_dir }}'
insertafter: 'EOF'
ansible.builtin.lineinfile:
dest: "{{ mysql_hardening_mysql_conf_file }}"
line: "!includedir {{ mysql_hardening_mysql_confd_dir }}"
insertafter: EOF
state: present
backup: true
notify: Restart mysql
- name: Apply hardening configuration
template:
src: 'hardening.cnf.j2'
dest: '{{ mysql_hardening_mysql_hardening_conf_file }}'
owner: '{{ mysql_cnf_owner }}'
group: '{{ mysql_cnf_group }}'
mode: '0640'
ansible.builtin.template:
src: hardening.cnf.j2
dest: "{{ mysql_hardening_mysql_hardening_conf_file }}"
owner: "{{ mysql_cnf_owner }}"
group: "{{ mysql_cnf_group }}"
mode: "0640"
notify: Restart mysql
- name: Enable mysql
service:
name: '{{ mysql_daemon }}'
enabled: '{{ mysql_daemon_enabled }}'
ansible.builtin.service:
name: "{{ mysql_daemon }}"
enabled: "{{ mysql_daemon_enabled }}"

View file

@ -1,14 +1,14 @@
---
- name: Fetch OS dependent variables
include_vars:
file: '{{ item }}'
name: 'os_vars'
ansible.builtin.include_vars:
file: "{{ item }}"
name: os_vars
with_first_found:
- files:
- '{{ ansible_facts.distribution }}_{{ ansible_facts.distribution_major_version }}.yml'
- '{{ ansible_facts.distribution }}.yml'
- '{{ ansible_facts.os_family }}_{{ ansible_facts.distribution_major_version }}.yml'
- '{{ ansible_facts.os_family }}.yml'
- "{{ ansible_facts.distribution }}_{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.distribution }}.yml"
- "{{ ansible_facts.os_family }}_{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.os_family }}.yml"
skip: true
tags: always
@ -16,16 +16,16 @@
# by default the lookup functions finds all varnames containing the string, therefore
# we add ^ and $ to denote start and end of string, so this returns only exact maches.
- name: Set OS dependent variables, if not already defined by user # noqa var-naming
set_fact:
'{{ item.key }}': '{{ item.value }}'
when: "not lookup('varnames', '^' + item.key + '$')"
with_dict: '{{ os_vars }}'
ansible.builtin.set_fact:
"{{ item.key }}": "{{ item.value }}"
when: not lookup('varnames', '^' + item.key + '$')
with_dict: "{{ os_vars }}"
tags: always
- name: Check that the variable mysql_distribution is set correctly
ansible.builtin.assert:
that: mysql_distribution == 'mysql' or mysql_distribution == 'mariadb'
fail_msg: 'mysql_distribution must be set to either mysql or mariadb!'
fail_msg: mysql_distribution must be set to either mysql or mariadb!
when: mysql_distribution is defined
- name: Gather package facts to check for mysql/mariadb version
@ -34,7 +34,7 @@
when: not mysql_distribution is defined
- name: Check if MySQL or MariaDB is used
set_fact:
ansible.builtin.set_fact:
mysql_distribution: "{{ ansible_facts.packages['mysql-server'] is defined | ternary('mysql', 'mariadb') }}"
when: not mysql_distribution is defined
@ -53,20 +53,20 @@
# see https://stackoverflow.com/a/59451077/2953919 for the
# dict2items and vice versa magic
- name: Drop the secure-auth parameter on MySQL >=8.0.3 (not mariadb)
set_fact:
ansible.builtin.set_fact:
mysql_hardening_options: "{{ mysql_hardening_options | dict2items | rejectattr('key', 'search', 'secure-auth') | list | items2dict }}"
when:
- mysql_version.version.full is version('8.0.3', '>=')
- mysql_distribution == "mysql"
- name: Include tasks for configuration
import_tasks: configure.yml
ansible.builtin.import_tasks: configure.yml
when: mysql_hardening_enabled | bool
tags:
- mysql_hardening
- name: Include tasks to secure mysql installation
import_tasks: mysql_secure_installation.yml
ansible.builtin.import_tasks: mysql_secure_installation.yml
when: mysql_hardening_enabled | bool
tags:
- mysql_hardening

View file

@ -1,22 +1,22 @@
---
- name: Fail the role if the mysql root password was not set
fail:
msg: 'ERROR - you have to change default mysql_root_password'
ansible.builtin.fail:
msg: ERROR - you have to change default mysql_root_password
when: mysql_root_password == '-----====>SetR00tPa$$wordH3r3!!!<====-----'
- name: Ensure that the root password is present
community.mysql.mysql_user:
name: 'root'
name: root
host_all: true
password: '{{ mysql_root_password | mandatory }}'
password: "{{ mysql_root_password | mandatory }}"
state: present
login_unix_socket: "{{ login_unix_socket | default(omit) }}"
- name: Install .my.cnf with credentials
template:
src: 'my.cnf.j2'
dest: '{{ mysql_user_home }}/.my.cnf'
mode: '0400'
ansible.builtin.template:
src: my.cnf.j2
dest: "{{ mysql_user_home }}/.my.cnf"
mode: "0400"
tags: my_cnf
- name: Ensure that the test database is absent
@ -28,7 +28,7 @@
- name: Ensure that anonymous users are absent
community.mysql.mysql_user:
name: ''
name: ""
state: absent
host_all: true
login_unix_socket: "{{ login_unix_socket | default(omit) }}"
@ -36,36 +36,38 @@
- name: Ensure that root can only login from localhost
community.mysql.mysql_query:
query:
- DELETE
query: >
DELETE
FROM mysql.user
WHERE USER='root'
AND HOST NOT IN ('localhost',
'127.0.0.1',
'::1')
'::1');
login_unix_socket: "{{ login_unix_socket | default(omit) }}"
when: mysql_remove_remote_root
- name: Get all users that have no authentication_string on MySQL version >= 5.7.6 or Mariadb version >= 10.4.0
community.mysql.mysql_query:
query:
- SELECT GROUP_CONCAT(QUOTE(USER), '@', QUOTE(HOST) SEPARATOR ', ') AS users
query: >
SELECT GROUP_CONCAT(QUOTE(USER), '@', QUOTE(HOST) SEPARATOR ', ') AS users
FROM mysql.user
WHERE (length(authentication_string)=0
OR authentication_string="")
AND USER NOT IN ('mysql.sys',
'mysqlxsys',
'mariadb.sys');
login_unix_socket: "{{ login_unix_socket | default(omit) }}"
register: mysql_users_wo_passwords_or_auth_string
when:
- (mysql_distribution == "mysql" and mysql_version.version.full is version('5.7.6', '>=')) or
(mysql_distribution == "mariadb" and mysql_version.version.full is version('10.4.0', '>='))
when: >
(mysql_distribution == "mysql" and mysql_version.version.full is version('5.7.6', '>=')) or
(mysql_distribution == "mariadb" and mysql_version.version.full
is version('10.4.0', '>='))
- name: Get all users that have no password or authentication_string on MySQL version < 5.7.6 or Mariadb version < 10.4.0
community.mysql.mysql_query:
query:
- SELECT GROUP_CONCAT(QUOTE(USER), '@', QUOTE(HOST) SEPARATOR ', ') AS users
query: >
SELECT GROUP_CONCAT(QUOTE(USER), '@', QUOTE(HOST) SEPARATOR ', ') AS users
FROM mysql.user
WHERE (length(password)=0
OR password="")
@ -76,19 +78,20 @@
'mariadb.sys');
login_unix_socket: "{{ login_unix_socket | default(omit) }}"
register: mysql_users_wo_passwords
when:
- (mysql_distribution == "mysql" and mysql_version.version.full is version('5.7.6', '<')) or
(mysql_distribution == "mariadb" and mysql_version.version.full is version('10.4.0', '<'))
when: >
(mysql_distribution == "mysql" and mysql_version.version.full is version('5.7.6', '<')) or
(mysql_distribution == "mariadb" and mysql_version.version.full is
version('10.4.0', '<'))
- name: Create a fact for users without password or authentication_string
set_fact:
ansible.builtin.set_fact:
users_wo_auth: "{{ mysql_users_wo_passwords_or_auth_string.query_result.0.0 | community.general.json_query('users') }}"
when:
- mysql_users_wo_passwords_or_auth_string.query_result is defined
- mysql_users_wo_passwords_or_auth_string.query_result != "" # noqa empty-string-compare
- name: Create a fact for users without password
set_fact:
ansible.builtin.set_fact:
users_wo_auth: "{{ mysql_users_wo_passwords.query_result.0.0 | community.general.json_query('users') }}"
when:
- mysql_users_wo_passwords.query_result is defined
@ -97,7 +100,7 @@
- name: Ensure that there are no users without password or authentication_string
community.mysql.mysql_query:
query:
- "DROP USER {{ users_wo_auth }}"
- DROP USER {{ users_wo_auth }}
login_unix_socket: "{{ login_unix_socket | default(omit) }}"
when:
- users_wo_auth is defined

View file

@ -1,10 +1,10 @@
---
mysql_daemon: mariadb
mysql_hardening_mysql_conf_file: '/etc/mysql/my.cnf'
mysql_hardening_mysql_confd_dir: '/etc/mysql/conf.d'
mysql_hardening_mysql_conf_file: /etc/mysql/my.cnf
mysql_hardening_mysql_confd_dir: /etc/mysql/conf.d
mysql_hardening_group: 'adm'
mysql_hardening_group: adm
mysql_cnf_owner: 'root' # owner of /etc/mysql/*.cnf files
mysql_cnf_group: 'mysql' # owner of /etc/mysql/*.cnf files
mysql_cnf_owner: root # owner of /etc/mysql/*.cnf files
mysql_cnf_group: mysql # owner of /etc/mysql/*.cnf files

View file

@ -1,4 +1,4 @@
---
mysql_daemon: mysqld
mysql_hardening_mysql_conf_file: '/etc/my.cnf'
mysql_hardening_mysql_confd_dir: '/etc/my.cnf.d'
mysql_hardening_mysql_conf_file: /etc/my.cnf
mysql_hardening_mysql_confd_dir: /etc/my.cnf.d

View file

@ -1,10 +1,10 @@
---
mysql_daemon: mysql-server
mysql_hardening_mysql_conf_file: '/usr/local/etc/mysql/my.cnf'
mysql_hardening_mysql_confd_dir: '/usr/local/etc/mysql/conf.d'
mysql_hardening_mysql_conf_file: /usr/local/etc/mysql/my.cnf
mysql_hardening_mysql_confd_dir: /usr/local/etc/mysql/conf.d
mysql_hardening_group: 'mysql'
mysql_hardening_group: mysql
mysql_cnf_owner: 'root' # owner of /usr/local/etc/mysql/*.cnf files
mysql_cnf_group: 'mysql' # owner of /usr/local/etc/mysql/*.cnf files
mysql_cnf_owner: root # owner of /usr/local/etc/mysql/*.cnf files
mysql_cnf_group: mysql # owner of /usr/local/etc/mysql/*.cnf files

View file

@ -1,7 +1,7 @@
---
mysql_daemon: mysqld
mysql_hardening_mysql_conf_file: '/etc/my.cnf'
mysql_hardening_mysql_confd_dir: '/etc/my.cnf.d'
mysql_hardening_mysql_conf_file: /etc/my.cnf
mysql_hardening_mysql_confd_dir: /etc/my.cnf.d
mysql_hardening_group: 'adm'
mysql_hardening_group: adm

View file

@ -1,9 +1,9 @@
---
mysql_daemon: mariadb
mysql_hardening_mysql_conf_file: '/etc/my.cnf'
mysql_hardening_mysql_confd_dir: '/etc/my.cnf.d'
mysql_hardening_mysql_conf_file: /etc/my.cnf
mysql_hardening_mysql_confd_dir: /etc/my.cnf.d
mysql_cnf_owner: 'root' # owner of /etc/mysql/*.cnf files
mysql_cnf_group: 'mysql' # owner of /etc/mysql/*.cnf files
mysql_cnf_owner: root # owner of /etc/mysql/*.cnf files
mysql_cnf_group: mysql # owner of /etc/mysql/*.cnf files
mysql_hardening_group: 'mysql'
mysql_hardening_group: mysql

View file

@ -1,10 +1,10 @@
---
mysql_daemon: mysql
mysql_hardening_mysql_conf_file: '/etc/mysql/my.cnf'
mysql_hardening_mysql_confd_dir: '/etc/mysql/conf.d'
mysql_hardening_mysql_conf_file: /etc/mysql/my.cnf
mysql_hardening_mysql_confd_dir: /etc/mysql/conf.d
mysql_cnf_owner: 'root' # owner of /etc/mysql/*.cnf files
mysql_cnf_group: 'mysql' # owner of /etc/mysql/*.cnf files
mysql_cnf_owner: root # owner of /etc/mysql/*.cnf files
mysql_cnf_group: mysql # owner of /etc/mysql/*.cnf files
mysql_hardening_group: 'adm'
mysql_hardening_group: adm

View file

@ -1,3 +1,2 @@
---
mysql_hardening_user: 'mysql' # owner of data
mysql_hardening_user: mysql # owner of data

View file

@ -1,20 +1,20 @@
---
nginx_client_body_buffer_size: '1k'
nginx_client_body_buffer_size: 1k
nginx_remove_default_site: true
nginx_client_max_body_size: '1k'
nginx_keepalive_timeout: '5 5'
nginx_server_tokens: 'off'
nginx_client_header_buffer_size: "1k"
nginx_large_client_header_buffers: "2 1k"
nginx_client_max_body_size: 1k
nginx_keepalive_timeout: 5 5
nginx_server_tokens: "off"
nginx_client_header_buffer_size: 1k
nginx_large_client_header_buffers: 2 1k
nginx_client_body_timeout: "10"
nginx_client_header_timeout: "10"
nginx_send_timeout: "10"
nginx_limit_conn_zone: "$binary_remote_addr zone=default:10m"
nginx_limit_conn: "default 5"
nginx_configuration_dir: "/etc/nginx"
nginx_configuration_hardening_dir: "/etc/nginx"
nginx_owner_user: "root"
nginx_owner_group: "root"
nginx_limit_conn_zone: $binary_remote_addr zone=default:10m
nginx_limit_conn: default 5
nginx_configuration_dir: /etc/nginx
nginx_configuration_hardening_dir: /etc/nginx
nginx_owner_user: root
nginx_owner_group: root
nginx_add_header:
# avoid clickjacking
- X-Frame-Options SAMEORIGIN
@ -27,7 +27,8 @@ nginx_add_header:
nginx_set_cookie_flag: "* HttpOnly secure"
nginx_ssl_prefer_server_ciphers: "on"
nginx_ssl_protocols: "TLSv1.2 TLSv1.3"
nginx_ssl_ciphers: "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256"
nginx_ssl_protocols: TLSv1.2 TLSv1.3
# yamllint disable-line rule:line-length
nginx_ssl_ciphers: ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
nginx_ssl_session_tickets: "off"
nginx_dh_size: "4096"

View file

@ -1,5 +1,5 @@
---
- name: Restart nginx
service:
name: "nginx"
ansible.builtin.service:
name: nginx
state: restarted

View file

@ -1,10 +1,10 @@
---
galaxy_info:
author: "Sebastian Gumprich"
description: 'This Ansible role provides secure nginx configurations. http://dev-sec.io/'
author: Sebastian Gumprich
description: This Ansible role provides secure nginx configurations. http://dev-sec.io/
company: Hardening Framework Team
license: Apache License 2.0
min_ansible_version: '2.9.10'
min_ansible_version: 2.9.10
platforms:
- name: EL
versions:

View file

@ -1,81 +1,81 @@
---
- name: Create additional configuration
template:
src: "hardening.conf.j2"
ansible.builtin.template:
src: hardening.conf.j2
dest: "{{ nginx_configuration_dir }}/conf.d/90.hardening.conf"
mode: '0600'
mode: "0600"
owner: "{{ nginx_owner_user }}"
group: "{{ nginx_owner_group }}"
notify: Restart nginx
- name: Change configuration in main nginx.conf
lineinfile:
ansible.builtin.lineinfile:
dest: "{{ nginx_configuration_dir }}/nginx.conf"
regexp: '^\s*server_tokens'
regexp: ^\s*server_tokens
line: " server_tokens {{ nginx_server_tokens }};"
insertafter: "http {"
mode: '0640'
insertafter: http {
mode: "0640"
owner: "{{ nginx_owner_user }}"
group: "{{ nginx_owner_group }}"
notify: Restart nginx
- name: Change ssl_protocols in main nginx.conf
lineinfile:
ansible.builtin.lineinfile:
dest: "{{ nginx_configuration_dir }}/nginx.conf"
regexp: '^\s*ssl_protocols'
regexp: ^\s*ssl_protocols
line: " ssl_protocols {{ nginx_ssl_protocols }};"
insertafter: "http {"
mode: '0640'
insertafter: http {
mode: "0640"
owner: "{{ nginx_owner_user }}"
group: "{{ nginx_owner_group }}"
notify: Restart nginx
- name: Change ssl_prefer_server_ciphers in main nginx.conf
lineinfile:
ansible.builtin.lineinfile:
dest: "{{ nginx_configuration_dir }}/nginx.conf"
regexp: '^\s*ssl_prefer_server_ciphers'
regexp: ^\s*ssl_prefer_server_ciphers
line: " ssl_prefer_server_ciphers {{ nginx_ssl_prefer_server_ciphers }};"
insertafter: "http {"
mode: '0640'
insertafter: http {
mode: "0640"
owner: "{{ nginx_owner_user }}"
group: "{{ nginx_owner_group }}"
notify: Restart nginx
- name: Change client_max_body_size in main nginx.conf
lineinfile:
ansible.builtin.lineinfile:
dest: "{{ nginx_configuration_dir }}/nginx.conf"
regexp: '^\s*client_max_body_size'
regexp: ^\s*client_max_body_size
line: " client_max_body_size {{ nginx_client_max_body_size }};"
insertafter: "http {"
mode: '0640'
insertafter: http {
mode: "0640"
owner: "{{ nginx_owner_user }}"
group: "{{ nginx_owner_group }}"
notify: Restart nginx
- name: Change client_body_buffer_size in main nginx.conf
lineinfile:
ansible.builtin.lineinfile:
dest: "{{ nginx_configuration_dir }}/nginx.conf"
regexp: '^\s*client_body_buffer_size'
regexp: ^\s*client_body_buffer_size
line: " client_body_buffer_size {{ nginx_client_body_buffer_size }};"
insertafter: "http {"
mode: '0640'
insertafter: http {
mode: "0640"
owner: "{{ nginx_owner_user }}"
group: "{{ nginx_owner_group }}"
notify: Restart nginx
- name: Change keepalive_timeout in main nginx.conf
lineinfile:
ansible.builtin.lineinfile:
dest: "{{ nginx_configuration_dir }}/nginx.conf"
regexp: '^\s*keepalive_timeout'
regexp: ^\s*keepalive_timeout
line: " keepalive_timeout {{ nginx_keepalive_timeout }};"
insertafter: "http {"
mode: '0640'
insertafter: http {
mode: "0640"
owner: "{{ nginx_owner_user }}"
group: "{{ nginx_owner_group }}"
notify: Restart nginx
- name: Remove default.conf
file:
ansible.builtin.file:
path: "{{ item }}"
state: absent
when: nginx_remove_default_site
@ -85,10 +85,10 @@
- "{{ nginx_configuration_dir }}/sites-enabled/default"
- name: Generate dh group
openssl_dhparam:
community.crypto.openssl_dhparam:
path: "{{ nginx_configuration_dir }}/dh{{ nginx_dh_size }}.pem"
size: "{{ nginx_dh_size }}"
mode: '0640'
mode: "0640"
owner: "{{ nginx_owner_user }}"
group: "{{ nginx_owner_group }}"
notify: Restart nginx

View file

@ -9,11 +9,10 @@ os_auth_lockout_time: 600 # Seconds (600 = 10min)
os_auth_timeout: 60
os_auth_allow_homeless: false
os_auth_pam_passwdqc_enable: true
os_auth_pam_passwdqc_options: 'min=disabled,disabled,16,12,8' # Used in Debian
os_auth_pam_pwquality_options: 'try_first_pass retry=3 authtok_type=' # Used in RHEL7 and RHEL8
os_auth_pam_passwdqc_options: min=disabled,disabled,16,12,8 # Used in Debian
os_auth_pam_pwquality_options: try_first_pass retry=3 authtok_type= # Used in RHEL7 and RHEL8
os_auth_root_ttys: [console, tty1, tty2, tty3, tty4, tty5, tty6]
os_chfn_restrict: ''
os_chfn_restrict: ""
# Set to false to disable chmod userhome folders to 700
os_chmod_rootuser_home_folder: true
@ -22,8 +21,7 @@ os_chmod_home_folders: true
# May contain: change_user
os_security_users_allow: []
# Specify user home folders in /home that shouldn't be chmodded to 700
os_ignore_home_folder_users: ['lost+found']
os_ignore_home_folder_users: [lost+found]
# Set to false to disable password age enforcement on existing users
os_rootuser_pw_ageing: false
@ -37,7 +35,7 @@ os_user_pw_ageing: true
os_users_without_password_ageing: []
# Specify system accounts whose login should not be disabled and password not changed
os_ignore_users: ['vagrant', 'kitchen']
os_ignore_users: [vagrant, kitchen]
os_security_kernel_enable_module_loading: true
os_security_kernel_enable_core_dump: false
os_security_suid_sgid_enforce: true
@ -49,8 +47,7 @@ os_security_suid_sgid_remove_from_unknown: false
# Remove packages with known security issues
os_security_packages_clean: true
os_security_packages_list: ['xinetd', 'inetd', 'ypserv', 'telnet-server', 'rsh-server', 'prelink']
os_security_packages_list: [xinetd, inetd, ypserv, telnet-server, rsh-server, prelink]
# Allow interactive startup (rhel, centos)
os_security_init_prompt: true
# Require root password for single user mode. (rhel, centos)
@ -63,15 +60,15 @@ ufw_manage_defaults: true
# By default in Ubuntu it is set to: /etc/ufw/sysctl.conf
# CAUTION!
# If you enable it - it overwrites /etc/sysctl.conf file, managed by hardening framework
ufw_ipt_sysctl: ''
ufw_ipt_sysctl: ""
# Default ufw variables
ufw_default_input_policy: 'DROP'
ufw_default_output_policy: 'ACCEPT'
ufw_default_forward_policy: 'DROP'
ufw_default_application_policy: 'SKIP'
ufw_manage_builtins: 'no'
ufw_ipt_modules: 'nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns'
ufw_default_input_policy: DROP
ufw_default_output_policy: ACCEPT
ufw_default_forward_policy: DROP
ufw_default_application_policy: SKIP
ufw_manage_builtins: "no"
ufw_ipt_modules: nf_conntrack_ftp nf_nat_ftp nf_conntrack_netbios_ns
# Set to true to apply rules to support IPv6 (no means only IPv6 on loopback
# accepted).
@ -307,27 +304,25 @@ sysctl_config:
# Do not delete the following line or otherwise the playbook will fail
# at task 'create a combined sysctl-dict if overwrites are defined'
sysctl_overwrite:
# Disable unused filesystems
os_unused_filesystems:
- "cramfs"
- "freevxfs"
- "jffs2"
- "hfs"
- "hfsplus"
- "squashfs"
- "udf"
- "vfat"
- cramfs
- freevxfs
- jffs2
- hfs
- hfsplus
- squashfs
- udf
- vfat
# Obsolete network protocols that should be disabled
# per CIS Oracle Linux 6 Benchmark (2016)
- "dccp" # CIS 3.5.1
- "rds" # CIS 3.5.3
- "sctp" # CIS 3.5.2
- "tipc" # CIS 3.5.4
- dccp # CIS 3.5.1
- rds # CIS 3.5.3
- sctp # CIS 3.5.2
- tipc # CIS 3.5.4
# Whitelist for used filesystems
os_filesystem_whitelist: []
# Set to false to turn the role into a no-op. Useful when using
# the Ansible role dependency mechanism.
os_hardening_enabled: true
@ -353,7 +348,7 @@ os_selinux_state: enforcing
os_selinux_policy: targeted
# Mount options for proc in /etc/fstab.
proc_mnt_options: 'rw,nosuid,nodev,noexec,relatime,hidepid={{ hidepid_option }}'
proc_mnt_options: rw,nosuid,nodev,noexec,relatime,hidepid={{ hidepid_option }}
# Set to false to disable installing and configuring cron.
os_cron_enabled: true
@ -399,7 +394,6 @@ os_yum_enabled: true
# List of yum repository files under /etc/yum.repos.d/ which should not be altered.
os_yum_repo_file_whitelist: []
# Set to false to disable installing and configuring apt.
os_apt_enabled: true
@ -412,72 +406,82 @@ os_selinux_enabled: true
os_sha_crypt_min_rounds: "640000"
os_sha_crypt_max_rounds: "640000"
os_mnt_boot_dir_mode: "0700"
os_mnt_boot_enabled: false
os_mnt_boot_src: ""
os_mnt_boot_options: 'rw,nosuid,nodev,noexec'
os_mnt_boot_options: rw,nosuid,nodev,noexec
os_mnt_boot_filesystem: ""
os_mnt_boot_dump: ""
os_mnt_boot_passno: ""
os_mnt_dev_dir_mode: "0755"
os_mnt_dev_enabled: true
os_mnt_dev_src: "devtmpfs"
os_mnt_dev_options: 'rw,nosuid,noexec'
os_mnt_dev_filesystem: "devtmpfs"
os_mnt_dev_src: devtmpfs
os_mnt_dev_options: rw,nosuid,noexec
os_mnt_dev_filesystem: devtmpfs
os_mnt_dev_dump: ""
os_mnt_dev_passno: ""
os_mnt_dev_shm_dir_mode: "1777"
os_mnt_dev_shm_enabled: true
os_mnt_dev_shm_src: "tmpfs"
os_mnt_dev_shm_options: 'rw,nosuid,nodev,noexec'
os_mnt_dev_shm_filesystem: "tmpfs"
os_mnt_dev_shm_src: tmpfs
os_mnt_dev_shm_options: rw,nosuid,nodev,noexec
os_mnt_dev_shm_filesystem: tmpfs
os_mnt_dev_shm_dump: ""
os_mnt_dev_shm_passno: ""
os_mnt_home_dir_mode: "0755"
os_mnt_home_enabled: false
os_mnt_home_src: ""
os_mnt_home_options: 'rw,nosuid,nodev'
os_mnt_home_options: rw,nosuid,nodev
os_mnt_home_filesystem: ""
os_mnt_home_dump: ""
os_mnt_home_passno: ""
os_mnt_run_dir_mode: "0755"
os_mnt_run_enabled: true
os_mnt_run_src: "tmpfs"
os_mnt_run_options: 'rw,nosuid,nodev'
os_mnt_run_filesystem: "tmpfs"
os_mnt_run_src: tmpfs
os_mnt_run_options: rw,nosuid,nodev
os_mnt_run_filesystem: tmpfs
os_mnt_run_dump: ""
os_mnt_run_passno: ""
os_mnt_tmp_dir_mode: "1777"
os_mnt_tmp_enabled: false
os_mnt_tmp_src: ""
os_mnt_tmp_options: 'rw,nosuid,nodev,noexec'
os_mnt_tmp_options: rw,nosuid,nodev,noexec
os_mnt_tmp_filesystem: ""
os_mnt_tmp_dump: ""
os_mnt_tmp_passno: ""
os_mnt_var_dir_mode: "0755"
os_mnt_var_enabled: false
os_mnt_var_src: ""
os_mnt_var_options: 'rw,nosuid,nodev'
os_mnt_var_options: rw,nosuid,nodev
os_mnt_var_filesystem: ""
os_mnt_var_dump: ""
os_mnt_var_passno: ""
os_mnt_var_log_dir_mode: "0755"
os_mnt_var_log_enabled: false
os_mnt_var_log_src: ""
os_mnt_var_log_options: 'rw,nosuid,nodev,noexec'
os_mnt_var_log_options: rw,nosuid,nodev,noexec
os_mnt_var_log_filesystem: ""
os_mnt_var_log_dump: ""
os_mnt_var_log_passno: ""
os_mnt_var_log_audit_dir_mode: "0700"
os_mnt_var_log_audit_enabled: false
os_mnt_var_log_audit_src: ""
os_mnt_var_log_audit_options: 'rw,nosuid,nodev,noexec'
os_mnt_var_log_audit_options: rw,nosuid,nodev,noexec
os_mnt_var_log_audit_filesystem: ""
os_mnt_var_log_audit_dump: ""
os_mnt_var_log_audit_passno: ""
os_mnt_var_tmp_dir_mode: "1777"
os_mnt_var_tmp_enabled: false
os_mnt_var_tmp_src: ""
os_mnt_var_tmp_options: 'rw,nosuid,nodev,noexec'
os_mnt_var_tmp_options: rw,nosuid,nodev,noexec
os_mnt_var_tmp_filesystem: ""
os_mnt_var_tmp_dump: ""
os_mnt_var_tmp_passno: ""

View file

@ -1,10 +1,10 @@
---
- name: Update-initramfs
ansible.builtin.command: 'update-initramfs -u'
ansible.builtin.command: update-initramfs -u
- name: Restart auditd
- name: Restart auditd # noqa command-instead-of-module
ansible.builtin.command:
cmd: 'service auditd restart' # rhel: see: https://access.redhat.com/solutions/2664811
cmd: service auditd restart # rhel: see: https://access.redhat.com/solutions/2664811
when: molecule_yml is not defined # restarting auditd in a container does not work
- name: Reload systemd

View file

@ -1,10 +1,10 @@
---
galaxy_info:
author: "Sebastian Gumprich"
description: 'This Ansible role provides numerous security-related ssh configurations, providing all-round base protection.'
author: Sebastian Gumprich
description: This Ansible role provides numerous security-related ssh configurations, providing all-round base protection.
company: Hardening Framework Team
license: Apache License 2.0
min_ansible_version: '2.9.10'
min_ansible_version: 2.9.10
platforms:
- name: EL
versions:

View file

@ -1,7 +1,7 @@
---
- name: Remove deprecated or insecure packages | package-01 - package-09
apt:
name: '{{ os_security_packages_list }}'
state: 'absent'
purge: 'yes'
ansible.builtin.apt:
name: "{{ os_security_packages_list }}"
state: absent
purge: true
when: os_security_packages_clean | bool

View file

@ -1,16 +1,16 @@
---
- name: Install auditd package | package-08
package:
name: '{{ auditd_package }}'
state: 'present'
ansible.builtin.package:
name: "{{ auditd_package }}"
state: present
tags: auditd
- name: Configure auditd | package-08
template:
src: 'etc/audit/auditd.conf.j2'
dest: '/etc/audit/auditd.conf'
owner: 'root'
group: 'root'
mode: '0640'
ansible.builtin.template:
src: etc/audit/auditd.conf.j2
dest: /etc/audit/auditd.conf
owner: root
group: root
mode: "0640"
notify: Restart auditd
tags: auditd

View file

@ -6,7 +6,7 @@
# CIS 5.1.2 - CIS 5.1.7
#
- name: Find cron files and directories
find:
ansible.builtin.find:
paths:
- /etc
patterns:

View file

@ -1,6 +1,6 @@
---
- name: Disable CTRL-ALT-DEL
systemd:
ansible.builtin.systemd:
name: ctrl-alt-del.target
masked: true
daemon_reload: true

View file

@ -1,14 +1,14 @@
---
- name: Fetch OS dependent variables
include_vars:
file: '{{ item }}'
name: 'os_vars'
ansible.builtin.include_vars:
file: "{{ item }}"
name: os_vars
with_first_found:
- files:
- '{{ ansible_facts.distribution }}_{{ ansible_facts.distribution_major_version }}.yml'
- '{{ ansible_facts.distribution }}.yml'
- '{{ ansible_facts.os_family }}_{{ ansible_facts.distribution_major_version }}.yml'
- '{{ ansible_facts.os_family }}.yml'
- "{{ ansible_facts.distribution }}_{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.distribution }}.yml"
- "{{ ansible_facts.os_family }}_{{ ansible_facts.distribution_major_version }}.yml"
- "{{ ansible_facts.os_family }}.yml"
skip: true
tags: always
@ -16,103 +16,103 @@
# by default the lookup functions finds all varnames containing the string, therefore
# we add ^ and $ to denote start and end of string, so this returns only exact matches
- name: Set OS dependent variables, if not already defined by user # noqa var-naming
set_fact:
'{{ item.key }}': '{{ item.value }}'
when: "not lookup('varnames', '^' + item.key + '$')"
with_dict: '{{ os_vars }}'
ansible.builtin.set_fact:
"{{ item.key }}": "{{ item.value }}"
when: not lookup('varnames', '^' + item.key + '$')
with_dict: "{{ os_vars }}"
tags: always
- name: Import tasks for auditd
import_tasks: auditd.yml
ansible.builtin.import_tasks: auditd.yml
tags: auditd
when: os_auditd_enabled | bool
- name: Import tasks for cron
import_tasks: cron.yml
ansible.builtin.import_tasks: cron.yml
tags: cron
when: os_cron_enabled | bool
- name: Import tasks to configure ctrl+alt+del
import_tasks: ctrlaltdel.yml
ansible.builtin.import_tasks: ctrlaltdel.yml
tags: ctrlaltdel
when: os_ctrlaltdel_disabled | bool
- name: Import tasks to configure limits
import_tasks: limits.yml
ansible.builtin.import_tasks: limits.yml
tags: limits
when: os_limits_enabled | bool
- name: Import tasks to configure login_defs
import_tasks: login_defs.yml
ansible.builtin.import_tasks: login_defs.yml
tags: login_defs
when: os_login_defs_enabled | bool
- name: Import tasks to minimize access permissions
import_tasks: minimize_access.yml
ansible.builtin.import_tasks: minimize_access.yml
tags: minimize_access
when: os_minimize_access_enabled | bool
- name: Import tasks to configure PAM
import_tasks: pam.yml
ansible.builtin.import_tasks: pam.yml
tags: pam
when: os_pam_enabled | bool
- name: Import tasks to configure modules
import_tasks: modprobe.yml
ansible.builtin.import_tasks: modprobe.yml
tags: modprobe
when: os_modprobe_enabled | bool
- name: Import tasks to configure profile
import_tasks: profile.yml
ansible.builtin.import_tasks: profile.yml
tags: profile
when: os_profile_enabled | bool
- name: Import tasks to configure securetty
import_tasks: securetty.yml
ansible.builtin.import_tasks: securetty.yml
tags: securetty
when: os_securetty_enabled | bool
- name: Import tasks to set suid and sgid
import_tasks: suid_sgid.yml
ansible.builtin.import_tasks: suid_sgid.yml
when: os_security_suid_sgid_enforce | bool
tags: suid_sgid
- name: Import tasks to configure sysctl
import_tasks: sysctl.yml
ansible.builtin.import_tasks: sysctl.yml
tags: sysctl
when: os_sysctl_enabled | bool
- name: Import tasks to harden user accounts
import_tasks: user_accounts.yml
ansible.builtin.import_tasks: user_accounts.yml
tags: user_accounts
when: os_user_accounts_enabled | bool
- name: Import tasks to configure rhosts
import_tasks: rhosts.yml
ansible.builtin.import_tasks: rhosts.yml
tags: rhosts
when: os_rhosts_enabled | bool
- name: Import tasks to configure netrc
import_tasks: netrc.yml
ansible.builtin.import_tasks: netrc.yml
tags: netrc
when: os_netrc_enabled | bool
- name: Import tasks to configure yum
import_tasks: yum.yml
ansible.builtin.import_tasks: yum.yml
tags: yum
when:
- ansible_facts.os_family == 'RedHat'
- os_yum_enabled | bool
- name: Import tasks to configure apt
import_tasks: apt.yml
ansible.builtin.import_tasks: apt.yml
tags: apt
when:
- ansible_facts.os_family == 'Debian'
- os_apt_enabled | bool
- name: Import tasks to configure selinux
import_tasks: selinux.yml
ansible.builtin.import_tasks: selinux.yml
tags: selinux
when:
- ansible_facts.selinux.status == 'enabled'

View file

@ -3,35 +3,35 @@
when: not os_security_kernel_enable_core_dump | bool
block:
- name: Create limits.d-directory if it does not exist | sysctl-31a, sysctl-31b
file:
path: '/etc/security/limits.d'
owner: 'root'
group: 'root'
mode: '0755'
state: 'directory'
ansible.builtin.file:
path: /etc/security/limits.d
owner: root
group: root
mode: "0755"
state: directory
- name: Create additional limits config file -> 10.hardcore.conf | sysctl-31a, sysctl-31b
pam_limits:
dest: '/etc/security/limits.d/10.hardcore.conf'
domain: '*'
community.general.pam_limits:
dest: /etc/security/limits.d/10.hardcore.conf
domain: "*"
limit_type: hard
limit_item: core
value: '0'
value: "0"
comment: Prevent core dumps for all users. These are usually not needed and may contain sensitive information
- name: Set 10.hardcore.conf perms to 0400 and root ownership
file:
ansible.builtin.file:
path: /etc/security/limits.d/10.hardcore.conf
owner: 'root'
group: 'root'
mode: '0440'
owner: root
group: root
mode: "0440"
state: touch
modification_time: preserve
access_time: preserve
- name: Create coredump.conf.d-directory if it does not exist
file:
path: '/etc/systemd/coredump.conf.d'
ansible.builtin.file:
path: /etc/systemd/coredump.conf.d
owner: root
group: root
mode: 0755
@ -39,9 +39,9 @@
when: ansible_service_mgr == "systemd"
- name: Create custom.conf for disabling coredumps
template:
src: 'etc/systemd/coredump.conf.d/coredumps.conf.j2'
dest: '/etc/systemd/coredump.conf.d/custom.conf'
ansible.builtin.template:
src: etc/systemd/coredump.conf.d/coredumps.conf.j2
dest: /etc/systemd/coredump.conf.d/custom.conf
owner: root
group: root
mode: 0644
@ -52,13 +52,13 @@
when: os_security_kernel_enable_core_dump | bool
block:
- name: Remove coredump.conf.d directory with files
file:
ansible.builtin.file:
path: /etc/systemd/coredump.conf.d
state: absent
when: ansible_service_mgr == "systemd"
notify: Reload systemd
- name: Remove 10.hardcore.conf config file
file:
ansible.builtin.file:
path: /etc/security/limits.d/10.hardcore.conf
state: absent

View file

@ -1,8 +1,8 @@
---
- name: Create login.defs | os-05, os-05b
template:
src: 'etc/login.defs.j2'
dest: '/etc/login.defs'
owner: 'root'
group: 'root'
mode: '0444'
ansible.builtin.template:
src: etc/login.defs.j2
dest: /etc/login.defs
owner: root
group: root
mode: "0444"

View file

@ -1,6 +1,6 @@
---
- name: Include hardening tasks
include_tasks: hardening.yml
ansible.builtin.include_tasks: hardening.yml
when: os_hardening_enabled | bool
tags:
- always

View file

@ -4,103 +4,193 @@
# still getting found and the permissions minimized in the next task.
# This is also the reason why there's ignore_errors: true on the task.
# also see: https://github.com/dev-sec/ansible-os-hardening/issues/219
- name: Find files with write-permissions for group
shell: "find -L {{ item }} -perm /go+w -type f" # noqa command-instead-of-shell
- name: Find files with write-permissions for group # noqa command-instead-of-shell
ansible.builtin.shell: find -L {{ item }} -perm /go+w -type f
with_community.general.flattened:
- '/usr/local/sbin'
- '/usr/local/bin'
- '/usr/sbin'
- '/usr/bin'
- '/sbin'
- '/bin'
- "{{ os_env_extra_user_paths }}" # noqa deprecated-bare-vars
- /usr/local/sbin
- /usr/local/bin
- /usr/sbin
- /usr/bin
- /sbin
- /bin
- "{{ os_env_extra_user_paths }}"
register: minimize_access_directories
ignore_errors: true
changed_when: false
- name: Minimize access on found files
file:
path: '{{ item.1 }}'
mode: 'go-w'
ansible.builtin.file:
path: "{{ item.1 }}"
mode: go-w
state: file
with_subelements:
- "{{ minimize_access_directories.results }}"
- stdout_lines
- name: Find shadow files
stat:
ansible.builtin.stat:
path: "{{ item }}"
loop:
- '/etc/shadow'
- '/etc/gshadow'
- '/etc/shadow-'
- '/etc/gshadow-'
- /etc/shadow
- /etc/gshadow
- /etc/shadow-
- /etc/gshadow-
register: minimize_access_shadow_files
- name: Change shadow ownership to root and mode to 0600 | os-02
file:
ansible.builtin.file:
dest: "{{ item.item }}"
owner: '{{ os_shadow_perms.owner }}'
group: '{{ os_shadow_perms.group }}'
mode: '{{ os_shadow_perms.mode }}'
owner: "{{ os_shadow_perms.owner }}"
group: "{{ os_shadow_perms.group }}"
mode: "{{ os_shadow_perms.mode }}"
when: item.stat.exists
loop: "{{ minimize_access_shadow_files.results }}"
- name: Find passwd files
stat:
ansible.builtin.stat:
path: "{{ item }}"
loop:
- '/etc/passwd'
- '/etc/group'
- '/etc/passwd-'
- '/etc/group-'
- /etc/passwd
- /etc/group
- /etc/passwd-
- /etc/group-
register: minimize_access_passwd_files
- name: Change passwd ownership to root and mode to 0644 | os-03
file:
ansible.builtin.file:
dest: "{{ item.item }}"
owner: '{{ os_passwd_perms.owner }}'
group: '{{ os_passwd_perms.group }}'
mode: '{{ os_passwd_perms.mode }}'
owner: "{{ os_passwd_perms.owner }}"
group: "{{ os_passwd_perms.group }}"
mode: "{{ os_passwd_perms.mode }}"
when: item.stat.exists
loop: "{{ minimize_access_passwd_files.results }}"
- name: Change su-binary to only be accessible to user and group root
file:
dest: '/bin/su'
owner: 'root'
group: 'root'
mode: '0750'
ansible.builtin.file:
dest: /bin/su
owner: root
group: root
mode: "0750"
when: '"change_user" not in os_security_users_allow'
- name: Set option hidepid for proc filesystem
mount:
ansible.posix.mount:
path: /proc
src: proc
fstype: proc
opts: '{{ proc_mnt_options }}'
opts: "{{ proc_mnt_options }}"
state: mounted
- name: Generate list of current available mounted filesystems on the system
set_fact:
ansible.builtin.set_fact:
mountpoints_list: "{{ ansible_mounts | map(attribute='mount') | list }}"
- name: Append special devices list to valid mountpoint list
set_fact:
ansible.builtin.set_fact:
mountpoints_list: "{{ mountpoints_list + ['/dev', '/dev/shm', '/run'] }}"
- name: Minimize access for filesystems
include_tasks: minimize_access_fs.yml
loop:
- { path: '/boot', src: '{{ os_mnt_boot_src }}', fstype: '{{ os_mnt_boot_filesystem }}', opts: '{{ os_mnt_boot_options }}', enabled: "{{ os_mnt_boot_enabled }}", mode: "{{ os_mnt_boot_dir_mode }}", group: "{{ os_mnt_boot_group }}", owner: "{{ os_mnt_boot_owner }}", dump: "{{ os_mnt_boot_dump }}", passno: "{{ os_mnt_boot_passno }}" }
- { path: '/dev', src: '{{ os_mnt_dev_src }}', fstype: '{{ os_mnt_dev_filesystem }}', opts: '{{ os_mnt_dev_options }}', enabled: "{{ os_mnt_dev_enabled }}", mode: "{{ os_mnt_dev_dir_mode }}", group: "{{ os_mnt_dev_group }}", owner: "{{ os_mnt_dev_owner }}", dump: "{{ os_mnt_dev_dump }}", passno: "{{ os_mnt_dev_passno }}" }
- { path: '/dev/shm', src: '{{ os_mnt_dev_shm_src }}', fstype: '{{ os_mnt_dev_shm_filesystem }}', opts: '{{ os_mnt_dev_shm_options }}', enabled: "{{ os_mnt_dev_shm_enabled }}", mode: "{{ os_mnt_dev_shm_dir_mode }}", group: "{{ os_mnt_dev_shm_group }}", owner: "{{ os_mnt_dev_shm_owner }}", dump: "{{ os_mnt_dev_shm_dump }}", passno: "{{ os_mnt_dev_shm_passno }}" }
- { path: '/home', src: '{{ os_mnt_home_src }}', fstype: '{{ os_mnt_home_filesystem }}', opts: '{{ os_mnt_home_options }}', enabled: "{{ os_mnt_home_enabled }}", mode: "{{ os_mnt_home_dir_mode }}", group: "{{ os_mnt_home_group }}", owner: "{{ os_mnt_home_owner }}", dump: "{{ os_mnt_home_dump }}", passno: "{{ os_mnt_home_passno }}" }
- { path: '/run', src: '{{ os_mnt_run_src }}', fstype: '{{ os_mnt_run_filesystem }}', opts: '{{ os_mnt_run_options }}', enabled: "{{ os_mnt_run_enabled }}", mode: "{{ os_mnt_run_dir_mode }}", group: "{{ os_mnt_run_group }}", owner: "{{ os_mnt_run_owner }}", dump: "{{ os_mnt_run_dump }}", passno: "{{ os_mnt_run_passno }}" }
- { path: '/tmp', src: '{{ os_mnt_tmp_src }}', fstype: '{{ os_mnt_tmp_filesystem }}', opts: '{{ os_mnt_tmp_options }}', enabled: "{{ os_mnt_tmp_enabled }}", mode: "{{ os_mnt_tmp_dir_mode }}", group: "{{ os_mnt_tmp_group }}", owner: "{{ os_mnt_tmp_owner }}", dump: "{{ os_mnt_tmp_dump }}", passno: "{{ os_mnt_tmp_passno }}" }
- { path: '/var', src: '{{ os_mnt_var_src }}', fstype: '{{ os_mnt_var_filesystem }}', opts: '{{ os_mnt_var_options }}', enabled: "{{ os_mnt_var_enabled }}", mode: "{{ os_mnt_var_dir_mode }}", group: "{{ os_mnt_var_group }}", owner: "{{ os_mnt_var_owner }}", dump: "{{ os_mnt_var_dump }}", passno: "{{ os_mnt_var_passno }}" }
- { path: '/var/log', src: '{{ os_mnt_var_log_src }}', fstype: '{{ os_mnt_var_log_filesystem }}', opts: '{{ os_mnt_var_log_options }}', enabled: "{{ os_mnt_var_log_enabled }}", mode: "{{ os_mnt_var_log_dir_mode }}", group: "{{ os_mnt_var_log_group }}", owner: "{{ os_mnt_var_log_owner }}", dump: "{{ os_mnt_var_log_dump }}", passno: "{{ os_mnt_var_log_passno }}" }
- { path: '/var/log/audit', src: '{{ os_mnt_var_log_audit_src }}', fstype: '{{ os_mnt_var_log_audit_filesystem }}', opts: '{{ os_mnt_var_log_audit_options }}', enabled: "{{ os_mnt_var_log_audit_enabled }}", mode: "{{ os_mnt_var_log_audit_dir_mode }}", group: "{{ os_mnt_var_log_audit_group }}", owner: "{{ os_mnt_var_log_audit_owner }}", dump: "{{ os_mnt_var_log_audit_dump }}", passno: "{{ os_mnt_var_log_audit_passno }}" }
- { path: '/var/tmp', src: '{{ os_mnt_var_tmp_src }}', fstype: '{{ os_mnt_var_tmp_filesystem }}', opts: '{{ os_mnt_var_tmp_options }}', enabled: "{{ os_mnt_var_tmp_enabled }}", mode: "{{ os_mnt_var_tmp_dir_mode }}", group: "{{ os_mnt_var_tmp_group }}", owner: "{{ os_mnt_var_tmp_owner }}", dump: "{{ os_mnt_var_tmp_dump }}", passno: "{{ os_mnt_var_tmp_passno }}" }
ansible.builtin.include_tasks: minimize_access_fs.yml
loop_control:
loop_var: mount
loop:
- path: /boot
src: "{{ os_mnt_boot_src }}"
fstype: "{{ os_mnt_boot_filesystem }}"
opts: "{{ os_mnt_boot_options }}"
enabled: "{{ os_mnt_boot_enabled }}"
mode: "{{ os_mnt_boot_dir_mode }}"
group: "{{ os_mnt_boot_group }}"
owner: "{{ os_mnt_boot_owner }}"
dump: "{{ os_mnt_boot_dump }}"
passno: "{{ os_mnt_boot_passno }}"
- path: /dev
src: "{{ os_mnt_dev_src }}"
fstype: "{{ os_mnt_dev_filesystem }}"
opts: "{{ os_mnt_dev_options }}"
enabled: "{{ os_mnt_dev_enabled }}"
mode: "{{ os_mnt_dev_dir_mode }}"
group: "{{ os_mnt_dev_group }}"
owner: "{{ os_mnt_dev_owner }}"
dump: "{{ os_mnt_dev_dump }}"
passno: "{{ os_mnt_dev_passno }}"
- path: /dev/shm
src: "{{ os_mnt_dev_shm_src }}"
fstype: "{{ os_mnt_dev_shm_filesystem }}"
opts: "{{ os_mnt_dev_shm_options }}"
enabled: "{{ os_mnt_dev_shm_enabled }}"
mode: "{{ os_mnt_dev_shm_dir_mode }}"
group: "{{ os_mnt_dev_shm_group }}"
owner: "{{ os_mnt_dev_shm_owner }}"
dump: "{{ os_mnt_dev_shm_dump }}"
passno: "{{ os_mnt_dev_shm_passno }}"
- path: /home
src: "{{ os_mnt_home_src }}"
fstype: "{{ os_mnt_home_filesystem }}"
opts: "{{ os_mnt_home_options }}"
enabled: "{{ os_mnt_home_enabled }}"
mode: "{{ os_mnt_home_dir_mode }}"
group: "{{ os_mnt_home_group }}"
owner: "{{ os_mnt_home_owner }}"
dump: "{{ os_mnt_home_dump }}"
passno: "{{ os_mnt_home_passno }}"
- path: /run
src: "{{ os_mnt_run_src }}"
fstype: "{{ os_mnt_run_filesystem }}"
opts: "{{ os_mnt_run_options }}"
enabled: "{{ os_mnt_run_enabled }}"
mode: "{{ os_mnt_run_dir_mode }}"
group: "{{ os_mnt_run_group }}"
owner: "{{ os_mnt_run_owner }}"
dump: "{{ os_mnt_run_dump }}"
passno: "{{ os_mnt_run_passno }}"
- path: /tmp
src: "{{ os_mnt_tmp_src }}"
fstype: "{{ os_mnt_tmp_filesystem }}"
opts: "{{ os_mnt_tmp_options }}"
enabled: "{{ os_mnt_tmp_enabled }}"
mode: "{{ os_mnt_tmp_dir_mode }}"
group: "{{ os_mnt_tmp_group }}"
owner: "{{ os_mnt_tmp_owner }}"
dump: "{{ os_mnt_tmp_dump }}"
passno: "{{ os_mnt_tmp_passno }}"
- path: /var
src: "{{ os_mnt_var_src }}"
fstype: "{{ os_mnt_var_filesystem }}"
opts: "{{ os_mnt_var_options }}"
enabled: "{{ os_mnt_var_enabled }}"
mode: "{{ os_mnt_var_dir_mode }}"
group: "{{ os_mnt_var_group }}"
owner: "{{ os_mnt_var_owner }}"
dump: "{{ os_mnt_var_dump }}"
passno: "{{ os_mnt_var_passno }}"
- path: /var/log
src: "{{ os_mnt_var_log_src }}"
fstype: "{{ os_mnt_var_log_filesystem }}"
opts: "{{ os_mnt_var_log_options }}"
enabled: "{{ os_mnt_var_log_enabled }}"
mode: "{{ os_mnt_var_log_dir_mode }}"
group: "{{ os_mnt_var_log_group }}"
owner: "{{ os_mnt_var_log_owner }}"
dump: "{{ os_mnt_var_log_dump }}"
passno: "{{ os_mnt_var_log_passno }}"
- path: /var/log/audit
src: "{{ os_mnt_var_log_audit_src }}"
fstype: "{{ os_mnt_var_log_audit_filesystem }}"
opts: "{{ os_mnt_var_log_audit_options }}"
enabled: "{{ os_mnt_var_log_audit_enabled }}"
mode: "{{ os_mnt_var_log_audit_dir_mode }}"
group: "{{ os_mnt_var_log_audit_group }}"
owner: "{{ os_mnt_var_log_audit_owner }}"
dump: "{{ os_mnt_var_log_audit_dump }}"
passno: "{{ os_mnt_var_log_audit_passno }}"
- path: /var/tmp
src: "{{ os_mnt_var_tmp_src }}"
fstype: "{{ os_mnt_var_tmp_filesystem }}"
opts: "{{ os_mnt_var_tmp_options }}"
enabled: "{{ os_mnt_var_tmp_enabled }}"
mode: "{{ os_mnt_var_tmp_dir_mode }}"
group: "{{ os_mnt_var_tmp_group }}"
owner: "{{ os_mnt_var_tmp_owner }}"
dump: "{{ os_mnt_var_tmp_dump }}"
passno: "{{ os_mnt_var_tmp_passno }}"

View file

@ -1,29 +1,29 @@
---
- name: Install modprobe to disable filesystems | os-10
package:
name: '{{ modprobe_package }}'
state: 'present'
ansible.builtin.package:
name: "{{ modprobe_package }}"
state: present
- name: Check if efi is installed
stat:
path: "/sys/firmware/efi"
ansible.builtin.stat:
path: /sys/firmware/efi
register: efi_installed
- name: Remove vfat from fs-list if efi is used
set_fact:
ansible.builtin.set_fact:
os_unused_filesystems: "{{ os_unused_filesystems | difference('vfat') }}"
when:
- efi_installed.stat.isdir is defined
- efi_installed.stat.isdir
- name: Remove used filesystems from fs-list
set_fact:
ansible.builtin.set_fact:
os_unused_filesystems: "{{ os_unused_filesystems | difference(ansible_mounts | map(attribute='fstype') | list) }}"
- name: Disable unused filesystems | os-10
template:
src: 'etc/modprobe.d/modprobe.j2'
dest: '/etc/modprobe.d/dev-sec.conf'
owner: 'root'
group: 'root'
mode: '0644'
ansible.builtin.template:
src: etc/modprobe.d/modprobe.j2
dest: /etc/modprobe.d/dev-sec.conf
owner: root
group: root
mode: "0644"

View file

@ -1,13 +1,13 @@
---
- name: Get user accounts | os-09
command: "awk -F: '{print $1}' /etc/passwd"
ansible.builtin.command: "awk -F: '{print $1}' /etc/passwd"
changed_when: false
check_mode: false
register: users_accounts
- name: Delete .netrc-files from system | os-09
file:
dest: '~{{ item }}/.netrc'
state: 'absent'
loop: '{{ users_accounts.stdout_lines | flatten | default([]) }}'
ansible.builtin.file:
dest: ~{{ item }}/.netrc
state: absent
loop: "{{ users_accounts.stdout_lines | flatten | default([]) }}"
when: item not in os_netrc_whitelist_user

View file

@ -1,6 +1,6 @@
---
- name: Gather package facts
package_facts:
ansible.builtin.package_facts:
manager: auto
when:
- ansible_facts.os_family != 'Suse'
@ -11,29 +11,29 @@
# normally caching credentials shouldn't be necessary for most machines.
# removing it provides some more security while not removing usability.
- name: Remove pam ccreds to disable password caching
package:
name: '{{ os_packages_pam_ccreds }}'
state: 'absent'
ansible.builtin.package:
name: "{{ os_packages_pam_ccreds }}"
state: absent
when:
- ansible_facts.os_family != 'Archlinux'
- name: Import tasks for Debian PAM
import_tasks: pam_debian.yml
ansible.builtin.import_tasks: pam_debian.yml
when:
- ansible_facts.os_family == 'Debian'
- name: Import tasks for RedHat PAM
import_tasks: pam_rhel.yml
ansible.builtin.import_tasks: pam_rhel.yml
when:
- ansible_facts.os_family == 'RedHat'
- name: NSA 2.3.3.5 Upgrade Password Hashing Algorithm to SHA-512
template:
src: 'etc/libuser.conf.j2'
dest: '/etc/libuser.conf'
mode: '0640'
owner: 'root'
group: 'root'
ansible.builtin.template:
src: etc/libuser.conf.j2
dest: /etc/libuser.conf
mode: "0640"
owner: root
group: root
when:
- ansible_facts.os_family != 'Suse'
- ansible_facts.os_family != 'Archlinux'

View file

@ -1,120 +1,120 @@
---
- name: Install the package for strong password checking
apt:
name: 'libpam-passwdqc'
state: 'present'
update_cache: 'yes'
ansible.builtin.apt:
name: libpam-passwdqc
state: present
update_cache: true
when:
- os_auth_pam_passwdqc_enable
- name: Configure passwdqc
template:
src: 'usr/share/pam-configs/pam_passwdqc.j2'
dest: '{{ passwdqc_path }}'
mode: '0644'
owner: 'root'
group: 'root'
ansible.builtin.template:
src: usr/share/pam-configs/pam_passwdqc.j2
dest: "{{ passwdqc_path }}"
mode: "0644"
owner: root
group: root
when:
- os_auth_pam_passwdqc_enable
- name: Install tally2
apt:
name: 'libpam-modules'
state: 'present'
ansible.builtin.apt:
name: libpam-modules
state: present
when:
- os_auth_retries|int > 0
- name: Manage tally on Debian stable
when:
- "'libpam-modules' in ansible_facts.packages"
- "ansible_facts.packages['libpam-modules'][0].version is version('1.4.0', '<')"
- ansible_facts.packages['libpam-modules'][0].version is version('1.4.0', '<')
block:
- name: Configure tally2
template:
src: 'usr/share/pam-configs/pam_tally2.j2'
dest: '{{ tally2_path }}'
mode: '0644'
owner: 'root'
group: 'root'
ansible.builtin.template:
src: usr/share/pam-configs/pam_tally2.j2
dest: "{{ tally2_path }}"
mode: "0644"
owner: root
group: root
when:
- os_auth_retries|int > 0
- name: Delete tally2 when retries is 0
file:
path: '{{ tally2_path }}'
state: 'absent'
ansible.builtin.file:
path: "{{ tally2_path }}"
state: absent
when:
- os_auth_retries|int == 0
- name: Manage tally/faillock on Debian unstable
when:
- "'libpam-modules' in ansible_facts.packages"
- "ansible_facts.packages['libpam-modules'][0].version is version('1.4.0', '>=')"
- ansible_facts.packages['libpam-modules'][0].version is version('1.4.0', '>=')
block:
- name: Delete tally2
file:
path: '{{ tally2_path }}'
state: 'absent'
ansible.builtin.file:
path: "{{ tally2_path }}"
state: absent
- name: Create tally directory
file:
path: '/var/run/faillock'
state: 'directory'
mode: '0755'
owner: 'root'
group: 'root'
ansible.builtin.file:
path: /var/run/faillock
state: directory
mode: "0755"
owner: root
group: root
- name: Configure faillock
template:
src: 'etc/security/faillock.conf.j2'
dest: '/etc/security/faillock.conf'
mode: '0644'
owner: 'root'
group: 'root'
ansible.builtin.template:
src: etc/security/faillock.conf.j2
dest: /etc/security/faillock.conf
mode: "0644"
owner: root
group: root
- name: Configure faillock pam
template:
src: 'usr/share/pam-configs/pam_faillock.j2'
dest: '/usr/share/pam-configs/faillock'
mode: '0644'
owner: 'root'
group: 'root'
ansible.builtin.template:
src: usr/share/pam-configs/pam_faillock.j2
dest: /usr/share/pam-configs/faillock
mode: "0644"
owner: root
group: root
when:
- os_auth_retries|int > 0
- name: Configure faillock pam authfail
template:
src: 'usr/share/pam-configs/pam_faillock_authfail.j2'
dest: '/usr/share/pam-configs/faillock_authfail'
mode: '0644'
owner: 'root'
group: 'root'
ansible.builtin.template:
src: usr/share/pam-configs/pam_faillock_authfail.j2
dest: /usr/share/pam-configs/faillock_authfail
mode: "0644"
owner: root
group: root
when:
- os_auth_retries|int > 0
- name: Delete faillock when retries is 0
file:
path: '/usr/share/pam-configs/faillock'
state: 'absent'
ansible.builtin.file:
path: /usr/share/pam-configs/faillock
state: absent
when:
- os_auth_retries|int == 0
- name: Delete faillock authfail when retries is 0
file:
path: '/usr/share/pam-configs/faillock_authfail'
state: 'absent'
ansible.builtin.file:
path: /usr/share/pam-configs/faillock_authfail
state: absent
when:
- os_auth_retries|int == 0
- name: Update pam on Debian systems
command: 'pam-auth-update --package'
ansible.builtin.command: pam-auth-update --package
environment:
DEBIAN_FRONTEND: noninteractive
changed_when: false
- name: Remove passwdqc
apt:
name: 'libpam-passwdqc'
state: 'absent'
ansible.builtin.apt:
name: libpam-passwdqc
state: absent
when:
- not os_auth_pam_passwdqc_enable

View file

@ -1,43 +1,43 @@
---
- name: Install sssd-clients
yum:
ansible.builtin.yum:
name: sssd-client
state: 'present'
state: present
when:
- os_auth_pam_sssd_enable | bool
- name: Configure passwdqc and faillock via central system-auth config
template:
src: 'etc/pam.d/rhel_auth.j2'
dest: '/etc/pam.d/system-auth-local'
mode: '0640'
owner: 'root'
group: 'root'
ansible.builtin.template:
src: etc/pam.d/rhel_auth.j2
dest: /etc/pam.d/system-auth-local
mode: "0640"
owner: root
group: root
- name: Enable our config for system-auth
file:
ansible.builtin.file:
src: /etc/pam.d/system-auth-local
dest: /etc/pam.d/system-auth
mode: '0640'
owner: 'root'
group: 'root'
mode: "0640"
owner: root
group: root
state: link
force: true
- name: Configure passwdqc and faillock via central password-auth config
template:
src: 'etc/pam.d/rhel_auth.j2'
dest: '/etc/pam.d/password-auth-local'
mode: '0640'
owner: 'root'
group: 'root'
ansible.builtin.template:
src: etc/pam.d/rhel_auth.j2
dest: /etc/pam.d/password-auth-local
mode: "0640"
owner: root
group: root
- name: Enable our config for password-auth
file:
ansible.builtin.file:
src: /etc/pam.d/password-auth-local
dest: /etc/pam.d/password-auth
mode: '0640'
owner: 'root'
group: 'root'
mode: "0640"
owner: root
group: root
state: link
force: true

View file

@ -1,23 +1,23 @@
---
- name: Add pinerolo_profile.sh to profile.d
template:
src: 'etc/profile.d/profile.conf.j2'
dest: '/etc/profile.d/pinerolo_profile.sh'
owner: 'root'
group: 'root'
mode: '0750'
ansible.builtin.template:
src: etc/profile.d/profile.conf.j2
dest: /etc/profile.d/pinerolo_profile.sh
owner: root
group: root
mode: "0750"
when: not os_security_kernel_enable_core_dump | bool
- name: Remove pinerolo_profile.sh from profile.d
file:
ansible.builtin.file:
path: /etc/profile.d/pinerolo_profile.sh
state: absent
when: os_security_kernel_enable_core_dump | bool
- name: Add autologout to profile env
template:
src: 'etc/profile.d/tmout.sh.j2'
dest: '/etc/profile.d/tmout.sh'
owner: 'root'
group: 'root'
mode: '0644'
ansible.builtin.template:
src: etc/profile.d/tmout.sh.j2
dest: /etc/profile.d/tmout.sh
owner: root
group: root
mode: "0644"

View file

@ -1,17 +1,17 @@
---
- name: Get user accounts | os-09
command: "awk -F: '{print $1}' /etc/passwd"
ansible.builtin.command: "awk -F: '{print $1}' /etc/passwd"
changed_when: false
check_mode: false
register: users_accounts
- name: Delete rhosts-files from system | os-09
file:
dest: '~{{ item }}/.rhosts'
state: 'absent'
loop: '{{ users_accounts.stdout_lines | flatten | default([]) }}'
ansible.builtin.file:
dest: ~{{ item }}/.rhosts
state: absent
loop: "{{ users_accounts.stdout_lines | flatten | default([]) }}"
- name: Delete hosts.equiv from system | os-01
file:
dest: '/etc/hosts.equiv'
state: 'absent'
ansible.builtin.file:
dest: /etc/hosts.equiv
state: absent

View file

@ -1,8 +1,8 @@
---
- name: Create securetty
template:
src: 'etc/securetty.j2'
dest: '/etc/securetty'
owner: 'root'
group: 'root'
mode: '0400'
ansible.builtin.template:
src: etc/securetty.j2
dest: /etc/securetty
owner: root
group: root
mode: "0400"

View file

@ -1,5 +1,5 @@
---
- name: Configure selinux | selinux-01
selinux:
ansible.posix.selinux:
policy: "{{ os_selinux_policy }}"
state: "{{ os_selinux_state }}"
state: "{{ os_selinux_state }}" # noqa args - see https://github.com/ansible/ansible-lint/issues/2930

View file

@ -1,32 +1,32 @@
---
- name: Remove suid/sgid bit from binaries in blacklist | os-06
file:
path: '{{ item }}'
mode: 'a-s'
state: 'file'
follow: 'yes'
ansible.builtin.file:
path: "{{ item }}"
mode: a-s
state: file
follow: true
failed_when: false
with_community.general.flattened:
- '{{ os_security_suid_sgid_system_blacklist }}'
- '{{ os_security_suid_sgid_blacklist }}'
- "{{ os_security_suid_sgid_system_blacklist }}"
- "{{ os_security_suid_sgid_blacklist }}"
- name: Find binaries with suid/sgid set | os-06
shell: find / -xdev \( -perm -4000 -o -perm -2000 \) -type f ! -path '/proc/*' -print 2>/dev/null
ansible.builtin.shell: find / -xdev \( -perm -4000 -o -perm -2000 \) -type f ! -path '/proc/*' -print 2>/dev/null
register: sbit_binaries
when: os_security_suid_sgid_remove_from_unknown | bool
changed_when: false
- name: Gather files from which to remove suids/sgids and remove system white-listed files | os-06
set_fact:
suid: '{{ sbit_binaries.stdout_lines | difference(os_security_suid_sgid_system_whitelist) }}'
ansible.builtin.set_fact:
suid: "{{ sbit_binaries.stdout_lines | difference(os_security_suid_sgid_system_whitelist) }}"
when: os_security_suid_sgid_remove_from_unknown | bool
- name: Remove suid/sgid bit from all binaries except in system and user whitelist | os-06
file:
path: '{{ item }}'
mode: 'a-s'
state: 'file'
follow: 'yes'
ansible.builtin.file:
path: "{{ item }}"
mode: a-s
state: file
follow: true
with_community.general.flattened:
- '{{ suid | default([]) | difference(os_security_suid_sgid_whitelist) }}'
- "{{ suid | default([]) | difference(os_security_suid_sgid_whitelist) }}"
when: os_security_suid_sgid_remove_from_unknown | bool

View file

@ -1,39 +1,39 @@
---
- name: Protect sysctl.conf
file:
path: '/etc/sysctl.conf'
owner: 'root'
group: 'root'
mode: '0440'
ansible.builtin.file:
path: /etc/sysctl.conf
owner: root
group: root
mode: "0440"
state: touch
modification_time: preserve
access_time: preserve
- name: Set Daemon umask, do config for rhel-family | NSA 2.2.4.1
template:
src: 'etc/sysconfig/rhel_sysconfig_init.j2'
dest: '/etc/sysconfig/init'
owner: 'root'
group: 'root'
mode: '0544'
ansible.builtin.template:
src: etc/sysconfig/rhel_sysconfig_init.j2
dest: /etc/sysconfig/init
owner: root
group: root
mode: "0544"
when: ansible_facts.os_family == 'RedHat'
- name: Install initramfs-tools
apt:
name: 'initramfs-tools'
state: 'present'
ansible.builtin.apt:
name: initramfs-tools
state: present
update_cache: true
when:
- ansible_facts.os_family == 'Debian'
- os_security_kernel_enable_module_loading
- name: Rebuild initramfs with starting pack of modules, if module loading at runtime is disabled
template:
src: 'etc/initramfs-tools/modules.j2'
dest: '/etc/initramfs-tools/modules'
owner: 'root'
group: 'root'
mode: '0440'
ansible.builtin.template:
src: etc/initramfs-tools/modules.j2
dest: /etc/initramfs-tools/modules
owner: root
group: root
mode: "0440"
notify:
- Update-initramfs
when:
@ -45,37 +45,37 @@
when: ansible_virtualization_type not in ['docker', 'lxc', 'openvz']
block:
- name: Create a combined sysctl-dict if os-dependent sysctls are defined
set_fact:
sysctl_config: '{{ sysctl_config | combine(sysctl_custom_config) }}'
ansible.builtin.set_fact:
sysctl_config: "{{ sysctl_config | combine(sysctl_custom_config) }}"
when: sysctl_custom_config | default()
# sysctl_rhel_config is kept for backwards-compatibility. use sysctl_custom_config instead
- name: Create a combined sysctl-dict if os-dependent sysctls are defined
set_fact:
sysctl_config: '{{ sysctl_config | combine(sysctl_rhel_config) }}'
ansible.builtin.set_fact:
sysctl_config: "{{ sysctl_config | combine(sysctl_rhel_config) }}"
when: sysctl_rhel_config | default()
- name: Create a combined sysctl-dict if overwrites are defined
set_fact:
sysctl_config: '{{ sysctl_config | combine(sysctl_overwrite) }}'
ansible.builtin.set_fact:
sysctl_config: "{{ sysctl_config | combine(sysctl_overwrite) }}"
when: sysctl_overwrite | default()
- name: Change various sysctl-settings, look at the sysctl-vars file for documentation
sysctl:
name: '{{ item.key }}'
value: '{{ item.value }}'
ansible.posix.sysctl:
name: "{{ item.key }}"
value: "{{ item.value }}"
sysctl_set: true
state: present
reload: true
ignoreerrors: true
with_dict: '{{ sysctl_config }}'
with_dict: "{{ sysctl_config }}"
when: item.key not in sysctl_unsupported_entries | default()
- name: Apply ufw defaults
template:
src: 'etc/default/ufw.j2'
dest: '/etc/default/ufw'
mode: '0644'
ansible.builtin.template:
src: etc/default/ufw.j2
dest: /etc/default/ufw
mode: "0644"
when:
- ufw_manage_defaults
- ansible_facts.os_family == 'Debian'

View file

@ -1,12 +1,12 @@
---
- name: Read local linux user database
getent:
ansible.builtin.getent:
database: passwd
# creates a dict for each user containing UID/HOMEDIR etc...
when: getent_passwd is undefined # skip this task if "getent" has run before
- name: Read local linux shadow database
getent:
ansible.builtin.getent:
database: shadow
- name: Extract regular (non-system, non-root) accounts from local user database
@ -36,11 +36,11 @@
loop: "{{ getent_passwd.keys() | list }}"
when:
- getent_passwd[item][1]|int == 0
set_fact:
ansible.builtin.set_fact:
root_users: "{{ root_users | default([]) + [item] }}"
- name: Set ownership of root user home directory(s) to 0700
file:
ansible.builtin.file:
mode: 0700
owner: "{{ item }}"
path: "{{ getent_passwd[item][4] }}"
@ -50,7 +50,7 @@
- os_chmod_rootuser_home_folder | bool
- name: Set password ageing for root user(s)
user:
ansible.builtin.user:
name: "{{ item }}"
password_expire_min: "{{ os_auth_pw_min_age }}"
password_expire_max: "{{ os_auth_pw_max_age }}"
@ -61,7 +61,7 @@
- getent_shadow[item][0] is not match("\!") # password hashes containing illegal characters like "!" are unusable (locked) and don't need to age
- name: Remove additional users with UID=0 ("root" user is not touched)
user:
ansible.builtin.user:
name: "{{ item }}"
state: absent
loop: "{{ root_users }}"
@ -71,7 +71,7 @@
- item != "root"
- name: Get UID_MIN from login.defs
shell: awk '/^\s*UID_MIN\s*([0-9]*).*?$/ {print $2}' /etc/login.defs
ansible.builtin.shell: awk '/^\s*UID_MIN\s*([0-9]*).*?$/ {print $2}' /etc/login.defs
args:
removes: /etc/login.defs
register: uid_min
@ -79,24 +79,24 @@
changed_when: false
- name: Calculate UID_MAX from UID_MIN by substracting 1
set_fact:
uid_max: '{{ uid_min.stdout | int - 1 }}'
ansible.builtin.set_fact:
uid_max: "{{ uid_min.stdout | int - 1 }}"
when: uid_min.stdout|int > 0
- name: Set UID_MAX on Debian-systems if no login.defs exist
set_fact:
uid_max: '999'
ansible.builtin.set_fact:
uid_max: "999"
when:
- ansible_facts.os_family == 'Debian'
- uid_max is not defined
- name: Set UID_MAX on other systems if no login.defs exist
set_fact:
uid_max: '499'
ansible.builtin.set_fact:
uid_max: "499"
when: uid_max is not defined
- name: Get all system accounts
command: awk -F'':'' '{ if ( $3 <= {{ uid_max | quote }} ) print $1}' /etc/passwd
ansible.builtin.command: awk -F'':'' '{ if ( $3 <= {{ uid_max | quote }} ) print $1}' /etc/passwd
args:
removes: /etc/passwd
changed_when: false
@ -104,21 +104,21 @@
register: sys_accs
- name: Remove always ignored system accounts from list
set_fact:
sys_accs_cond: '{{ sys_accs.stdout_lines | difference(os_always_ignore_users) }}'
ansible.builtin.set_fact:
sys_accs_cond: "{{ sys_accs.stdout_lines | difference(os_always_ignore_users) }}"
check_mode: false
- name: Change system accounts not on the user provided ignore-list
user:
name: '{{ item }}'
shell: '{{ os_nologin_shell_path }}'
password: '*'
ansible.builtin.user:
name: "{{ item }}"
shell: "{{ os_nologin_shell_path }}"
password: "*"
createhome: false
with_community.general.flattened:
- '{{ sys_accs_cond | default([]) | difference(os_ignore_users) | list }}'
- "{{ sys_accs_cond | default([]) | difference(os_ignore_users) | list }}"
- name: Get all home directories in /home, but skip ignored users
find:
ansible.builtin.find:
paths: /home/
recurse: false
file_type: directory
@ -127,7 +127,7 @@
when: os_chmod_home_folders | bool
- name: Set ownership of /home directories to 0700
file:
ansible.builtin.file:
mode: 0700
path: "{{ item.path }}"
state: directory

View file

@ -1,50 +1,51 @@
---
- name: Remove unused repositories
file:
name: '/etc/yum.repos.d/{{ item }}.repo'
state: 'absent'
ansible.builtin.file:
name: /etc/yum.repos.d/{{ item }}.repo
state: absent
loop:
- 'CentOS-Debuginfo'
- 'CentOS-Media'
- 'CentOS-Vault'
- CentOS-Debuginfo
- CentOS-Media
- CentOS-Vault
when: os_security_packages_clean | bool
- name: Get yum repository files
find:
paths: '/etc/yum.repos.d'
patterns: '*.repo'
ansible.builtin.find:
paths: /etc/yum.repos.d
patterns: "*.repo"
register: yum_repos
# for the 'default([])' see here:
# https://github.com/dev-sec/ansible-os-hardening/issues/99 and
# https://stackoverflow.com/questions/37067827/ansible-deprecation-warning-for-undefined-variable-despite-when-clause
- name: Activate gpg-check for yum repository files
replace:
path: '{{ item }}'
regexp: '^\s*gpgcheck.*'
replace: 'gpgcheck=1'
mode: '0644'
ansible.builtin.replace:
path: "{{ item }}"
regexp: ^\s*gpgcheck.*
replace: gpgcheck=1
mode: "0644"
with_items:
# yamllint disable-line rule:line-length
- "{{ yum_repos.files | default([]) | map(attribute='path') | difference(os_yum_repo_file_whitelist | map('regex_replace', '^', '/etc/yum.repos.d/') | list) }}"
# failed_when is needed because by default replace module will fail if the file doesn't exists.
# status.rc is only defined if an error accrued and only error code (rc) 257 will be ignored.
# All other errors will still be raised.
- name: Activate gpg-check for config files
replace:
path: '{{ item }}'
regexp: '^\s*gpgcheck\W.*'
replace: 'gpgcheck=1'
mode: '0644'
ansible.builtin.replace:
path: "{{ item }}"
regexp: ^\s*gpgcheck\W.*
replace: gpgcheck=1
mode: "0644"
register: status
failed_when: status.rc is defined and status.rc not in (257, 0)
loop:
- '/etc/yum.conf'
- '/etc/dnf/dnf.conf'
- '/etc/yum/pluginconf.d/rhnplugin.conf'
- /etc/yum.conf
- /etc/dnf/dnf.conf
- /etc/yum/pluginconf.d/rhnplugin.conf
- name: Remove deprecated or insecure packages | package-01 - package-09
yum:
name: '{{ os_security_packages_list }}'
state: 'absent'
ansible.builtin.yum:
name: "{{ os_security_packages_list }}"
state: absent
when: os_security_packages_clean | bool

View file

@ -1,7 +1,6 @@
---
os_packages_pam_ccreds: 'pam_ccreds'
os_nologin_shell_path: '/sbin/nologin'
os_packages_pam_ccreds: pam_ccreds
os_nologin_shell_path: /sbin/nologin
# Different distros use different standards for /etc/shadow perms, e.g.
# RHEL derivatives use root:root 0000, whereas Debian-based use root:shadow 0640.
@ -9,14 +8,14 @@ os_nologin_shell_path: '/sbin/nologin'
os_shadow_perms:
owner: root
group: root
mode: '0000'
mode: "0000"
os_passwd_perms:
owner: root
group: root
mode: '0644'
mode: "0644"
os_env_umask: '077'
os_env_umask: "077"
os_auth_uid_min: 1000
os_auth_uid_max: 60000
@ -79,10 +78,9 @@ os_mnt_var_tmp_owner: 'root'
os_useradd_mail_dir: /var/spool/mail
os_useradd_create_home: true
modprobe_package: 'module-init-tools'
auditd_package: 'audit'
modprobe_package: module-init-tools
auditd_package: audit
# system accounts that do not get their login disabled and pasword changed
os_always_ignore_users: ['root', 'sync', 'shutdown', 'halt', 'ec2-user']
hidepid_option: '2' # allowed values: 0, 1, 2
os_always_ignore_users: [root, sync, shutdown, halt, ec2-user]
hidepid_option: "2" # allowed values: 0, 1, 2

View file

@ -1,18 +1,17 @@
---
os_nologin_shell_path: '/sbin/nologin'
os_nologin_shell_path: /sbin/nologin
os_shadow_perms:
owner: root
group: root
mode: '0600'
mode: "0600"
os_passwd_perms:
owner: root
group: root
mode: '0644'
mode: "0644"
os_env_umask: '027'
os_env_umask: "027"
os_auth_uid_min: 1000
os_auth_uid_max: 60000
@ -69,10 +68,10 @@ os_mnt_var_tmp_dir_mode: '1777'
os_mnt_var_tmp_group: 'root'
os_mnt_var_tmp_owner: 'root'
modprobe_package: 'kmod'
auditd_package: 'audit'
modprobe_package: kmod
auditd_package: audit
hidepid_option: '2' # allowed values: 0, 1, 2
hidepid_option: "2" # allowed values: 0, 1, 2
sysctl_custom_config:
# Mitigation of vulnerability CVE-2021-33909

View file

@ -1,7 +1,6 @@
---
os_packages_pam_ccreds: 'libpam-ccreds'
os_nologin_shell_path: '/usr/sbin/nologin'
os_packages_pam_ccreds: libpam-ccreds
os_nologin_shell_path: /usr/sbin/nologin
# Different distros use different standards for /etc/shadow perms, e.g.
# RHEL derivatives use root:root 0000, whereas Debian-based use root:shadow 0640.
@ -9,14 +8,14 @@ os_nologin_shell_path: '/usr/sbin/nologin'
os_shadow_perms:
owner: root
group: shadow
mode: '0640'
mode: "0640"
os_passwd_perms:
owner: root
group: root
mode: '0644'
mode: "0644"
os_env_umask: '027'
os_env_umask: "027"
os_auth_uid_min: 1000
os_auth_uid_max: 60000
@ -76,13 +75,13 @@ os_mnt_var_tmp_owner: 'root'
# defaults for useradd
os_useradd_mail_dir: /var/mail
modprobe_package: 'kmod'
auditd_package: 'auditd'
modprobe_package: kmod
auditd_package: auditd
tally2_path: '/usr/share/pam-configs/tally2'
passwdqc_path: '/usr/share/pam-configs/passwdqc'
tally2_path: /usr/share/pam-configs/tally2
passwdqc_path: /usr/share/pam-configs/passwdqc
hidepid_option: '2' # allowed values: 0, 1, 2
hidepid_option: "2" # allowed values: 0, 1, 2
sysctl_custom_config:
# Mitigation of vulnerability CVE-2021-33909

View file

@ -1,7 +1,6 @@
---
os_packages_pam_ccreds: 'pam_ccreds'
os_nologin_shell_path: '/sbin/nologin'
os_packages_pam_ccreds: pam_ccreds
os_nologin_shell_path: /sbin/nologin
# Different distros use different standards for /etc/shadow perms, e.g.
# RHEL derivatives use root:root 0000, whereas Debian-based use root:shadow 0640.
@ -9,14 +8,14 @@ os_nologin_shell_path: '/sbin/nologin'
os_shadow_perms:
owner: root
group: root
mode: '0000'
mode: "0000"
os_passwd_perms:
owner: root
group: root
mode: '0644'
mode: "0644"
os_env_umask: '027'
os_env_umask: "027"
os_auth_uid_min: 1000
os_auth_uid_max: 60000
@ -79,7 +78,7 @@ os_mnt_var_tmp_owner: 'root'
os_useradd_mail_dir: /var/spool/mail
os_useradd_create_home: true
modprobe_package: 'module-init-tools'
auditd_package: 'audit'
modprobe_package: module-init-tools
auditd_package: audit
hidepid_option: '2' # allowed values: 0, 1, 2
hidepid_option: "2" # allowed values: 0, 1, 2

View file

@ -1,7 +1,6 @@
---
os_packages_pam_ccreds: 'pam_ccreds'
os_nologin_shell_path: '/sbin/nologin'
os_packages_pam_ccreds: pam_ccreds
os_nologin_shell_path: /sbin/nologin
# Different distros use different standards for /etc/shadow perms, e.g.
# RHEL derivatives use root:root 0000, whereas Debian-based use root:shadow 0640.
@ -9,14 +8,14 @@ os_nologin_shell_path: '/sbin/nologin'
os_shadow_perms:
owner: root
group: root
mode: '0000'
mode: "0000"
os_passwd_perms:
owner: root
group: root
mode: '0644'
mode: "0644"
os_env_umask: '077'
os_env_umask: "077"
os_auth_uid_min: 1000
os_auth_uid_max: 60000
@ -79,7 +78,7 @@ os_mnt_var_tmp_owner: 'root'
os_useradd_mail_dir: /var/spool/mail
os_useradd_create_home: true
modprobe_package: 'module-init-tools'
auditd_package: 'audit'
modprobe_package: module-init-tools
auditd_package: audit
hidepid_option: '2' # allowed values: 0, 1, 2
hidepid_option: "2" # allowed values: 0, 1, 2

View file

@ -1,7 +1,6 @@
---
os_packages_pam_ccreds: 'pam_ccreds'
os_nologin_shell_path: '/sbin/nologin'
os_packages_pam_ccreds: pam_ccreds
os_nologin_shell_path: /sbin/nologin
# Different distros use different standards for /etc/shadow perms, e.g.
# RHEL derivatives use root:root 0000, whereas Debian-based use root:shadow 0640.
@ -9,14 +8,14 @@ os_nologin_shell_path: '/sbin/nologin'
os_shadow_perms:
owner: root
group: root
mode: '0000'
mode: "0000"
os_passwd_perms:
owner: root
group: root
mode: '0644'
mode: "0644"
os_env_umask: '077'
os_env_umask: "077"
os_auth_uid_min: 1000
os_auth_uid_max: 60000
@ -79,11 +78,11 @@ os_mnt_var_tmp_owner: 'root'
os_useradd_mail_dir: /var/spool/mail
os_useradd_create_home: true
modprobe_package: 'module-init-tools'
auditd_package: 'audit'
modprobe_package: module-init-tools
auditd_package: audit
hidepid_option: '0' # allowed values: 0, 1, 2
hidepid_option: "0" # allowed values: 0, 1, 2
sysctl_unsupported_entries:
- 'fs.protected_fifos'
- 'fs.protected_regular'
- fs.protected_fifos
- fs.protected_regular

View file

@ -1,7 +1,6 @@
---
os_packages_pam_ccreds: 'pam_ccreds'
os_nologin_shell_path: '/sbin/nologin'
os_packages_pam_ccreds: pam_ccreds
os_nologin_shell_path: /sbin/nologin
# Different distros use different standards for /etc/shadow perms, e.g.
# RHEL derivatives use root:root 0000, whereas Debian-based use root:shadow 0640.
@ -9,14 +8,14 @@ os_nologin_shell_path: '/sbin/nologin'
os_shadow_perms:
owner: root
group: shadow
mode: '0640'
mode: "0640"
os_passwd_perms:
owner: root
group: root
mode: '0644'
mode: "0644"
os_env_umask: '027'
os_env_umask: "027"
os_auth_uid_min: 1000
os_auth_uid_max: 60000
@ -76,7 +75,7 @@ os_mnt_var_tmp_owner: 'root'
# defaults for useradd
os_useradd_create_home: false
modprobe_package: 'kmod-compat'
auditd_package: 'audit'
modprobe_package: kmod-compat
auditd_package: audit
hidepid_option: '2' # allowed values: 0, 1, 2
hidepid_option: "2" # allowed values: 0, 1, 2

View file

@ -11,102 +11,102 @@
# list of suid/sgid entries that must be removed
os_security_suid_sgid_system_blacklist:
# blacklist as provided by NSA
- '/usr/bin/rcp'
- '/usr/bin/rlogin'
- '/usr/bin/rsh'
- /usr/bin/rcp
- /usr/bin/rlogin
- /usr/bin/rsh
# sshd must not use host-based authentication (see ssh cookbook)
- '/usr/libexec/openssh/ssh-keysign'
- '/usr/lib/openssh/ssh-keysign'
- /usr/libexec/openssh/ssh-keysign
- /usr/lib/openssh/ssh-keysign
# misc others
- '/sbin/netreport' # not normally required for user
- '/usr/sbin/usernetctl' # modify interfaces via functional accounts
- /sbin/netreport # not normally required for user
- /usr/sbin/usernetctl # modify interfaces via functional accounts
# connecting to ...
- '/usr/sbin/userisdnctl' # no isdn...
- '/usr/sbin/pppd' # no ppp / dsl ...
- /usr/sbin/userisdnctl # no isdn...
- /usr/sbin/pppd # no ppp / dsl ...
# lockfile
- '/usr/bin/lockfile'
- '/usr/bin/mail-lock'
- '/usr/bin/mail-unlock'
- '/usr/bin/mail-touchlock'
- '/usr/bin/dotlockfile'
- /usr/bin/lockfile
- /usr/bin/mail-lock
- /usr/bin/mail-unlock
- /usr/bin/mail-touchlock
- /usr/bin/dotlockfile
# need more investigation blacklist for now
- '/usr/bin/arping'
- '/usr/sbin/uuidd'
- '/usr/bin/mtr' # investigate current state...
- '/usr/lib/evolution/camel-lock-helper-1.2' # investigate current state...
- '/usr/lib/pt_chown' # pseudo-tty needed?
- '/usr/lib/eject/dmcrypt-get-device'
- '/usr/lib/mc/cons.saver' # midnight commander screensaver
- /usr/bin/arping
- /usr/sbin/uuidd
- /usr/bin/mtr # investigate current state...
- /usr/lib/evolution/camel-lock-helper-1.2 # investigate current state...
- /usr/lib/pt_chown # pseudo-tty needed?
- /usr/lib/eject/dmcrypt-get-device
- /usr/lib/mc/cons.saver # midnight commander screensaver
# list of suid/sgid entries that can remain untouched
os_security_suid_sgid_system_whitelist:
# whitelist as provided by NSA
- '/bin/mount'
- '/bin/ping'
- '/bin/su'
- '/usr/bin/su'
- '/bin/umount'
- '/sbin/pam_timestamp_check'
- '/sbin/unix_chkpwd'
- '/usr/bin/at'
- '/usr/bin/gpasswd'
- '/usr/bin/locate'
- '/usr/bin/newgrp'
- '/usr/bin/passwd'
- '/usr/bin/ssh-agent'
- '/usr/libexec/utempter/utempter'
- '/usr/sbin/lockdev'
- '/usr/sbin/sendmail.sendmail'
- '/usr/bin/expiry'
- /bin/mount
- /bin/ping
- /bin/su
- /usr/bin/su
- /bin/umount
- /sbin/pam_timestamp_check
- /sbin/unix_chkpwd
- /usr/bin/at
- /usr/bin/gpasswd
- /usr/bin/locate
- /usr/bin/newgrp
- /usr/bin/passwd
- /usr/bin/ssh-agent
- /usr/libexec/utempter/utempter
- /usr/sbin/lockdev
- /usr/sbin/sendmail.sendmail
- /usr/bin/expiry
# whitelist ipv6
- '/bin/ping6'
- '/usr/bin/traceroute6.iputils'
- /bin/ping6
- /usr/bin/traceroute6.iputils
# whitelist nfs
- '/sbin/mount.nfs'
- '/sbin/umount.nfs'
- /sbin/mount.nfs
- /sbin/umount.nfs
# whitelist nfs4
- '/sbin/mount.nfs4'
- '/sbin/umount.nfs4'
- /sbin/mount.nfs4
- /sbin/umount.nfs4
# whitelist cron
- '/usr/bin/crontab'
- /usr/bin/crontab
# whitelist consolemssaging
- '/usr/bin/wall'
- '/usr/bin/write'
- /usr/bin/wall
- /usr/bin/write
# whitelist: only SGID with utmp group for multi-session access
# impact is limited; installation/usage has some remaining risk
- '/usr/bin/screen'
- /usr/bin/screen
# whitelist locate
- '/usr/bin/mlocate'
- /usr/bin/mlocate
# whitelist usermanagement
- '/usr/bin/chage'
- '/usr/bin/chfn'
- '/usr/bin/chsh'
- /usr/bin/chage
- /usr/bin/chfn
- /usr/bin/chsh
# whitelist fuse
- '/bin/fusermount'
- /bin/fusermount
# whitelist pkexec
- '/usr/bin/pkexec'
- /usr/bin/pkexec
# whitelist sudo
- '/usr/bin/sudo'
- '/usr/bin/sudoedit'
- /usr/bin/sudo
- /usr/bin/sudoedit
# whitelist postfix
- '/usr/sbin/postdrop'
- '/usr/sbin/postqueue'
- /usr/sbin/postdrop
- /usr/sbin/postqueue
# whitelist apache
- '/usr/sbin/suexec'
- /usr/sbin/suexec
# whitelist squid
- '/usr/lib/squid/ncsa_auth'
- '/usr/lib/squid/pam_auth'
- /usr/lib/squid/ncsa_auth
- /usr/lib/squid/pam_auth
# whitelist kerberos
- '/usr/kerberos/bin/ksu'
- /usr/kerberos/bin/ksu
# whitelist pam_caching
- '/usr/sbin/ccreds_validate'
- /usr/sbin/ccreds_validate
# whitelist Xorg
- '/usr/bin/Xorg' # xorg
- '/usr/bin/X' # xorg
- '/usr/lib/dbus-1.0/dbus-daemon-launch-helper' # freedesktop ipc
- '/usr/lib/vte/gnome-pty-helper' # gnome
- '/usr/lib/libvte9/gnome-pty-helper' # gnome
- '/usr/lib/libvte-2.90-9/gnome-pty-helper' # gnome
- /usr/bin/Xorg # xorg
- /usr/bin/X # xorg
- /usr/lib/dbus-1.0/dbus-daemon-launch-helper # freedesktop ipc
- /usr/lib/vte/gnome-pty-helper # gnome
- /usr/lib/libvte9/gnome-pty-helper # gnome
- /usr/lib/libvte-2.90-9/gnome-pty-helper # gnome
# system accounts that do not get their login disabled and pasword changed
os_always_ignore_users: ['root', 'sync', 'shutdown', 'halt']
os_always_ignore_users: [root, sync, shutdown, halt]

View file

@ -9,14 +9,16 @@ ssh_server_config_file: /etc/ssh/sshd_config # sshd
# true if sshd should be started and enabled
ssh_server_enabled: true # sshd
# true if DNS resolutions are needed, look up the remote host name, defaults to false from 6.8, see: http://www.openssh.com/txt/release-6.8
# true if DNS resolutions are needed, look up the remote host name,
# defaults to false from 6.8, see: http://www.openssh.com/txt/release-6.8
ssh_use_dns: false # sshd
# true or value if compression is needed
ssh_client_compression: false # ssh
ssh_compression: false # sshd
# For which components (client and server) to generate the configuration for. Can be useful when running against a client without an SSH server.
# For which components (client and server) to generate the configuration for.
# Can be useful when running against a client without an SSH server.
ssh_client_hardening: true # ssh
ssh_server_hardening: true # sshd
@ -25,13 +27,14 @@ ssh_client_password_login: false # ssh
ssh_server_password_login: false # sshd
# ports on which ssh-server should listen
ssh_server_ports: ['22'] # sshd
ssh_server_ports: ["22"] # sshd
# port to which ssh-client should connect
ssh_client_port: '22' # ssh
ssh_client_port: "22" # ssh
# one or more ip addresses, to which ssh-server should listen to. Default is empty, but should be configured for security reasons!
ssh_listen_to: ['0.0.0.0'] # sshd
# one or more ip addresses, to which ssh-server should listen to.
# Default is empty, but should be configured for security reasons!
ssh_listen_to: [0.0.0.0] # sshd
# Host keys to look for when starting sshd.
ssh_host_key_files: [] # sshd
@ -51,7 +54,8 @@ ssh_client_host_key_algorithms: [] # ssh
# specifies the time allowed for successful authentication to the SSH server
ssh_login_grace_time: 30s
# Specifies the maximum number of authentication attempts permitted per connection. Once the number of failures reaches half this value, additional failures are logged.
# Specifies the maximum number of authentication attempts permitted per connection.
# Once the number of failures reaches half this value, additional failures are logged.
ssh_max_auth_retries: 2
# Specifies the maximum number of open sessions permitted from a given connection
@ -71,14 +75,15 @@ ssh_permit_tunnel: false
# - names: ['example3.com']
# options: ['StrictHostKeyChecking no']
ssh_remote_hosts: []
# Set this to "without-password" or "yes" to allow root to login
ssh_permit_root_login: 'no' # sshd
ssh_permit_root_login: "no" # sshd
# false to disable TCP Forwarding. Set to 'yes', 'no', 'local', 'all' or 'remote' to allow TCP Forwarding.
ssh_allow_tcp_forwarding: 'no' # sshd
# false to disable TCP Forwarding. Set to 'yes', 'no', 'local', 'all' or 'remote'
# to allow TCP Forwarding.
ssh_allow_tcp_forwarding: "no" # sshd
# false to disable binding forwarded ports to non-loopback addresses. Set to true to force binding on wildcard address.
# false to disable binding forwarded ports to non-loopback addresses.
# Set to true to force binding on wildcard address.
# Set to 'clientspecified' to allow the client to specify which address to bind to.
ssh_gateway_ports: false # sshd
@ -92,7 +97,7 @@ ssh_x11_forwarding: false # sshd
ssh_use_pam: true # sshd
# specify AuthenticationMethods
sshd_authenticationmethods: 'publickey'
sshd_authenticationmethods: publickey
# Set to true to enable GSSAPI authentication (both client and server)
ssh_gssapi_support: false
@ -101,22 +106,22 @@ ssh_gssapi_support: false
ssh_gssapi_delegation: false
# if specified, login is disallowed for user names that match one of the patterns.
ssh_deny_users: '' # sshd
ssh_deny_users: "" # sshd
# if specified, login is allowed only for user names that match one of the patterns.
ssh_allow_users: '' # sshd
ssh_allow_users: "" # sshd
# if specified, login is disallowed for users whose primary group or supplementary group list matches one of the patterns.
ssh_deny_groups: '' # sshd
ssh_deny_groups: "" # sshd
# if specified, login is allowed only for users whose primary group or supplementary group list matches one of the patterns.
ssh_allow_groups: '' # sshd
ssh_allow_groups: "" # sshd
# change default file that contains the public keys that can be used for user authentication.
ssh_authorized_keys_file: '' # sshd
ssh_authorized_keys_file: "" # sshd
# specifies the file containing trusted certificate authorities public keys used to sign user certificates.
ssh_trusted_user_ca_keys_file: '' # sshd
ssh_trusted_user_ca_keys_file: "" # sshd
# set the trusted certificate authorities public keys used to sign user certificates.
# Example:
@ -133,12 +138,13 @@ ssh_trusted_user_ca_keys: [] # sshd
# replaced by the username of that user. After expansion, the path is taken to be
# an absolute path or one relative to the user's home directory.
#
ssh_authorized_principals_file: '' # sshd
ssh_authorized_principals_file: "" # sshd
# list of hashes containing file paths and authorized principals. Only used if ssh_authorized_principals_file is set.
# Example:
# ssh_authorized_principals:
# - { path: '/etc/ssh/auth_principals/root', principals: [ 'root' ], owner: "{{ ssh_owner }}", group: "{{ ssh_group }}", directoryowner: "{{ ssh_owner }}", directorygroup: "{{ ssh_group}}" }
# - { path: '/etc/ssh/auth_principals/root', principals: [ 'root' ], owner: "{{ ssh_owner }}",
# group: "{{ ssh_group }}", directoryowner: "{{ ssh_owner }}", directorygroup: "{{ ssh_group}}" }
# - { path: '/etc/ssh/auth_principals/myuser', principals: [ 'masteradmin', 'webserver' ] }
ssh_authorized_principals: [] # sshd
@ -153,7 +159,7 @@ ssh_print_last_log: false # sshd
ssh_banner: false # sshd
# path to file with ssh warning banner
ssh_banner_path: '/etc/ssh/banner.txt'
ssh_banner_path: /etc/ssh/banner.txt
# false to disable distribution version leakage during initial protocol handshake
ssh_print_debian_banner: false # sshd (Debian OS family only)
@ -165,7 +171,7 @@ sftp_enabled: true
sftp_chroot: true
# sftp default umask
sftp_umask: '0027'
sftp_umask: "0027"
# change default sftp chroot location
sftp_chroot_dir: /home/%u
@ -185,20 +191,19 @@ ssh_server_match_address: false # sshd
# list of hashes (containing port and rules) to generate Match LocalPort blocks for
ssh_server_match_local_port: false # sshd
ssh_server_permit_environment_vars: 'no'
ssh_server_accept_env_vars: ''
ssh_server_permit_environment_vars: "no"
ssh_server_accept_env_vars: ""
# maximum number of concurrent unauthenticated connections to the SSH daemon
ssh_max_startups: '10:30:60' # sshd
ssh_max_startups: 10:30:60 # sshd
ssh_ps59: 'sandbox'
ssh_ps59: sandbox
ssh_macs: []
ssh_ciphers: []
ssh_kex: []
# directory where to store ssh_password policy
ssh_custom_selinux_dir: '/etc/selinux/local-policies'
ssh_custom_selinux_dir: /etc/selinux/local-policies
sshd_moduli_minimum: 2048
@ -207,19 +212,16 @@ ssh_challengeresponseauthentication: false
# a list of public keys that are never accepted by the ssh server
ssh_server_revoked_keys: []
# Set to false to turn the role into a no-op. Useful when using
# the Ansible role dependency mechanism.
ssh_hardening_enabled: true
# Custom options for SSH client configuration file
ssh_custom_options: []
# Custom options for SSH daemon configuration file
sshd_custom_options: []
# Logging
sshd_syslog_facility: 'AUTH'
sshd_log_level: 'VERBOSE'
sshd_syslog_facility: AUTH
sshd_log_level: VERBOSE
sshd_strict_modes: true

View file

@ -1,7 +1,7 @@
---
- name: Restart sshd
service:
name: '{{ sshd_service_name }}'
ansible.builtin.service:
name: "{{ sshd_service_name }}"
state: restarted
when: ssh_server_enabled | bool
become: true

View file

@ -1,10 +1,10 @@
---
galaxy_info:
author: "Sebastian Gumprich"
description: 'This Ansible role provides numerous security-related ssh configurations, providing all-round base protection.'
author: Sebastian Gumprich
description: This Ansible role provides numerous security-related ssh configurations, providing all-round base protection.
company: Hardening Framework Team
license: Apache License 2.0
min_ansible_version: '2.9.10'
min_ansible_version: 2.9.10
platforms:
- name: EL
versions:

View file

@ -1,27 +1,27 @@
---
- name: Set ssh CA pub keys
template:
src: 'trusted_user_ca_keys.j2'
dest: '{{ ssh_trusted_user_ca_keys_file }}'
mode: '0644'
owner: '{{ ssh_owner }}'
group: '{{ ssh_group }}'
ansible.builtin.template:
src: trusted_user_ca_keys.j2
dest: "{{ ssh_trusted_user_ca_keys_file }}"
mode: "0644"
owner: "{{ ssh_owner }}"
group: "{{ ssh_group }}"
notify: Restart sshd
- name: Create ssh authorized principals directories
file:
path: '{{ item.path | dirname }}'
ansible.builtin.file:
path: "{{ item.path | dirname }}"
mode: '{{ item.directorymode | default("700") }}'
owner: '{{ item.directoryowner | default(ssh_owner) }}'
group: '{{ item.directorygroup | default(ssh_group) }}'
owner: "{{ item.directoryowner | default(ssh_owner) }}"
group: "{{ item.directorygroup | default(ssh_group) }}"
state: directory
loop: '{{ ssh_authorized_principals }}'
loop: "{{ ssh_authorized_principals }}"
- name: Set ssh authorized principals
template:
src: 'authorized_principals.j2'
dest: '{{ item.path }}'
ansible.builtin.template:
src: authorized_principals.j2
dest: "{{ item.path }}"
mode: '{{ item.filemode | default("600") }}'
owner: '{{ item.owner | default(ssh_owner) }}'
group: '{{ item.group | default(ssh_group) }}'
loop: '{{ ssh_authorized_principals }}'
owner: "{{ item.owner | default(ssh_owner) }}"
group: "{{ item.group | default(ssh_group) }}"
loop: "{{ ssh_authorized_principals }}"

View file

@ -1,10 +1,10 @@
---
- name: Set ciphers according to openssh-version if openssh >= 5.3
set_fact:
ssh_ciphers: '{{ ssh_ciphers_53_default }}'
ansible.builtin.set_fact:
ssh_ciphers: "{{ ssh_ciphers_53_default }}"
when: sshd_version is version('5.3', '>=')
- name: Set ciphers according to openssh-version if openssh >= 6.6
set_fact:
ssh_ciphers: '{{ ssh_ciphers_66_default }}'
ansible.builtin.set_fact:
ssh_ciphers: "{{ ssh_ciphers_66_default }}"
when: sshd_version is version('6.6', '>=')

View file

@ -11,28 +11,28 @@
# In RHEL and Fedora, the 'ssh_keys' group is the group owner of the host private SSH keys.
# Since the openssh_keypair module needs to read the key to provide idempotency, we need to set ownership and group based on specific OS vars.
- name: Change host private key ownership, group and permissions
file:
ansible.builtin.file:
path: "{{ ssh_host_keys_dir }}/ssh_host_rsa_key"
owner: "{{ ssh_host_keys_owner }}"
group: "{{ ssh_host_keys_group }}"
mode: "0640"
when: "ansible_facts.os_family == 'RedHat'"
when: ansible_facts.os_family == 'RedHat'
- name: Set hostkeys according to openssh-version if openssh >= 5.3
set_fact:
ansible.builtin.set_fact:
ssh_host_key_files:
- "{{ ssh_host_keys_dir }}/ssh_host_rsa_key"
when: sshd_version is version('5.3', '>=')
- name: Set hostkeys according to openssh-version if openssh >= 6.0
set_fact:
ansible.builtin.set_fact:
ssh_host_key_files:
- "{{ ssh_host_keys_dir }}/ssh_host_rsa_key"
- "{{ ssh_host_keys_dir }}/ssh_host_ecdsa_key"
when: sshd_version is version('6.0', '>=')
- name: Set hostkeys according to openssh-version if openssh >= 6.3
set_fact:
ansible.builtin.set_fact:
ssh_host_key_files:
- "{{ ssh_host_keys_dir }}/ssh_host_rsa_key"
- "{{ ssh_host_keys_dir }}/ssh_host_ecdsa_key"

View file

@ -1,20 +1,20 @@
---
- name: Set kex according to openssh-version if openssh >= 5.9
set_fact:
ssh_kex: '{{ ssh_kex_59_default }}'
ansible.builtin.set_fact:
ssh_kex: "{{ ssh_kex_59_default }}"
when: sshd_version is version('5.9', '>=')
- name: Set kex according to openssh-version if openssh >= 6.6
set_fact:
ssh_kex: '{{ ssh_kex_66_default }}'
ansible.builtin.set_fact:
ssh_kex: "{{ ssh_kex_66_default }}"
when: sshd_version is version('6.6', '>=')
- name: Set kex according to openssh-version if openssh >= 8.0
set_fact:
ssh_kex: '{{ ssh_kex_80_default }}'
ansible.builtin.set_fact:
ssh_kex: "{{ ssh_kex_80_default }}"
when: sshd_version is version('8.0', '>=')
- name: Set kex according to openssh-version if openssh >= 8.5
set_fact:
ssh_kex: '{{ ssh_kex_85_default }}'
ansible.builtin.set_fact:
ssh_kex: "{{ ssh_kex_85_default }}"
when: sshd_version is version('8.5', '>=')

View file

@ -1,20 +1,20 @@
---
- name: Set macs according to openssh-version if openssh >= 5.3
set_fact:
ssh_macs: '{{ ssh_macs_53_default }}'
ansible.builtin.set_fact:
ssh_macs: "{{ ssh_macs_53_default }}"
when: sshd_version is version('5.3', '>=')
- name: Set macs according to openssh-version if openssh >= 5.9
set_fact:
ssh_macs: '{{ ssh_macs_59_default }}'
ansible.builtin.set_fact:
ssh_macs: "{{ ssh_macs_59_default }}"
when: sshd_version is version('5.9', '>=')
- name: Set macs according to openssh-version if openssh >= 6.6
set_fact:
ssh_macs: '{{ ssh_macs_66_default }}'
ansible.builtin.set_fact:
ssh_macs: "{{ ssh_macs_66_default }}"
when: sshd_version is version('6.6', '>=')
- name: Set macs according to openssh-version if openssh >= 7.6
set_fact:
ssh_macs: '{{ ssh_macs_76_default }}'
ansible.builtin.set_fact:
ssh_macs: "{{ ssh_macs_76_default }}"
when: sshd_version is version('7.6', '>=')

View file

@ -1,14 +1,14 @@
---
- name: Fetch OS dependent variables
include_vars:
file: '{{ item }}'
name: 'os_vars'
ansible.builtin.include_vars:
file: "{{ item }}"
name: os_vars
with_first_found:
- files:
- '{{ ansible_facts.distribution }}_{{ ansible_facts.distribution_major_version | default() }}.yml'
- '{{ ansible_facts.distribution }}.yml'
- '{{ ansible_facts.os_family }}_{{ ansible_facts.distribution_major_version | default() }}.yml'
- '{{ ansible_facts.os_family }}.yml'
- "{{ ansible_facts.distribution }}_{{ ansible_facts.distribution_major_version | default() }}.yml"
- "{{ ansible_facts.distribution }}.yml"
- "{{ ansible_facts.os_family }}_{{ ansible_facts.distribution_major_version | default() }}.yml"
- "{{ ansible_facts.os_family }}.yml"
skip: true
tags: always
@ -16,63 +16,63 @@
# by default the lookup functions finds all varnames containing the string, therefore
# we add ^ and $ to denote start and end of string, so this returns only exact matches
- name: Set OS dependent variables, if not already defined by user # noqa var-naming
set_fact:
'{{ item.key }}': '{{ item.value }}'
when: "not lookup('varnames', '^' + item.key + '$')"
with_dict: '{{ os_vars }}'
ansible.builtin.set_fact:
"{{ item.key }}": "{{ item.value }}"
when: not lookup('varnames', '^' + item.key + '$')
with_dict: "{{ os_vars }}"
tags: always
- name: Get openssh-version
command: ssh -V
ansible.builtin.command: ssh -V
register: sshd_version_raw
changed_when: false
check_mode: false
- name: Parse openssh-version
set_fact:
ansible.builtin.set_fact:
sshd_version: "{{ sshd_version_raw.stderr | regex_replace('.*_([0-9]*.[0-9]).*', '\\1') }}"
- name: Set default for ssh_host_key_files if not supplied
include_tasks: crypto_hostkeys.yml
ansible.builtin.include_tasks: crypto_hostkeys.yml
when:
- ssh_server_hardening | bool
- not ssh_host_key_files
- name: Set default for ssh_macs if not supplied
include_tasks: crypto_macs.yml
ansible.builtin.include_tasks: crypto_macs.yml
when: not ssh_macs
- name: Set default for ssh_ciphers if not supplied
include_tasks: crypto_ciphers.yml
ansible.builtin.include_tasks: crypto_ciphers.yml
when: not ssh_ciphers
- name: Set default for ssh_kex if not supplied
include_tasks: crypto_kex.yml
ansible.builtin.include_tasks: crypto_kex.yml
when: not ssh_kex
- 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 }}'
ansible.builtin.template:
src: revoked_keys.j2
dest: /etc/ssh/revoked_keys
mode: "0600"
owner: "{{ ssh_owner }}"
group: "{{ ssh_group }}"
notify: Restart sshd
when: ssh_server_hardening | bool
- name: Create sshd_config and set permissions to root/600
template:
src: 'opensshd.conf.j2'
ansible.builtin.template:
src: opensshd.conf.j2
dest: "{{ ssh_server_config_file }}"
mode: '0600'
owner: '{{ ssh_owner }}'
group: '{{ ssh_group }}'
validate: '{{ sshd_path }} -T -C user=root -C host=localhost -C addr=localhost -C lport=22 -f %s'
mode: "0600"
owner: "{{ ssh_owner }}"
group: "{{ ssh_group }}"
validate: "{{ sshd_path }} -T -C user=root -C host=localhost -C addr=localhost -C lport=22 -f %s"
notify: Restart sshd
when: ssh_server_hardening | bool
- name: Disable dynamic MOTD
pamd:
community.general.pamd:
name: sshd
type: session
control: optional
@ -85,52 +85,53 @@
- not (ssh_print_pam_motd | bool)
- name: Create ssh_config and set permissions to root/644
template:
src: 'openssh.conf.j2'
ansible.builtin.template:
src: openssh.conf.j2
dest: "{{ ssh_client_config_file }}"
mode: '0644'
owner: '{{ ssh_owner }}'
group: '{{ ssh_group }}'
mode: "0644"
owner: "{{ ssh_owner }}"
group: "{{ ssh_group }}"
when: ssh_client_hardening | bool
- name: Check if {{ sshd_moduli_file }} contains weak DH parameters
shell: awk '$5 < {{ sshd_moduli_minimum }}' {{ sshd_moduli_file }}
ansible.builtin.shell: awk '$5 < {{ sshd_moduli_minimum }}' {{ sshd_moduli_file }}
register: sshd_register_moduli
changed_when: false
check_mode: false
when: ssh_server_hardening | bool
- name: Remove all small primes
shell: awk '$5 >= {{ sshd_moduli_minimum }}' {{ sshd_moduli_file }} > {{ sshd_moduli_file }}.new ;
[ -r {{ sshd_moduli_file }}.new -a -s {{ sshd_moduli_file }}.new ] && mv {{ sshd_moduli_file }}.new {{ sshd_moduli_file }} || true
ansible.builtin.shell: >
awk '$5 >= {{ sshd_moduli_minimum }}' {{ sshd_moduli_file }} > {{ sshd_moduli_file }}.new ; [ -r {{ sshd_moduli_file }}.new
-a -s {{ sshd_moduli_file }}.new ] && mv {{ sshd_moduli_file }}.new {{ sshd_moduli_file }} || true
notify: Restart sshd
when:
- ssh_server_hardening | bool
- sshd_register_moduli.stdout
- name: Include tasks to setup ca keys and principals
include_tasks: ca_keys_and_principals.yml
ansible.builtin.include_tasks: ca_keys_and_principals.yml
when:
- ssh_trusted_user_ca_keys_file | length > 0
- ssh_trusted_user_ca_keys | length > 0
- name: Include selinux specific tasks
include_tasks: selinux.yml
ansible.builtin.include_tasks: selinux.yml
when: ansible_facts.selinux and ansible_facts.selinux.status == "enabled"
- name: Gather package facts
package_facts:
ansible.builtin.package_facts:
check_mode: false
when:
- sshd_disable_crypto_policy | bool
- name: Disable SSH server CRYPTO_POLICY
copy:
ansible.builtin.copy:
src: sshd
dest: /etc/sysconfig/sshd
owner: 'root'
group: 'root'
mode: '0640'
owner: root
group: root
mode: "0640"
when:
- sshd_disable_crypto_policy | bool
- ('crypto-policies' in ansible_facts.packages)

View file

@ -1,6 +1,6 @@
---
- name: Include hardening tasks
include_tasks: hardening.yml
ansible.builtin.include_tasks: hardening.yml
args:
apply:
become: true

View file

@ -1,19 +1,19 @@
---
- name: Install selinux dependencies when selinux is installed
package:
name: '{{ ssh_selinux_packages }}'
ansible.builtin.package:
name: "{{ ssh_selinux_packages }}"
state: present
- name: Authorize {{ ssh_server_ports }} ports for selinux
seport:
ports: '{{ item }}'
community.general.seport:
ports: "{{ item }}"
proto: tcp
setype: ssh_port_t
state: present
loop: '{{ ssh_server_ports }}'
loop: "{{ ssh_server_ports }}"
- name: Check if ssh_password module is already installed
shell: 'set -o pipefail && semodule -l | grep ssh_password'
ansible.builtin.shell: set -o pipefail && semodule -l | grep ssh_password
args:
executable: /bin/bash
register: ssh_password_module
@ -30,36 +30,35 @@
- ('ssh_password' not in ssh_password_module.stdout)
block:
- name: Create selinux custom policy drop folder
file:
path: '{{ ssh_custom_selinux_dir }}'
state: 'directory'
owner: 'root'
group: 'root'
mode: '0750'
ansible.builtin.file:
path: "{{ ssh_custom_selinux_dir }}"
state: directory
owner: root
group: root
mode: "0750"
- name: Distributing custom selinux policies
copy:
src: 'ssh_password'
dest: '{{ ssh_custom_selinux_dir }}'
owner: 'root'
group: 'root'
mode: '0600'
ansible.builtin.copy:
src: ssh_password
dest: "{{ ssh_custom_selinux_dir }}"
owner: root
group: root
mode: "0600"
- name: Check and compile policy # noqa no-changed-when
command: checkmodule -M -m -o {{ ssh_custom_selinux_dir }}/ssh_password.mod {{ ssh_custom_selinux_dir }}/ssh_password
ansible.builtin.command: checkmodule -M -m -o {{ ssh_custom_selinux_dir }}/ssh_password.mod {{ ssh_custom_selinux_dir }}/ssh_password
- name: Create selinux policy module package # noqa no-changed-when
command: semodule_package -o {{ ssh_custom_selinux_dir }}/ssh_password.pp -m {{ ssh_custom_selinux_dir }}/ssh_password.mod
ansible.builtin.command: semodule_package -o {{ ssh_custom_selinux_dir }}/ssh_password.pp -m {{ ssh_custom_selinux_dir }}/ssh_password.mod
- name: Install selinux policy # noqa no-changed-when
command: semodule -i {{ ssh_custom_selinux_dir }}/ssh_password.pp
ansible.builtin.command: semodule -i {{ ssh_custom_selinux_dir }}/ssh_password.pp
# The following tasks only get executed when selinux is installed, UsePam is
# 'yes' and the ssh_password module is installed. See
# http://danwalsh.livejournal.com/12333.html for more info
- name: Remove selinux-policy when Pam is used, because Allowing sshd to read the shadow file directly is considered a potential security risk
command: semodule -r ssh_password
ansible.builtin.command: semodule -r ssh_password
when:
- ssh_use_pam | bool
- ('ssh_password' in ssh_password_module.stdout)

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/sbin/sshd
ssh_host_keys_dir: '/etc/ssh'
ssh_host_keys_dir: /etc/ssh
sshd_service_name: sshd
ssh_owner: root
ssh_group: root
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'root'
ssh_host_keys_owner: root
ssh_host_keys_group: root
# true if SSH support Kerberos
ssh_kerberos_support: true
@ -13,7 +13,7 @@ ssh_kerberos_support: true
# true if SSH has PAM support
ssh_pam_support: true
sshd_moduli_file: '/etc/ssh/moduli'
sshd_moduli_file: /etc/ssh/moduli
# CRYPTO_POLICY is not supported on Archlinux
# and the package check only works in Ansible >2.10

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/sbin/sshd
ssh_host_keys_dir: '/etc/ssh'
ssh_host_keys_dir: /etc/ssh
sshd_service_name: ssh
ssh_owner: root
ssh_group: root
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'root'
ssh_host_keys_owner: root
ssh_host_keys_group: root
ssh_selinux_packages:
- policycoreutils-python
- checkpolicy
@ -16,6 +16,6 @@ ssh_kerberos_support: true
# true if SSH has PAM support
ssh_pam_support: true
sshd_moduli_file: '/etc/ssh/moduli'
sshd_moduli_file: /etc/ssh/moduli
sshd_disable_crypto_policy: false

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/sbin/sshd
ssh_host_keys_dir: '/etc/ssh'
ssh_host_keys_dir: /etc/ssh
sshd_service_name: sshd
ssh_owner: root
ssh_group: root
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'ssh_keys'
ssh_host_keys_owner: root
ssh_host_keys_group: ssh_keys
ssh_selinux_packages:
- python3-policycoreutils
- checkpolicy
@ -16,7 +16,7 @@ ssh_kerberos_support: true
# true if SSH has PAM support
ssh_pam_support: true
sshd_moduli_file: '/etc/ssh/moduli'
sshd_moduli_file: /etc/ssh/moduli
# disable CRYPTO_POLICY to take settings from sshd configuration
# see: https://access.redhat.com/solutions/4410591

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/sbin/sshd
ssh_host_keys_dir: '/etc/ssh'
ssh_host_keys_dir: /etc/ssh
sshd_service_name: sshd
ssh_owner: root
ssh_group: wheel
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'root'
ssh_host_keys_owner: root
ssh_host_keys_group: root
# true if SSH support Kerberos
ssh_kerberos_support: true
@ -13,6 +13,6 @@ ssh_kerberos_support: true
# true if SSH has PAM support
ssh_pam_support: true
sshd_moduli_file: '/etc/ssh/moduli'
sshd_moduli_file: /etc/ssh/moduli
sshd_disable_crypto_policy: false

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/sbin/sshd
ssh_host_keys_dir: '/etc/ssh'
ssh_host_keys_dir: /etc/ssh
sshd_service_name: sshd
ssh_owner: root
ssh_group: wheel
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'root'
ssh_host_keys_owner: root
ssh_host_keys_group: root
# true if SSH support Kerberos
ssh_kerberos_support: false
@ -13,6 +13,6 @@ ssh_kerberos_support: false
# true if SSH has PAM support
ssh_pam_support: false
sshd_moduli_file: '/etc/moduli'
sshd_moduli_file: /etc/moduli
sshd_disable_crypto_policy: false

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/sbin/sshd
ssh_host_keys_dir: '/etc/ssh'
ssh_host_keys_dir: /etc/ssh
sshd_service_name: sshd
ssh_owner: root
ssh_group: root
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'ssh_keys'
ssh_host_keys_owner: root
ssh_host_keys_group: ssh_keys
ssh_selinux_packages:
- policycoreutils-python-utils
- checkpolicy
@ -16,7 +16,7 @@ ssh_kerberos_support: true
# true if SSH has PAM support
ssh_pam_support: true
sshd_moduli_file: '/etc/ssh/moduli'
sshd_moduli_file: /etc/ssh/moduli
# disable CRYPTO_POLICY to take settings from sshd configuration
# see: https://access.redhat.com/solutions/4410591

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/sbin/sshd
ssh_host_keys_dir: '/etc/ssh'
ssh_host_keys_dir: /etc/ssh
sshd_service_name: sshd
ssh_owner: root
ssh_group: root
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'ssh_keys'
ssh_host_keys_owner: root
ssh_host_keys_group: ssh_keys
ssh_selinux_packages:
- policycoreutils-python
- checkpolicy
@ -16,7 +16,7 @@ ssh_kerberos_support: true
# true if SSH has PAM support
ssh_pam_support: true
sshd_moduli_file: '/etc/ssh/moduli'
sshd_moduli_file: /etc/ssh/moduli
# disable CRYPTO_POLICY to take settings from sshd configuration
# see: https://access.redhat.com/solutions/4410591

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/lib/ssh/sshd
ssh_host_keys_dir: '/var/ssh'
ssh_host_keys_dir: /var/ssh
sshd_service_name: ssh
ssh_owner: root
ssh_group: root
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'root'
ssh_host_keys_owner: root
ssh_host_keys_group: root
# true if SSH support Kerberos
ssh_kerberos_support: true
@ -13,6 +13,6 @@ ssh_kerberos_support: true
# true if SSH has PAM support
ssh_pam_support: false
sshd_moduli_file: '/etc/ssh/moduli'
sshd_moduli_file: /etc/ssh/moduli
sshd_disable_crypto_policy: false

View file

@ -1,11 +1,11 @@
---
sshd_path: /usr/sbin/sshd
ssh_host_keys_dir: '/etc/ssh'
ssh_host_keys_dir: /etc/ssh
sshd_service_name: sshd
ssh_owner: root
ssh_group: root
ssh_host_keys_owner: 'root'
ssh_host_keys_group: 'root'
ssh_host_keys_owner: root
ssh_host_keys_group: root
# true if SSH support Kerberos
ssh_kerberos_support: true
@ -13,6 +13,6 @@ ssh_kerberos_support: true
# true if SSH has PAM support
ssh_pam_support: true
sshd_moduli_file: '/etc/ssh/moduli'
sshd_moduli_file: /etc/ssh/moduli
sshd_disable_crypto_policy: false