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