Changeset - 2f8747288649
[Not reviewed]
0 4 0
Branko Majic (branko) - 5 years ago 2021-01-13 22:52:40
branko@majic.rs
MAR-151: Added support for Debian 10 Buster to ldap_server role:

- Updated role reference documentaiton.
- Updated role meta information.
- Updated tests.
4 files changed with 34 insertions and 2 deletions:
0 comments (0 inline, 0 general)
docs/rolereference.rst
Show inline comments
 
@@ -589,384 +589,385 @@ The role implements the following:
 
* Configures TLS versions and ciphers suppported by the server.
 
* Installs OpenLDAP server (package ``slapd``).
 
* Configures OpenLDAP server (base DN - domain, organisation, TLS, SSF, log levels).
 
* Sets-up separate log file for OpenLDAP server at ``/var/log/slapd.log`` (with
 
  log rotation included).
 
* Enables the ``misc`` LDAP schema (from ``/etc/ldap/schema/misc.ldif``). This
 
  is necessary for the mail server role.
 
* Enables the ``memberof`` overlay on top of default database. The overlay is
 
  configured to keep track of membership changes for object class
 
  ``groupOfUniqueNames`` via attribute ``uniqueMember``. Enforcement of
 
  referential integrity is turned on as well (modifications of ``memberof``
 
  attribute will update corresponding group as well.
 
* Creates a basic directory structure used by most of the other roles.
 
* Creates a basic directory structure used by the mail server role.
 
* Creates login entries for services that need to consume LDAP directory data in
 
  some way.
 
* Creates user-supplied groups in LDAP.
 
* Configures permissions.
 
* Creates LDAP entries.
 
* Configures firewall to allow incoming connections to the LDAP server (via both
 
  TCP 389 and 636).
 
* Sets the LDAP server administrator's password.
 

	
 

	
 
LDIF Templates
 
~~~~~~~~~~~~~~
 

	
 
For adding users, use::
 

	
 
  dn: uid=USERNAME,ou=people,BASE_DN
 
  objectClass: inetOrgPerson
 
  objectClass: simpleSecurityObject
 
  uid: USERNAME
 
  userPassword: PASSWORD_FROM_SLAPPASSWD
 
  cn: NAME SURNAME
 
  sn: SURNAME
 
  gn: NAME
 
  displayName: DISPLAYNAME
 
  initials: INITIALS
 
  mail: MAIL
 
  mobile: MOBILE
 

	
 

	
 

	
 
Role dependencies
 
~~~~~~~~~~~~~~~~~
 

	
 
Depends on the following roles:
 

	
 
* **common**
 
* **ldap_client**
 
* **backup_client**
 

	
 

	
 
Backups
 
~~~~~~~
 

	
 
If the backup for this role has been enabled, the following paths are backed-up:
 

	
 
**/srv/backup/slapd.bak**
 
  Dump of the LDAP database. LDAP database dump is created every day at 01:45 in
 
  the morning. This does *not* include the dump of the config database
 
  (``cn=config``).
 

	
 

	
 
Parameters
 
~~~~~~~~~~
 

	
 
**ldap_admin_password** (string, mandatory)
 
  Password for the default administrator account of LDAP server (the
 
  ``cn=admin,DOMAIN`` entry/user).
 

	
 
**ldap_entries** (list, optional, ``[]``)
 
  List of entries that should be kept in the LDAP directory. Each item is a
 
  dictionary describing a single LDAP entry with the following keys:
 

	
 
  **dn** (string, mandatory)
 
    LDAP DN entry.
 

	
 
  **state** (string, optional, ``present``)
 
    Whether the entry should be present or not. Value can be anything
 
    supported by the ``ldap_entry`` module. Keep in mind that state
 
    ``present`` will not update the attributes and their values if the
 
    entry is already present.
 

	
 
  **attributes** (dictionary, mandatory)
 
    Dictionary describing remaining attributes (except ``dn``). The keys in this
 
    dictionary should be the attribute names. The values should be either
 
    strings, for setting a single attribute value, or a list of strings if it is
 
    necessary to set multiple values for the same attribute.
 

	
 
**ldap_permissions** (list, optional, ``see below``)
 
  List of LDAP access rules to apply to base DN served by the LDAP server. The
 
  listed access control rules will *replace* all existing rules, and will be
 
  added in the same order they are listed in. Each item is a string that
 
  constitutes a single access control rule. The format should be the same as
 
  described in `OpenLDAP Administrator's Guide
 
  <http://www.openldap.org/doc/admin24/access-control.html#Access%20Control%20via%20Dynamic%20Configuration>`.
 

	
 
  Default value is:
 

	
 
  .. code-block:: yaml
 

	
 
    - >
 
      to *
 
      by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
 
      by * break
 
    - >
 
      to attrs=userPassword,shadowLastChange
 
      by self write
 
      by anonymous auth
 
      by dn="cn=admin,BASEDN" write
 
      by * none
 
    - >
 
      to dn.base=""
 
      by * read
 
    - >
 
      to *
 
      by self write
 
      by dn="cn=admin,BASEDN" write
 
      by * none
 

	
 
**ldap_server_consumers** (list, optional, ``[]``)
 
  List of items describing additional login entries that should be created for
 
  services that want to be able to log-in into the LDAP server and consume the
 
  data present within. Each item should be a dictionary, with the following keys
 
  avaialable:
 

	
 
  - **name** (name of the service, mandatory, this will be used to construct the
 
    login entry DN in format of ``cn=NAME,ou=services,BASE_DN``)
 
  - **password** (password for the login entry, mandatory)
 
  - **state** (state of the service, optional, defaults to ``present``, this
 
    should be ``present`` or ``absent``, allowing for removal of old services)
 

	
 
**ldap_server_groups** (list, optional, ``[]``)
 
  List of groups that should be created in the LDAP directory. Each item should
 
  be a dictionary containing the following keys:
 

	
 
  - **name** (name of the group, mandatory, this will be used to construct the
 
    group DN in format of ``cn=NAME,ou=groups,BASE_DN``)
 
  - **state** (state of the group, optional, defaults to ``present``, this
 
    should be ``present`` or ``absent``, allowing for removal of old groups)
 

	
 
**ldap_server_domain** (string, mandatory)
 
  Domain that should be used for constructing the base DN of default user LDAP
 
  database. This should be a sub-domain dedicated to organisation. The base DN
 
  will be constructed by putting all elements of the sub-domain as ``dc``
 
  entries (as per standard Debian convention). E.g. ``example.com`` would get
 
  transformed into ``dc=example,dc=com``.
 

	
 
**ldap_server_organization** (string, optional, ``Private``)
 
  Organization that should be specified in the base DN entry.
 

	
 
**ldap_server_log_level** (string, optional, ``256``)
 
  Log level to use for the server. This should be compatible with OpenLDAP
 
  configuration option ``olcLogLevel``. See `OpenLDAP Administrator's Guide
 
  <http://www.openldap.org/doc/admin24/slapdconf2.html#cn=config>` for value
 
  description and syntax.
 

	
 
**ldap_server_tls_certificate** (string, mandatory)
 
  X.509 certificate used for TLS for LDAP service. The file will be stored in
 
  directory ``/etc/ssl/certs/`` under name ``{{ ansible_fqdn }}_ldap.pem``.
 

	
 
**ldap_server_tls_key** (string, mandatory)
 
  Private key used for TLS for LDAP service. The file will be stored in
 
  directory ``/etc/ssl/private/`` under name ``{{ ansible_fqdn }}_ldap.key``.
 

	
 
**ldap_server_ssf** (number, optional, ``128``)
 
  Minimum *Security Strength Factor* to require from all incoming
 
  connections. This applies for both remote and local connections.
 

	
 
**ldap_tls_ciphers** (string, optional ``NONE:+VERS-TLS1.2:+CTYPE-X509:+COMP-NULL:+SIGN-RSA-SHA256:+SIGN-RSA-SHA384:+SIGN-RSA-SHA512:+DHE-RSA:+ECDHE-RSA:+SHA256:+SHA384:+SHA512:+AEAD:+AES-128-GCM:+AES-256-GCM:+CHACHA20-POLY1305:+CURVE-ALL``)
 

	
 
  .. warning::
 
     Under Debian Stretch, the DHE ciphers are not usable due to a bug
 
     present in OpenLDAP 2.4.44. See
 
     https://bugs.launchpad.net/ubuntu/+source/openldap/+bug/1656979
 
     for details.
 

	
 
  TLS ciphers to enable on the LDAP server. This should be a GnuTLS-compatible
 
  cipher specification that should also include what TLS protocol versions
 
  should be used. Value should be compatible with OpenLDAP server option
 
  ``olcTLSCipherSuite``. Default value allows only TLSv1.2 and strong PFS
 
  ciphers.
 

	
 

	
 
Distribution compatibility
 
~~~~~~~~~~~~~~~~~~~~~~~~~~
 

	
 
Role is compatible with the following distributions:
 

	
 
- Debian 9 (Stretch)
 
- Debian 10 (Buster)
 

	
 

	
 
Examples
 
~~~~~~~~
 

	
 
Here is an example configuration for setting-up LDAP server:
 

	
 
.. code-block:: yaml
 

	
 
  ---
 

	
 
  ldap_server_domain: "example.com"
 
  ldap_server_organization: "Example Corporation"
 
  ldap_server_log_level: 256
 
  ldap_server_tls_certificate: "{{ lookup('file', '~/tls/ldap.example.com_ldap.pem') }}"
 
  ldap_server_tls_key: "{{ lookup('file', '~/tls/ldap.example.com_ldap.key') }}"
 
  ldap_server_ssf: 128
 

	
 
  ldap_permissions:
 
    - >
 
      to *
 
      by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage
 
      by * break
 
    - >
 
      to attrs=userPassword,shadowLastChange
 
      by self write
 
      by anonymous auth
 
      by dn="cn=admin,dc=example,dc=com" write
 
      by * none
 
    - >
 
      to dn.base=""
 
      by * read
 
    - >
 
      to *
 
      by self write
 
      by dn="cn=admin,dc=example,dc=com" write
 
      by users read
 
      by * none
 

	
 
  ldap_entries:
 
    - dn: ou=people,dc=example,dc=com
 
      attributes:
 
        objectClass: organizationalUnit
 
        ou: people
 
    - dn: ou=groups,dc=example,dc=com
 
      attributes:
 
        objectClass: organizationalUnit
 
        ou: groups
 
    - dn: uid=john,dc=example,dc=com
 
      attributes:
 
        objectClass:
 
          - inetOrgPerson
 
          - simpleSecurityObject
 
        userPassword: somepassword
 
        uid: john
 
        cn: John Doe
 
        sn: Doe
 

	
 

	
 
XMPP Server
 
-----------
 

	
 
The ``xmpp_server`` role can be used for setting-up Prosody, an XMPP server, on
 
destination machine.
 

	
 
The role implements the following:
 

	
 
* Sets-up the Prosody apt repository.
 
* Sets-up the Debian backports repository and pins the ``lua-ldap``
 
  package to it (needed for Lua 5.2 support with Prosody 0.11).
 
* Deploys XMPP TLS private key and certificate.
 

	
 
  .. warning::
 
     The issued certificate must have multiple FQDNs listed as subject
 
     alternative names (DNS names) for each configured domain:
 

	
 
     - domain itself
 
     - ``conference.DOMAIN``
 
     - ``proxy.DOMAIN``
 

	
 
     A daily cron job is run to validate that all certificates have
 
     been configured and issued correctly.
 

	
 
* Installs Prosody.
 
* Configures Prosody.
 
* Configures firewall to allow incoming connections to the XMPP server.
 

	
 
Prosody is configured as follows:
 

	
 
* Modules enabled: roster, saslauth, tls, dialback, posix, private, vcard,
 
  version, uptime, time, ping, pep, register, admin_adhoc, announce,
 
  legacyauth, carbons, mam.
 
* Self-registration is not allowed.
 
* TLS is configured. Legacy TLS is available on port 5223.
 
* Client-to-server communication requires encryption (TLS).
 
* Uses 2048-bit Diffie-Hellman parameters for relevant TLS ciphers for
 
  incoming connections.
 
* Configures TLS versions and ciphers supported by Prosody (for
 
  *c2s*/client connections only).
 
* Authentication is done via LDAP. For setting the LDAP TLS truststore, see
 
  :ref:`LDAP Client <ldap_client>`.
 
* Internal storage is used.
 
* For each domain specified, a dedicated conference/multi-user chat (MUC)
 
  service is set-up, with FQDN set to ``conference.DOMAIN``.
 
* For each domain specified, a dedicated file proxy service will be set-up, with
 
  FQDN set to ``proxy.DOMAIN``.
 

	
 
Prosody expects a specific directory structure in LDAP when doing look-ups:
 

	
 
* Prosody will log-in to LDAP as user
 
  ``cn=prosody,ou=services,XMPP_LDAP_BASE_DN``.
 
* User entries are read from sub-tree (first-level only)
 
  ``ou=people,XMPP_LDAP_BASE_DN``. Query filter used for finding users is
 
  ``(&(mail=$user@$host)(memberOf=cn=xmpp,ou=groups,XMPP_LDAP_BASE_DN))``. This
 
  allows group-based granting of XMPP service to users.
 

	
 

	
 
LDIF Templates
 
~~~~~~~~~~~~~~
 

	
 
For adding user to a group, use::
 

	
 
  dn: cn=xmpp,ou=groups,BASE_DN
 
  changetype: modify
 
  add: uniqueMember
 
  uniqueMember: uid=USERNAME,ou=people,BASE_DN
 

	
 

	
 
Role dependencies
 
~~~~~~~~~~~~~~~~~
 

	
 
Depends on the following roles:
 

	
 
* **common**
 
* **backup_client**
 

	
 

	
 
Backups
 
~~~~~~~
 

	
 
If the backup for this role has been enabled, the following paths are backed-up:
 

	
 
**/var/lib/prosody/**
 
  Roster information, as well as undelivered (offline) messages for all XMPP
 
  users. Keep in mind that list of available users and their credentials are
 
  stored in the LDAP directory (which is backed-up via LDAP server role).
 

	
 

	
 
Parameters
 
~~~~~~~~~~
 

	
 
**xmpp_administrators** (list, mandatory)
 
  List of Prosody users that should be granted administrator privileges over
 
  Prosody. Each item is a string with value equal to XMPP user ID
 
  (i.e. ``john.doe@example.com``).
 

	
 
**xmpp_domains** (list, mandatory)
 
  List of domains that are served by this Prosody instance. Each item is a
 
  string specifying a domain.
 

	
 
**xmpp_ldap_base_dn** (string, mandatory)
 
  Base DN on the LDAP server. A specific directory structure is expected under
 
  this entry (as explained above) in order to locate the available domains,
 
  users, aliases etc.
 

	
 
**xmpp_ldap_password** (string, mandatory)
 
  Password used for authenticating to the LDAP server.
 

	
 
**xmpp_ldap_server** (string, mandatory)
 
  Fully qualified domain name, hostname, or IP address of the LDAP server used
 
  for user authentication and listing.
 

	
 
**xmpp_prosody_package** (string, optional, ``prosody-0.11``)
 
  Name of Prosody package from the Prosody repositories to
 
  install. This makes it possible to easily test the latest Prosody or
 
  to switch to a different nightly build. It should be noted that
 
  only the default version is getting properly tested. Prosody
 
  versions lower than ``0.10.x`` are not supported.
 

	
 
**xmpp_server_archive_expiration** (string, optional, ``never``)
 
  Expiration period for messages stored server-side using `XEP-0313:
 
  Message Archive Management
 
  <https://xmpp.org/extensions/xep-0313.html>`_. The value should be
 
  compatible with `Prosody mod_mam
 
  <https://prosody.im/doc/modules/mod_mam>`_ configuration option
 
  ``archive_expires_after``.
 

	
 
**xmpp_server_tls_ciphers** (string, optional ``DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:!aNULL:!MD5:!EXPORT``)
 
  TLS ciphers to enable on the XMPP server. This should be an
 
  OpenSSL-compatible cipher specification. Value should be compatible
 
  with Prosody's option ``ciphers`` normally defined within the
 
  ``ssl`` section of configuration file (see `official documentation
roles/ldap_server/meta/main.yml
Show inline comments
 
---
 

	
 
dependencies:
 
  - common
 
  - ldap_client
 
  - role: backup
 
    when: enable_backup
 
    backup_patterns_filename: "ldap_server"
 
    backup_patterns:
 
      - "/srv/backup/slapd.bak"
 

	
 
galaxy_info:
 
  author: Branko Majic
 
  description: Sets-up an OpenLDAP server
 
  license: BSD
 
  min_ansible_version: 2.9
 
  platforms:
 
    - name: Debian
 
      versions:
 
        - 8
 
        - 9
 
        - 10
roles/ldap_server/molecule/default/molecule.yml
Show inline comments
 
---
 

	
 
dependency: {}
 

	
 
driver:
 
  name: vagrant
 
  provider:
 
    name: virtualbox
 

	
 
lint:
 
  name: yamllint
 
  options:
 
    config-file: ../../.yamllint.yml
 

	
 
platforms:
 

	
 
  - name: client
 
    box: debian/contrib-stretch64
 
    box: debian/contrib-buster64
 
    memory: 512
 
    cpus: 1
 
    interfaces:
 
      - auto_config: true
 
        ip: 10.31.127.10
 
        network_name: private_network
 
        type: static
 

	
 
  - name: parameters-mandatory-stretch64
 
    groups:
 
      - parameters-mandatory
 
    box: debian/contrib-stretch64
 
    memory: 256
 
    cpus: 1
 
    interfaces:
 
      - auto_config: true
 
        ip: 10.31.127.22
 
        network_name: private_network
 
        type: static
 

	
 
  - name: parameters-optional-stretch64
 
    groups:
 
      - parameters-optional
 
      - backup-server
 
    box: debian/contrib-stretch64
 
    memory: 256
 
    cpus: 1
 
    interfaces:
 
      - auto_config: true
 
        ip: 10.31.127.23
 
        network_name: private_network
 
        type: static
 

	
 
  - name: parameters-mandatory-buster64
 
    groups:
 
      - parameters-mandatory
 
    box: debian/contrib-buster64
 
    memory: 256
 
    cpus: 1
 
    interfaces:
 
      - auto_config: true
 
        ip: 10.31.127.12
 
        network_name: private_network
 
        type: static
 

	
 
  - name: parameters-optional-buster64
 
    groups:
 
      - parameters-optional
 
      - backup-server
 
    box: debian/contrib-buster64
 
    memory: 256
 
    cpus: 1
 
    interfaces:
 
      - auto_config: true
 
        ip: 10.31.127.13
 
        network_name: private_network
 
        type: static
 

	
 
provisioner:
 
  name: ansible
 
  playbooks:
 
    cleanup: cleanup.yml
 
  config_options:
 
    defaults:
 
      force_valid_group_names: "ignore"
 
      interpreter_python: "/usr/bin/python3"
 
    ssh_connection:
 
      pipelining: "True"
 
  lint:
 
    name: ansible-lint
 

	
 
scenario:
 
  name: default
 

	
 
verifier:
 
  name: testinfra
 
  lint:
 
    name: flake8
roles/ldap_server/molecule/default/prepare.yml
Show inline comments
 
---
 

	
 
- name: Set-up fixtures
 
  hosts: localhost
 
  connection: local
 
  gather_facts: false
 
  tasks:
 

	
 
    - name: Initialise CA hierarchy
 
      command: "gimmecert init"
 
      args:
 
        creates: ".gimmecert/ca/level1.cert.pem"
 
        chdir: "tests/data/"
 

	
 
    - name: Generate server private keys and certificates
 
      command:
 
      args:
 
        chdir: "tests/data/"
 
        creates: ".gimmecert/server/{{ item.name }}.cert.pem"
 
        argv:
 
          - "gimmecert"
 
          - "server"
 
          - "{{ item.name }}"
 
          - "{{ item.fqdn }}"
 
      with_items:
 
        - name: parameters-mandatory-stretch64_ldap
 
          fqdn: parameters-mandatory
 
        - name: parameters-optional-stretch64_ldap
 
          fqdn: parameters-optional
 
        - name: parameters-mandatory-buster64_ldap
 
          fqdn: parameters-mandatory
 
        - name: parameters-optional-buster64_ldap
 
          fqdn: parameters-optional
 

	
 
    - name: Set-up link to generated X.509 material
 
      file:
 
        src: ".gimmecert"
 
        dest: "tests/data/x509"
 
        state: link
 

	
 
- name: Prepare
 
  hosts: all
 
  gather_facts: false
 
  tasks:
 
    - name: Install python for Ansible
 
      raw: test -e /usr/bin/python3 || (apt -y update && apt install -y python3-minimal)
 
      become: true
 
      changed_when: false
 

	
 
- hosts: all
 
  become: true
 
  tasks:
 

	
 
    - name: Update all caches to avoid errors due to missing remote archives
 
      apt:
 
        update_cache: true
 
      changed_when: false
 

	
 
    - name: Deploy CA certificate
 
      copy:
 
        src: tests/data/x509/ca/level1.cert.pem
 
        dest: /etc/ssl/certs/testca.cert.pem
 
        owner: root
 
        group: root
 
        mode: 0644
 

	
 
- hosts: client
 
  become: true
 
  tasks:
 

	
 
    - name: Install tool for teting TCP connectivity
 
      apt:
 
        name: hping3
 
        state: present
 

	
 
    - name: Set-up /etc/hosts with entries for all servers
 
      lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: 0644
 
        state: present
 
      with_dict:
 
        10.31.127.22: parameters-mandatory-stretch64
 
        10.31.127.23: parameters-optional-stretch64
 
        10.31.127.12: parameters-mandatory-buster64
 
        10.31.127.13: parameters-optional-buster64
 

	
 
- hosts: parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Set-up the hosts file
 
      lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: 0644
 
        state: present
 
      with_dict:
 
        127.0.2.1: parameters-optional
 

	
 
- hosts: parameters-mandatory
 
  become: true
 
  tasks:
 

	
 
    - name: Set-up the hosts file
 
      lineinfile:
 
        path: /etc/hosts
 
        regexp: "^{{ item.key }}"
 
        line: "{{ item.key }} {{ item.value }}"
 
        owner: root
 
        group: root
 
        mode: 0644
 
        state: present
 
      with_dict:
 
        127.0.2.1: parameters-mandatory
 

	
 
- hosts: backup-server
 
  become: true
 
  roles:
 
    - role: backup_server
 
      backup_host_ssh_private_keys:
 
        rsa: "{{ lookup('file', 'tests/data/ssh/server_rsa') }}"
 
        ed25519: "{{ lookup('file', 'tests/data/ssh/server_ed25519') }}"
 
        ecdsa: "{{ lookup('file', 'tests/data/ssh/server_ecdsa') }}"
 
      backup_clients:
 
        - server: localhost
 
          ip: 127.0.0.1
 
          public_key: "{{ lookup('file', 'tests/data/ssh/parameters-optional.pub') }}"
 

	
 
- hosts: parameters-mandatory,parameters-optional
 
  become: true
 
  tasks:
 

	
 
    - name: Remove the ss utility (see https://github.com/philpep/testinfra/pull/320)
 
      file:
 
        path: "/bin/ss"
 
        state: absent
 

	
 
    - name: Install netstat utility
 
      apt:
 
        name: net-tools
 
        state: present
 

	
 
    - name: Install nmap utility for testing TLS
 
      apt:
 
        name: nmap
 
        state: present
0 comments (0 inline, 0 general)