From fca827779f8dc040c748940294969f2d0dc2b333 Mon Sep 17 00:00:00 2001 From: Akos Balla Date: Thu, 7 Mar 2024 03:10:34 +0100 Subject: [PATCH] try OS-level LDAP auth --- files/ldap/allowpwchange.ldif | 5 + handlers/main.yml | 18 +++ tasks/kolab.yml | 36 +++--- tasks/ldap.yml | 212 ++++++++++++++++++---------------- tasks/main.yml | 10 +- tasks/os.yml | 21 +--- tasks/packages.yml | 26 +++++ tasks/postfix.yml | 1 + tasks/users.yml | 46 ++++++++ 9 files changed, 234 insertions(+), 141 deletions(-) create mode 100644 files/ldap/allowpwchange.ldif create mode 100644 tasks/users.yml diff --git a/files/ldap/allowpwchange.ldif b/files/ldap/allowpwchange.ldif new file mode 100644 index 0000000..182bdde --- /dev/null +++ b/files/ldap/allowpwchange.ldif @@ -0,0 +1,5 @@ +dn: olcDatabase={1}mdb,cn=config +changetype: modify +replace: olcAccess +olcAccess: {0}to attrs=cn,givenName,sn,userPassword,shadowLastChange,mail,loginShell,photo by self write by anonymous auth by dn.base="cn=Manager,dc=example,dc=org" write by * none +olcAccess: {1}to * by self read by dn.base="cn=Manager,dc=example,dc=org" write by * read diff --git a/handlers/main.yml b/handlers/main.yml index 760452b..51e1a48 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -82,6 +82,18 @@ daemon_reload: yes enabled: yes state: restarted +- name: Restart nscd + ansible.builtin.systemd_service: + name: nscd + daemon_reload: yes + enabled: yes + state: restarted +- name: Restart oddjobd + ansible.builtin.systemd_service: + name: oddjobd + daemon_reload: yes + enabled: yes + state: restarted - name: Restart opendkim ansible.builtin.systemd_service: name: opendkim @@ -141,6 +153,12 @@ daemon_reload: yes enabled: yes state: restarted +- name: Restart sssd + ansible.builtin.systemd_service: + name: sssd + daemon_reload: yes + enabled: yes + state: restarted - name: Default to localhost in resolv.conf ansible.builtin.copy: dest: /etc/resolv.conf diff --git a/tasks/kolab.yml b/tasks/kolab.yml index dfeaff2..d4c636d 100644 --- a/tasks/kolab.yml +++ b/tasks/kolab.yml @@ -514,21 +514,21 @@ - kolab-saslauthd loop_control: loop_var: kolab_service -- name: Add Kolab users - no_log: true - tags: - - users - block: - - name: "Add user to Kolab: {{ user.name }}" - ansible.builtin.include_tasks: add_kolab_user.yml - loop: "{{ users }}" - loop_control: - loop_var: user - rescue: - - name: Authenticate against the Kolab API - ansible.builtin.include_tasks: kolab_auth.yml - - name: "Add user to Kolab: {{ user.name }}" - ansible.builtin.include_tasks: add_kolab_user.yml - loop: "{{ users }}" - loop_control: - loop_var: user +# - name: Add Kolab users +# no_log: true +# tags: +# - users +# block: +# - name: "Add user to Kolab: {{ user.name }}" +# ansible.builtin.include_tasks: add_kolab_user.yml +# loop: "{{ users }}" +# loop_control: +# loop_var: user +# rescue: +# - name: Authenticate against the Kolab API +# ansible.builtin.include_tasks: kolab_auth.yml +# - name: "Add user to Kolab: {{ user.name }}" +# ansible.builtin.include_tasks: add_kolab_user.yml +# loop: "{{ users }}" +# loop_control: +# loop_var: user diff --git a/tasks/ldap.yml b/tasks/ldap.yml index 6dd3c1e..51f7d51 100644 --- a/tasks/ldap.yml +++ b/tasks/ldap.yml @@ -1,105 +1,117 @@ --- -# - name: Open firewall -# ansible.builtin.import_tasks: firewall.yml -# vars: -# port: "{{ item }}" # noqa var-naming[no-reserved] we refer to a port here, so I call it a port -# loop: -# - ldap -# - ldaps -# - name: Add ldap group -# group: -# name: ldap -# system: yes -# gid: 55 -# - name: Add ldap user -# ansible.builtin.user: -# name: ldap -# group: ldap -# create_home: yes -# system: yes -# uid: 55 -# home: /var/lib/openldap -# shell: /usr/sbin/nologin -- name: Render dscreate config template - ansible.builtin.template: - src: "ldap/389.dscreate.conf.j2" - dest: "/tmp/ansible-mailserver-install.dscreate.conf" - mode: u=rw +# TODO: follow https://wiki.archlinux.org/title/LDAP_authentication and apply allowpwchange.ldif +- name: Configure sssd + community.general.ini_file: + path: /etc/sssd/sssd.conf + section: "{{ sssd_item.section }}" + option: "{{ sssd_item.option }}" + value: "{{ sssd_item.value }}" + backup: true + mode: u=rw,og= owner: root group: root + notify: Restart sssd + loop: + - { section: 'domain/LDAP', option: 'id_provider', value: 'ldap' } + - { section: 'domain/LDAP', option: 'autofs_provider', value: 'ldap' } + - { section: 'domain/LDAP', option: 'auth_provider', value: 'ldap' } + - { section: 'domain/LDAP', option: 'chpass_provider', value: 'ldap' } + - { section: 'domain/LDAP', option: 'ldap_uri', value: 'ldaps://localhost' } + - { section: 'domain/LDAP', option: 'ldap_chpass_uri', value: 'ldaps://localhost' } + - { section: 'domain/LDAP', option: 'ldap_search_base', value: "dc={{ mailserver_domain | split('.') | join(',dc=') }}" } + - { section: 'domain/LDAP', option: 'sudoers_base', value: "dc={{ mailserver_domain | split('.') | join(',dc=') }}" } + - { section: 'domain/LDAP', option: 'sudo_provider', value: 'ldap' } + - { section: 'domain/LDAP', option: 'ldap_id_use_start_tls', value: 'True' } + - { section: 'domain/LDAP', option: 'ldap_tls_cacert', value: '/etc/dirsrv/slapd-{{ mailserver_domain | split(".") | first }}/ca.crt' } + - { section: 'domain/LDAP', option: 'cache_credentials', value: 'True' } + - { section: 'domain/LDAP', option: 'enumerate', value: 'True' } + - { section: 'domain/LDAP', option: 'ldap_tls_reqcert', value: 'allow' } + - { section: 'domain/LDAP', option: 'entry_cache_timeout', value: '600' } + - { section: 'domain/LDAP', option: 'ldap_network_timeout', value: '2' } + - { section: 'domain/LDAP', option: 'ldap_schema', value: 'rfc2307bis' } + - { section: 'domain/LDAP', option: 'ldap_group_member', value: 'uniqueMember' } + - { section: 'sssd', option: 'services', value: 'nss, pam, autofs, sudo' } + - { section: 'sssd', option: 'domains', value: 'LDAP' } + - { section: 'nss', option: 'homedir_substring', value: '/home' } + - { section: 'sudo', option: '', value: '' } + loop_control: + loop_var: sssd_item +- name: Configure nscd + ansible.builtin.lineinfile: + path: /etc/nscd.conf + line: "{{ nscd_item }}" + regex: "^{{ nscd_item | split('\t') | first }}\t" + state: present + backup: yes + loop: + - "enable-cache passwd no" + - "enable-cache group no" + - "enable-cache hosts yes" + - "enable-cache netgroup no" + loop_control: + loop_var: nscd_item + notify: + - Restart nscd + - Restart sssd +- name: Configure nsswitch.conf + ansible.builtin.lineinfile: + path: /etc/nsswitch.conf + line: '\1 sss' + regex: "^({{ nsswitch_item }}: .*$)" + backrefs: yes + state: present + backup: yes + loop: + - passwd + - group + - shadow + - sudoers + loop_control: + loop_var: nsswitch_item + notify: Restart sssd +- name: Configure /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + line: "{{ system_auth_item }}" + insertbefore: "^{{ system_auth_item | split(' ') | first }} " + state: present backup: yes - notify: "Restart dirsrv@{{ mailserver_hostname }}" -- name: Apply LDAP server configuration - block: - - name: Configure LDAP server - ansible.builtin.command: dscreate from-file /tmp/ansible-mailserver-install.dscreate.conf - register: dscreate_status - changed_when: dscreate_status.rc == 0 - rescue: - - name: Start LDAP server - ansible.builtin.command: "dsctl {{ mailserver_hostname }} start" - register: start_ldap_server - changed_when: start_ldap_server.rc == 0 - when: reset == "yes" - - name: Create backup before taking destructive actions - ansible.builtin.command: "dsconf {{ mailserver_hostname }} backup create" - when: reset == "yes" - register: backup_ldap_server - changed_when: backup_ldap_server.rc == 0 - - name: List LDAP server backups - ansible.builtin.command: "dsctl {{ mailserver_hostname }} backups" - register: ldap_backups - when: reset == "yes" - changed_when: ldap_backups.rc == 0 - - name: Create backup directory - ansible.builtin.file: - path: "/backup/{{ item }}" - state: directory - recurse: yes - owner: root - group: root - mode: u=rwX - when: reset == "yes" - loop: - - '' - - ldap - - name: Save last LDAP backup - community.general.archive: - path: "{{ (ldap_backups.stdout_lines | last).split(' ')[1] }}" - dest: "/backup/ldap/LDAP_backup.{{ (ldap_backups.stdout_lines | last).split(' ')[1].split('/') | last }}.tar.bz2" - owner: root - group: root - mode: u=rw - format: bz2 - force_archive: yes - when: reset == "yes" - - name: Uninstall LDAP server - ansible.builtin.command: "dsctl {{ mailserver_hostname }} remove --do-it" - when: reset == "yes" - register: uninstall_ldap_server - changed_when: uninstall_ldap_server.rc == 0 - - name: Configure LDAP server - ansible.builtin.command: dscreate from-file /tmp/ansible-mailserver-install.dscreate.conf - when: reset == "yes" - register: dscreate_status - changed_when: dscreate_status.rc == 0 -- name: Start LDAP server - ansible.builtin.command: "dsctl {{ mailserver_hostname }} start" - register: start_ldap_server - changed_when: start_ldap_server.rc == 0 -- name: Import TLS certificate for LDAP - ansible.builtin.command: "dsctl {{ mailserver_hostname }} tls import-server-key-cert /etc/letsencrypt/live/{{ mailserver_domain }}/cert.pem /etc/letsencrypt/certificates/{{ mailserver_domain }}.key" - register: import_ldap_cert - changed_when: import_ldap_cert.rc == 0 -- name: Enable LDAP plugins - ansible.builtin.command: "dsconf {{ mailserver_hostname }} plugin {{ item }} enable" loop: - - memberof - - automember - register: enable_ldap_plugin - changed_when: enable_ldap_plugin.rc == 0 -- name: Configure the memberof plugin to search all entries - ansible.builtin.command: "dsconf {{ mailserver_hostname }} plugin memberof set --scope dc={{ mailserver_domain.split('.') | join(',dc=') }}" - register: enable_ldap_memberof_plugin - changed_when: enable_ldap_memberof_plugin.rc == 0 - when: "dscreate_status is defined and dscreate_status.rc is defined and dscreate_status.rc == 0" + - "auth sufficient pam_sss.so forward_pass" + - "account [default=bad success=ok user_unknown=ignore authinfo_unavail=ignore] pam_sss.so" + - "password sufficient pam_sss.so" + - "session required pam_mkhomedir.so skel=/etc/skel/ umask=0077" + loop_control: + loop_var: system_auth_item + notify: Restart sssd +- name: Add pam_sss to /etc/pam.d/system-auth + ansible.builtin.lineinfile: + path: /etc/pam.d/system-auth + insertafter: "session required pam_unix.so" + line: "session optional pam_sss.so" + # insertbefore: "session optional pam_permit.so" + state: present + backup: yes + notify: Restart sssd +- name: Configure /etc/pam.d/su + ansible.builtin.lineinfile: + path: /etc/pam.d/su + insertafter: "^{{ su_item | split(' ') | first }}\\s*sufficient" + line: "{{ su_item }}" + state: present + backup: yes + loop: + - "auth sufficient pam_sss.so forward_pass" + - "account [default=bad success=ok user_unknown=ignore authinfo_unavail=ignore] pam_sss.so" + - "session optional pam_sss.so" + loop_control: + loop_var: su_item + notify: Restart sssd +- name: Configure /etc/pam.d/sudo + ansible.builtin.lineinfile: + path: /etc/pam.d/sudo + insertafter: "^#%PAM-.*" + line: "auth sufficient pam_sss.so" + state: present + backup: yes + notify: Restart sssd \ No newline at end of file diff --git a/tasks/main.yml b/tasks/main.yml index 812b148..7641c86 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -40,15 +40,17 @@ - name: Set up SSL ansible.builtin.import_tasks: ssl.yml tags: ssl -# - name: Configure LDAP -# ansible.builtin.import_tasks: ldap.yml -# tags: ldap # - name: Set up Horde # ansible.builtin.import_tasks: horde.yml # tags: horde - name: Set up Kolab ansible.builtin.import_tasks: kolab.yml - tags: kolab + tags: + - kolab + - users +- name: Add users + ansible.builtin.import_tasks: users.yml + tags: users - name: Set up ElasticSearch ansible.builtin.import_tasks: elasticsearch.yml tags: elasticsearch diff --git a/tasks/os.yml b/tasks/os.yml index baed05d..274afeb 100644 --- a/tasks/os.yml +++ b/tasks/os.yml @@ -79,27 +79,10 @@ group: root state: present backup: yes -- name: Create OS users - ansible.builtin.user: - name: "{{ item.name }}" - password: "{{ item.password | password_hash('sha512') | default(lookup('password', '/tmp/ansible-mailserver-install.' + item.name + '_password chars=ascii_letters,digits,punctuation')) }}" - groups: "{{ 'wheel' if item.name == mailserver_admin_user }}" - append: yes - state: present - loop: "{{ users }}" - register: user_info - no_log: yes - notify: Warn on passwords +- name: Configure LDAP + ansible.builtin.import_tasks: ldap.yml tags: - - all - - ftp - - httpd - - poweradmin - - wireguard - - dns - # - horde - ldap - # - postfixadmin - users - name: Enable ip_conntrack community.general.modprobe: diff --git a/tasks/packages.yml b/tasks/packages.yml index 599bc41..a2c9254 100644 --- a/tasks/packages.yml +++ b/tasks/packages.yml @@ -79,6 +79,26 @@ tags: kolab ansible.builtin.dnf: name: "https://mirror.apheleia-it.ch/repos/Kolab:/16/kolab-16-for-el{{ ansible_distribution_major_version }}.rpm" +# - name: Set up Symas OpenLDAP for Linux RPM repository +# tags: +# - ldap +# - users +# ansible.builtin.blockinfile: +# path: /etc/yum.repos.d/sofl.repo +# marker: "# {mark} ANSIBLE MANAGED BLOCK Symas OpenLDAP for Linux RPM repository" +# block: | +# [sofl] +# name=Symas OpenLDAP for Linux RPM repository +# baseurl=https://repo.symas.com/repo/rpm/SOFL/rhel{{ ansible_distribution_major_version }} +# gpgkey=https://repo.symas.com/repo/gpg/RPM-GPG-KEY-symas-com-signing-key +# gpgcheck=1 +# enabled=1 +# mode: u=rw,og=r +# owner: root +# group: root +# state: present +# backup: yes +# create: yes - name: Set up Extra Packages for Enterprise Linux 7 repository ansible.builtin.blockinfile: path: /etc/yum.repos.d/epel-el7.repo @@ -357,6 +377,12 @@ - aide - kolab - php74-php-pecl-memcache + # - sssd + # - oddjob-mkhomedir + # - libsss_sudo + # - symas-openldap-clients + # - symas-openldap-servers + - nss-pam-ldapd # - php56-php-bcmath # - php56-php-channel-horde # - php56-php-horde-horde-lz4 diff --git a/tasks/postfix.yml b/tasks/postfix.yml index f45558b..8402984 100644 --- a/tasks/postfix.yml +++ b/tasks/postfix.yml @@ -239,6 +239,7 @@ group: root state: present backup: yes + create: yes loop: "{{ postgrey_whitelist_clients }}" notify: Restart postgrey - name: Set POSTGREY_DELAY to 1 diff --git a/tasks/users.yml b/tasks/users.yml new file mode 100644 index 0000000..06c124d --- /dev/null +++ b/tasks/users.yml @@ -0,0 +1,46 @@ +--- +# - name: Create OpenLDAP SUDO schema +# ansible.builtin.copy: +# src: /usr/share/doc/sudo/schema.OpenLDAP +# dest: /etc/openldap/schema/sudo.schema +# remote_src: yes +# owner: root +# group: root +# mode: u=rw,og=r +# - name: Create SUDO LDIF file +# ansible.builtin.copy: +# src: ldap/sudo.ldif +# dest: /etc/openldap/schema/sudo.ldif +# owner: root +# group: root +# mode: u=rw,og=r +# - name: Enable OpenLDAP schemas +# ansible.builtin.command: "ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/{{ ldif_item }}.ldif" +# loop: +# - cosine +# - nis +# - sudo +# loop_control: +# loop_var: ldif_item +- name: Create OS users + ansible.builtin.user: + name: "{{ item.name }}" + password: "{{ item.password | password_hash('sha512') | default(lookup('password', '/tmp/ansible-mailserver-install.' + item.name + '_password chars=ascii_letters,digits,punctuation')) }}" + groups: "{{ 'wheel' if item.name == mailserver_admin_user }}" + append: yes + state: present + loop: "{{ users }}" + register: user_info + no_log: yes + notify: Warn on passwords + tags: + - all + - ftp + - httpd + - poweradmin + - wireguard + - dns + # - horde + - ldap + # - postfixadmin + - users