Files @ 9837860d0e76
Branch filter:

Location: majic-ansible-roles/roles/ldap_server/tasks/main.yml

branko
MAR-218: Fix erroneous test for ipv6 address (copy/paste error).
---

- name: Set domain for slapd
  ansible.builtin.debconf:
    name: slapd
    question: slapd/domain
    vtype: string
    value: "{{ ldap_server_domain }}"

- name: Set organisation for slapd
  ansible.builtin.debconf:
    name: slapd
    question: shared/organization
    vtype: string
    value: "{{ ldap_server_organization }}"

- name: Install slapd
  ansible.builtin.apt:
    name: slapd
    state: present

- name: Allow OpenLDAP user to traverse the directory with TLS private keys
  ansible.builtin.user:
    name: openldap
    append: true
    groups: ssl-cert
  register: openldap_in_ssl_cert

- name: Restart slapd if group membership has changed (apply immediatelly)  # noqa no-handler
  # [no-handler] Tasks that run when changed should likely be handlers
  #   In order to be able to change LDAP server TLS configuration, it must be
  #   able to read both the private key and certificate. Therefore we need to
  #   immediatelly restart (since configuration is done live on the server.
  ansible.builtin.service:
    name: slapd
    state: restarted
  when: openldap_in_ssl_cert.changed

- name: Install Python LDAP bindings
  ansible.builtin.apt:
    name: python3-pyldap
    state: present

- name: Set-up LDAP server to listen on legacy SSL port
  ansible.builtin.lineinfile:
    dest: /etc/default/slapd
    state: present
    backrefs: true
    regexp: '^SLAPD_SERVICES=.*'
    line: 'SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"'
  notify:
    - Restart slapd

- name: Enable and start slapd service
  ansible.builtin.service:
    name: slapd
    state: started
    enabled: true

- name: Change log level for slapd
  community.general.ldap_attrs:
    dn: cn=config
    attributes:
      olcLogLevel: "{{ ldap_server_log_level }}"
    state: exact

- name: Test if LDAP misc schema has been applied
  ansible.builtin.command: "ldapsearch -H ldapi:/// -Q -LLL -A -Y EXTERNAL -b cn=schema,cn=config -s one '(cn={*}misc)' cn"
  register: ldap_misc_schema_present
  changed_when: false

- name: Deploy LDAP misc schema
  ansible.builtin.command: "ldapadd -H ldapi:/// -Q -Y EXTERNAL -f /etc/ldap/schema/misc.ldif"
  when: not ldap_misc_schema_present.stdout
  changed_when: true  # Always results in change due to task logic.

# Technically, the only thing this does is pick the size of DH
# parameters to use, with GnuTLS (against which slapd is linked
# against under Debian) picking a matching DH parameter from RFC-7919
# (https://www.ietf.org/rfc/rfc7919.txt).
- name: Generate the LDAP server Diffie-Hellman parameter
  community.crypto.openssl_dhparam:
    owner: root
    group: openldap
    mode: "0640"
    path: "/etc/ssl/private/{{ ansible_fqdn }}_ldap.dh.pem"
    size: 2048
  notify:
    - Restart slapd

- name: Deploy LDAP TLS private key
  ansible.builtin.template:
    src: "ldap_tls_key.j2"
    dest: "/etc/ssl/private/{{ ansible_fqdn }}_ldap.key"
    mode: "0640"
    owner: root
    group: openldap
  notify:
    - Restart slapd

- name: Deploy LDAP TLS certificate
  ansible.builtin.template:
    src: "ldap_tls_cert.j2"
    dest: "/etc/ssl/certs/{{ ansible_fqdn }}_ldap.pem"
    mode: "0644"
    owner: root
    group: root
  notify:
    - Restart slapd

- name: Deploy configuration file for checking certificate validity via cron
  ansible.builtin.copy:
    content: "/etc/ssl/certs/{{ ansible_fqdn }}_ldap.pem"
    dest: "/etc/check_certificate/{{ ansible_fqdn }}_ldap.conf"
    owner: root
    group: root
    mode: "0644"

- name: Configure TLS
  community.general.ldap_attrs:
    dn: cn=config
    attributes:
      olcTLSCertificateFile: "/etc/ssl/certs/{{ ansible_fqdn }}_ldap.pem"
      olcTLSCertificateKeyFile: "/etc/ssl/private/{{ ansible_fqdn }}_ldap.key"
      olcTLSDHParamFile: "/etc/ssl/private/{{ ansible_fqdn }}_ldap.dh.pem"
      olcTLSCipherSuite: "{{ ldap_tls_ciphers }}"
    state: exact

- name: Configure required SSF (make sure local unix socket connections are allowed)
  community.general.ldap_attrs:
    dn: cn=config
    attributes:
      olcLocalSSF: "{{ ldap_server_ssf }}"
      olcSecurity: "ssf={{ ldap_server_ssf }}"
    state: exact

- name: Enable the memberof module
  community.general.ldap_attrs:
    dn: "cn=module{0},cn=config"
    attributes:
      olcModuleLoad: "{1}memberof"
    state: present

- name: Enable the memberof overlay for database
  community.general.ldap_entry:
    dn: "olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config"
    objectClass:
      - olcConfig
      - olcMemberOf
      - olcOverlayConfig
    attributes:
      olcOverlay: memberof
      olcMemberOfRefInt: "TRUE"
      olcMemberOfGroupOC: groupOfUniqueNames
      olcMemberOfMemberAD: uniqueMember

- name: Apply database permissions
  m_ldap_permissions:
    filter: "(olcSuffix={{ ldap_server_int_basedn }})"
    rules: "{{ ldap_permissions }}"

- name: Drop the admin entry corresponding to olcRootDN for database from directory
  community.general.ldap_entry:
    dn: "cn=admin,{{ ldap_server_int_basedn }}"
    state: absent

- name: Create basic LDAP directory structure
  community.general.ldap_entry:
    dn: "ou={{ item }},{{ ldap_server_int_basedn }}"
    objectClass:
      - organizationalUnit
    attributes:
      ou: "{{ item }}"
  with_items:
    - people
    - groups
    - services

- name: Create the entry that will contain mail service information
  community.general.ldap_entry:
    dn: "ou=mail,ou=services,{{ ldap_server_int_basedn }}"
    objectClass:
      - organizationalUnit
    attributes:
      ou: mail

- name: Create LDAP directory structure for mail service
  community.general.ldap_entry:
    dn: "ou={{ item }},ou=mail,ou=services,{{ ldap_server_int_basedn }}"
    objectClass:
      - organizationalUnit
    attributes:
      ou: "{{ item }}"
  with_items:
    - domains
    - aliases

- name: Create or remove login entries for services
  community.general.ldap_entry:
    dn: "cn={{ item.name }},ou=services,{{ ldap_server_int_basedn }}"
    objectClass:
      - applicationProcess
      - simpleSecurityObject
    attributes:
      cn: "{{ item.name }}"
      userPassword: "{{ item.password }}"
    state: "{{ item.state | default('present') }}"
  with_items: "{{ ldap_server_consumers }}"

- name: Update services login passwords
  community.general.ldap_attrs:
    dn: "cn={{ item.name }},ou=services,{{ ldap_server_int_basedn }}"
    attributes:
      userPassword: "{{ item.password }}"
    state: exact
  with_items: "{{ ldap_server_consumers }}"
  when: "item.state | default('present') == 'present'"

- name: Create or remove user-supplied groups
  community.general.ldap_entry:
    dn: "cn={{ item.name }},ou=groups,{{ ldap_server_int_basedn }}"
    objectClass:
      - groupOfUniqueNames
    attributes:
      cn: "{{ item.name }}"
      uniqueMember: "cn=NONE"
    state: "{{ item.state | default('present') }}"
  with_items: "{{ ldap_server_groups }}"

- name: Create user-supplied LDAP entries
  community.general.ldap_entry:
    dn: "{{ item.dn }}"
    objectClass: "{{ item.attributes.objectClass }}"
    attributes: "{{ item.attributes }}"
    state: "{{ item.state | default('present') }}"
  with_items: "{{ ldap_entries }}"

- name: Deploy firewall configuration for LDAP
  ansible.builtin.copy:
    src: "ferm_ldap.conf"
    dest: "/etc/ferm/conf.d/10-ldap.conf"
    owner: root
    group: root
    mode: "0640"
  notify:
    - Restart ferm

# @TODO: This whole thing could be dropped if newer version of Ansible
#        was in use (where community collection has the ldap_search
#        module.
- name: Deploy temporary file with LDAP admin password
  ansible.builtin.template:
    src: "ldap_admin_password.j2"
    dest: "/root/.ldap_admin_password"
    owner: root
    group: root
    mode: "0400"
  changed_when: false

- name: Test if LDAP admin password needs to be changed
  ansible.builtin.command: "ldapwhoami -H ldapi:/// -D 'cn=admin,{{ ldap_server_int_basedn }}' -x -y /root/.ldap_admin_password"
  register: ldap_admin_password_check
  changed_when: ldap_admin_password_check.rc != 0
  failed_when: false

- name: Update LDAP admin password
  community.general.ldap_attrs:
    dn: "olcDatabase={1}mdb,cn=config"
    attributes:
      olcRootPW: "{{ ldap_admin_password | ldap_password_hash }}"
    state: exact
  when: ldap_admin_password_check.rc != 0

- name: Remove temporary file with LDAP admin password
  ansible.builtin.file:
    path: "/root/.ldap_admin_password"
    state: absent
  changed_when: false

- name: Enable backup
  ansible.builtin.include_tasks: backup.yml
  when: enable_backup

- name: Explicitly run all handlers
  ansible.builtin.include_tasks: ../handlers/main.yml
  when: "run_handlers | default(False) | bool()"
  tags:
    - handlers