Deploying OpenLDAP w/ Ansible
Requirements
- Physical or VPN connection to the VT network
- Local installation of Ansible 2.7 or newer
- Local installation of HashiCorp Vault v1.12 or newer
- Local installation of Git 2.13 or newer
- Local installation of OpenPGP (gpg)
- Local installation of OpenSSH client (ssh)
- VT Username (PID) with Duo MFA
- Membership in one or more of these ED groups
- middleware.vault.neo-ldap.prod
- middleware.vault.neo-ldap.prod.admin
- Designation as a recipient with your PGP public key signing the files in the certificates repository
- An account with the ability to
sudo su - openldap
on each LDAP server to be managed.
Overview
The OpenLDAP software is deployed by the CNS/ansibile-admin playbook using the Middleware/neo-ldap and Middleware/neo-ldap-group_vars roles as submodules at tasks/roles/openldap
and group_vars/openldap
, respectively. A separate certificates submodule at certificates
contains the PKI certificates used by OpenLDAP and other software on the servers. The ansible-admin playbook needs to be passed options to use several vault encrypted variables, using the vault-id openldap
.
ansible-playbook -i ansible_hosts --vault-id openldap@contrib/vault/vault-client.sh tasks/main.yml --tags openldap,certs [--limit hostname[,hostname]]
The contrib/vault/vault-client.sh
helper script in the command above obtains the Ansible Vault password from a HashiCorp Vault secret. If the --limit
option is not passed, careful attention should be paid to the inventory file to be sure that only the desired hosts are listed in the openldap role.
Some advice about tags
This Ansible playbook is flexible enough to address multiple deployment and maintenance scenarios through different combinations of tags, which also means it is possible to produce undesired results through incorrect use of tags. Here is a summary of the available tags, and some recommended combinations for common scenarios.
- openldap
- certs
- dump
- load
- tests
- start
- stop
- purge_db
Tag usage examples
Fresh install of OpenLDAP on a new machine
--tags openldap,certs --limit newmachine.vt.edu
Upgrade OpenLDAP on an existing machine
--tags dump,load,openldap,certs --limit existingmachine.vt.edu
Purge all o=vt data from an OpenLDAP consumer node and syncrepl the entire o=vt DIT from the provider
--tags stop,purge_db,start --limit consumernode.vt.edu
Using pass and vault to avoid password prompts from ansible-playbook
The vault
command can be used to obtain a valid vault token before running the ansible-playbook
command. We can also provide a gpg passphrase for the certificates decryption to ansible-playbook
with its --extra-vars
option. Consider the following example, which assumes you have stored your VT password and gpg passphrase in pass as vt
and gpg
, respectively.
export VAULT_ADDR=https://vault.es.cloud.vt.edu && \
vault login -method=ldap username=your_vt_username password=$(pass vt) && \
pass gpg | ansible-playbook --extra-vars "gpg_passphrase=@/dev/stdin" -i ansible_hosts --vault-id openldap@contrib/vault/vault-client.sh --tags openldap,certs --limit LDAP_server_hostname tasks/main.yml
While this method of executing the playbook makes the entry of passphrases much more convenient, it still requires two separate Duo authentications when it runs, so be prepared to answer the multifactor notifications.
Upgrading OpenLDAP
Upgrade a host by updating the openldap_active_version
varable in the host_vars/hostname
file and run the playbook with the proper tags. The dump
and load
tags are used to export and import the directory data during OpenLDAP version upgrades, and can also be used independently for ad-hoc logical backup and restore operations if desired.
ansible-playbook -i ansible_hosts --vault-id openldap@contrib/vault/vault-client.sh tasks/main.yml --tags dump,openldap,certs,load --limit LDAP_server_hostname
Rotating secrets
HashiCorp Vault
The Ansible vault password is stored in HashiCorp Vault in a key/value (kv) secrets engine at dit.middleware/neo-ldap/prod
with a key of openldap
. If you do not already have a valid token from Vault, set the VAULT_ADDR=https://vault.es.cloud.vt.edu
environment variable and login with your VT username and password.
export VAULT_ADDR=https://vault.es.cloud.vt.edu && vault login -method=ldap username=your_vt_username
Ansible vault
The playbook uses variables stored in encrypted form in the group_vars/openldap/vault
file. These variables have corresponding entries in the group_vars/openldap/vars
file that point to those in the group_vars/openldap/vault
file so as to keep encrypted variables visible to playbook editors and users. We must rekey the Ansible vault with the secret in the HashiCorp Vault whenever it is updated (see above).
ansible-vault rekey --vault-id openldap@contrib/vault/vault-client.sh group_vars/openldap/vault
Whenever a variable needs updating in the Ansible vault, we must edit the group_vars/openldap/vault file by supplying the vault password
ansible-vault edit --vault-id openldap@contrib/vault/vault-client.sh group_vars/openldap/vault
Stripping sensitive data from production data exports
When setting up new dev and pprd instances, passwords and secrets should be redacted from LDIF backups of the production directory:
sed -i "s/userPassword:: .\+/userPassword:: `echo somegarbagepasswordthatdoesnotwork | base64 -`/g" backup/o_vt.ldif
sed -i "s/radiusClientSecret: .\+/radiusClientSecret: somegarbagesecretthatdoesnotwork/g" backup/o_vt.ldif
or simply replaced inline when exporting data for that specific purpose:
slapcat -b o=vt -F /apps/openldap/openldap/etc/openldap/slapd.d \
| sed "s/userPassword:: .\+/userPassword:: `echo somegarbagepasswordthatdoesnotwork | base64 -`/g" \
| sed "s/radiusClientSecret: .\+/radiusClientSecret: somegarbagesecretthatdoesnotwork/g" > backup/o_vt_exported.ldif