summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2020-02-12 19:54:50 -0800
committerGitHub <noreply@github.com>2020-02-12 19:54:50 -0800
commit62229382cbf4cadab76c9d75fb3d7d7337c138f2 (patch)
tree38c7b4e7751ac361fef553af83d600ffc61a56eb
parent7ed90d771a40eefcc1c399e889871556d8e3dc8b (diff)
parent19163410401c224dfaba82d288482528773f530e (diff)
downloadchef-62229382cbf4cadab76c9d75fb3d7d7337c138f2.tar.gz
Merge pull request #9364 from chef/vault_resource
Add chef_vault_secret resource from chef-vault cookbook
-rw-r--r--Gemfile.lock2
-rw-r--r--chef.gemspec1
-rw-r--r--kitchen-tests/cookbooks/end_to_end/recipes/chef-vault.rb32
-rw-r--r--kitchen-tests/cookbooks/end_to_end/recipes/default.rb6
-rw-r--r--lib/chef/resource/chef_vault_secret.rb134
-rw-r--r--lib/chef/resources.rb1
-rw-r--r--spec/unit/resource/chef_vault_secret_spec.rb40
7 files changed, 214 insertions, 2 deletions
diff --git a/Gemfile.lock b/Gemfile.lock
index 5703f26bb7..0a982ac873 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -33,6 +33,7 @@ PATH
bundler (>= 1.10)
chef-config (= 16.0.63)
chef-utils (= 16.0.63)
+ chef-vault
chef-zero (>= 14.0.11)
diff-lcs (~> 1.2, >= 1.2.4)
ed25519 (~> 1.2)
@@ -65,6 +66,7 @@ PATH
bundler (>= 1.10)
chef-config (= 16.0.63)
chef-utils (= 16.0.63)
+ chef-vault
chef-zero (>= 14.0.11)
diff-lcs (~> 1.2, >= 1.2.4)
ed25519 (~> 1.2)
diff --git a/chef.gemspec b/chef.gemspec
index 1ec8c967ee..9046365b9b 100644
--- a/chef.gemspec
+++ b/chef.gemspec
@@ -41,6 +41,7 @@ Gem::Specification.new do |s|
s.add_dependency "diff-lcs", "~> 1.2", ">= 1.2.4"
s.add_dependency "ffi-libarchive"
s.add_dependency "chef-zero", ">= 14.0.11"
+ s.add_dependency "chef-vault"
s.add_dependency "plist", "~> 3.2"
s.add_dependency "iniparse", "~> 1.4"
diff --git a/kitchen-tests/cookbooks/end_to_end/recipes/chef-vault.rb b/kitchen-tests/cookbooks/end_to_end/recipes/chef-vault.rb
new file mode 100644
index 0000000000..504a91da2b
--- /dev/null
+++ b/kitchen-tests/cookbooks/end_to_end/recipes/chef-vault.rb
@@ -0,0 +1,32 @@
+#
+# Cookbook:: end_to_end
+# Recipe:: chef-vault
+#
+# Copyright:: 2020, Chef Software, Inc.
+#
+
+chef_data_bag 'creds'
+
+openssl_rsa_private_key '/root/bob_bobberson.pem' do
+ key_length 2048
+ action :create
+end
+
+chef_client 'bob_bobberson' do
+ source_key_path '/root/bob_bobberson.pem'
+end
+
+chef_node 'bob_bobberson'
+
+chef_vault_secret 'super_secret_1' do
+ data_bag 'creds'
+ raw_data('auth' => '1234')
+ admins 'bob_bobberson'
+ search '*:*'
+end
+
+chef_vault_secret 'super_secret_2' do
+ data_bag 'creds'
+ raw_data('auth' => '4321')
+ admins 'bob_bobberson'
+end \ No newline at end of file
diff --git a/kitchen-tests/cookbooks/end_to_end/recipes/default.rb b/kitchen-tests/cookbooks/end_to_end/recipes/default.rb
index 0af35f8c7a..6202efcc68 100644
--- a/kitchen-tests/cookbooks/end_to_end/recipes/default.rb
+++ b/kitchen-tests/cookbooks/end_to_end/recipes/default.rb
@@ -2,7 +2,7 @@
# Cookbook:: end_to_end
# Recipe:: default
#
-# Copyright:: 2014-2019, Chef Software Inc.
+# Copyright:: 2014-2020, Chef Software Inc.
#
hostname "chef-bk-ci.chef.io"
@@ -33,7 +33,7 @@ yum_repository "epel" do
gpgkey "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-#{node["platform_version"].to_i}"
gpgcheck true
mirrorlist "https://mirrors.fedoraproject.org/metalink?repo=epel-#{node["platform_version"].to_i}&arch=$basearch"
- only_if { platform_family?("rhel") }
+ only_if { rhel? }
end
build_essential do
@@ -118,4 +118,6 @@ end
end
end
+include_recipe "::chef-vault" unless includes_recipe?("end_to_end::chef-vault")
+
include_recipe "::tests"
diff --git a/lib/chef/resource/chef_vault_secret.rb b/lib/chef/resource/chef_vault_secret.rb
new file mode 100644
index 0000000000..a2292439e6
--- /dev/null
+++ b/lib/chef/resource/chef_vault_secret.rb
@@ -0,0 +1,134 @@
+#
+# Author:: Joshua Timberman <joshua@chef.io>
+# Copyright:: 2014-2020, Chef Software Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require_relative "../resource"
+require "chef-vault"
+
+class Chef
+ class Resource
+ class ChefVaultSecret < Chef::Resource
+ resource_name :chef_vault_secret
+ provides :chef_vault_secret
+
+ introduced "16.0"
+ description "Use the chef_vault_secret resource to store secrets in Chef Vault items. Where possible and relevant, this resource attempts to map behavior and functionality to the knife vault sub-commands."
+ examples <<~DOC
+ To create a 'foo' item in an existing 'bar' data bag:
+
+ ```ruby
+ chef_vault_secret 'foo' do
+ data_bag 'bar'
+ raw_data({'auth' => 'baz'})
+ admins 'jtimberman'
+ search '*:*'
+ end
+ ```
+
+ To allow multiple admins access to an item:
+
+ ```ruby
+ chef_vault_secret 'root-password' do
+ admins 'jtimberman,paulmooring'
+ data_bag 'secrets'
+ raw_data({'auth' => 'DontUseThisPasswordForRoot'})
+ search '*:*'
+ end
+ ```
+ DOC
+
+ property :id, String, name_property: true,
+ description: "The name of the data bag item if it differs from the name of the resource block"
+
+ property :data_bag, String, required: true, desired_state: false,
+ description: "The data bag that contains the item."
+
+ property :admins, [String, Array], required: true, desired_state: false,
+ description: "A list of admin users who should have access to the item. Corresponds to the 'admin' option when using the chef-vault knife plugin. Can be specified as a comma separated string or an array."
+
+ property :clients, [String, Array], desired_state: false,
+ description: "A search query for the nodes' API clients that should have access to the item."
+
+ property :search, String, default: "*:*", desired_state: false,
+ description: "Search query that would match the same used for the clients, gets stored as a field in the item."
+
+ property :raw_data, [Hash, Mash], default: {},
+ description: "The raw data, as a Ruby Hash, that will be stored in the item."
+
+ property :environment, [String, NilClass], desired_state: false,
+ description: "The Chef environment of the data if storing per environment values."
+
+ load_current_value do
+ begin
+ item = ChefVault::Item.load(data_bag, id)
+ raw_data item.raw_data
+ clients item.get_clients
+ admins item.get_admins
+ search item.search
+ rescue ChefVault::Exceptions::KeysNotFound
+ current_value_does_not_exist!
+ rescue Net::HTTPServerException => e
+ current_value_does_not_exist! if e.response_code == "404"
+ end
+ end
+
+ action :create do
+ description "Creates the item, or updates it if it already exists."
+
+ converge_if_changed do
+ item = ChefVault::Item.new(new_resource.data_bag, new_resource.id)
+
+ Chef::Log.debug("#{new_resource.id} environment: '#{new_resource.environment}'")
+ item.raw_data = if new_resource.environment.nil?
+ new_resource.raw_data.merge("id" => new_resource.id)
+ else
+ { "id" => new_resource.id, new_resource.environment => new_resource.raw_data }
+ end
+
+ Chef::Log.debug("#{new_resource.id} search query: '#{new_resource.search}'")
+ item.search(new_resource.search)
+ Chef::Log.debug("#{new_resource.id} clients: '#{new_resource.clients}'")
+ item.clients([new_resource.clients].flatten.join(",")) unless new_resource.clients.nil?
+ Chef::Log.debug("#{new_resource.id} admins (users): '#{new_resource.admins}'")
+ item.admins([new_resource.admins].flatten.join(","))
+ item.save
+ end
+ end
+
+ action :create_if_missing do
+ description "Calls the create action unless it exists."
+
+ action_create if current_resource.nil?
+ end
+
+ action :delete do
+ description "Deletes the item and the item's keys ('id'_keys)."
+
+ converge_by("remove #{new_resource.id} and #{new_resource.id}_keys from #{new_resource.data_bag}") do
+ chef_data_bag_item new_resource.id do
+ data_bag new_resource.data_bag
+ action :delete
+ end
+
+ chef_data_bag_item [new_resource.id, "keys"].join("_") do
+ data_bag new_resource.data_bag
+ action :delete
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index 70b7c88fa8..3681d9bd54 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -29,6 +29,7 @@ require_relative "resource/cookbook_file"
require_relative "resource/chef_gem"
require_relative "resource/chef_handler"
require_relative "resource/chef_sleep"
+require_relative "resource/chef_vault_secret"
require_relative "resource/chocolatey_config"
require_relative "resource/chocolatey_feature"
require_relative "resource/chocolatey_package"
diff --git a/spec/unit/resource/chef_vault_secret_spec.rb b/spec/unit/resource/chef_vault_secret_spec.rb
new file mode 100644
index 0000000000..79b3bf8996
--- /dev/null
+++ b/spec/unit/resource/chef_vault_secret_spec.rb
@@ -0,0 +1,40 @@
+#
+# Copyright:: 2020, Chef Software, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+
+describe Chef::Resource::ChefVaultSecret do
+ let(:resource) { Chef::Resource::ChefVaultSecret.new("foo") }
+
+ it "has a resource name of :chef_vault_secret" do
+ expect(resource.resource_name).to eql(:chef_vault_secret)
+ end
+
+ it "sets the default action as :create" do
+ expect(resource.action).to eql([:create])
+ end
+
+ it "id is the name property" do
+ expect(resource.id).to eql("foo")
+ end
+
+ it "supports :create, :create_if_missing, and :delete actions" do
+ expect { resource.action :create }.not_to raise_error
+ expect { resource.action :create_if_missing }.not_to raise_error
+ expect { resource.action :delete }.not_to raise_error
+ end
+end