| --- |
| layout: docs |
| page_title: LDAP - Secrets Engine |
| description: >- |
| The LDAP secret engine manages LDAP entry passwords. |
| --- |
| |
| # LDAP secrets engine |
| |
| @include 'x509-sha1-deprecation.mdx' |
| |
| The LDAP secrets engine provides management of LDAP credentials as well as dynamic |
| creation of credentials. It supports integration with implementations of the LDAP |
| v3 protocol, including OpenLDAP, Active Directory, and IBM Resource Access Control |
| Facility (RACF). |
| |
| The secrets engine has three primary features: |
| - [Static Credentials](/vault/docs/secrets/ldap#static-credentials) |
| - [Dynamic Credentials](/vault/docs/secrets/ldap#dynamic-credentials) |
| - [Service Account Check-Out](/vault/docs/secrets/ldap#service-account-check-out) |
| |
| ## Setup |
| |
| 1. Enable the LDAP secret engine: |
| |
| ```sh |
| $ vault secrets enable ldap |
| ``` |
| |
| By default, the secrets engine will mount at the name of the engine. To |
| enable the secrets engine at a different path, use the `-path` argument. |
| |
| 2. Configure the credentials that Vault uses to communicate with LDAP |
| to generate passwords: |
| |
| ```sh |
| $ vault write ldap/config \ |
| binddn=$USERNAME \ |
| bindpass=$PASSWORD \ |
| url=ldaps://138.91.247.105 |
| ``` |
| |
| Note: it's recommended a dedicated entry management account be created specifically for Vault. |
| |
| 3. Rotate the root password so only Vault knows the credentials: |
| |
| ```sh |
| $ vault write -f ldap/rotate-root |
| ``` |
| |
| Note: it's not possible to retrieve the generated password once rotated by Vault. |
| It's recommended a dedicated entry management account be created specifically for Vault. |
| |
| ### Schemas |
| |
| The LDAP Secret Engine supports three different schemas: |
| |
| - `openldap` (default) |
| - `racf` |
| - `ad` |
| |
| #### OpenLDAP |
| |
| By default, the LDAP Secret Engine assumes the entry password is stored in `userPassword`. |
| There are many object classes that provide `userPassword` including for example: |
| |
| - `organization` |
| - `organizationalUnit` |
| - `organizationalRole` |
| - `inetOrgPerson` |
| - `person` |
| - `posixAccount` |
| |
| #### Resource access control facility (RACF) |
| |
| For managing IBM's Resource Access Control Facility (RACF) security system, the secret |
| engine must be configured to use the schema `racf`. |
| |
| Generated passwords must be 8 characters or less to support RACF. The length of the |
| password can be configured using a [password policy](/vault/docs/concepts/password-policies): |
| |
| ```bash |
| $ vault write ldap/config \ |
| binddn=$USERNAME \ |
| bindpass=$PASSWORD \ |
| url=ldaps://138.91.247.105 \ |
| schema=racf \ |
| password_policy=racf_password_policy |
| ``` |
| |
| #### Active directory (AD) |
| |
| For managing Active Directory instances, the secret engine must be configured to use the |
| schema `ad`. |
| |
| ```bash |
| $ vault write ldap/config \ |
| binddn=$USERNAME \ |
| bindpass=$PASSWORD \ |
| url=ldaps://138.91.247.105 \ |
| schema=ad |
| ``` |
| |
| ## Static credentials |
| |
| ### Setup |
| |
| 1. Configure a static role that maps a name in Vault to an entry in LDAP. |
| Password rotation settings will be managed by this role. |
| |
| ```sh |
| $ vault write ldap/static-role/hashicorp \ |
| dn='uid=hashicorp,ou=users,dc=hashicorp,dc=com' \ |
| username='hashicorp' \ |
| rotation_period="24h" |
| ``` |
| |
| 2. Request credentials for the "hashicorp" role: |
| |
| ```sh |
| $ vault read ldap/static-cred/hashicorp |
| ``` |
| |
| ### Password rotation |
| |
| Passwords can be managed in two ways: |
| |
| - automatic time based rotation |
| - manual rotation |
| |
| ### Auto password rotation |
| |
| Passwords will automatically be rotated based on the `rotation_period` configured |
| in the static role (minimum of 5 seconds). When requesting credentials for a static |
| role, the response will include the time before the next rotation (`ttl`). |
| |
| Auto-rotation is currently only supported for static roles. The `binddn` account used |
| by Vault should be rotated using the `rotate-root` endpoint to generate a password |
| only Vault will know. |
| |
| ### Manual rotation |
| |
| Static roles can be manually rotated using the `rotate-role` endpoint. When manually |
| rotated the rotation period will start over. |
| |
| ### Deleting static roles |
| |
| Passwords are not rotated upon deletion of a static role. The password should be manually |
| rotated prior to deleting the role or revoking access to the static role. |
| |
| ## Dynamic credentials |
| |
| ### Setup |
| |
| Dynamic credentials can be configured by calling the `/role/:role_name` endpoint: |
| |
| ```bash |
| $ vault write ldap/role/dynamic-role \ |
| creation_ldif=@/path/to/creation.ldif \ |
| deletion_ldif=@/path/to/deletion.ldif \ |
| rollback_ldif=@/path/to/rollback.ldif \ |
| default_ttl=1h \ |
| max_ttl=24h |
| ``` |
| |
| -> Note: The `rollback_ldif` argument is optional, but recommended. The statements within `rollback_ldif` will be |
| executed if the creation fails for any reason. This ensures any entities are removed in the event of a failure. |
| |
| To generate credentials: |
| |
| ```bash |
| $ vault read ldap/creds/dynamic-role |
| Key Value |
| --- ----- |
| lease_id ldap/creds/dynamic-role/HFgd6uKaDomVMvJpYbn9q4q5 |
| lease_duration 1h |
| lease_renewable true |
| distinguished_names [cn=v_token_dynamic-role_FfH2i1c4dO_1611952635,ou=users,dc=learn,dc=example] |
| password xWMjkIFMerYttEbzfnBVZvhRQGmhpAA0yeTya8fdmDB3LXDzGrjNEPV2bCPE9CW6 |
| username v_token_testrole_FfH2i1c4dO_1611952635 |
| ``` |
| |
| The `distinguished_names` field is an array of DNs that are created from the `creation_ldif` statements. If more than |
| one LDIF entry is included, the DN from each statement will be included in this field. Each entry in this field |
| corresponds to a single LDIF statement. No de-duplication occurs and order is maintained. |
| |
| ### LDIF entries |
| |
| User account management is provided through LDIF entries. The LDIF entries may be a base64-encoded version of the |
| LDIF string. The string will be parsed and validated to ensure that it adheres to LDIF syntax. A good reference |
| for proper LDIF syntax can be found [here](https://ldap.com/ldif-the-ldap-data-interchange-format/). |
| |
| Some important things to remember when crafting your LDIF entries: |
| |
| - There should not be any trailing spaces on any line, including empty lines |
| - Each `modify` block needs to be preceded with an empty line |
| - Multiple modifications for a `dn` can be defined in a single `modify` block. Each modification needs to close |
| with a single dash (`-`) |
| |
| ### Active directory (AD) |
| |
| For Active Directory, there are a few additional details that are important to remember: |
| |
| To create a user programmatically in AD, you first `add` a user object and then `modify` that user to provide a |
| password and enable the account. |
| |
| - Passwords in AD are set using the `unicodePwd` field. This must be proceeded by two (2) colons (`::`). |
| - When setting a password programmatically in AD, the following criteria must be met: |
| |
| - The password must be enclosed in double quotes (`" "`) |
| - The password must be in [`UTF16LE` format](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/6e803168-f140-4d23-b2d3-c3a8ab5917d2) |
| - The password must be `base64`-encoded |
| - Additional details can be found [here](https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/set-user-password-with-ldifde) |
| |
| - Once a user's password has been set, it can be enabled. AD uses the `userAccountControl` field for this purpose: |
| - To enable the account, set `userAccountControl` to `512` |
| - You will likely also want to disable AD's password expiration for this dynamic user account. The |
| `userAccountControl` value for this is: `65536` |
| - `userAccountControl` flags are cumulative, so to set both of the above two flags, add up the two values |
| (`512 + 65536 = 66048`): set `userAccountControl` to `66048` |
| - See [here](https://docs.microsoft.com/en-us/troubleshoot/windows-server/identity/useraccountcontrol-manipulate-account-properties#property-flag-descriptions) |
| for details on `userAccountControl` flags |
| |
| `sAMAccountName` is a common field when working with AD users. It is used to provide compatibility with legacy |
| Windows NT systems and has a limit of 20 characters. Keep this in mind when defining your `username_template`. |
| See [here](https://docs.microsoft.com/en-us/windows/win32/adschema/a-samaccountname) for additional details. |
| |
| Since the default `username_template` is longer than 20 characters which follows the template of `v_{{.DisplayName}}_{{.RoleName}}_{{random 10}}_{{unix_time}}`, we recommend customising the `username_template` on the role configuration to generate accounts with names less than 20 characters. Please refer to the [username templating document](/vault/docs/concepts/username-templating) for more information. |
| |
| With regard to adding dynamic users to groups, AD doesn't let you directly modify a user's `memberOf` attribute. |
| The `member` attribute of a group and `memberOf` attribute of a user are |
| [linked attributes](https://docs.microsoft.com/en-us/windows/win32/ad/linked-attributes). Linked attributes are |
| forward link/back link pairs, with the forward link able to be modified. In the case of AD group membership, the |
| group's `member` attribute is the forward link. In order to add a newly-created dynamic user to a group, we also |
| need to issue a `modify` request to the desired group and update the group membership with the new user. |
| |
| #### Active directory LDIF example |
| |
| The various `*_ldif` parameters are templates that use the [go template](https://golang.org/pkg/text/template/) |
| language. A complete LDIF example for creating an Active Directory user account is provided here for reference: |
| |
| ```ldif |
| dn: CN={{.Username}},OU=HashiVault,DC=adtesting,DC=lab |
| changetype: add |
| objectClass: top |
| objectClass: person |
| objectClass: organizationalPerson |
| objectClass: user |
| userPrincipalName: {{.Username}}@adtesting.lab |
| sAMAccountName: {{.Username}} |
| |
| dn: CN={{.Username}},OU=HashiVault,DC=adtesting,DC=lab |
| changetype: modify |
| replace: unicodePwd |
| unicodePwd::{{ printf "%q" .Password | utf16le | base64 }} |
| - |
| replace: userAccountControl |
| userAccountControl: 66048 |
| - |
| |
| dn: CN=test-group,OU=HashiVault,DC=adtesting,DC=lab |
| changetype: modify |
| add: member |
| member: CN={{.Username}},OU=HashiVault,DC=adtesting,DC=lab |
| - |
| ``` |
| |
| ## Service account Check-Out |
| |
| Service account check-out provides a library of service accounts that can be checked out |
| by a person or by machines. Vault will automatically rotate the password each time a |
| service account is checked in. Service accounts can be voluntarily checked in, or Vault |
| will check them in when their lending period (or, "ttl", in Vault's language) ends. |
| |
| The service account check-out functionality works with various [schemas](/vault/api-docs/secret/ldap#schema), |
| including OpenLDAP, Active Directory, and RACF. In the following usage example, the secrets |
| engine is configured to manage a library of service accounts in an Active Directory instance. |
| |
| First we'll need to enable the LDAP secrets engine and tell it how to securely connect |
| to an AD server. |
| |
| ```shell-session |
| $ vault secrets enable ldap |
| Success! Enabled the ad secrets engine at: ldap/ |
| |
| $ vault write ldap/config \ |
| binddn=$USERNAME \ |
| bindpass=$PASSWORD \ |
| url=ldaps://138.91.247.105 \ |
| userdn='dc=example,dc=com' |
| ``` |
| |
| Our next step is to designate a set of service accounts for check-out. |
| |
| ```shell-session |
| $ vault write ldap/library/accounting-team \ |
| service_account_names=fizz@example.com,buzz@example.com \ |
| ttl=10h \ |
| max_ttl=20h \ |
| disable_check_in_enforcement=false |
| ``` |
| |
| In this example, the service account names of `fizz@example.com` and `buzz@example.com` have |
| already been created on the remote AD server. They've been set aside solely for Vault to handle. |
| The `ttl` is how long each check-out will last before Vault checks in a service account, |
| rotating its password during check-in. The `max_ttl` is the maximum amount of time it can live |
| if it's renewed. These default to `24h`, and both use [duration format strings](/vault/docs/concepts/duration-format). |
| Also by default, a service account must be checked in by the same Vault entity or client token that |
| checked it out. However, if this behavior causes problems, set `disable_check_in_enforcement=true`. |
| |
| When a library of service accounts has been created, view their status at any time to see if they're |
| available or checked out. |
| |
| ```shell-session |
| $ vault read ldap/library/accounting-team/status |
| Key Value |
| --- ----- |
| buzz@example.com map[available:true] |
| fizz@example.com map[available:true] |
| ``` |
| |
| To check out any service account that's available, simply execute: |
| |
| ```shell-session |
| $ vault write -f ldap/library/accounting-team/check-out |
| Key Value |
| --- ----- |
| lease_id ldap/library/accounting-team/check-out/EpuS8cX7uEsDzOwW9kkKOyGW |
| lease_duration 10h |
| lease_renewable true |
| password ?@09AZKh03hBORZPJcTDgLfntlHqxLy29tcQjPVThzuwWAx/Twx4a2ZcRQRqrZ1w |
| service_account_name fizz@example.com |
| ``` |
| |
| If the default `ttl` for the check-out is higher than needed, set the check-out to last |
| for a shorter time by using: |
| |
| ```shell-session |
| $ vault write ldap/library/accounting-team/check-out ttl=30m |
| Key Value |
| --- ----- |
| lease_id ldap/library/accounting-team/check-out/gMonJ2jB6kYs6d3Vw37WFDCY |
| lease_duration 30m |
| lease_renewable true |
| password ?@09AZerLLuJfEMbRqP+3yfQYDSq6laP48TCJRBJaJu/kDKLsq9WxL9szVAvL/E1 |
| service_account_name buzz@example.com |
| ``` |
| |
| This can be a nice way to say, "Although I _can_ have a check-out for 24 hours, if I |
| haven't checked it in after 30 minutes, I forgot or I'm a dead instance, so you can just |
| check it back in." |
| |
| If no service accounts are available for check-out, Vault will return a 400 Bad Request. |
| |
| ```shell-session |
| $ vault write -f ldap/library/accounting-team/check-out |
| Error writing data to ldap/library/accounting-team/check-out: Error making API request. |
| |
| URL: POST http://localhost:8200/v1/ldap/library/accounting-team/check-out |
| Code: 400. Errors: |
| |
| * No service accounts available for check-out. |
| ``` |
| |
| To extend a check-out, renew its lease. |
| |
| ```shell-session |
| $ vault lease renew ldap/library/accounting-team/check-out/0C2wmeaDmsToVFc0zDiX9cMq |
| Key Value |
| --- ----- |
| lease_id ldap/library/accounting-team/check-out/0C2wmeaDmsToVFc0zDiX9cMq |
| lease_duration 10h |
| lease_renewable true |
| ``` |
| |
| Renewing a check-out means its current password will live longer, since passwords are rotated |
| anytime a password is _checked in_ either by a caller, or by Vault because the check-out `ttl` |
| ends. |
| |
| To check a service account back in for others to use, call: |
| |
| ```shell-session |
| $ vault write -f ldap/library/accounting-team/check-in |
| Key Value |
| --- ----- |
| check_ins [fizz@example.com] |
| ``` |
| |
| Most of the time this will just work, but if multiple service accounts are checked out by the same |
| caller, Vault will need to know which one(s) to check in. |
| |
| ```shell-session |
| $ vault write ldap/library/accounting-team/check-in service_account_names=fizz@example.com |
| Key Value |
| --- ----- |
| check_ins [fizz@example.com] |
| ``` |
| |
| To perform a check-in, Vault verifies that the caller _should_ be able to check in a given service account. |
| To do this, Vault looks for either the same [entity ID](/vault/tutorials/auth-methods/identity) |
| used to check out the service account, or the same client token. |
| |
| If a caller is unable to check in a service account, or simply doesn't try, |
| Vault will check it back in automatically when the `ttl` expires. However, if that is too long, |
| service accounts can be forcibly checked in by a highly privileged user through: |
| |
| ```shell-session |
| $ vault write -f ldap/library/manage/accounting-team/check-in |
| Key Value |
| --- ----- |
| check_ins [fizz@example.com] |
| ``` |
| |
| Or, alternatively, revoking the secret's lease has the same effect. |
| |
| ```shell-session |
| $ vault lease revoke ldap/library/accounting-team/check-out/PvBVG0m7pEg2940Cb3Jw3KpJ |
| All revocation operations queued successfully! |
| ``` |
| |
| ## Password generation |
| |
| This engine previously allowed configuration of the length of the password that is generated |
| when rotating credentials. This mechanism was deprecated in Vault 1.5 in favor of |
| [password policies](/vault/docs/concepts/password-policies). This means the `length` field should |
| no longer be used. The following password policy can be used to mirror the same behavior |
| that the `length` field provides: |
| |
| ```hcl |
| length=<length> |
| rule "charset" { |
| charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" |
| } |
| ``` |
| |
| ## LDAP password policy |
| |
| The LDAP secret engine does not hash or encrypt passwords prior to modifying |
| values in LDAP. This behavior can cause plaintext passwords to be stored in LDAP. |
| |
| To avoid having plaintext passwords stored, the LDAP server should be configured |
| with an LDAP password policy (ppolicy, not to be confused with a Vault password |
| policy). A ppolicy can enforce rules such as hashing plaintext passwords by default. |
| |
| The following is an example of an LDAP password policy to enforce hashing on the |
| data information tree (DIT) `dc=hashicorp,dc=com`: |
| |
| ``` |
| dn: cn=module{0},cn=config |
| changetype: modify |
| add: olcModuleLoad |
| olcModuleLoad: ppolicy |
| |
| dn: olcOverlay={2}ppolicy,olcDatabase={1}mdb,cn=config |
| changetype: add |
| objectClass: olcPPolicyConfig |
| objectClass: olcOverlayConfig |
| olcOverlay: {2}ppolicy |
| olcPPolicyDefault: cn=default,ou=pwpolicies,dc=hashicorp,dc=com |
| olcPPolicyForwardUpdates: FALSE |
| olcPPolicyHashCleartext: TRUE |
| olcPPolicyUseLockout: TRUE |
| ``` |
| |
| ## Tutorial |
| |
| Refer to the [LDAP Secrets Engine](/vault/tutorials/secrets-management/openldap) |
| tutorial to learn how to configure and use the LDAP secrets engine. |
| |
| |
| ## API |
| |
| The LDAP secrets engine has a full HTTP API. Please see the [LDAP secrets engine API docs](/vault/api-docs/secret/ldap) |
| for more details. |