Dynamic Password Rotation for vCenter with HashiCorp Vault | Writing about tech and anything else I find interesting

Dynamic Password Rotation for vCenter with HashiCorp Vault

The proliferation of sharing code over the last few years has led to an exponential number of usernames and passwords being accidentally exposed to the world. This is true for both hard coded application credentials in XML files, and infrastructure credentials in PowerShell, Python, and even my beloved Terraform. One of the easiest ways to combat this problem is to make sure that those credentials aren’t valid for long enough that they could be abused.

In this post we are going to take a look at how you can leverage HashiCorp Vault to dynamically rotate Active Directory credentials for use with vSphere - or anything else that supports Active Directory as an identity source.

Active Directory Configuration

In order to rotate account passwords, we need to provide Vault with a user account that has appropriate permissions to change passwords in your domain. My approach to this was to create an AD user called “Vault Account”, to whom I then delegated permissions to reset passwords in a single OU, which happens to be called “Vault Managed Accounts”. In this OU, I place the service accounts that I want to rotate the passwords of, including the account I use to login to vCenter.

Assigning a user for password rotation

vCenter Configuration

I’m not here to rehash the vCenter documentation, so if you don’t have your vCenter integrated with Active Directory yet, have a read here.
Once that is done, add your user account as explained here.

Assigning administrator role

Now that my account has been added to the administrator role, I’m ready to head over to Vault and setup the password rotation. Before you ask - yes, I should create and use a custom role. That’s outside the scope of this post.

Setting up Vault

You can find a Packer file and sample Terraform code in this repo to get a single node Vault instance up and running in your vSphere environment. If you just want to play around with this use case without all the fuss of deploying, you could also install the Vault binary on your local machine, or grab a Docker image.

If you are coming in from a clean install, you can work through this with the root token. If however, you are attempting to do this properly then the account you are using to set this up will need the following policy applied:

Once you have Vault running and initialised you will need to enable the Active Directory secrets engine.

vault secrets enable ad -default_lease_ttl_seconds=300

This enables the ad secrets engine at the default path (ad) and provides a single tuning parameter to the secrets engine to tell it that we want the password TTL to be a default of 300 seconds.

With that out of the way, we want to tell Vault how to go about communicating with Active Directory to perform password rotation.

An few important notes here.

  • I discovered along the way that you can only change passwords over a secure ldap connection, so don’t try and use url=ldap://
  • If you created your account in the Users “OU” pay attention to the fact that in the binddn, it is actually a CN, and not an OU.
  • If the accounts you intend to manage are (or have been) Domain Admins, then you will have permissions issues using Delegated Authority. They can be resolved, but definitely something to be aware of.

The final configuration step is to tell Vault which accounts you want it to manage passwords for. We do this by creating a role for the ad secrets engine, and mapping it to the AD user account like so.

When it comes time for me to kick off a run with Terraform, all I need to do is issue a simple command to read the credentials from my role:
Requesting credentials

Every time I perform that read, Vault will check the TTL of the password (300 seconds in this case) rotate it if needed, and then return the password value to me.

If I wanted to be clever and write that password to an environment variable that Terraform could read in, I might shift the output format to json, and use jq to grab the password like so:
Setting vSphere password for Terraform

With that, you are ready to go and can begin to worry less about accidentally sharing vCenter credentials with the world!

If you have any questions about doing this in a more complex scenario, hit me up on Twitter.