summaryrefslogtreecommitdiff
path: root/chef-config/lib
diff options
context:
space:
mode:
authorThom May <thom@chef.io>2017-12-12 17:32:48 +0000
committerThom May <thom@chef.io>2017-12-13 10:17:15 +0000
commit65109e8b87c0493b76d64622b8e57679b7b909d2 (patch)
tree6ac6fc5c72b70d53069b5748bb589804c67c168c /chef-config/lib
parent2ed7c7be81b930e99affb139f1854309d55fabb5 (diff)
downloadchef-65109e8b87c0493b76d64622b8e57679b7b909d2.tar.gz
implement credential management
Signed-off-by: Thom May <thom@chef.io>
Diffstat (limited to 'chef-config/lib')
-rw-r--r--chef-config/lib/chef-config/config.rb7
-rw-r--r--chef-config/lib/chef-config/mixin/credentials.rb57
-rw-r--r--chef-config/lib/chef-config/workstation_config_loader.rb34
3 files changed, 97 insertions, 1 deletions
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb
index beb78f25d0..63dd4ecda2 100644
--- a/chef-config/lib/chef-config/config.rb
+++ b/chef-config/lib/chef-config/config.rb
@@ -592,6 +592,12 @@ module ChefConfig
# If chef-zero is enabled, this defaults to nil (no authentication).
default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") }
+ # A credentials file may contain a complete client key, rather than the path
+ # to one.
+ #
+ # We'll use this preferentially.
+ default :client_key_contents, nil
+
# When registering the client, should we allow the client key location to
# be a symlink? eg: /etc/chef/client.pem -> /etc/chef/prod-client.pem
# If the path of the key goes through a directory like /tmp this should
@@ -631,6 +637,7 @@ module ChefConfig
default(:validation_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/validation.pem") }
default :validation_client_name, "chef-validator"
+ default :validation_key_contents, nil
# When creating a new client via the validation_client account, Chef 11
# servers allow the client to generate a key pair locally and send the
# public key to the server. This is more secure and helps offload work from
diff --git a/chef-config/lib/chef-config/mixin/credentials.rb b/chef-config/lib/chef-config/mixin/credentials.rb
new file mode 100644
index 0000000000..4c0192fff8
--- /dev/null
+++ b/chef-config/lib/chef-config/mixin/credentials.rb
@@ -0,0 +1,57 @@
+#
+# Copyright:: Copyright 2017, 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 "tomlrb"
+require "chef-config/path_helper"
+
+module ChefConfig
+ module Mixin
+ module Credentials
+
+ def load_credentials(profile = nil)
+ credentials_file = PathHelper.home(".chef", "credentials").freeze
+ context_file = PathHelper.home(".chef", "context").freeze
+
+ return unless File.file?(credentials_file)
+
+ context = File.read(context_file) if File.file?(context_file)
+
+ environment = ENV.fetch("CHEF_PROFILE", nil)
+
+ profile = if !profile.nil?
+ profile
+ elsif !environment.nil?
+ environment
+ elsif !context.nil?
+ context
+ else
+ "default"
+ end
+
+ config = Tomlrb.load_file(credentials_file)
+ apply_credentials(config[profile], profile)
+ rescue ChefConfig::ConfigurationError
+ raise
+ rescue => e
+ # TOML's error messages are mostly rubbish, so we'll just give a generic one
+ message = "Unable to parse Credentials file: #{credentials_file}\n"
+ message << e.message
+ raise ChefConfig::ConfigurationError, message
+ end
+ end
+ end
+end
diff --git a/chef-config/lib/chef-config/workstation_config_loader.rb b/chef-config/lib/chef-config/workstation_config_loader.rb
index babb78aeb8..4c07cac702 100644
--- a/chef-config/lib/chef-config/workstation_config_loader.rb
+++ b/chef-config/lib/chef-config/workstation_config_loader.rb
@@ -22,19 +22,23 @@ require "chef-config/logger"
require "chef-config/path_helper"
require "chef-config/windows"
require "chef-config/mixin/dot_d"
+require "chef-config/mixin/credentials"
module ChefConfig
class WorkstationConfigLoader
include ChefConfig::Mixin::DotD
+ include ChefConfig::Mixin::Credentials
# Path to a config file requested by user, (e.g., via command line option). Can be nil
attr_accessor :explicit_config_file
+ attr_reader :profile
# TODO: initialize this with a logger for Chef and Knife
- def initialize(explicit_config_file, logger = nil)
+ def initialize(explicit_config_file, logger = nil, profile: nil)
@explicit_config_file = explicit_config_file
@chef_config_dir = nil
@config_location = nil
+ @profile = profile
@logger = logger || NullLogger.new
end
@@ -62,6 +66,7 @@ module ChefConfig
end
def load
+ load_credentials(profile)
# Ignore it if there's no explicit_config_file and can't find one at a
# default path.
if !config_location.nil?
@@ -138,6 +143,33 @@ module ChefConfig
a
end
+ def apply_credentials(creds, _profile)
+ Config.node_name = creds.fetch("node_name") if creds.key?("node_name")
+ Config.node_name = creds.fetch("client_name") if creds.key?("client_name")
+ Config.chef_server_url = creds.fetch("chef_server_url") if creds.key?("chef_server_url")
+ Config.validation_client_name = creds.fetch("validation_client_name") if creds.key?("validation_client_name")
+
+ extract_key(creds, "validation_key", :validation_key, :validation_key_contents)
+ extract_key(creds, "validator_key", :validation_key, :validation_key_contents)
+ extract_key(creds, "client_key", :client_key, :client_key_contents)
+ end
+
+ def extract_key(creds, name, config_path, config_contents)
+ return unless creds.has_key?(name)
+
+ val = creds.fetch(name)
+ if val.start_with?("-----BEGIN RSA PRIVATE KEY-----")
+ Config.send(config_contents, val)
+ else
+ abs_path = Pathname.new(val).expand_path(home_chef_dir)
+ Config.send(config_path, abs_path)
+ end
+ end
+
+ def home_chef_dir
+ @home_chef_dir ||= PathHelper.home(".chef")
+ end
+
def apply_config(config_content, config_file_path)
Config.from_string(config_content, config_file_path)
rescue SignalException