Changeset - b8bfc506359f
[Not reviewed]
1 1 0
Branko Majic (branko) - 7 days ago 2024-09-21 13:29:58
branko@majic.rs
MAR-218: Rework/improve code for setting LDAP server admin password:

- Avoid dropping temporary file with password by invoking a search on
the LDAP server using the supplied credentials.
- Do not log sensitive informationi when setting the LDAP server admin
password.
2 files changed with 9 insertions and 23 deletions:
0 comments (0 inline, 0 general)
roles/ldap_server/tasks/main.yml
Show inline comments
 
---
 

	
 
- 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"
 
- name: Test LDAP admin password
 
  community.general.ldap_search:
 
    bind_dn: "cn=admin,{{ ldap_server_int_basedn }}"
 
    bind_pw: "{{ ldap_admin_password }}"
 
    server_uri: "ldapi:///"
 
    dn: "{{ ldap_server_int_basedn }}"
 
    scope: base
 
  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
 
  no_log: true
 
  when: "'results' not in ldap_admin_password_check"
 

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

	
 
- name: Explicitly run all handlers
 
  ansible.builtin.import_tasks: ../handlers/main.yml
 
  when: "run_handlers | default(False) | bool()"
 
  tags:
 
    - handlers
roles/ldap_server/templates/ldap_admin_password.j2
Show inline comments
 
deleted file
0 comments (0 inline, 0 general)