.gitignore | ||
__init__.py | ||
ldap_attr | ||
ldap_entry | ||
ldap_search | ||
ldap_upsert | ||
LICENSE | ||
README.md | ||
requirements.txt |
Ansible LDAP Modules
For whatever reasons, Ansible doesn't include modules to manipulate an LDAP server in its core.
Peter Sagerson implemented a pair of modules and has attempted to get them into Ansible, but no luck yet. He's instead hosted his code on Bitbucket.
This repository is a fork of his original work with some additions (and cosmetic improvements) hosted on GitHub.
Installation
The python-ldap
library is required on whatever host is executing
these modules. This can be confusing if you use both
local_action
-type tasks and tasks which run on remote hosts and both
need to talk do an LDAP server -- you'll need to install python-ldap
both locally on your controller as well as remotely on the hosts you
run the tasks on.
In addition, you'll need to clone this repository itself to your
controller and put it somewhere ansible
can find it.
python-ldap Installation
Install it locally via the following commands:
$ cd ansible-ldap-modules
$ sudo pip -r requirements.txt
You may need to install some system dependencies first:
$ sudo apt-get install python-dev libsasl2-dev libldap2-dev libssl-dev
For remote hosts, this can be automated via Ansible:
# in prepare_remote_ldap_host.yml, for example
- name: Install dependencies
apt: name="{{ item }}" state=present
with_items:
- python-pip
- libsasl2-dev
- libldap2-dev
- libssl-dev
- name: Upgrade pip
command: pip install --upgrade pip
- name: Install python-ldap
pip: name=python-ldap state=present
Modules Installation
You'll need to clone this repository somewhere on your controller
machine so that ansible
can find it.
$ git clone https://github.com/unchained-capital/ansible-ldap-modules
Once you have python-ldap
installed, you'll need to link the
executable files in this repository into Ansible's library path. The
simplest way to do this is to create a library
folder at the
top-level of your playbook repository and create symlinks within it to
the module files in this repository:
$ mkdir -p library
$ ln -s ansible-ldap-modules/ldap_entry library/ldap_entry
$ ln -s ansible-ldap-modules/ldap_attr library/ldap_attr
You can also explicitly set the ANSIBLE_LIBRARY
environment variable
or the library
entry within the defaults
section of your
ansible.cfg
to include this repository's directory.
Usage
Remember, if you run these tasks locally, you need python-ldap
installed locally. If you run them on a remote machine, you need
python-ldap
installed on that remote machine.
Shared Behavior
All the modules in this repository share some behaviors. This section describes those behaviors. The next section describes each module in detail.
Specifying an LDAP Server
Here is a simple example of creating an entry (more details on this below):
- hosts: server0
tasks:
- name: Ensure an LDAP entry exists for ou=People
ldap_entry:
dn: "ou=People,dc=example,dc=com"
ou: People
objectClass: organizationalUnit
description: Getting together and having a good time.
The target host of an LDAP operation is assumed to be the same host as
the Ansible task is executing so the above task would attempt to talk
to LDAP server running on server0
listenting on port 389. This example:
- hosts: server0
tasks:
- name: Ensure an LDAP entry exists for ou=People
ldap_entry:
server_uri: ldapi://server1/
dn: "ou=People,dc=example,dc=com"
ou: People
objectClass: organizationalUnit
description: Getting together and having a good time.
would target an LDAP server at server1
.
Choosing Credentials
Without any credentials (as in the above examples), the request will
be made via a SASL EXTERNAL
bind (similar to ldapadd ... -Y EXTERNAL ...
on the command-line).
Credentials can be specified as well:
- hosts: server0
tasks:
- name: Ensure an LDAP entry exists for ou=People
ldap_entry:
bind_dn: "cn=admin,dc=example,dc=com"
bind_pw: "password"
dn: "ou=People,dc=example,dc=com"
ou: People
objectClass: organizationalUnit
description: Getting together and having a good time.
Modules
This repository provides four different modules:
ldap_entry
Ensures that an entry with a given dn
exists/doesn't exist. If
missing, it creates it. It present it does nothing. In particular,
even if the entry has different attributes from those specified in
Ansible, ldap_entry
does nothing. You can, however, use
ldap_entry
to remove LDAP entries if you specify state=absent
.
Creating an entry
- name: Ensure an LDAP entry exists for ou=People
ldap_entry:
dn: "ou=People,dc=example,dc=com"
ou: People
objectClass: organizationalUnit
description: Getting together and having a good time.
If the ou=People,dc=example,dc=com
entry has its description
field
changed, this task will not update it. It's therefore best to only
specify the minimal number of fields required to successfully create
the entity, given its LDAP objectClass
values and later use
ldap_attr
to explicitly declare the expected state for each
attribute individually. Or use ldap_upsert
.
Removing an entry
- name: Ensure an LDAP entry exists for ou=People
ldap_entry:
dn: "ou=People,dc=example,dc=com"
state: absent
ldap_attr
Ensures that an attribute with a given value exists/doesn't exist for
a given entry. If the entry does not exist, it throws an error. If
the doesn't exist, it creates it. If it exists but has a different
value, it updates it. You can use ldap_attr
to remove LDAP
attributes if you specify state=absent
.
Specifying an attribute exactly
Here's a simple example.
- name: Ensure description is correct for ou=People
ldap_attr:
dn: "ou=People,dc=example,dc=com"
name: description
state: exact
values: Getting together and having a good time.
- name: Ensure members are correct for cn=Admins,ou=Groups
ldap_attr:
dn: "cn=Admins,ou=Groups,dc=example,dc=com"
name: member
state: exact
values:
- cn=joe,ou=People,dc=example,dc=com
- cn=bob,ou=People,dc=example,dc=com
This is a lot of work for many entries with many attributes. Consider
ldap_upsert
in these cases.
Appending to an attribute
- name: Ensure members are present in cn=Admins,ou=Groups
ldap_attr:
dn: "cn=Admins,ou=Groups,dc=example,dc=com"
name: member
state: present
values:
- cn=joe,ou=People,dc=example,dc=com
- cn=bob,ou=People,dc=example,dc=com
The user cn=mike,ou=People,dc=example,dc=com
could still be a
member
of cn=Admins,ou=Groups,dc=example,dc=com
after this task
runs.
Removing an attribute
- name: Ensure user's password is not set
ldap_attr:
dn: "cn=joe,ou=People,dc=example,dc=com"
state: absent
name: userPassword
ldap_upsert
Ensures both that an entry exists as well as that its attributs have
particular values. You cannot use ldap_upsert
to remove entries or
their attributes, but it useful when creating lots of entities with
their attributes.
- name: Create a user
ldap_upsert:
dn: "uid=joe1234,ou=People,dc=example,dc=com"
objectClass:
- account
- posixAccount
cn: "Joe Smith"
gn: "Joe"
sn: "Smith"
uid: "joe1234"
homeDirectory: "/home/joe1234"
userPassword: "..."
ldap_search
Perform an LDAP search. Useful in combination with Ansible's
register
keyword.
This example performs a task for each LDAP user account
:
- name:
ldap_search:
base: "ou=People,dc=example,dc=com"
scope: onelevel
filter: "(objectClass=account)"
register: ldap_user_search
- name: View search results
debug: var=ldap_user_search
- name: Do something for each user
# ...
with_items: "{{ ldap_user_search.results }}"