Keeping your secrets private. Vault Project.

Vaulr Project

Every project contains secret configuration. Mostly such configurations are stored in .env files or simply written into config.

When your project really scales up and moreover, secrets change time to time as a matter of security, a better way to store might be required.

There are several alternatives available and most have own purpose (Chef, Puppet, Amazon KMS, Keywhiz). in this article I am going to focus on the Vault Project by Hashicorp.

Concepts of Vault

Vault is an encrypted storage for sensitive data, which uses CLI commands and API endpoints to manage configuration and storage data.

All data is being stored using paths. Every path contains raw value or key/value collection.

Internal Vault ACL contains various permissions to paths.

Initially there is a single admin account which is being used to configure the service.

Sealing

One of main concepts of Vault is sealing. When the vault has been initialized it remains in sealed state and 5 unseal keys are provided.

$ vault init
Unseal Key 1: gaCU7aagpbDuR3L+VSNNXhBQf9Qer+aE+3XleiKwpX1p
Unseal Key 2: r44P+YqSdCwapXMBRHzcJ4/8lCl9+z4xtSjsAEykVKrx
Unseal Key 3: 0u8pfpL1g4wQCWF0WBWQZ3uzrqs2SmVVrP/1e2tZgzXc
Unseal Key 4: blUhaHwJycutj4jo8C3c0AE1dSXGQBZhIvXas9WEl+8c
Unseal Key 5: jHpbbaE0FPxMvdL/wIryDecOaLwmHf+AYQnEvLtcMNpr
Initial Root Token: 56152536-59da-6c77-4305-6d4990606d07

Every unseal key has an equal power, however at least 3 of them are required to unseal the vault.

This is very much useful for security cases when not any person must have full power over the service.

$ vault unseal r44P+YqSdCwapXMBRHzcJ4/8lCl9+z4xtSjsAEykVKrx
Sealed: true
Key Shares: 5
Key Threshold: 3
Unseal Progress: 2
Unseal Nonce: d3828c0f-fa17-f0af-9aad-5d045f9a2d7d

Once you suspect that vault has been compromised or there is any other need to hide all your secrets, any of admin users can seal the vault back.

$ vault seal
Vault is now sealed.

After sealing, not any data can be written or read.

Authentication and policies

The default authentication driver is using token and only one token for root user is created.

Vault supports custom-defined policies for everything. Which means you are free to configure access rights in any way your architecture needs. Also, there is no direct relation of authentication tokens and policies defined. So these procedures can be run independently.

New token is created by sending API or CLI request to /auth/token/create endpoint.

$ vault write auth/token/create policies=webserver
Key            	Value
---            	-----
token          	dfaabe18-b572-5245-8b6b-184c3ce13bc1
token_accessor 	25e4c0a8-13a9-ff7e-23a1-ab96f7999268
token_duration 	168h0m0s
token_renewable	true
token_policies 	[default webserver]

Vault supports following authentication backends as well:

Storages

By default, development server uses in-memory storage, which is not persisted after shut down and does not provide much security.

Vault supports HCL or JSON files for configuration and supports various Storage backends including MySQL, PostgreSQL, Consul etc.

Storages are setup in configuration file and might require a little setup on the backend itself (like creating database in SQL). Read the docs for details.

storage "consul" {
  address = "127.0.0.1:8500"
  path    = "vault"
}

Secret backends

Storing and accessing secrets is the main workflow required with vault. And here Vault provides a lot of convenient features for your connected service to integrate seamlessly.

Every secret backend requires setup. The simplest one is generic which works as encrypted key/value storage. It might be used for storing any sensitive data.

$ vault write secret/foo \
    zip=zap \
    ttl=1h
Success! Data written to: secret/foo

And accessing data:

$ vault read secret/foo
Key               Value
---               -----
refresh_interval  3600
ttl               1h
zip               zap

The most common use case for such backend is storing something like Oauth secret IDs.

Database backend

Database backend, on the opposite to generic backend, provides seamless integration features to any SQL database.

First you need to mount the database backend to Vault:

$ vault mount database
Successfully mounted 'database' at 'database’!

Next, you need to provide Vault connection url and credentials:

$ vault write database/config/mysql \
    plugin_name=mysql-database-plugin \
    connection_url="root:[email protected](127.0.0.1:3306)/" \
    allowed_roles="readonly,webserver"

And next comes the most interesting part. You can define any custom roles, which execute SQL queries upon create or destroy. This gives you complete freedom of ACL management and granting access rights as well as storing authentication data in your database itself.

$ vault write database/roles/readonly \
    db_name=mysql \
    creation_statements="CREATE USER '{{name}}'@'%' IDENTIFIED BY '{{password}}';GRANT SELECT ON *.* TO '{{name}}'@'%';" \
    default_ttl="1h" \
    max_ttl="24h"
Success! Data written to: database/roles/readonly

Notice, how {{password}} and {{name}} variables are used. This means that upon each request to this role, new user will be created on SQL database and it’s credentials will be provided to your app.

$ vault read database/creds/readonly
Key             Value
---             -----
lease_id        database/creds/readonly/2f6a614c-4aa2-7b19-24b9-ad944a8d4de6
lease_duration  1h0m0s
lease_renewable true
password        8cab931c-d62e-a73d-60d3-5ee85139cd66
username        v-root-e2978cd0-

Now your app can read the credentials from storage to access SQL database.

Other backends

Vault currently doesn’t support custom backends creation, but this feature will be available soon.

Currently list of backends includes SSH, Consul, AWS, PKI, etc.

Client libraries

How can Vault be connected to your app? Very simple. On most cases it is enough to setup HTTP client, with proper requests to Vault API.

For example the role reading CLI requests mentioned above, can be done using HTTP:

$ curl \
    --header "X-Vault-Token: ..." \
    https://vault.localhost/v1/database/roles/readonly

But if you want better integration with your code, take a look at official List of Libraries, which includes PHP, Node.js, Java, C#, Go, Ruby and even Ansible.

Conclusion

Currently Vault is one of the most advanced encrypted key/value storages and if you infrastructure intends to grow up, you definitely need to pay attention to it.