Keeping your secrets private. Vault 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 ...
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.
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:
- App ID
- AppRole
- AWS
- GitHub
- LDAP
- MFA
- Okta
- RADIUS
- TLS Certificates
- Username & Password
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" }
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:mysql@tcp(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.
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.
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.