diff --git a/CHANGELOG.md b/CHANGELOG.md index 12c19b85..f545fd9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The **patch** part changes incrementally at each release. ### Changed * evolinux-base: fail2ban is not enabled by default +* evolinux-users: refactoring of the SSH configuration * mysql-oracle: copy evolinux config files in mysql.cond.d ### Fixed @@ -53,6 +54,7 @@ The **patch** part changes incrementally at each release. * elasticsearch: RESTART_ON_UPGRADE is configurable (default: `true`) * elasticsearch: use ES_TMPDIR variable for custom tmpdir, (from `/etc/default/elasticsearch` instead of changing `/etc/elesticsearch/jvm.options`). * evolinux-base: Exec the firewall tasks sooner (to avoid dependency issues) +* evolinux-users: split AllowGroups/AllowUsers modes for SSH directives * mongodb: allow unauthenticated packages for Jessie * mongodb: configuration is forced by default but it's configurable (default: `false`) * mongodb: rename logrotate script diff --git a/evolinux-base/tasks/ssh.yml b/evolinux-base/tasks/ssh.yml index 773de28f..40970ca6 100644 --- a/evolinux-base/tasks/ssh.yml +++ b/evolinux-base/tasks/ssh.yml @@ -63,16 +63,16 @@ - name: "Get current user" command: logname + changed_when: False register: logname check_mode: no - changed_when: False when: evolinux_ssh_allow_current_user # we must double-escape caracters, because python - name: verify AllowUsers directive command: "grep -E '^AllowUsers' /etc/ssh/sshd_config" - changed_when: False failed_when: False + changed_when: False register: grep_allowusers_ssh check_mode: no when: evolinux_ssh_allow_current_user diff --git a/evolinux-users/defaults/main.yml b/evolinux-users/defaults/main.yml index d7d6f958..fe97185c 100644 --- a/evolinux-users/defaults/main.yml +++ b/evolinux-users/defaults/main.yml @@ -1,4 +1,7 @@ --- evolinux_users: {} + evolinux_sudo_group: "evolinux-sudo" +evolinux_ssh_group: "evolinux-ssh" + evolinux_root_disable_ssh: True diff --git a/evolinux-users/tasks/account.yml b/evolinux-users/tasks/account.yml deleted file mode 100644 index 1ed142f9..00000000 --- a/evolinux-users/tasks/account.yml +++ /dev/null @@ -1,57 +0,0 @@ ---- - -- name: "Test if '{{ user.name }}' exists" - command: 'getent passwd {{ user.name }}' - register: loginisbusy - failed_when: False - changed_when: False - check_mode: no - -- name: "Test if uid exists for '{{ user.name }}'" - command: 'getent passwd {{ user.uid }}' - register: uidisbusy - failed_when: False - changed_when: False - check_mode: no - -- name: "Add Unix account with classical uid for '{{ user.name }}'" - user: - state: present - uid: '{{ user.uid }}' - name: '{{ user.name }}' - comment: '{{ user.fullname }}' - shell: /bin/bash - password: '{{ user.password_hash }}' - update_password: on_create - when: loginisbusy.rc != 0 and uidisbusy.rc != 0 - -- name: "Add Unix account with random uid for '{{ user.name }}'" - user: - state: present - name: '{{ user.name }}' - comment: '{{ user.fullname }}' - shell: /bin/bash - password: '{{ user.password_hash }}' - update_password: on_create - when: loginisbusy.rc != 0 and uidisbusy.rc == 0 - -- name: "Create secondary groups" - group: - name: "{{ group }}" - with_items: "{{ user.groups }}" - loop_control: - loop_var: group - when: user.groups is defined - -- name: "Add user '{{ user.name }}' to secondary groups" - user: - name: '{{ user.name }}' - groups: "{{ user.groups }}" - append: yes - when: user.groups is defined - -- name: "Fix perms on home directory for '{{ user.name }}'" - file: - name: '/home/{{ user.name }}' - mode: "0700" - state: directory diff --git a/evolinux-users/tasks/main.yml b/evolinux-users/tasks/main.yml index ec1400bd..a32bbd13 100644 --- a/evolinux-users/tasks/main.yml +++ b/evolinux-users/tasks/main.yml @@ -1,9 +1,10 @@ --- -- fail: +- assert: + that: + - ansible_distribution == "Debian" + - ansible_distribution_major_version | version_compare('8', '>=') msg: only compatible with Debian >= 8 - when: - - ansible_distribution != "Debian" or ansible_distribution_major_version | version_compare('8', '<') - debug: msg: "Warning: empty 'evolinux_users' variable, tasks will be skipped!" @@ -16,5 +17,13 @@ with_dict: "{{ evolinux_users }}" when: evolinux_users != {} -- include: root_disable_ssh.yml - when: evolinux_root_disable_ssh +- name: Configure sudo + include: sudo.yml + vars: + user: "{{ item.value }}" + with_dict: "{{ evolinux_users }}" + when: evolinux_users != {} + +- name: Configure SSH + include: ssh.yml + when: evolinux_users != {} diff --git a/evolinux-users/tasks/profile.yml b/evolinux-users/tasks/profile.yml deleted file mode 100644 index 6a046e52..00000000 --- a/evolinux-users/tasks/profile.yml +++ /dev/null @@ -1,18 +0,0 @@ ---- - -- name: search profile for presence of evomaintenance - command: 'grep -q "trap.*sudo.*evomaintenance.sh"' - changed_when: False - failed_when: False - check_mode: no - register: grep_profile_evomaintenance - -# Don't add the trap if it is present or commented -- name: "Add evomaintenance trap for '{{ user.name }}'" - lineinfile: - state: present - dest: '/home/{{ user.name }}/.profile' - insertafter: EOF - line: 'trap "sudo /usr/share/scripts/evomaintenance.sh" 0' - create: yes - when: grep_profile_evomaintenance.rc != 0 diff --git a/evolinux-users/tasks/root_disable_ssh.yml b/evolinux-users/tasks/root_disable_ssh.yml deleted file mode 100644 index 7906307f..00000000 --- a/evolinux-users/tasks/root_disable_ssh.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- - -- name: disable root login - replace: - dest: /etc/ssh/sshd_config - regexp: '^PermitRootLogin (yes|without-password|prohibit-password)' - replace: "PermitRootLogin no" - notify: reload sshd - -### Disabled : it seems useless and too dangerous for now -# - name: remove root from AllowUsers directive -# replace: -# dest: /etc/ssh/sshd_config -# regexp: '^(AllowUsers ((?!root(?:@\S+)?).)*)(\sroot(?:@\S+)?|root(?:@\S+)?\s)(.*)$' -# replace: '\1\4' -# validate: '/usr/sbin/sshd -T -f %s' -# notify: reload sshd diff --git a/evolinux-users/tasks/ssh.yml b/evolinux-users/tasks/ssh.yml index 75b47ce2..ff7cf85a 100644 --- a/evolinux-users/tasks/ssh.yml +++ b/evolinux-users/tasks/ssh.yml @@ -1,97 +1,64 @@ --- - -- name: "Create .ssh directory for '{{ user.name }}'" - file: - dest: '/home/{{ user.name }}/.ssh/' - state: directory - mode: "0700" - owner: '{{ user.name }}' - group: '{{ user.name }}' - -- name: "Add user's SSH public key for '{{ user.name }}'" - authorized_key: - user: "{{ user.name }}" - key: "{{ user.ssh_key }}" - state: present - when: user.ssh_key is defined - -- name: "Add user's SSH public keys for '{{ user.name }}'" - authorized_key: - user: "{{ user.name }}" - key: "{{ ssk_key }}" - state: present - with_items: "{{ user.ssh_keys }}" - loop_control: - loop_var: ssk_key - when: user.ssh_keys is defined - - name: verify AllowGroups directive command: "grep -E '^AllowGroups' /etc/ssh/sshd_config" changed_when: False failed_when: False - register: grep_allowgroups_ssh check_mode: no + register: grep_allowgroups_ssh - # If AllowGroups is present, we don't change - debug: - msg: "AllowGroups detected : You have to configure SSH manually" - when: grep_allowgroups_ssh.rc == 0 + var: grep_allowgroups_ssh + verbosity: 1 -- block: - # If AllowGroups is not present, we proceed as usual - - name: verify AllowUsers directive - command: "grep -E '^AllowUsers' /etc/ssh/sshd_config" - changed_when: False - failed_when: False - register: grep_allowusers_ssh - check_mode: no +- name: verify AllowUsers directive + command: "grep -E '^AllowUsers' /etc/ssh/sshd_config" + changed_when: False + failed_when: False + check_mode: no + register: grep_allowusers_ssh - - name: "Add AllowUsers sshd directive for '{{ user.name }}'" - lineinfile: - dest: /etc/ssh/sshd_config - line: "\nAllowUsers {{ user.name }}" - insertafter: 'Subsystem' - validate: '/usr/sbin/sshd -T -f %s' - notify: reload sshd - when: grep_allowusers_ssh.rc != 0 +- debug: + var: grep_allowusers_ssh + verbosity: 1 - - name: "Modify AllowUsers sshd directive for '{{ user.name }}'" - replace: - dest: /etc/ssh/sshd_config - regexp: '^(AllowUsers ((?!\b{{ user.name }}\b).)*)$' - replace: '\1 {{ user.name }}' - validate: '/usr/sbin/sshd -T -f %s' - notify: reload sshd - when: grep_allowusers_ssh.rc == 0 +- assert: + that: "not (grep_allowusers_ssh.rc == 0 and grep_allowgroups_ssh.rc == 0)" + msg: "We can't deal with AllowUsers and AllowGroups at the same time" - - name: "verify Match User directive" - command: "grep 'Match User' /etc/ssh/sshd_config" - changed_when: False - failed_when: False - register: grep_matchuser_ssh - check_mode: no +- set_fact: + # If "AllowGroups is present" or "AllowUsers is absent and Debian 9+", + ssh_allowgroups: "{{ (grep_allowgroups_ssh.rc == 0) or (grep_allowusers_ssh.rc != 0 and (ansible_distribution_major_version | version_compare('9', '>='))) }}" + # If "AllowGroups is absent" and "AllowUsers is absent or Debian <9" + ssh_allowusers: "{{ (grep_allowusers_ssh.rc == 0) or (grep_allowgroups_ssh.rc != 0 and (ansible_distribution_major_version | version_compare('9', '<'))) }}" - - name: "Add Match User sshd directive for '{{ user.name }}' (Jessie)" - lineinfile: - dest: /etc/ssh/sshd_config - line: "\nMatch User {{ user.name }}\n PasswordAuthentication no" - insertafter: "# END EVOLINUX PASSWORD RESTRICTIONS BY ADDRESS" - validate: '/usr/sbin/sshd -T -f %s' - notify: reload sshd - when: - - ansible_distribution_release == "jessie" - - grep_matchuser_ssh.rc != 0 +- debug: + var: ssh_allowgroups + verbosity: 1 - - name: "Modify Match User's sshd directive for '{{ user.name }}' (Jessie)" - replace: - dest: /etc/ssh/sshd_config - regexp: '^(Match User ((?!{{ user.name }}).)*)$' - replace: '\1,{{ user.name }}' - validate: '/usr/sbin/sshd -T -f %s' - notify: reload sshd - when: - - ansible_distribution_release == "jessie" - - grep_matchuser_ssh.rc == 0 +- debug: + var: ssh_allowusers + verbosity: 1 - when: grep_allowgroups_ssh.rc != 0 +- include: ssh_allowgroups.yml + when: + - ssh_allowgroups + - not ssh_allowusers + +- include: ssh_allowusers.yml + vars: + user: "{{ item.value }}" + with_dict: "{{ evolinux_users }}" + when: + - ssh_allowusers + - not ssh_allowgroups + +- name: disable root login + replace: + dest: /etc/ssh/sshd_config + regexp: '^PermitRootLogin (yes|without-password|prohibit-password)' + replace: "PermitRootLogin no" + notify: reload sshd + when: evolinux_root_disable_ssh + +- meta: flush_handlers diff --git a/evolinux-users/tasks/ssh_allowgroups.yml b/evolinux-users/tasks/ssh_allowgroups.yml new file mode 100644 index 00000000..68635548 --- /dev/null +++ b/evolinux-users/tasks/ssh_allowgroups.yml @@ -0,0 +1,28 @@ +--- + +# this check must be repeated for each user +# even if it's been done before +- name: verify AllowGroups directive + command: "grep -E '^AllowGroups' /etc/ssh/sshd_config" + changed_when: False + failed_when: False + check_mode: no + register: grep_allowgroups_ssh + +- name: "Add AllowGroups sshd directive with '{{ evolinux_ssh_group }}'" + lineinfile: + dest: /etc/ssh/sshd_config + line: "\nAllowGroups {{ evolinux_ssh_group }}" + insertafter: 'Subsystem' + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: grep_allowgroups_ssh.rc != 0 + +- name: "Append '{{ evolinux_ssh_group }}' to AllowGroups sshd directive" + replace: + dest: /etc/ssh/sshd_config + regexp: '^(AllowGroups ((?!\b{{ evolinux_ssh_group }}\b).)*)$' + replace: '\1 {{ evolinux_ssh_group }}' + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: grep_allowgroups_ssh.rc == 0 diff --git a/evolinux-users/tasks/ssh_allowusers.yml b/evolinux-users/tasks/ssh_allowusers.yml new file mode 100644 index 00000000..fff04f8c --- /dev/null +++ b/evolinux-users/tasks/ssh_allowusers.yml @@ -0,0 +1,53 @@ +--- + +# this check must be repeated for each user +# even if it's been done before +- name: verify AllowUsers directive + command: "grep -E '^AllowUsers' /etc/ssh/sshd_config" + changed_when: False + failed_when: False + check_mode: no + register: grep_allowusers_ssh + +- name: "Add AllowUsers sshd directive with '{{ user.name }}'" + lineinfile: + dest: /etc/ssh/sshd_config + line: "\nAllowUsers {{ user.name }}" + insertafter: 'Subsystem' + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: grep_allowusers_ssh.rc != 0 + +- name: "Append '{{ user.name }}' to AllowUsers sshd directive" + replace: + dest: /etc/ssh/sshd_config + regexp: '^(AllowUsers ((?!\b{{ user.name }}\b).)*)$' + replace: '\1 {{ user.name }}' + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: grep_allowusers_ssh.rc == 0 + +- name: "verify Match User directive" + command: "grep -E '^Match User' /etc/ssh/sshd_config" + changed_when: False + failed_when: False + check_mode: no + register: grep_matchuser_ssh + +- name: "Add Match User sshd directive with '{{ user.name }}'" + lineinfile: + dest: /etc/ssh/sshd_config + line: "\nMatch User {{ user.name }}\n PasswordAuthentication no" + insertafter: "# END EVOLINUX PASSWORD RESTRICTIONS BY ADDRESS" + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: grep_matchuser_ssh.rc != 0 + +- name: "Append '{{ user.name }}' to Match User's sshd directive" + replace: + dest: /etc/ssh/sshd_config + regexp: '^(Match User ((?!{{ user.name }}).)*)$' + replace: '\1,{{ user.name }}' + validate: '/usr/sbin/sshd -T -f %s' + notify: reload sshd + when: grep_matchuser_ssh.rc == 0 diff --git a/evolinux-users/tasks/sudo.yml b/evolinux-users/tasks/sudo.yml new file mode 100644 index 00000000..ed696b43 --- /dev/null +++ b/evolinux-users/tasks/sudo.yml @@ -0,0 +1,9 @@ +--- + +- include: sudo_jessie.yml + when: ansible_distribution_release == "jessie" + +- include: sudo_stretch.yml + when: ansible_distribution_major_version | version_compare('9', '>=') + +- meta: flush_handlers diff --git a/evolinux-users/tasks/sudo_stretch.yml b/evolinux-users/tasks/sudo_stretch.yml index 3aa89e63..dc744c56 100644 --- a/evolinux-users/tasks/sudo_stretch.yml +++ b/evolinux-users/tasks/sudo_stretch.yml @@ -5,6 +5,7 @@ src: sudoers_stretch.j2 dest: /etc/sudoers.d/evolinux force: no + mode: "0440" validate: '/usr/sbin/visudo -cf %s' register: copy_sudoers_evolinux diff --git a/evolinux-users/tasks/user.yml b/evolinux-users/tasks/user.yml index 73fea728..ff2b7390 100644 --- a/evolinux-users/tasks/user.yml +++ b/evolinux-users/tasks/user.yml @@ -1,15 +1,125 @@ --- -- include: account.yml +# Unix account -- include: profile.yml +- name: "Test if '{{ user.name }}' exists" + command: 'getent passwd {{ user.name }}' + register: loginisbusy + failed_when: False + changed_when: False + check_mode: no -- include: ssh.yml +- name: "Test if uid exists for '{{ user.name }}'" + command: 'getent passwd {{ user.uid }}' + register: uidisbusy + failed_when: False + changed_when: False + check_mode: no -- include: sudo_jessie.yml - when: ansible_distribution_release == "jessie" +- name: "Unix account for '{{ user.name }}' is present (with uid '{{ user.uid }}')" + user: + state: present + uid: '{{ user.uid }}' + name: '{{ user.name }}' + comment: '{{ user.fullname }}' + shell: /bin/bash + password: '{{ user.password_hash }}' + update_password: on_create + when: + - loginisbusy.rc != 0 + - uidisbusy.rc != 0 -- include: sudo_stretch.yml +- name: "Unix account for '{{ user.name }}' is present (with random uid)" + user: + state: present + name: '{{ user.name }}' + comment: '{{ user.fullname }}' + shell: /bin/bash + password: '{{ user.password_hash }}' + update_password: on_create + when: + - loginisbusy.rc != 0 + - uidisbusy.rc == 0 + +# Unix groups + +- name: "Unix group '{{ evolinux_ssh_group }}' is present (Debian 9 or later)" + group: + name: "{{ evolinux_ssh_group }}" + state: present when: ansible_distribution_major_version | version_compare('9', '>=') +- name: "Unix user '{{ user.name }}' belongs to group '{{ evolinux_ssh_group }}' (Debian 9 or later)" + user: + name: '{{ user.name }}' + groups: "{{ evolinux_ssh_group }}" + append: yes + when: ansible_distribution_major_version | version_compare('9', '>=') + +- name: "Secondary Unix groups are present" + group: + name: "{{ group }}" + with_items: "{{ user.groups }}" + loop_control: + loop_var: group + when: user.groups is defined + +- name: "Unix user '{{ user.name }}' belongs to secondary groups" + user: + name: '{{ user.name }}' + groups: "{{ user.groups }}" + append: yes + when: user.groups is defined + +- name: "Home directory for '{{ user.name }}' is not accessible by group and other users" + file: + name: '/home/{{ user.name }}' + mode: "0700" + state: directory + +# Evomaintenance + +- name: Search profile for presence of evomaintenance + command: 'grep -q "trap.*sudo.*evomaintenance.sh" /home/{{ user.name }}/.profile' + changed_when: False + failed_when: False + check_mode: no + register: grep_profile_evomaintenance + +# Don't add the trap if it is present or commented +- name: "User '{{ user.name }}' has its shell trap for evomaintenance" + lineinfile: + state: present + dest: '/home/{{ user.name }}/.profile' + insertafter: EOF + line: 'trap "sudo /usr/share/scripts/evomaintenance.sh" 0' + when: grep_profile_evomaintenance.rc != 0 + +# SSH keys + +- name: "SSH directory for '{{ user.name }}' is present" + file: + dest: '/home/{{ user.name }}/.ssh/' + state: directory + mode: "0700" + owner: '{{ user.name }}' + group: '{{ user.name }}' + +- name: "SSH public key for '{{ user.name }}' is present" + authorized_key: + user: "{{ user.name }}" + key: "{{ user.ssh_key }}" + state: present + when: user.ssh_key is defined + +- name: "SSH public keys for '{{ user.name }}' are present" + authorized_key: + user: "{{ user.name }}" + key: "{{ ssk_key }}" + state: present + with_items: "{{ user.ssh_keys }}" + loop_control: + loop_var: ssk_key + when: user.ssh_keys is defined + - meta: flush_handlers