This week I researched chef-vault and struggled quite a bit with the documentation, so I thought I would write a bit of a tutorial on the technology for those who are interested in quickly understanding how it might work for their organizations.
Why chef-vault?
Encrypted data bags force you to copy the shared secret that is used for decryption to your infrastructure. It’s very easy to take that secret file and nefariously decrypt the data from somewhere else without anyone knowing about it. Chef-vault makes this much more difficult by giving both nodes and chef server users expressed permission to decrypt certain data. With chef-vault you don’t have to share a secret file with all of your nodes. This is a step up that simplifies everything.
The solution isn’t without its drawbacks. The main one is if you add nodes, you have to rerun something on the server to get that node to be able to decrypt the data bag. With Hashicorp’s vault you get better control over that, and better lease management, and credentials creation. To me, encrypted data bags are an unreliable used car, chef-vault is a nice mid-size sedan, and Hashicorp’s vault is like a luxury car.
So now that we know where the tool sits within our choices, let’s look at the basics:
Setup
To get started with chef-vault, have the latest ChefDK installed (0.12 or greater) and install the chef-vault gem:
chef gem install chef-vault
And then ensure you have a .chef directory that connects to a chef server.
Creation
Creating a vault is easy:
knife vault create passwords root -S "policy_name:webserver" -A "michael" -J root.json -M client
For whatever reason the knife vault
command doesn’t default to talk to a chef server. So to create a knife vault, you have to specify -M client
at the end. Or you can make your life easier going forward by adding this line to your knife.rb:
knife[:vault_mode] = 'client'
For the command, I used this root.json:
{
"username": "mhedgpeth",
"password": "myPassword"
}
Let’s review the options:
Team | Natural Alignment | Natural Misalignment |
---|---|---|
Development | Faster Delivery of features | Have to be engaged in operations, more “work” to do |
Operations | Less fires, more consistency | Have to learn a new skillset and be a beginner |
Security | More consistency, compliance | Automation can cause unknown vulnerabilities |
Business | Faster ROI for development, lower cost for operations, and a scale model that works | Takes ongoing investment in culture and tools |
This uploads two data bag items to a data bag called “passwords”:
root
which has the data aboveroot_keys
which stores the metadata about which clients can read and edit this data bag (as you specified above in the search criteria and administrators list.
Making it Even More Secure
Noah Kantrowitz helped me understand the vulnerabilities of the above approach using the -S
flag. With that flag, you give the nodes the ability to define the criteria by which they are allowed to decrypt the vault. So if you say I want nodes that have policy_name:webserver
to decrypt this data, all it takes is someone saying they are 'policy_name:webserver'
and they will be granted the keys.
A better way to handle this is through specifying each node explicitly through the -A flag. So your command would be:
knife vault create passwords root -A "michael,webserver1,webserver2" -J root.json -M client
Viewing a Vault
Now that we have created a vault, let’s view it:
knife vault show passwords root -M client
which will output:
id: root
password: myPassword
username: mhedgpeth
It lets me view it in cleartext because I am one of the administrators on the vault itself. If I want, I can even view it in JSON if you want to move the file to another chef server:
knife vault show passwords root -M client -Fjson
Viewing Encrypted Version
To view the encrypted version of the vault, you can simply use the normal commands for viewing data bag, just realizing that the vault data bag also has a _keys one too:
knife data bag show passwords root
and
knife data bag show password root_keys
Will show you lots of encrypted goodness which I will not show. The keys is helpful to see what clients are connected to it.
Adding nodes
Probably the weakest part of chef-vault is what to do when you add nodes. If you have an elastic situation this can be dicey, because when you add nodes, you have to run this command to generate keys for those nodes to read the encrypted data:
knife vault refresh passwords root --clean-unknown-clients
This updates the root_keys
encrypted data bag with information on the nodes that now match the search criteria. So it’s important to know that the nodes that can read a vault is a snapshot in time based on the search criteria, not a dynamic list.
If you aren’t using a search criteria, you’ll need to add nodes to the administrators list itself:
knife vault update passwords root -A 'newnode,newnode2'
Rotating keys
You might want to rotate the key that encrypts the data in the data bag. The way this works is the clients use their own key as a private key to combine with the public key on the chef server to decrypt the data bag’s key. That key encrypts the real data bag. This command will change that key:
knife vault rotate all keys
Cookbook Development
What use is a data bag without using it in a cookbook? To be able to deal with this data bag in the cookbook, include the chef-vault::default
recipe in your runlist. Then you will have the chef_vault_item
method that you can call like this:
item = chef_vault_item("passwords", "root")
password = item['password']
Using chef_vault_item
will make your cookbook more testable by test kitchen (see below).
Version Control
With data bags, we like to have a data_bags repository that we use to promote shared data and version control changes. This kind of thing doesn’t work with chef-vault. Instead you get a small team that can update the vault and then have them manually do it. This isn’t ideal, but secrets are hard and, as I wrote above, using a dedicated secrets management tool like Hashicorp Vault will keep you from that level of work.
Kitchen Support
To make this work in kitchen, just put a cleartext data bag in the data_bags folder that your kitchen run refers to (probably in test/integration/data_bags
). Then the vault commands fall back into using that dummy data when you use chef_vault_item
to retrieve it.
Conclusion
The chef-vault functionality is compelling enough for serious consideration. Hopefully this walkthrough will help you decide if it is right for you.