Storing sensitive Data in Cookbooks


Deploying sensitive data with Chef and storing passwords in cookbooks leavs you and your system open to attack. Best option is to remove data from the cookbooks itself as it will remove opportunity fot it to be discovered.

In this article, we will be focusing on using knife to create, read and write databags, which are typically used to store and deploy sensitive data outside of a version control system.

Create Cookbook

Before we start we have to create cookbook

Storing Data in Bags

A data bag is global variable that is stored as JSON data and it’s accesible from a Chef server. A data bag is indexed for searching.

Data bag example:

"id" : "unique_value"
"name": "Emin"
"surname": "Dedic" 
"password": "thisismypassword"

Data Bag Configuration

I’m going to write how to create, edit, delete and show Data Bags and its Items.

Create Data Bag

We are going to create data bag locally named data_for_bag.json

Create data bag with create argument to add a data bag to the Chef server.

$ knife data bag create account_bag

We will upload items to data beg from file that we made:

$ knife data bag from file account_bag ./mail_data.json

Updated data_bag_item[account_bag::mail]

Edit Data Bag

For using knife edit command we need to provide editor. If you didn’t configurate it you need to add text editor that will be used by knife. For example, to configure knife to open the nano text editor, add the following to your knife.rb file:

knife[:editor] = "/usr/bin/nano"

Edit out databag

$ EDITOR=nano knife data bag edit account_bag mail

Delete Data Bag

We have to use delete argument to delete data bag and item from Chef server:

$ knife data bag delete account_bag 

Show the Data Bag Items

To verify this worked, we can verify the databag exists:

$ knife data bag list

…and then view its contents:

$ knife data bag show account_bag

Output: mail

Chek mail secret:

$ knife data bag show account_bag mail

id:       mail
account:  [email protected]
password: eydujahy3u78ddj

Now, our cookbook can use this information during a chef run!

Inserting Data Bag Item Value into a Chef Recipe

We are going to use data bag data for mail notifications for monit on our server:

Loading data into Chef recepie:

# Made variable with data_bag_item method
mail_account = data_bag_item('account_bag', 'mail')

template "/etc/monit/conf.d/mail" do
  source "monit/mail.erb"
  owner "root"
  group "root"
  mode 00755
  verify "monit -t -c %{path}"
  notifies :reload, 'service[monit]', :immediately

  # Put to variables
    username: mail_account['account'],
    password: mail_account['password']

And then loading it into mail template:

set mailserver port 587
    # Adding variables from mail.rb recepie
    username "<%= @username %>" password "<%= @password %>"
    using tlsv1
    with timeout 30 second

After doing this things, our data is still exposed on chef server or our version control account.

Encrypting in Data Bag

A data bag item may be encrypted using sharen secret encryption. This allows each data bag item to store confidental informations (in our case, for example account password).

Create Secret Key for Encryption

We have to take data bag item and encrypt it with shared secret.

First of all we have to create a shared secret. Let’s secure data in bag using openssl:

$ openssl rand -base64 512 | tr -d '\r\n' > my_secret

Encrypt Our Existing Data Bag

Encrypt Data Bag from created my_secret file:

$ knife data bag from file account_bag ./mail_data.json --secret-file my_secret

If you wnat show item value and specify the secret-file on the command line, you’ll get the original values back.

$ knife data bag show encrypted mail --secret-file my_secret

Copy Shared Secret to Node

After this, we have to copy out my_secret file to server and named file encrypted_data_bag_secret file.

$ scp my_secret [email protected]:/etc/chef/encrypted_data_bag_secret

And, we don’t have to change anything in recepie for mail account, becouse Chef client will look to Data Beg item, find secret on server and decrypt an informations.

Using this approach, it is possible to store sensitive data directly in the repo without exposing those credentials to the wrong individuals.

Now, the secret is available to only the nodes and workstations that have the shared secret.