Vault
Configure password generation polices for secret engines
Vault supports configurable password generation defined by a password policy. A policy defines the rules and requirements that the password must adhere and can provide that password directly through a new endpoint or within secrets engines.
In the dynamic secrets tutorial, you configured Vault to generate dynamic credentials for a PostgreSQL database. In this tutorial, you will learn how to configure Vault to generate passwords that meet your organization's standards.
If you are not familiar with how to configure Vault for dynamic credentials, follow the database secrets engine tutorial before you begin.
Scenario
HashiCups has a password policy that must be used for all application. Vault's database secrets engine generates passwords that adhere to a default pattern.
Secrets engines with support for password policies:
You can edit the default pattern to fit usecases such as:
- Lengths that are smaller or exceed the default length
- Differing character sets
- Frequency of characters
- Disallowed repetition
- Disallowed words from a dictionary
Oliver will create a custom password policy that fulfills HashiCups security standards. The password requirements are:
- Length of 20 characters
- Multiple character sets
- Minimum number of characters from each set
Launch Terminal
This tutorial includes a free interactive command-line lab that lets you follow along on actual cloud infrastructure.
Prerequisites
This lab was tested on macOS using an x86_64 based and Apple silicon-based processors. You may also run this tutorial by clicking the Start interactive lab button.
To perform the tasks described in this tutorial, you need to have:
- Docker to run a Vault and PostgreSQL container.
- Vault binary installed.
- Git installed.
- Terraform installed.
Policy requirements
Note
For the purpose of this tutorial, you can use your 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, you need a policy for the operations team to configure the database secrets engine and manage password policies.
Vault admin policy
This policy allows you to configure the database secrets engine and manage password policies.
# Mount the database secret engine
path "sys/mounts/database" {
capabilities = [ "create", "update", "delete" ]
}
# Manage leases for the database secrets engine readonly role
path "sys/policies/password/example/generate" {
capabilities = [ "read" ]
}
# Generate a password using the example password policy
path "sys/policies/password/example" {
capabilities = [ "read", "create", "delete", "update", "list" ]
}
# Configure the database secrets engine and create roles
path "database/*" {
capabilities = [ "create", "read", "update", "delete", "list" ]
}
If you are not familiar with policies, complete the policies tutorial.
Set up the lab
Clone the
learn-vault-dynamic-credentialsrepository.$ git clone git@github.com:hashicorp-education/learn-vault-dynamic-credentials.gitChange into the
learn-vault-dynamic-credentialsdirectory.$ cd learn-vault-dynamic-credentialsDeploy the Vault and PostgreSQL containers.
$ terraform -chdir=vault-dynamic-creds-docker/ init && \ terraform -chdir=vault-dynamic-creds-docker/ apply -auto-approveExample output:
Initializing the backend... Initializing provider plugins... - Finding kreuzwerker/docker versions matching "3.0.2"... - Installing kreuzwerker/docker v3.0.2... ...snip... Apply complete! Resources: 4 added, 0 changed, 0 destroyed. Outputs: POSTGRES_URL = "export TF_VAR_POSTGRES_URL=172.17.0.2:5432" POSTGRES_URL_HOST = "export 127.0.0.1:5432" VAULT_ADDR = "export VAULT_ADDR=http://127.0.0.1:8200" VAULT_TOKEN = "export VAULT_TOKEN=root"Using
terraform outputexport the environment variables.Example:
$ eval "$(terraform output -state=vault-dynamic-creds-docker/terraform.tfstate -json ENVIRONMENT_VARIABLES | jq -r ".")"Verify the PostgreSQL and Vault containers have started.
$ docker ps -f name=learn --format "table {{.Names}}\t{{.Status}}" NAMES STATUS learn-postgres Up 4 minutes learn-vault Up 4 minutesVault and PostgreSQL are running. Vault connects to PostgreSQL over the Docker bridge network.
Apply the PostgreSQL configuration used in the dynamic secrets tutorial.
$ terraform -chdir=vault-dynamic-creds-postgres/ init && \ terraform -chdir=vault-dynamic-creds-postgres/ apply -auto-approveExample output:
Initializing the backend... Initializing provider plugins... - Finding cyrilgdn/postgresql versions matching "1.25.0"... - Installing cyrilgdn/postgresql v1.25.0... - Installed cyrilgdn/postgresql v1.25.0 (self-signed, key ID 418F268A88A6D481) ...snip... Plan: 2 to add, 0 to change, 0 to destroy. postgresql_role.ro: Creating... postgresql_grant.readonly_tables: Creating... postgresql_role.ro: Creation complete after 0s [id=ro] postgresql_grant.readonly_tables: Creation complete after 0s [id=ro_postgres_public_table] Apply complete! Resources: 2 added, 0 changed, 0 destroyed.Apply the Vault configuration used in the dynamic secrets tutorial.
$ terraform -chdir=vault-dynamic-creds-vault/ init && \ terraform -chdir=vault-dynamic-creds-vault/ apply -auto-approveExample output:
Initializing the backend... Initializing provider plugins... - Finding hashicorp/vault versions matching "4.5.0"... ...snip... vault_database_secrets_mount.database: Creating... vault_database_secrets_mount.database: Creation complete after 0s [id=database] vault_database_secret_backend_role.readonly: Creating... vault_database_secret_backend_role.readonly: Creation complete after 0s [id=database/roles/readonly] Apply complete! Resources: 2 added, 0 changed, 0 destroyed.Vault and PostgreSQL are running and configured. You are ready to proceed with the tutorial.
Request credentials with default password policy
Each supported secrets engine has a default password policy that generates passwords.
Generate credentials from the
readonlyrole.$ vault read database/creds/readonlyExample output:
Key Value --- ----- lease_id database/creds/readonly/5ZJXSIyWN5k4A8u6AMZs5I0s lease_duration 1h lease_renewable true password -LL23iRQqsAD0YmS1eq3 username v-token-readonly-xboXz3doC1jBe9ntlKaA-1737490496The credentials display the
usernameandpasswordgenerated. The password generated adheres to the default password policy for the secrets engine.
Define a password policy
Create a policy file named
example_policy.hcl.$ tee example_policy.hcl <<EOF length=20 rule "charset" { charset = "abcdefghijklmnopqrstuvwxyz" min-chars = 1 } rule "charset" { charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" min-chars = 1 } rule "charset" { charset = "0123456789" min-chars = 1 } rule "charset" { charset = "!@#$%^&*" min-chars = 1 } EOFPolicies use the HashiCorp Configuration Language (HCL). The
lengthfield sets the length of the password returned to20characters. Each rule stanza defines a character set and the minimum number of occurrences those characters need to appear in the generated password. These rules are cumulative so each one adds more requirements on the password generated.Create a Vault password policy named
examplewith the password policy rules defined inexample_policy.hcl.$ vault write sys/policies/password/example policy=@example_policy.hcl Success! Data written to sys/polices/password/example_policyThis policy is accessible directly to generate a password or referenced by its name
examplewhen configuring supported secrets engines.Generate a password from the
examplepassword policy.$ vault read sys/policies/password/example/generate Key Value --- ----- password #v!RQDHxHunJ1TUmCyysThe password generated adheres to the requirements:
- length of 20 characters
- at least 1 uppercase character
- at least 1 lowercase character
- at least 1 number
- at least 1 symbol
Configure a custom password policy
Review the current database secrets engine configuration.
$ vault read database/config/postgres Key Value --- ----- allowed_roles [readonly] connection_details map[connection_url:postgresql://{{username}}:{{password}}@172.17.0.2:5432/postgres?sslmode=disable disable_escaping:false max_open_connections:2 username:root] password_policy n/a plugin_name postgresql-database-plugin plugin_version n/a root_credentials_rotate_statements [] verify_connection trueThe secrets engine initially configured does not contain a password policy.
Configure the secrets engine to use the
examplepassword policy.$ vault write database/config/postgres password_policy="example" Success! Data written to: database/config/postgresReview the updated database secrets engine configuration.
$ vault read database/config/postgresExample output:
Key Value --- ----- allowed_roles [readonly] connection_details map[connection_url:postgresql://{{username}}:{{password}}@172.17.0.2:5432/postgres?sslmode=disable disable_escaping:false max_open_connections:2 username:root] password_policy example ...snip...The secrets engine now generates passwords that adhere to the
examplepassword policy.Generate credentials from the
readonlyrole with theexamplepassword policy.$ vault read database/creds/readonly Key Value --- ----- lease_id database/creds/readonly/AppmaMdS5mtMPwaZOnNnX2O9 lease_duration 1h lease_renewable true password ba8oWN@106l6uffb*GbY username v-token-readonly-W1guRN3Sr2SEw4Oj0uJU-1737491327The credentials display the
usernameandpasswordgenerated. Thepasswordgenerated adheres to the example password policy defined in the secrets engine's configuration.
Clean up
Destroy the Terraform resources.
$ terraform -chdir=vault-dynamic-creds-vault/ destroy -auto-approve && \ terraform -chdir=vault-dynamic-creds-postgres/ destroy -auto-approve && \ terraform -chdir=vault-dynamic-creds-docker/ destroy -auto-approveUnset the environment variables.
$ unset VAULT_ADDR VAULT_TOKEN TF_VAR_POSTGRES_URLDelete the
example_policy.hclpassword policy file.$ rm example_policy.hcl
Summary
You requested credentials from the database secrets engine that generated credentials with the default password policy. Then you defined a password policy and generated a password. Finally, you updated the secrets engine configuration to use the custom password policy.