--- layout: post title: Workflow - Using Chef Vaults in Workflow category: chef_automate_1 tags: [chef, workflow] summary: Secrets are hard. Shared key encryption is bad. Use Chef Vault. --- ## What is Chef Vault Chef Vault is a solution for securing data used during a Chef Client run. Chef Vault solves the shared key encryption problem present in encrypted data bags. Currently, encrypted data bags use shared key encryption; this means that both the key to encrypt and decrypt the data are the same. This leads to security issues due to the fact that this single key must be shared with anyone who wants to use the data. Chef Vault solves the shared key encryption problem by using the already present trust relationship between Chef clients and the Chef Server. By using each client's public key to encrypt the data and allowing the clients to decrypt the data using their secret private key at no point do sensitive keys need to be transmitted. For more info on how Chef Vaults work see [here](https://github.com/chef/chef-vault). --- ## Using Chef Vaults in Chef Automate Workflow The method demonstrated in this post uses a data bag called `workflow-vaults` to hold all of the Chef Vaults used by Workflow projects. The vaults inside of `workflow-vaults` are created with a specific naming and scoping scheme to enable the following: - Using the `*-slug` helper methods in [delivery-sugar](https://github.com/chef-cookbooks/delivery-sugar#workflow_project_slug) to load vaults - Sharing data within the Enterprise, Organization, and Project - Reducing variable duplication through merging down to a single Ruby hash --- ## Naming Scheme and Scope Vaults should be named and data be scoped as follows: | Vault
Name | Enterprise
Scope | Organization
Scope | Project
Scope | |------------------------------------------ | --------------------- | ----------------------- | ------------------ | | `#{ent_name}` | Y | Y | Y | | `#{ent_name}-#{org_name}` | | Y | Y | | `#{ent_name}-#{org_name}-#{project_name}` | | | Y | --- ## Creating the Chef Vaults There are a few options for creating Chef Vaults. You can set your `EDITOR` environment variable and type the JSON at creation, pass the JSON in as a string, or create JSON files on disk and reference them. I personally prefer creating the files on disk and referencing them. To use this method do the following: ### Create your directory structure ```none workflow-vaults ├── my_ent.json ├── my_ent-my_org.json ├── my_ent-my_org-project1.json └── my_ent-my_org-project2.json ``` ### Populate your JSON files (EXAMPLE) ```none { "id":"my_ent-my_org-project1", "secret_data": "something secret", "other_data": "something else" } ``` > NOTE: Keys with the same name in multiple vaults will be merged in such a way that Project level data will overwrite Organization data and Organization data will overwrite Enterprise data ### Create your vaults using `knife vault create` (EXAMPLE) ```none knife vault create \ workflow-vaults \ my_ent-my_org-project1 \ -J '/path/to/my_ent-my_org-project1.json' \ -A 'delivery,jerry' \ -S 'tags:delivery-job-runner' \ -M client ``` | Argument | Purpose | | --------------------------------- | --------------------------------------------------------- | | `workflow-vaults` | Selects the data bag that will contain our vaults | | `my_ent-my_org-my_project` | Sets the Chef Vault name in `workflow-vaults` | | `-A 'delivery,jerry'` | Comma separated list of Admins to grant access | | `-S 'tags:delivery-job-runner'` | SOLR search that gives access to all Workflow runners | | `-M client` | Enables creating vaults on Chef Server instead of locally | > NOTE: After creating your vaults it is recommended that you delete the JSON files from disk --- ## Using Chef Vaults in your build_cookbook There are two methods of accessing your Chef Vaults in your build_cookbook. You can add the code snippet below or use the built-in `get_workflow_vault_data` method included when you generate a cookbook with ChefDK. ### Using the built-in method By default, when you generate a cookbook with the ChefDK via `chef generate cookbook` it creates a `.delivery/build_cookbook`. This default build_cookbook exposes the `get_workflow_vault_data` method to you. To use this method just assign the output to a Ruby Hash: ```ruby vault_data = get_workflow_vault_data ``` ### Using a code snippet. > Note: This is functionally equivalent to using the `get_workflow_vault_data` method above From any recipe in your build_cookbook you can now use the below code to access your vault data: ```ruby # Load the `chef-vault` gem require 'chef-vault' # Load a Chef config that has rights to view workflow-vaults Chef::Config.from_file(automate_knife_rb) # Compile list of Vault items using `delivery-sugar` helper methods vault_items = [ workflow_change_enterprise, workflow_organization_slug, workflow_project_slug ] # Populate a list of hashes with empty hashes for non-existent vaults vault_data_list = [] vault_items.each do |item| vault_data_list.push( begin ChefVault::Item.load('workflow-vaults', item) rescue ChefVault::Exceptions::KeysNotFound {} end ) end # Merge each of the hashes above into a single hash vault_data = vault_data_list.inject(&:merge) # Raise an error if no data is found if vault_data.empty? raise 'No Chef Vaults found in \'workflow-vaults\' that match naming standard' end ``` > NOTE: The above code only works if you added `-A 'delivery'` when creating your Chef Vaults ## Extra Resources - [Chef Vault GitHub](https://github.com/chef/chef-vault) - [Chef Vault Blog Post](https://blog.chef.io/2016/01/21/chef-vault-what-is-it-and-what-can-it-do-for-you/) - [Knife Examples](https://github.com/chef/chef-vault/blob/master/KNIFE_EXAMPLES.md)