summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2018-04-16 13:44:00 -0700
committerTim Smith <tsmith@chef.io>2018-06-11 11:22:08 -0700
commit787bde4cea59d8fefbaae9b0fe930fc2d9d8b710 (patch)
tree9de8e985c2a36054cb23289a318b8b4f14147459
parent4c9fbad697420f0fcd67d5a9ee7202d406aa5a35 (diff)
downloadchef-787bde4cea59d8fefbaae9b0fe930fc2d9d8b710.tar.gz
Add ssh_known_hosts_entry from ssh_known_hosts cookbook
Port this from the 6.1 release of the cookbook Signed-off-by: Tim Smith <tsmith@chef.io>
-rw-r--r--kitchen-tests/cookbooks/base/recipes/default.rb3
-rw-r--r--lib/chef/resource/ssh_known_hosts_entry.rb116
-rw-r--r--lib/chef/resource/support/ssh_known_hosts.erb3
-rw-r--r--lib/chef/resources.rb1
4 files changed, 123 insertions, 0 deletions
diff --git a/kitchen-tests/cookbooks/base/recipes/default.rb b/kitchen-tests/cookbooks/base/recipes/default.rb
index ea0215ca96..9175bfbd26 100644
--- a/kitchen-tests/cookbooks/base/recipes/default.rb
+++ b/kitchen-tests/cookbooks/base/recipes/default.rb
@@ -38,6 +38,9 @@ users_manage "sysadmin" do
action [:create]
end
+ssh_known_hosts_entry "github.com"
+ssh_known_hosts_entry "travis.org"
+
sudo "sysadmins" do
group ["sysadmin", "%superadmin"]
nopasswd true
diff --git a/lib/chef/resource/ssh_known_hosts_entry.rb b/lib/chef/resource/ssh_known_hosts_entry.rb
new file mode 100644
index 0000000000..5a016842e5
--- /dev/null
+++ b/lib/chef/resource/ssh_known_hosts_entry.rb
@@ -0,0 +1,116 @@
+#
+# Author:: Seth Vargo (<sethvargo@gmail.com>)
+#
+# Copyright:: 2013-2018, Seth Vargo
+# Copyright:: 2017-2018, 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/resource"
+
+class Chef
+ class Resource
+ class SshKnownHostsEntry < Chef::Resource
+ resource_name :ssh_known_hosts_entry
+ provides(:ssh_known_hosts_entry) { true }
+
+ description "Use the ssh_known_hosts_entry resource to append an entry for the specified host in /etc/ssh/ssh_known_hosts or a user's known hosts file if specified."
+ introduced "15.0"
+
+ property :host, String, name_property: true
+ property :key, String
+ property :key_type, String, default: "rsa"
+ property :port, Integer, default: 22
+ property :timeout, Integer, default: 30
+ property :mode, String, default: "0644"
+ property :owner, String, default: "root"
+ property :group, String, default: "root"
+ property :hash_entries, [true, false], default: false
+ property :file_location, String, default: "/etc/ssh/ssh_known_hosts"
+
+ action :create do
+ key =
+ if new_resource.key
+ hoststr = (new_resource.port != 22) ? "[#{new_resource.host}]:#{new_resource.port}" : new_resource.host
+ "#{hoststr} #{type_string(new_resource.key_type)} #{new_resource.key}"
+ else
+ keyscan_cmd = ["ssh-keyscan", "-t#{new_resource.key_type}", "-p #{new_resource.port}"]
+ keyscan_cmd << "-H" if new_resource.hash_entries
+ keyscan_cmd << new_resource.host
+ keyscan = shell_out!(keyscan_cmd.join(" "), timeout: new_resource.timeout)
+ keyscan.stdout
+ end
+
+ key.sub!(/^#{new_resource.host}/, "[#{new_resource.host}]:#{new_resource.port}") if new_resource.port != 22
+
+ comment = key.split("\n").first || ""
+
+ r = with_run_context :root do
+ find_resource(:template, "update ssh known hosts file #{new_resource.file_location}") do
+ source "ssh_known_hosts.erb"
+ path new_resource.file_location
+ owner new_resource.owner
+ group new_resource.group
+ mode new_resource.mode
+ action :nothing
+ delayed_action :create
+ backup false
+ variables(entries: [])
+ end
+ end
+
+ # messing with the run_context appears to cause issues with the cookbook_name
+ r.cookbook_name = "ssh_known_hosts"
+
+ keys = r.variables[:entries].reject(&:empty?)
+
+ if key_exists?(keys, key, comment)
+ Chef::Log.debug "Known hosts key for #{new_resource.name} already exists - skipping"
+ else
+ r.variables[:entries].push(key)
+ end
+ end
+
+ # all this does is send an immediate run_action(:create) to the template resource
+ action :flush do
+ with_run_context :root do
+ # if you haven't ever called ssh_known_hosts_entry before you're definitely doing it wrong so we blow up hard.
+ find_resource!(:template, "update ssh known hosts file #{new_resource.file_location}").run_action(:create)
+ # it is the user's responsibility to only call this *after* all the ssh_known_hosts_entry resources have been called.
+ # if you call this too early in your run_list you will get a partial known_host file written to disk, and the resource
+ # behavior will not be idempotent (template resources will flap and never show 0 resources updated on converged boxes).
+ Chef::Log.warn "flushed ssh_known_hosts entries to file, later ssh_known_hosts_entry resources will not have been written"
+ end
+ end
+
+ action_class do
+ def key_exists?(keys, key, comment)
+ keys.any? do |line|
+ line.match(/#{Regexp.escape(comment)}|#{Regexp.escape(key)}/)
+ end
+ end
+
+ def type_string(key_type)
+ type_map = {
+ "rsa" => "ssh-rsa",
+ "dsa" => "ssh-dss",
+ "ecdsa" => "ecdsa-sha2-nistp256",
+ "ed25519" => "ssh-ed25519",
+ }
+ type_map[key_type] || key_type
+ end
+ end
+ end
+ end
+end
diff --git a/lib/chef/resource/support/ssh_known_hosts.erb b/lib/chef/resource/support/ssh_known_hosts.erb
new file mode 100644
index 0000000000..0073b250ff
--- /dev/null
+++ b/lib/chef/resource/support/ssh_known_hosts.erb
@@ -0,0 +1,3 @@
+<% @entries.sort.each do |entry| -%>
+<%= entry %>
+<% end -%>
diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb
index c232ce04e1..c001e56055 100644
--- a/lib/chef/resources.rb
+++ b/lib/chef/resources.rb
@@ -92,6 +92,7 @@ require "chef/resource/sudo"
require "chef/resource/sysctl"
require "chef/resource/swap_file"
require "chef/resource/systemd_unit"
+require "chef/resource/ssh_known_hosts_entry"
require "chef/resource/windows_service"
require "chef/resource/subversion"
require "chef/resource/smartos_package"