diff options
author | Noah Kantrowitz <noah@coderanger.net> | 2018-05-30 15:59:57 -0700 |
---|---|---|
committer | Noah Kantrowitz <noah@coderanger.net> | 2018-05-30 15:59:57 -0700 |
commit | 3f7ffb322fb8f414ebf28eaa4b6fe4c94d7857a9 (patch) | |
tree | 848b088488ae5f92f0d785e8c4ba0165d302c2b5 | |
parent | a074d491722bf665da843e76672ffbadf92e3661 (diff) | |
download | chef-3f7ffb322fb8f414ebf28eaa4b6fe4c94d7857a9.tar.gz |
Add support for signing requests using ssh-agent.
Signed-off-by: Noah Kantrowitz <noah@coderanger.net>
-rw-r--r-- | chef-config/lib/chef-config/config.rb | 6 | ||||
-rw-r--r-- | lib/chef/http/auth_credentials.rb | 8 | ||||
-rw-r--r-- | lib/chef/http/authenticator.rb | 9 | ||||
-rw-r--r-- | lib/chef/knife/raw.rb | 7 | ||||
-rw-r--r-- | lib/chef/server_api.rb | 2 |
5 files changed, 24 insertions, 8 deletions
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb index ef792b2db7..5e641138d3 100644 --- a/chef-config/lib/chef-config/config.rb +++ b/chef-config/lib/chef-config/config.rb @@ -592,7 +592,7 @@ module ChefConfig # the 'mixlib-authorization' project for more detail). Currently, versions # 1.0, 1.1, and 1.3 are available. default :authentication_protocol_version do - if fips + if fips || ssh_agent_signing "1.3" else "1.1" @@ -621,6 +621,10 @@ module ChefConfig # never be set to true or its possibly an easily exploitable security hole. default :follow_client_key_symlink, false + # Enable ssh-agent signing mode. This requires {client_key} be set to a + # public key rather than the usual private key. + default :ssh_agent_signing, false + # This secret is used to decrypt encrypted data bag items. default(:encrypted_data_bag_secret) do if File.exist?(platform_specific_path("/etc/chef/encrypted_data_bag_secret")) diff --git a/lib/chef/http/auth_credentials.rb b/lib/chef/http/auth_credentials.rb index e2494c9405..eeb9136607 100644 --- a/lib/chef/http/auth_credentials.rb +++ b/lib/chef/http/auth_credentials.rb @@ -28,8 +28,10 @@ class Chef class AuthCredentials attr_reader :client_name, :key - def initialize(client_name = nil, key = nil) - @client_name, @key = client_name, key + def initialize(client_name = nil, key = nil, use_ssh_agent: false) + @client_name = client_name + @key = key + @use_ssh_agent = use_ssh_agent end def sign_requests? @@ -48,7 +50,7 @@ class Chef host = request_params.delete(:host) || "localhost" sign_obj = Mixlib::Authentication::SignedHeaderAuth.signing_object(request_params) - signed = sign_obj.sign(key).merge({ :host => host }) + signed = sign_obj.sign(key, use_ssh_agent: @use_ssh_agent).merge({ :host => host }) signed.inject({}) { |memo, kv| memo["#{kv[0].to_s.upcase}"] = kv[1]; memo } end diff --git a/lib/chef/http/authenticator.rb b/lib/chef/http/authenticator.rb index 65367af107..a20653a055 100644 --- a/lib/chef/http/authenticator.rb +++ b/lib/chef/http/authenticator.rb @@ -40,7 +40,7 @@ class Chef @sign_request = true @signing_key_filename = opts[:signing_key_filename] @key = load_signing_key(opts[:signing_key_filename], opts[:raw_key]) - @auth_credentials = AuthCredentials.new(opts[:client_name], @key) + @auth_credentials = AuthCredentials.new(opts[:client_name], @key, use_ssh_agent: opts[:ssh_agent_signing]) @version_class = opts[:version_class] @api_version = opts[:api_version] end @@ -89,12 +89,15 @@ class Chef else return nil end - @key = OpenSSL::PKey::RSA.new(@raw_key) + # Pass in '' as the passphrase to avoid OpenSSL prompting on the TTY if + # given an encrypted key. This also helps if using a single file for + # both the public and private key with ssh-agent mode. + @key = OpenSSL::PKey::RSA.new(@raw_key, '') rescue SystemCallError, IOError => e Chef::Log.warn "Failed to read the private key #{key_file}: #{e.inspect}" raise Chef::Exceptions::PrivateKeyMissing, "I cannot read #{key_file}, which you told me to use to sign requests!" rescue OpenSSL::PKey::RSAError - msg = "The file #{key_file} or :raw_key option does not contain a correctly formatted private key.\n" + msg = "The file #{key_file} or :raw_key option does not contain a correctly formatted private key or the key is encrypted.\n" msg << "The key file should begin with '-----BEGIN RSA PRIVATE KEY-----' and end with '-----END RSA PRIVATE KEY-----'" raise Chef::Exceptions::InvalidPrivateKey, msg end diff --git a/lib/chef/knife/raw.rb b/lib/chef/knife/raw.rb index 76b83d2212..2916736e66 100644 --- a/lib/chef/knife/raw.rb +++ b/lib/chef/knife/raw.rb @@ -39,10 +39,15 @@ class Chef :default => false, :description => "Use webui proxy authentication. Client key must be the webui key." + # We need a custom HTTP client class here because we don't want to even + # try to decode the body, in case we get back corrupted JSON or whatnot. class RawInputServerAPI < Chef::HTTP def initialize(options = {}) + # If making a change here, also update Chef::ServerAPI. options[:client_name] ||= Chef::Config[:node_name] - options[:signing_key_filename] ||= Chef::Config[:client_key] + options[:raw_key] ||= Chef::Config[:client_key_contents] + options[:signing_key_filename] ||= Chef::Config[:client_key] unless options[:raw_key] + options[:ssh_agent_signing] ||= Chef::Config[:ssh_agent_signing] super(Chef::Config[:chef_server_url], options) end use Chef::HTTP::JSONOutput diff --git a/lib/chef/server_api.rb b/lib/chef/server_api.rb index c501544954..62fe319b86 100644 --- a/lib/chef/server_api.rb +++ b/lib/chef/server_api.rb @@ -30,9 +30,11 @@ class Chef class ServerAPI < Chef::HTTP def initialize(url = Chef::Config[:chef_server_url], options = {}) + # # If making a change here, also update Chef::Knife::Raw::RawInputServerAPI. options[:client_name] ||= Chef::Config[:node_name] options[:raw_key] ||= Chef::Config[:client_key_contents] options[:signing_key_filename] ||= Chef::Config[:client_key] unless options[:raw_key] + options[:ssh_agent_signing] ||= Chef::Config[:ssh_agent_signing] options[:signing_key_filename] = nil if chef_zero_uri?(url) options[:inflate_json_class] = false super(url, options) |