LDAP is a critical protocol commonly in use with UNIX and Linux applications, with OpenLDAP being the most popular implementation.
The OpenLDAP secrets engine provides a centralized workflow for efficiently managing existing LDAP entry passwords, empowering users with access to their own credentials, and the benefits of automatic password rotation.
»Challenge
The hardest problems encountered with administration of OpenLDAP and its associated credentials can be summarized as follows.
- The volume of user entries in an OpenLDAP directory can be difficult to efficiently manage
- Access to OpenLDAP is required to empower users with credential management capabilities
- There is a lack of available solutions aimed at automatically rotating OpenLDAP credentials, requiring the use of in house solutions
»Solution
Use the OpenLDAP secrets engine with Vault to provide a variety of authentication methods to users for accessing their own LDAP credentials.
Users can be empowered to manage their own LDAP entries, and their passwords can be configured to be automatically rotated based on a time to live value configured by the administrator.
The following diagram illustrates this credential management workflow.
By making the passwords as short-lived as possible, you reduce the chance that they might be compromised. If an credential is compromised, it can be revoked revoked and rotated rather than changing a global set of credentials.
»Personas
The end-to-end scenario described in this tutorial involves two personas.
admin
a Vault administrator with privileged permissions to configure secrets enginesalice
a user with existing OpenLDAP credential who needs to access a Secure Shell Daemon (sshd) server with this credential password
»Prerequisites
To perform the tasks described in this tutorial, you need to have the following items.
A Vault version 1.4 or later environment; refer to the Getting Started tutorial to install Vault. Make sure that your Vault server has been initialized and unsealed.
An OpenLDAP environment you can connect Vault to, or Docker to run an OpenLDAP container.
Local installation of the
ldapadd
binary; if your operating system distribution does not provide it by default, you can typically find it in a LDAP utilities package (such as ldap-utils on Debian based Linux) or by installing OpenLDAP locally.Local installation of the curl binary; if you want to follow the HTTP API examples, please be sure to install
curl
.Local installation of the jq binary; this is optional but makes reading JSON output from the HTTP API operations more friendly to humans.
NOTE: An interactive tutorial is also available if you do not have a Vault environment to perform the steps described in this tutorial. Click the Show Terminal button to start.
»Policy requirements
NOTE: For the purpose of this tutorial, you can use the root
token to work with Vault. However, it is recommended that root tokens are only used for just enough initial setup or in emergencies. As a best practice, use tokens with appropriate set of policies based on your role in the organization.
To perform all tasks demonstrated in this tutorial, your admin persona policy must include the following capabilities.
# Mount secrets engines
path "sys/mounts/*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
# Configure the openldap secrets engine and create roles
path "openldap/*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
# Write ACL policies
path "sys/policies/acl/*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
# Manage tokens for verification
path "auth/token/create" {
capabilities = [ "create", "read", "update", "delete", "list", "sudo" ]
}
If you are not familiar with policies, complete the policies tutorial.
Use a token with these policies attached for all steps performed by the admin persona in this tutorial.
»Scenario Introduction
In this scenario, you are going to assume two personas, first as admin to configure the OpenLDAP secrets engine, and then as alice to request a new OpenLDAP credential.
- Enable the OpenLDAP secrets engine
- Configure OpenLDAP secrets engine
- Rotate root password
- Create a role
- Request OpenLDAP credentials
Step 1 through 4 need to be performed by the admin persona. Step 5 describes the commands that the user alice performs to get an OpenLDAP credential from Vault.
»Step 1: Enable the OpenLDAP secrets engine
(Persona: admin)
The first step is to enable an openldap
secrets engine at the desired path.
Execute the following command to enable the openldap
secrets engine at the path openldap/
.
$ vault secrets enable openldap
If you want to enable the secrets engine at a different path, use the -path
parameter to specify your desired path. Otherwise, the secrets engine gets
enabled at a path named after its type. Since the type is openldap
in this
example, its path becomes openldap
in absence of any -path
parameter.
Successful output:
Success! Enabled the openldap secrets engine at: openldap/
Successful operations against this endpoint are expected to result in no body output. You can confirm that the secrets engine is enabled with a request to the /sys/mounts API.
$ curl \
--silent \
--header "X-Vault-Token: $VAULT_TOKEN" \
$VAULT_ADDR/v1/sys/mounts \
| jq '.data."openldap/"'
If the secrets engine is enabled, you should observe output like this example.
{
"accessor": "openldap_18a28534",
"config": {
"default_lease_ttl": 0,
"force_no_cache": false,
"max_lease_ttl": 0
},
"description": "",
"external_entropy_access": false,
"local": false,
"options": null,
"seal_wrap": false,
"type": "openldap",
"uuid": "e3ed93a0-f6ad-c100-03c0-745f0f5b41f4"
}
If the output is empty instead, then the openldap secrets engine is not enabled and you should check your API call and try again.
»Step 2: Configure OpenLDAP secrets engine
(Persona: admin)
The OpenLDAP secrets engine needs to be configured with valid credentials. It is common to give Vault the superuser credentials and let Vault manage the auditing and lifecycle credentials; it's much better than having one person manage the credentials.
»Start an OpenLDAP Server
For the purpose of this tutorial, let's run a community based OpenLDAP Docker image in a container.
NOTE: If you already have an OpenLDAP server that you can connect to, you can ignore this step and modify your values in the examples accordingly.
Use docker run
to run an openldap
container; options are detailed after the example.
$ docker run \
--name vault-openldap \
--env LDAP_ORGANISATION="learn" \
--env LDAP_DOMAIN="learn.example" \
--env LDAP_ADMIN_PASSWORD="2LearnVault" \
-p 389:389 \
-p 636:636 \
--detach \
--rm \
osixia/openldap:latest
The options we use in the example are as follows.
- Name the container vault-openldap
- Set LDAP organization value to learn
- Set LDAP domain to learn.example
- Set LDAP administrator password to 2LearnVault
- Listen on default LDAP and LDAPS ports TCP/389 and 636
- Expose these ports to the Docker host
- Detach the container from terminal
- Remove the container when it exits
After starting the container, you can verify that it is running.
$ docker ps -f name=vault-openldap --format "table {{.Names}}\t{{.Status}}"
NAMES STATUS
vault-openldap Up 9 seconds
»Configure OpenLDAP with example data
With the OpenLDAP container now available, we can add some initial configuration including groups and the example user, alice.
We use the cat
utility here to quickly write file examples for this tutorial in the present working directory. If you wish to edit and write files another way, then remove the first and last lines of the example in each case to use it verbatim.
Example: learn-vault-example.ldif
$ cat > learn-vault-example.ldif <<EOF
dn: ou=groups,dc=learn,dc=example
objectClass: organizationalunit
objectClass: top
ou: groups
description: groups of users
dn: ou=users,dc=learn,dc=example
objectClass: organizationalunit
objectClass: top
ou: users
description: users
dn: cn=dev,ou=groups,dc=learn,dc=example
objectClass: groupofnames
objectClass: top
description: testing group for dev
cn: dev
member: cn=alice,ou=users,dc=learn,dc=example
dn: cn=alice,ou=users,dc=learn,dc=example
objectClass: person
objectClass: top
cn: learn
sn: learn
memberOf: cn=dev,ou=groups,dc=learn,dc=example
userPassword: 1LearnedVault
EOF
Use the ldapadd
utility to add this configuration.
$ ldapadd -cxWD "cn=admin,dc=learn,dc=example" -f learn-vault-example.ldif
When prompted for password, enter 2LearnVault
which was the value of LDAP_ADMIN_PASSWORD
when starting the docker container. If using an existing OpenLDAP, enter the known administrator password.
Successful output:
adding new entry "ou=groups,dc=learn,dc=example"
adding new entry "ou=users,dc=learn,dc=example"
adding new entry "cn=dev,ou=groups,dc=learn,dc=example"
adding new entry "cn=alice,ou=users,dc=learn,dc=example"
Now you are ready to configure the OpenLDAP secrets engine in Vault.
The following command configures the OpenLDAP secrets engine using the openldap
plugin to communicate with our Docker based OpenLDAP container.
$ vault write openldap/config \
binddn=cn=admin,dc=learn,dc=example \
bindpass=2LearnVault \
url=ldap://127.0.0.1
If your OpenLDAP connection URL is different from this example, be sure to replace the example values with correct binddn
, bindpass
, and url
values that match your environment. This user should have the necessary privileges to search and change entry passwords in OpenLDAP.
Successful output:
Success! Data written to: openldap/config
NOTE: While our previous example uses a default OpenLDAP administrator user, it is recommended that a dedicated entry management account be used specifically for Vault in production environments.
»Step 3: Rotate the root credential
It is a best practice when configuring dynamic secrets engines with Vault to rotate the credential used in the configuration of a secrets engine (known to Vault as the root credential) immediately after configuring the secrets engine.
This helps to minimize exposure of the configured credential, ensures that Vault has exclusive control of the rotated root credential, and guarantees that the new root credential is not exposed outside of Vault.
With that in mind, let's rotate the root credential now so that you can get acquainted with the process.
$ vault write -f openldap/rotate-root
Successful output:
Success! Data written to: openldap/rotate-root
NOTE: It is not possible to retrieve the generated root credential once rotated by Vault.
»Step 4: Create a role
(Persona: admin)
Now that you have successfully configured the OpenLDAP secrets engine, the next step is to create a role that maps a name in Vault to an entry in OpenLDAP.
Example:
$ vault write openldap/static-role/learn \
dn='cn=alice,ou=users,dc=learn,dc=example' \
username='alice' \
rotation_period="24h"
Successfully adding the role results in output like this:
Success! Data written to: openldap/static-role/learn
You can now move on to requesting an OpenLDAP credential from the learn role.
»Step 5: Request OpenLDAP credentials
(Persona: alice)
Our example user alice has previously authenticated to Vault and her token has a policy attached which provides the capability needed to request a new OpenLDAP credential from the learn role.
# Request OpenLDAP credential from the learn role
path "openldap/static-cred/learn" {
capabilities = [ "read" ]
}
Alice's token id value should be used as the value of VAULT_TOKEN
in the following API steps performed as alice.
Finally, using an example application token as previously described, you can use this command to read from the role to request a credential.
$ vault read openldap/static-cred/learn
Successful output:
Key Value
--- -----
dn cn=alice,ou=users,dc=learn,dc=example
last_vault_rotation 2020-03-05T17:06:52.345894964Z
password pIBLIY9kc2yoiqEFbyibMOlyW0cQCPcKoZ3AC3Nzb8l1fS9Yze7eWtLgMKQqyRg6
rotation_period 24h
ttl 23h59m51s
username alice
Generate another set of credentials from the learn
role and save the password to a variable named LDAP_PASSWORD
.
$ LDAP_PASSWORD=$(vault read --format=json openldap/static-cred/learn | jq -r ".data.password")
Perform an LDAP search with the generated dn
and password
.
$ ldapsearch -b "cn=alice,ou=users,dc=learn,dc=example" \
-D 'cn=alice,ou=users,dc=learn,dc=example' \
-w $LDAP_PASSWORD
The results display the password for this user.
There is more to learn about credentials, roles, and rotation from the OpenLDAP secrets engine documentation and OpenLDAP Secrets Engine HTTP API.
»Next steps
You can explore a deeper dive into the OpenLDAP secrets engine that further extends the example in this tutorial with a full environment based on Docker containers.
Please check out the Docker OpenLDAP Secrets Engine with SSH Demonstration to learn more.