An application cannot always work with dynamic credentials: some systems require a pre-created account with a fixed name. In this case, Stronghold takes over the password of an existing account and changes it on a schedule. Consumers always get the current password from Stronghold.

Goal

Set up automatic password rotation for a PostgreSQL service account and for an LDAP or Active Directory account, and set up checking out accounts from a shared pool (library) with check-in.

Prerequisites

To follow this example, you need:

  • A Stronghold token with permissions to configure the database and ldap secrets engines.
  • A configured PostgreSQL connection in the database engine (for example, database/config/myapp-postgres from Dynamic PostgreSQL credentials).
  • An existing billing_svc account in PostgreSQL.
  • An LDAP or Active Directory server and an account for Stronghold that can change service account passwords.

Do not assign a static role to the account that Stronghold uses to connect in config/. After rotation, the password in config/ becomes invalid, and all roles of this connection stop working. To change the password of the Stronghold service account, use rotate-root.

Part 1. Database static role

Create a static role for an existing database account:

  1. Allow the connection to use the new role by adding it to allowed_roles:

    d8 stronghold write database/config/myapp-postgres allowed_roles="myapp,billing-svc"

    On update, the passed parameters are merged with the stored ones, so you do not need to pass the other connection parameters again.

  2. Create a static role. Stronghold changes the account password immediately and then every 24 hours:

    d8 stronghold write database/static-roles/billing-svc db_name="myapp-postgres" username="billing_svc" rotation_period=24h
  3. Create a policy for consumers:

    d8 stronghold policy write billing-svc-creds - <<'POLICY'
    path "database/static-creds/billing-svc" {
      capabilities = ["read"]
    }
    POLICY
  4. Get the current credentials:

    d8 stronghold read database/static-creds/billing-svc

    The ttl field shows the time until the next rotation, and last_vault_rotation shows when the password was last changed.

  5. If needed, change the password immediately, for example if you suspect a compromise:

    d8 stronghold write -f database/rotate-role/billing-svc

The application must request the password again after each rotation. For applications that read the password from a file, use Stronghold Agent templates: Agent re-renders the file after rotation and runs a reload command.

Part 2. LDAP static role

Create a static role for an existing LDAP account:

  1. Enable the secrets engine and configure the connection. For Active Directory, set schema=ad:

    d8 stronghold secrets enable ldap
    d8 stronghold write ldap/config binddn="CN=stronghold,OU=Service,DC=example,DC=com" bindpass="<BIND_PASSWORD>" url=ldaps://dc01.example.com schema=ad

    <BIND_PASSWORD> is the current password of the CN=stronghold account. In the next step, Stronghold replaces it with a generated one.

  2. Rotate the Stronghold account password so that only Stronghold knows it:

    d8 stronghold write -f ldap/rotate-root
  3. Create a static role for the service account:

    d8 stronghold write ldap/static-role/svc-backup dn="CN=svc-backup,OU=Service,DC=example,DC=com" username="svc-backup" rotation_period=24h
  4. Get the current password:

    d8 stronghold read ldap/static-cred/svc-backup
  5. Rotate the password manually if needed:

    d8 stronghold write -f ldap/rotate-role/svc-backup

The LDAP engine does not hash the password before writing it. Make sure the LDAP server has a password policy that stores passwords hashed. For details, see LDAP secrets engine.

Part 3. Service account library

A library is a pool of service accounts that are lent out temporarily. When an account is checked in, Stronghold changes its password, so the password given to the previous user stops working.

  1. Create a library:

    d8 stronghold write ldap/library/ops-team service_account_names="ops-svc1@example.com,ops-svc2@example.com" ttl=4h max_ttl=8h
  2. Check out an account:

    d8 stronghold write -f ldap/library/ops-team/check-out

    The response contains service_account_name, password, and lease_id.

  3. Check the account back in after work:

    d8 stronghold write ldap/library/ops-team/check-in service_account_names="ops-svc1@example.com"

    If the account is not checked in, Stronghold checks it in automatically when the lease ttl expires.

Verification

Check the result:

  1. Read database/static-creds/billing-svc, run rotate-role, and read the credentials again: the password must change.

  2. Connect to PostgreSQL with the new password and make sure the old password is rejected.

  3. Check the library status:

    d8 stronghold read ldap/library/ops-team/status

    Checked-out accounts are marked available:false.

Cleanup

Deleting a static role does not change the password. Before deleting, rotate the password manually so that the last value issued by Stronghold stops working:

d8 stronghold write -f database/rotate-role/billing-svc
d8 stronghold delete database/static-roles/billing-svc

d8 stronghold write -f ldap/rotate-role/svc-backup
d8 stronghold delete ldap/static-role/svc-backup

d8 stronghold delete ldap/library/ops-team
d8 stronghold policy delete billing-svc-creds

After deletion, hand password management back to the account owners or disable the accounts.

Additional resources