ansible-ldap-modules/README.md

288 lines
7.4 KiB
Markdown
Raw Normal View History

2016-09-13 01:00:04 +03:00
# Ansible LDAP Modules
For whatever reasons, Ansible doesn't include modules to manipulate an
LDAP server in its
[core](http://docs.ansible.com/ansible/modules_by_category.html).
2016-09-13 01:00:04 +03:00
Peter Sagerson implemented a pair of modules and has
[attempted to get them into Ansible](http://grokbase.com/t/gg/ansible-devel/148892tek3/ldap-modules),
but no luck yet. He's instead hosted his code on
[Bitbucket](https://bitbucket.org/psagers/ansible-ldap).
This repository is a fork of his original work with some additions
(and cosmetic improvements) hosted on GitHub.
2016-09-13 01:00:04 +03:00
# 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.
2016-09-13 01:00:04 +03:00
## python-ldap Installation
Install it locally via the following commands:
2016-09-13 01:00:04 +03:00
```
$ 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:
```yaml
# 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
```
2016-09-19 10:19:29 +03:00
Now either set the `ANSIBLE_LIBRARY` environment variable or the
`library` entry within the `defaults` section of your `ansible.cfg` to
include this repository's directory.
2016-09-13 01:00:04 +03:00
# 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):
```yaml
- 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
2016-09-19 10:19:29 +03:00
description: A bunch of Ansible-lovers.
```
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:
```yaml
- 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
2016-09-19 10:19:29 +03:00
description: A bunch of Ansible-lovers.
```
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:
```yaml
- 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
2016-09-19 10:19:29 +03:00
description: A bunch of Ansible-lovers.
```
## Modules
This repository provides four different modules:
2016-09-13 01:00:04 +03:00
### 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
```yaml
- name: Ensure an LDAP entry exists for ou=People
ldap_entry:
dn: "ou=People,dc=example,dc=com"
ou: People
objectClass: organizationalUnit
2016-09-19 10:19:29 +03:00
description: A bunch of Ansible-lovers.
```
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
```yaml
- 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.
```yaml
- name: Ensure description is correct for ou=People
ldap_attr:
dn: "ou=People,dc=example,dc=com"
name: description
state: exact
2016-09-19 10:19:29 +03:00
values: A bunch of Ansible-lovers.
- 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
```yaml
- 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
```yaml
- 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.
```yaml
- 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`:
```yaml
- 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 }}"
```
2016-09-13 01:00:04 +03:00