Commit f8e88c23 authored by Maciej Delmanowski's avatar Maciej Delmanowski

Merge branch 'drybjed-ldap-improvements'

parents dae15f82 bdb19791
Pipeline #55178921 failed with stages
in 26 minutes and 48 seconds
......@@ -922,6 +922,14 @@ stages:
JANE_DIFF_PATTERN: '.*/debops.nodejs/.*'
JANE_LOG_PATTERN: '\[debops\.nodejs\]'
'nslcd role':
<<: *test_role_2nd_deps
variables:
JANE_TEST_PLAY: '${DEBOPS_PLAYBOOKS}/service/nslcd.yml'
JANE_INVENTORY_GROUPS: 'debops_service_nslcd'
JANE_DIFF_PATTERN: '.*/debops.nslcd/.*'
JANE_LOG_PATTERN: '\[debops\.nslcd\]'
'nsswitch role':
<<: *test_role_no_deps
variables:
......
......@@ -32,6 +32,9 @@ Added
roles, playbooks, and users via Ansible inventory. The role is included in
the ``common.yml`` playbook, but is disabled by default.
- :ref:`debops.nslcd` role can be used to configure LDAP lookups for NSS and
PAM services on a Linux host.
- [debops.nginx] The role will automatically generate configuration which
redirects short hostnames or subdomains to their FQDN equivalents. This
allows HTTP clients to reach websites by specifying their short names via DNS
......@@ -149,6 +152,30 @@ Changed
Agent. This configuration should work better in clustered environments, where
there is a central mail hub/MX that receives the mail and redirects it.
- [debops.root_account] If the :ref:`debops.ldap` Ansible role has been applied
on a host, the :ref:`debops.root_account` role will use the UID/GID ranges
defined by it, which include UIDs/GIDs used in the LDAP directory, to define
subUID/subGID range of the ``root`` account. This allows usage of the LDAP
directory as a source of UNIX accounts and groups in unprivileged containers.
Existing systems will not be changed.
- [debops.system_groups] If the LDAP support is enabled on a host via the
:ref:`debops.ldap` role, the UNIX system groups created by the
:ref:`debops.system_groups` role by default will use a ``_`` prefix to make
them separate from any LDAP-based groups of the same name. Existing
installations should be unaffected, as long as the updated
:ref:`debops.system_groups` role was applied before the :ref:`debops.ldap`
role.
Removed
~~~~~~~
- [debops.auth] The :file:`/etc/ldap/ldap.conf` file configuration,
:command:`nslcd` service configuration and related variables have been
removed from the :ref:`debops.auth` role. This functionality is now available
in the :ref:`debops.ldap` and :ref:`debops.nslcd` roles, which manage the
client-side LDAP support.
Fixed
~~~~~
......
---
- name: Manage nslcd service
hosts: [ 'debops_service_nslcd' ]
become: True
environment: '{{ inventory__environment | d({})
| combine(inventory__group_environment | d({}))
| combine(inventory__host_environment | d({})) }}'
roles:
- role: debops.python
tags: [ 'role::python', 'skip::python', 'role::ldap' ]
python__dependent_packages3:
- '{{ ldap__python__dependent_packages3 }}'
python__dependent_packages2:
- '{{ ldap__python__dependent_packages2 }}'
- role: debops.ldap
tags: [ 'role::ldap', 'skip::ldap' ]
ldap__dependent_tasks:
- '{{ nslcd__ldap__dependent_tasks }}'
- role: debops.nslcd
tags: [ 'role::nslcd', 'skip::nslcd' ]
- role: debops.nsswitch
tags: [ 'role::nsswitch', 'skip::nsswitch' ]
nsswitch__dependent_services:
- '{{ nslcd__nsswitch__dependent_services }}'
......@@ -24,6 +24,8 @@
- import_playbook: slapd.yml
- import_playbook: nslcd.yml
- import_playbook: iscsi.yml
- import_playbook: cryptsetup.yml
......
../service/nslcd.yml
\ No newline at end of file
......@@ -15,18 +15,6 @@
# List of Debian/Ubuntu packages installed by debops.auth
auth_packages: [ 'libpam-cracklib' ]
# ]]]
# ---- nsswitch.conf options ----
# .. envvar:: auth_nsswitch [[[
#
# List of lookup databases that will be enabled in /etc/nsswitch.conf.
# Possible parameters: compat, files, ldap, sss, mdns
# Use of this variable for NSS management is depracted (see :ref:`debops.nsswitch`
# instead). It's still present here due to usage in other parts of
# the role.
auth_nsswitch: [ 'compat' ]
# ]]]
# ---- Local user account configuration ----
......@@ -40,199 +28,6 @@ auth_pwhistory_remember: '5'
#
# Enable password checking via cracklib
auth_cracklib: True
# ]]]
# ---- /etc/ldap/ldap.conf options ----
# .. envvar:: auth_ldap_conf [[[
#
# Enable or disable /etc/ldap/ldap.conf configuration
auth_ldap_conf: True
# ]]]
# .. envvar:: auth_ldap_conf_domain [[[
#
# Default DNS domain to use to generate base DN. Set to False to disable and
# configure custom BaseDN in 'auth_ldap_conf_hostdn'
auth_ldap_conf_domain: '{{ ansible_domain }}'
# ]]]
# .. envvar:: auth_ldap_conf_hostdn [[[
#
# Custom prefix for base DN, each domain component should be an element of
# a list. If 'auth_ldap_conf_domain' is empty or False, you can configure here
# full base DN for your LDAP server
auth_ldap_conf_hostdn: []
# ]]]
# .. envvar:: auth_ldap_conf_uri [[[
#
# List od LDAP servers accessed by this host. See ldap.conf(5) for details
auth_ldap_conf_uri: [ 'ldaps://ldap.{{ ansible_domain }}/' ]
# ]]]
# .. envvar:: auth_ldap_conf_tls_cacert [[[
#
# CA certificate bundle used to authorize server certificates
auth_ldap_conf_tls_cacert: '/etc/ssl/certs/ca-certificates.crt'
# ]]]
# .. envvar:: auth_ldap_conf_tls_reqcert [[[
#
# Level of certificate checking performed by ldap-utils (never, allow, try, demand)
auth_ldap_conf_tls_reqcert: 'demand'
# ]]]
# .. envvar:: auth_ldap_conf_options [[[
#
# Other LDAP options in text block format
auth_ldap_conf_options: |
SISZELIMIT 12
TIMELIMIT 15
DEREF never
# ]]]
# ---- Local LDAP Name Service Daemon ----
# .. envvar:: auth_nslcd_conf [[[
#
# Enable or disable configuration
auth_nslcd_conf: True
# ]]]
# .. envvar:: auth_nslcd_domain [[[
#
# Base domain to use for nslcd configuration
auth_nslcd_domain: '{{ ansible_domain }}'
# ]]]
# .. envvar:: auth_nslcd_ldap_server [[[
#
# FQDN address of a LDAP server to configure in /etc/nslcd.conf
auth_nslcd_ldap_server: 'ldap.{{ auth_nslcd_domain }}'
# ]]]
# .. envvar:: auth_nslcd_uri [[[
#
# List of LDAP servers to connect to
auth_nslcd_uri: [ 'ldap://{{ auth_nslcd_ldap_server }}/' ]
# ]]]
# .. envvar:: auth_nslcd_base [[[
#
# List of LDAP search bases to use
auth_nslcd_base: [ '{{ "dc=" + auth_nslcd_domain.split(".") | join(",dc=") }}' ]
# ]]]
# .. envvar:: auth_nslcd_tls_reqcert [[[
#
# Level of certificate checking performed by nslcd (never, allow, try, demand)
auth_nslcd_tls_reqcert: 'demand'
# ]]]
# .. envvar:: auth_nslcd_tls_cacertfile [[[
#
# CA certficiate file to use to check server certificates
auth_nslcd_tls_cacertfile: '/etc/ssl/certs/ca-certificates.crt'
# ]]]
# ---- LDAP host account ----
# A separate LDAP host account is required for by each host to have access to
# the LDAP database, because anonymous connections are denied.
# .. envvar:: auth_nslcd_bind_host_basedn [[[
#
# Base DN to use for host account
auth_nslcd_bind_host_basedn: '{{ "ou=Machines," + auth_nslcd_base[0] }}'
# ]]]
# .. envvar:: auth_nslcd_bind_host_cn [[[
#
# Host account name
auth_nslcd_bind_host_cn: 'cn={{ ansible_hostname }}'
# ]]]
# .. envvar:: auth_nslcd_bind_host_dn [[[
#
# Host account in LDAP database
auth_nslcd_bind_host_dn: '{{ auth_nslcd_bind_host_cn + "," + auth_nslcd_bind_host_basedn }}'
# ]]]
# .. envvar:: auth_nslcd_bind_host_basepw [[[
#
# Base path to host password in 'secret/' directory.
# See 'debops.secret' Ansible role for more detauls.
auth_nslcd_bind_host_basepw: '{{ secret + "/credentials/" + ansible_fqdn + "/ldap/host/binddn/" + auth_nslcd_bind_host_dn }}'
# ]]]
# .. envvar:: auth_nslcd_bind_host_password [[[
#
# Path to file with plaintext host password saved in secrets
auth_nslcd_bind_host_password: '{{ auth_nslcd_bind_host_basepw + ".password" }}'
# ]]]
# .. envvar:: auth_nslcd_bind_host_hash [[[
#
# Path to file with Hash of host password saved in secrets
auth_nslcd_bind_host_hash: '{{ auth_nslcd_bind_host_basepw + ".hash" }}'
# ]]]
# .. envvar:: auth_nslcd_password_length [[[
#
# Length of generated host password
auth_nslcd_password_length: '48'
# ]]]
# .. envvar:: auth_nslcd_options [[[
#
# Additional options added to /etc/nslcd.conf, in a text block
auth_nslcd_options: False
# ]]]
# ---- NSS LDAP authentication and filters ----
# .. envvar:: auth_nslcd_nss_min_uid [[[
#
# Minimal uidNumber which is considered for an LDAP query
auth_nslcd_nss_min_uid: '1000'
# ]]]
# .. envvar:: auth_pam_mkhomedir_umask [[[
#
# Default umask for new home directories created by pam_mkhomedir module
auth_pam_mkhomedir_umask: '{{ ansible_local.core.homedir_umask
if (ansible_local|d() and
ansible_local.core|d() and
ansible_local.core.homedir_umask|d())
else "0027" }}'
# ]]]
# .. envvar:: auth_nslcd_pam_authz_search [[[
#
# LDAP search filters which are used to limit access to the host or services.
# At least one search needs to return a valid entry, otherwise access is
# denied.
# Apparently this option can be specified multiple times in nslcd.conf but that
# didn't work. You still need to specify a list.
auth_nslcd_pam_authz_search: [ '{{ auth_nslcd_pam_authz_search_host_and_service }}' ]
# ]]]
# .. envvar:: auth_nslcd_pam_authz_search_host [[[
#
# User account needs to have host= attribute
auth_nslcd_pam_authz_search_host: '(&(objectClass=posixAccount)(uid=$username)(|(host=$hostname)(host=$fqdn)(host=\\*.{{ ansible_domain }})(host=\\*)))'
# ]]]
# .. envvar:: auth_nslcd_pam_authz_search_service [[[
#
# User account needs to to have authorizedService= attribute
auth_nslcd_pam_authz_search_service: '(&(objectClass=posixAccount)(uid=$username)(authorizedService=$service))'
# ]]]
# .. envvar:: auth_nslcd_pam_authz_search_host_and_service [[[
#
# User account needs to have both host= and authorizedService= attributes
auth_nslcd_pam_authz_search_host_and_service: '(&(objectClass=posixAccount)(uid=$username)(authorizedService=$service)(|(host=$hostname)(host=$fqdn)(host=\\*.{{ ansible_domain }})(host=\\*)))'
# ]]]
# ]]]
......@@ -3,7 +3,3 @@
- name: Update PAM common configuration
shell: pam-auth-update --package libpam-modules 2>/dev/null
when: ansible_distribution_release not in ["bionic", "buster"]
- name: Enable mkhomedir PAM module
shell: pam-auth-update --enable mkhomedir 2>/dev/null
when: ansible_distribution_release in ["bionic", "buster"]
---
- name: Make sure libldap is installed
apt:
name: 'libldap-2.4-2'
state: 'present'
install_recommends: False
- name: Divert original LDAP configuration
command: dpkg-divert --quiet --local --divert /etc/ldap/ldap.conf.dpkg-divert --rename /etc/ldap/ldap.conf
creates=/etc/ldap/ldap.conf.dpkg-divert
- name: Configure system-wide LDAP access
template:
src: '{{ lookup("template_src", "etc/ldap/ldap.conf.j2") }}'
dest: '/etc/ldap/ldap.conf'
owner: 'root'
group: 'root'
mode: '0644'
---
- name: Check if host password hash exists
stat:
path: '{{ auth_nslcd_bind_host_hash }}'
register: auth_register_local_nslcd_bind_host_hash
become: False
delegate_to: 'localhost'
no_log: True
- name: Read hash of host password
set_fact:
auth_register_nslcd_bind_host_hash: '{{ lookup( "file", auth_nslcd_bind_host_hash) }}'
when: auth_register_local_nslcd_bind_host_hash.stat.exists
no_log: True
- name: Generate host password
shell: set -o nounset -o pipefail -o errexit &&
echo -n {{ lookup('password', auth_nslcd_bind_host_password + ' length='
+ auth_nslcd_password_length) }} \
| openssl dgst -sha1 -binary | openssl enc -base64 | awk '{print "{SHA}"$0}'
args:
executable: '/bin/bash'
register: auth_register_nslcd_bind_host_password
when: (auth_register_nslcd_bind_host_hash is undefined or
(auth_register_nslcd_bind_host_hash is defined and not auth_register_nslcd_bind_host_hash))
changed_when: False
no_log: True
- name: Save hash of host password
copy:
content: '{{ auth_register_nslcd_bind_host_password.stdout }}'
dest: '{{ auth_nslcd_bind_host_hash }}'
become: False
delegate_to: 'localhost'
when: (auth_register_nslcd_bind_host_hash is undefined or
(auth_register_nslcd_bind_host_hash is defined and not auth_register_nslcd_bind_host_hash))
no_log: True
- name: Make sure that host base DN exists
ldap_entry:
dn: '{{ auth_nslcd_bind_host_basedn }}'
objectClass: [ 'organizationalUnit', 'top' ]
state: 'present'
server_uri: '{{ secret_ldap_server_uri }}'
start_tls: '{{ secret_ldap_start_tls }}'
bind_dn: '{{ secret_ldap_admin_bind_dn }}'
bind_pw: '{{ secret_ldap_admin_bind_pw }}'
become: '{{ secret_ldap_sudo }}'
delegate_to: '{{ secret_ldap_delegate_to }}'
no_log: True
- name: Make sure that host account exists
ldap_entry:
dn: '{{ auth_nslcd_bind_host_dn }}'
objectClass: [ 'device', 'simpleSecurityObject' ]
attributes:
userPassword: '{{ auth_register_nslcd_bind_host_password.stdout
| default(auth_register_nslcd_bind_host_hash) }}'
state: 'present'
server_uri: '{{ secret_ldap_server_uri }}'
start_tls: '{{ secret_ldap_start_tls }}'
bind_dn: '{{ secret_ldap_admin_bind_dn }}'
bind_pw: '{{ secret_ldap_admin_bind_pw }}'
become: '{{ secret_ldap_sudo }}'
delegate_to: '{{ secret_ldap_delegate_to }}'
no_log: True
- name: Set host bind password in LDAP
ldap_attr:
dn: '{{ auth_nslcd_bind_host_dn }}'
name: '{{ item.key }}'
values: '{{ item.value }}'
state: 'exact'
server_uri: '{{ secret_ldap_server_uri }}'
start_tls: '{{ secret_ldap_start_tls }}'
bind_dn: '{{ secret_ldap_admin_bind_dn }}'
bind_pw: '{{ secret_ldap_admin_bind_pw }}'
become: '{{ secret_ldap_sudo }}'
delegate_to: '{{ secret_ldap_delegate_to }}'
with_dict:
userPassword: '{{ auth_register_nslcd_bind_host_password.stdout
| default(auth_register_nslcd_bind_host_hash | d()) }}'
no_log: True
......@@ -18,25 +18,12 @@
owner: 'root'
group: 'root'
mode: '0644'
notify: [ 'Update PAM common configuration', 'Enable mkhomedir PAM module' ]
notify: [ 'Update PAM common configuration' ]
when: auth_cracklib|bool
- name: Configure PAM password history module
include: pam_pwhistory.yml
when: auth_pwhistory_remember is defined and auth_pwhistory_remember
- name: Check if /etc/ldap exists
stat:
path: '/etc/ldap'
register: auth_register_etc_ldap
- include: etc_ldap_conf.yml
when: ((auth_ldap_conf|bool) and
((auth_register_etc_ldap.stat.exists) or
('ldap' in auth_nsswitch)))
- include: nss_pam_ldap.yml
when: (('ldap' in auth_nsswitch) and (auth_nslcd_conf|bool))
- name: DebOps post_tasks hook
include: "{{ lookup('task_src', 'auth/post_main.yml') }}"
---
- name: Configure pam-mkhomedir for LDAP authentication
template:
src: 'usr/share/pam-configs/mkhomedir.j2'
dest: '/usr/share/pam-configs/mkhomedir'
owner: 'root'
group: 'root'
mode: '0644'
notify: [ 'Update PAM common configuration' ]
- name: Install packages require for LDAP authentication
apt:
name:
- 'libnss-ldapd'
- 'libpam-ldapd'
- 'openssl'
- 'ca-certificates'
state: 'present'
install_recommends: False
register: auth__register_pam_ldap_packages
until: auth__register_pam_ldap_packages is succeeded
- name: Divert original /etc/nslcd.conf
command: dpkg-divert --quiet --local --divert /etc/nslcd.conf.dpkg-divert --rename /etc/nslcd.conf
creates=/etc/nslcd.conf.dpkg-divert
- include: machine_bind_account.yml
when: auth_nslcd_ldap_server is defined and auth_nslcd_ldap_server
- name: Configure nslcd for LDAP authentication
template:
src: '{{ lookup("template_src", "etc/nslcd.conf.j2") }}'
dest: '/etc/nslcd.conf'
owner: 'root'
group: 'nslcd'
mode: '0640'
register: auth_register_nslcd_conf
- name: Restart nslcd if configuration changed
service:
name: 'nslcd'
state: 'restarted'
when: auth_register_nslcd_conf is defined and auth_register_nslcd_conf is changed
# {{ ansible_managed }}
# See ldap.conf(5) for details
# This file should be world readable but not world writable.
{% set auth_tpl_ldap_conf_domain = [] %}
{% set auth_tpl_ldap_conf_hostdn = [] %}
{% if auth_ldap_conf_domain is defined and auth_ldap_conf_domain %}
{% for element in auth_ldap_conf_domain.split(".") %}
{% set _ = auth_tpl_ldap_conf_domain.append("dc=" + element) %}
{% endfor %}
{% endif %}
{% if auth_ldap_conf_hostdn is defined and auth_ldap_conf_hostdn %}
{% for element in auth_ldap_conf_hostdn %}
{% set _ = auth_tpl_ldap_conf_hostdn.append(element | replace(",","2C")) %}
{% endfor %}
{% endif %}
BASE {{ (auth_tpl_ldap_conf_hostdn + auth_tpl_ldap_conf_domain) | join(",") }}
URI {{ auth_ldap_conf_uri | join(" ") }}
# TLS options
TLS_CACERT {{ auth_ldap_conf_tls_cacert }}
TLS_REQCERT {{ auth_ldap_conf_tls_reqcert }}
{% if auth_ldap_conf_options is defined and auth_ldap_conf_options %}
# Other options
{{ auth_ldap_conf_options }}
{% endif %}
# {{ ansible_managed }}
# /etc/nslcd.conf
# nslcd configuration file. See nslcd.conf(5)
# for details.
# The user and group nslcd should run as.
uid nslcd
gid nslcd
# The location at which the LDAP server(s) should be reachable.
{% for address in auth_nslcd_uri %}
uri {{ address }}
{% endfor %}
# The search base that will be used for all queries.
{% for basedn in auth_nslcd_base %}
base {{ basedn }}
{% endfor %}
# The LDAP protocol version to use.
#ldap_version 3
# The DN to bind with for normal lookups.
binddn {{ auth_nslcd_bind_host_dn }}
bindpw {{ lookup('password', auth_nslcd_bind_host_password + ' length=' + auth_nslcd_password_length) }}
# The DN used for password modifications by root.
#rootpwmoddn cn=admin,dc=example,dc=com
# SSL options
ssl start_tls
tls_reqcert {{ auth_nslcd_tls_reqcert | default('demand') }}
tls_cacertfile {{ auth_nslcd_tls_cacertfile }}
# The search scope.
#scope sub
{% if auth_nslcd_nss_min_uid is defined and auth_nslcd_nss_min_uid %}
# Lookup users above this uidNumber in LDAP
nss_min_uid {{ auth_nslcd_nss_min_uid }}
{% endif %}
{% if auth_nslcd_pam_authz_search is defined and auth_nslcd_pam_authz_search %}
# Allow/Deny access according to LDAP attributes
{% for entry in auth_nslcd_pam_authz_search %}
pam_authz_search {{ entry }}
{% endfor %}
{% endif %}
{% if auth_nslcd_options is defined and auth_nslcd_options %}
{{ auth_nslcd_options }}{% endif %}
......@@ -17,7 +17,7 @@
#
# List of base APT packages to install for LXC support.
lxc__base_packages:
- [ 'lxc', 'lxcfs', 'debootstrap' ]
- [ 'lxc', 'lxcfs', 'debootstrap', 'xz-utils' ]
- '{{ [ "dnsmasq-base", "resolvconf" ] if (lxc__net_deploy_state == "present") else [] }}'
# ]]]
......
debops.nslcd - Configure LDAP support for NSS and PAM lookups
Copyright (C) 2019 Maciej Delmanowski <drybjed@gmail.com>
Copyright (C) 2019 DebOps Project https://debops.org/
This Ansible role is part of DebOps.
DebOps is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3, as
published by the Free Software Foundation.
DebOps is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DebOps. If not, see http://www.gnu.org/licenses/.
---
# .. vim: foldmarker=[[[,]]]:foldmethod=marker
# debops.nslcd default variables
# ==============================
# .. contents:: Sections
# :local:
#
# .. include:: ../../../includes/global.rst
# APT packages [[[
# ----------------
# .. envvar:: nslcd__base_packages [[[
#
# List of APT packages required for LDAP lookups via NSS and PAM.
nslcd__base_packages: [ 'libpam-ldapd', 'libnss-ldapd',
'nslcd', 'nslcd-utils',
'openssl', 'ca-certificates' ]
# ]]]
# .. envvar:: nslcd__packages [[[
#
# List of additional APT packages to install with :command:`nslcd` package.
nslcd__packages: []
# ]]]
# ]]]
# UNIX environment [[[
# --------------------
# .. envvar:: nslcd__user [[[
#
# Name of the UNIX system account which will be used to perform LDAP lookups
# via the :command:`nslcd` service.
nslcd__user: 'nslcd'
# ]]]
# .. envvar:: nslcd__group [[[
#
# Name of the UNIX system group which will be used to perform LDAP lookups via
# the :command:`nslcd` service.
nslcd__group: 'nslcd'
# ]]]
# .. envvar:: nslcd__mkhomedir_umask [[[
#
# Default umask for new home directories created by the ``pam_mkhomedir`` PAM
# module.
nslcd__mkhomedir_umask: '{{ ansible_local.core.homedir_umask
if (ansible_local|d() and ansible_local.core|d() and
ansible_local.core.homedir_umask|d())
else "0027" }}'
# ]]]
# ]]]
# LDAP environment [[[
# --------------------
# .. envvar:: nslcd__ldap_base_dn [[[
#
# The base Distinguished Name which should be used to create Distinguished
# Names of the LDAP directory objects, defined as a YAML list.
nslcd__ldap_base_dn: '{{ ansible_local.ldap.base_dn
if (ansible_local|d() and ansible_local.ldap|d() and
ansible_local.ldap.base_dn|d())
else [] }}'
# ]]]
# .. envvar:: nslcd__ldap_device_dn [[[
#
# The Distinguished Name of the current host LDAP object, defined as a YAML
# list. It will be used as a base for the :command:`nslcd` service account LDAP
# object. If the list is empty, the role will not create the account LDAP
# object automatically.
nslcd__ldap_device_dn: '{{ ansible_local.ldap.device_dn
if (ansible_local|d() and ansible_local.ldap|d() and
ansible_local.ldap.device_dn|d())
else [] }}'
# ]]]
# .. envvar:: nslcd__ldap_self_rdn [[[
#
# The Relative Distinguished Name of the account LDAP object used by the
# :command:`nslcd` service to access the LDAP directory.
nslcd__ldap_self_rdn: '{{ "uid=" + nslcd__user }}'
# ]]]
# .. envvar:: nslcd__ldap_self_object_classes [[[
#
# List of the LDAP object classes which will be used to create the LDAP object