LDAP tasks and administrative operations
In addition to maintaining the system-wide LDAP client configuration on a host,
the debops.ldap role can be used to perform tasks in the LDAP directory
itself, using ldap_entry
or ldap_attrs
1 Ansible modules. The LDAP
tasks are performed via Ansible task delegation functionality, on the Ansible
Controller. This behaviour can be controlled using the ldap__admin_*
default variables. Check the ldap__tasks documentation for syntax
and examples of usage.
Authentication to the LDAP directory
The role will use the username of the current Ansible user (from the Ansible
Controller host) as the value of the uid=
attribute to bind to the LDAP
directory. This is done to avoid sharing passwords between users of a single
administrator account in the LDAP directory.
By default LDAP connection will be bound as a Distinguished Name:
uid=<user>,ou=People,dc=example,dc=org
The DN can be overridden in the ldap__admin_binddn
variable, either
via the Ansible inventory (this should be avoided if the inventory is shared
between multiple administrators), on the command line (using the
--extra-vars
argument), or using an environment variable on the Ansible
Controller:
export DEBOPS_LDAP_ADMIN_BINDDN="cn=ansible,ou=Services,dc=example,dc=org"
How the bind password is obtained is described in the next section. If the bind
password is not provided (the ldap__admin_bindpw
variable is empty),
the LDAP tasks will be skipped. This allows the debops.ldap role to be
used in a playbook with other roles without the fear that lack of LDAP
credentials will break execution of said playbook.
Secure handling of LDAP admin credentials
The LDAP password of the current Ansible user is defined in the
ldap__admin_bindpw
inventory variable.
Environment variable
By default, the role first checks if the DEBOPS_LDAP_ADMIN_BINDPW
environment variable is defined on the Ansible Controller and uses its value as
the password during connections to the LDAP directory.
Plaintext file
Next, the role will look for credentials in the secret/ldap/credentials/
directory. The files in this directory are named based on the UUID of the
current user's Distinguished Name (see the previous section).
The UUID conversion is done because LDAP Distinguished Names can contain
spaces, and the Ansible lookups don't work too well with filenames that contain
spaces. You can use the ldap/get-uuid.yml
playbook to convert user
account DNs or arbitrary LDAP Distinguished Names to an UUID value you can use
to look up the passwords manually, if needed.
Password Store
Finally, the role will try and lookup the password using the passwordstore Ansible lookup plugin. The plugin uses the pass password manager as a backend to store credentials encrypted using the GPG key of the user.
The path in the pass storage directory where the debops.ldap
will look for credentials is defined by the
ldap__admin_passwordstore_path
, by default it's
debops/ldap/credentials/
. The actual encrypted files with the password
are named based on the UUID, like for the plaintext password.
You can store new credentials in the pass password manager using the
ansible/playbooks/ldap/save-credential.yml
Ansible playbook included
in the DebOps monorepo. All you need to do is run this playbook against one of
the LDAP servers by following this steps:
Make sure you have GPGv2 and pass installed, ie.
apt-get install gpgv2 pass
Make sure you have a GPG key pair
Initialize the password store:
pass init <your-gpg-id>
. Example:pass init admin@example.com
Run the playbook
debops run ldap/save-credential -l <host>
Re-run the playbook for each user you want to store a password for
The playbook will ask interactively for the uid=
username, and if not
provided, for the full LDAP Distinguished Name, and after that, for a password
to store encrypted using your GPG key. If you don't specify one, a random
password will be automatically generated, saved in the password store, and
displayed for you to use in the LDAP directory. The encrypted passwords will be stored
by default under ~/.password-store
.
Different modes of operation
The role acts differently depending on the current configuration of the remote host and its own environment:
If the debops.ldap role configuration was not applied on the host, the role will set up system-wide LDAP configuration file, and perform the default LDAP tasks, tasks defined in the Ansible inventory, and any tasks provided via role dependent variables which are usually defined by other roles (see Use as a dependent role for more details).
If the debops.ldap role configuration was already applied on the host, and there are no LDAP tasks defined by other Ansible roles, the debops.ldap role will apply the default LDAP tasks and the tasks from Ansible inventory (standalone mode).
If the debops.ldap role configuration was already applied on the host, and the role is used as a dependency for another role, the default LDAP tasks and the tasks from Ansible inventory will be ignored, and only those provided via the
ldap__dependent_tasks
variable by other Ansible roles will be executed in the LDAP directory (dependent mode).
This ensures that the list of LDAP tasks is short, and tasks defined by default in the role, and those defined in the Ansible inventory, which are presumed to be done previously, are not unnecessarily repeated when dependent role LDAP tasks are performed.
Because the debops.ldap role relies on the LDAP credentials of the current Ansible user, the person that executes Ansible does not require full access to the entire LDAP directory. The role can perform tasks only on specific parts of the directory depending on the Access Control List of the LDAP directory server and permissions of the current user.
Footnotes
- 1
Currently a custom
ldap_attrs
module, included in the debops.ansible_plugins role is used instead of theldap_attr
plugin included in Ansible.