Encrypting dynamically to a set of nodes in chef is possible using data bags.
I created a plugin that creates a symmetric key, and two data bag item .json files based on name of the file you feed to it. ie where filebasename is filebasebasename.ext
One file it creates is filebasename_keys.json, which has encrypts the symmetric key to each node returned from the search using the nodes 'client api' public key.
The other is filebasename.json, which is an EncryptedDataBag encrypted using the symmetric shared key.
The symmetric key used for encryption of the file contents is never stored on disk and is only stored encrypted to the nodes returned from the search.
With knife_encrypted_plugin.rb in your .chef/plugins/knife directory and two nodes tagged with 'encrypt_to_me'
# knife encrypt 'tags:encrypt_to_me' afilename.secretfileextension
This would result in afilename.json and afilename_keys.json.
You would then upload them to a databag on the chef server for searching by nodes:
# knife data bag create databag_name
# knife data bag from file databag_name ./afilename.json
# knife data bag from file databag_name ./afilename_keys.json
To access the unencrypted contents (only from the nodes returned from search and that have the secret encrypted to their public key in afilename_keys), put the following in a recipe:
# Load the _keys data bag item, and extract the datbag key as encrypted the node
public_encrypted_secret = Base64.decode64(
Chef::DataBagItem.load('databag_name','afilename_keys')[node.name])
# use the private client_key file to create a decryptor
pkey = OpenSSL::PKey::RSA.new(open(Chef::Config[:client_key]).read())
# the private client_key is then used to decrypt data encrypted with the public_key
encrypted_data_bag_secret = pkey.private_decrypt public_encrypted_secret
# afilename works like any other encrypted data bag
# we just distributed the encrypted_data_bag_secret in a new way
afilename_contents = Chef::EncryptedDataBagItem.load(
'databag_name','afilename',encrypted_data_bag_secret)['contents']
Instead of searching for all nodes to extract node names, you can just list the nodes. Far more efficient:
Take care that on OHC
api.get("clients/CLIENT")
will return a hash, but not so in OSC where you will get an inflated object.Since you are using the
data_bag_shared_key
as the key to a symmetric cipher, I think you can just generate a secure random key. So you might find useful: