summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortylercloke <tylercloke@gmail.com>2015-04-29 18:07:11 -0700
committertylercloke <tylercloke@gmail.com>2015-04-30 15:29:51 -0700
commit69647cefc41058e4d653e113b47107b9eb926430 (patch)
tree63884ee62cf3fe103e40e49e09ca114becd9d369
parent00fff6a2dd7a33554413b1f1b140d0cf9856f303 (diff)
downloadchef-69647cefc41058e4d653e113b47107b9eb926430.tar.gz
Implemented `knife user key show` and `knife client key show`.
-rw-r--r--RELEASE_NOTES.md8
-rw-r--r--lib/chef/knife/client_key_delete.rb2
-rw-r--r--lib/chef/knife/client_key_show.rb76
-rw-r--r--lib/chef/knife/key_edit.rb2
-rw-r--r--lib/chef/knife/key_show.rb53
-rw-r--r--lib/chef/knife/key_update_base.rb55
-rw-r--r--lib/chef/knife/user_key_create.rb1
-rw-r--r--lib/chef/knife/user_key_delete.rb2
-rw-r--r--lib/chef/knife/user_key_show.rb76
-rw-r--r--spec/unit/knife/key_delete_spec.rb2
-rw-r--r--spec/unit/knife/key_show_spec.rb126
11 files changed, 344 insertions, 59 deletions
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index b05498e36d..4520a37d44 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,2 +1,10 @@
# Chef Client Release Notes <unreleased>:
+## Knife Key Management Commands for Users and Clients
+
+`knife user` and `knife client` now have a suite of subcommands that live under
+the `key` subcommand. These subcommands allow you to list, show, create, delete
+and edit keys for a given user or client. They can be used to implement
+key rotation with multiple expiring keys for a single actor or just
+for basic key management. See `knife user key` and `knife client key`
+for a full list of subcommands and their usage.
diff --git a/lib/chef/knife/client_key_delete.rb b/lib/chef/knife/client_key_delete.rb
index 91c088a1d1..8ecdfe1ec8 100644
--- a/lib/chef/knife/client_key_delete.rb
+++ b/lib/chef/knife/client_key_delete.rb
@@ -27,7 +27,7 @@ class Chef
#
# @attr_reader [String] actor the name of the client that this key is for
class ClientKeyDelete < Knife
- banner "knife client key delete CLIENT KEYNAME"
+ banner "knife client key delete CLIENT KEYNAME (options)"
attr_reader :actor
diff --git a/lib/chef/knife/client_key_show.rb b/lib/chef/knife/client_key_show.rb
new file mode 100644
index 0000000000..c39a279000
--- /dev/null
+++ b/lib/chef/knife/client_key_show.rb
@@ -0,0 +1,76 @@
+#
+# Author:: Tyler Cloke (tyler@chef.io)
+# Copyright:: Copyright (c) 2015 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 'chef/knife'
+
+class Chef
+ class Knife
+ # Implements knife client key show using Chef::Knife::KeyShow
+ # as a service class.
+ #
+ # @author Tyler Cloke
+ #
+ # @attr_reader [String] actor the name of the client that this key is for
+ class ClientKeyShow < Knife
+ banner "knife client key show CLIENT KEYNAME (options)"
+
+ attr_reader :actor
+
+ def initialize(argv=[])
+ super(argv)
+ @service_object = nil
+ end
+
+ def run
+ apply_params!(@name_args)
+ service_object.run
+ end
+
+ def load_method
+ :load_by_client
+ end
+
+ def actor_missing_error
+ 'You must specify a client name'
+ end
+
+ def keyname_missing_error
+ 'You must specify a key name'
+ end
+
+ def service_object
+ @service_object ||= Chef::Knife::KeyShow.new(@name, @actor, load_method, ui)
+ end
+
+ def apply_params!(params)
+ @actor = params[0]
+ if @actor.nil?
+ show_usage
+ ui.fatal(actor_missing_error)
+ exit 1
+ end
+ @name = params[1]
+ if @name.nil?
+ show_usage
+ ui.fatal(keyname_missing_error)
+ exit 1
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/knife/key_edit.rb b/lib/chef/knife/key_edit.rb
index 542311805e..48ae344e6e 100644
--- a/lib/chef/knife/key_edit.rb
+++ b/lib/chef/knife/key_edit.rb
@@ -99,7 +99,7 @@ EOS
key = update_key_from_hash(output)
to_display = "Updated key: #{key.name}"
- to_display = "#{to_display} (formally #{@original_name})" if key.name != @original_name
+ to_display << " (formally #{@original_name})" if key.name != @original_name
display_info(to_display)
if key.private_key
if @config[:file]
diff --git a/lib/chef/knife/key_show.rb b/lib/chef/knife/key_show.rb
new file mode 100644
index 0000000000..522f7a1a77
--- /dev/null
+++ b/lib/chef/knife/key_show.rb
@@ -0,0 +1,53 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 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 'chef/key'
+require 'chef/json_compat'
+require 'chef/exceptions'
+
+class Chef
+ class Knife
+ # Service class for UserKeyShow and ClientKeyShow, used to show keys.
+ # Implements common functionality of knife [user | org client] key show.
+ #
+ # @author Tyler Cloke
+ #
+ # @attr_accessor [Hash] cli input, see UserKeyShow and ClientKeyShow for what could populate it
+ class KeyShow
+
+ attr_accessor :config
+
+ def initialize(name, actor, load_method, ui)
+ @name = name
+ @actor = actor
+ @load_method = load_method
+ @ui = ui
+ end
+
+ def display_output(key)
+ @ui.output(@ui.format_for_display(key))
+ end
+
+ def run
+ key = Chef::Key.send(@load_method, @actor, @name)
+ key.public_key(key.public_key.strip)
+ display_output(key)
+ end
+ end
+ end
+end
diff --git a/lib/chef/knife/key_update_base.rb b/lib/chef/knife/key_update_base.rb
deleted file mode 100644
index f9cfd9180d..0000000000
--- a/lib/chef/knife/key_update_base.rb
+++ /dev/null
@@ -1,55 +0,0 @@
-#
-# Author:: Tyler Cloke (<tyler@chef.io>)
-# Copyright:: Copyright (c) 2015 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.
-#
-
-class Chef
- class Knife
- # Extendable module that class_eval's common options into UserKeyUpdate and ClientKeyUpdate
- #
- # @author Tyler Cloke
- module KeyUpdateBase
- def self.included(includer)
- includer.class_eval do
- option :public_key,
- :short => "-p FILENAME",
- :long => "--public-key FILENAME",
- :description => "Replace the public_key field from a file on disk. If not passed, the public_key field will not change."
-
- option :create_key,
- :short => "-c",
- :long => "--create-key",
- :description => "Replace the public_key field with a key generated by the server. The private key will be returned."
-
- option :file,
- :short => "-f FILE",
- :long => "--file FILE",
- :description => "Write the private key to a file, if you requested the server to create one."
-
- option :key_name,
- :short => "-k NAME",
- :long => "--key-name NAME",
- :description => "The new name for your key. Pass if you wish to update the name field of your key."
-
- option :expiration_date,
- :short => "-e DATE",
- :long => "--expiration-date DATE",
- :description => "Updates the expiration_date field of your key if passed. Pass in ISO 8601 fomatted string: YYYY-MM-DDTHH:MM:SSZ e.g. 2013-12-24T21:00:00Z or infinity. UTC timezone assumed."
- end
- end
- end
- end
-end
diff --git a/lib/chef/knife/user_key_create.rb b/lib/chef/knife/user_key_create.rb
index bb8a019184..5ed699ff5b 100644
--- a/lib/chef/knife/user_key_create.rb
+++ b/lib/chef/knife/user_key_create.rb
@@ -17,6 +17,7 @@
#
require 'chef/knife'
+require 'chef/knife/key_create_base'
class Chef
class Knife
diff --git a/lib/chef/knife/user_key_delete.rb b/lib/chef/knife/user_key_delete.rb
index 0bde52509f..6db1c9f552 100644
--- a/lib/chef/knife/user_key_delete.rb
+++ b/lib/chef/knife/user_key_delete.rb
@@ -27,7 +27,7 @@ class Chef
#
# @attr_reader [String] actor the name of the client that this key is for
class UserKeyDelete < Knife
- banner "knife user key delete USER KEYNAME"
+ banner "knife user key delete USER KEYNAME (options)"
attr_reader :actor
diff --git a/lib/chef/knife/user_key_show.rb b/lib/chef/knife/user_key_show.rb
new file mode 100644
index 0000000000..b8453dd28e
--- /dev/null
+++ b/lib/chef/knife/user_key_show.rb
@@ -0,0 +1,76 @@
+#
+# Author:: Tyler Cloke (tyler@chef.io)
+# Copyright:: Copyright (c) 2015 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 'chef/knife'
+
+class Chef
+ class Knife
+ # Implements knife user key show using Chef::Knife::KeyShow
+ # as a service class.
+ #
+ # @author Tyler Cloke
+ #
+ # @attr_reader [String] actor the name of the client that this key is for
+ class UserKeyShow < Knife
+ banner "knife user key show USER KEYNAME (options)"
+
+ attr_reader :actor
+
+ def initialize(argv=[])
+ super(argv)
+ @service_object = nil
+ end
+
+ def run
+ apply_params!(@name_args)
+ service_object.run
+ end
+
+ def load_method
+ :load_by_user
+ end
+
+ def actor_missing_error
+ 'You must specify a user name'
+ end
+
+ def keyname_missing_error
+ 'You must specify a key name'
+ end
+
+ def service_object
+ @service_object ||= Chef::Knife::KeyShow.new(@name, @actor, load_method, ui)
+ end
+
+ def apply_params!(params)
+ @actor = params[0]
+ if @actor.nil?
+ show_usage
+ ui.fatal(actor_missing_error)
+ exit 1
+ end
+ @name = params[1]
+ if @name.nil?
+ show_usage
+ ui.fatal(keyname_missing_error)
+ exit 1
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/knife/key_delete_spec.rb b/spec/unit/knife/key_delete_spec.rb
index 36a24ae6e4..1d4b9f825f 100644
--- a/spec/unit/knife/key_delete_spec.rb
+++ b/spec/unit/knife/key_delete_spec.rb
@@ -81,7 +81,7 @@ describe Chef::Knife::KeyDelete do
shared_examples_for "key delete run command" do
let(:key_delete_object) {
- described_class.new(keyname, actor, actor_field_name, ui,)
+ described_class.new(keyname, actor, actor_field_name, ui)
}
before do
diff --git a/spec/unit/knife/key_show_spec.rb b/spec/unit/knife/key_show_spec.rb
new file mode 100644
index 0000000000..5a0d839e4f
--- /dev/null
+++ b/spec/unit/knife/key_show_spec.rb
@@ -0,0 +1,126 @@
+#
+# Author:: Tyler Cloke (<tyler@chef.io>)
+# Copyright:: Copyright (c) 2015 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'
+require 'chef/knife/user_key_show'
+require 'chef/knife/client_key_show'
+require 'chef/knife/key_show'
+require 'chef/key'
+
+describe "key show commands that inherit knife" do
+ shared_examples_for "a key show command" do
+ let(:stderr) { StringIO.new }
+ let(:params) { [] }
+ let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+ let(:command) do
+ c = described_class.new([])
+ c.ui.config[:disable_editing] = true
+ allow(c.ui).to receive(:stderr).and_return(stderr)
+ allow(c.ui).to receive(:stdout).and_return(stderr)
+ allow(c).to receive(:show_usage)
+ c
+ end
+
+ context "after apply_params! is called with valid args" do
+ let(:params) { ["charmander", "charmander-key"] }
+ before do
+ command.apply_params!(params)
+ end
+
+ context "when the service object is called" do
+ it "creates a new instance of Chef::Knife::KeyShow with the correct args" do
+ expect(Chef::Knife::KeyShow).to receive(:new).
+ with("charmander-key", "charmander", command.load_method, command.ui).
+ and_return(service_object)
+ command.service_object
+ end
+ end # when the service object is called
+ end # after apply_params! is called with valid args
+ end # a key show command
+
+ describe Chef::Knife::UserKeyShow do
+ it_should_behave_like "a key show command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command with a keyname as the second arg"
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+ let(:params) { ["charmander", "charmander-key"] }
+ end
+ end
+
+ describe Chef::Knife::ClientKeyShow do
+ it_should_behave_like "a key show command"
+ # defined in key_helpers.rb
+ it_should_behave_like "a knife key command with a keyname as the second arg"
+ it_should_behave_like "a knife key command" do
+ let(:service_object) { instance_double(Chef::Knife::KeyShow) }
+ let(:params) { ["charmander", "charmander-key"] }
+ end
+ end
+end
+
+describe Chef::Knife::KeyShow do
+ let(:actor) { "charmander" }
+ let(:keyname) { "charmander" }
+ let(:ui) { instance_double("Chef::Knife::UI") }
+ let(:expected_hash) {
+ {
+ actor_field_name => "charmander",
+ "name" => "charmander-key",
+ "public_key" => "some-public-key",
+ "expiration_date" => "infinity"
+ }
+ }
+
+ shared_examples_for "key show run command" do
+ let(:key_show_object) {
+ described_class.new(keyname, actor, load_method, ui)
+ }
+
+ before do
+ allow(key_show_object).to receive(:display_output)
+ allow(Chef::Key).to receive(load_method).and_return(Chef::Key.from_hash(expected_hash))
+ end
+
+ context "when the command is run" do
+ it "loads the key using the proper method and args" do
+ expect(Chef::Key).to receive(load_method).with(actor, keyname)
+ key_show_object.run
+ end
+
+ it "displays the key" do
+ expect(key_show_object).to receive(:display_output)
+ key_show_object.run
+ end
+ end
+ end
+
+ context "when load_method is :load_by_user" do
+ it_should_behave_like "key show run command" do
+ let(:load_method) { :load_by_user }
+ let(:actor_field_name) { 'user' }
+ end
+ end
+
+ context "when load_method is :load_by_client" do
+ it_should_behave_like "key show run command" do
+ let(:load_method) { :load_by_client }
+ let(:actor_field_name) { 'user' }
+ end
+ end
+end