chef-config 13.6.4 → 13.7.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f0968dc4c615d0642e82e8462d97c17d78c158ef
4
- data.tar.gz: 13d09213de2fcaeb6098f2c5522a2d95445a5dfe
3
+ metadata.gz: c1d509df602bb95a13b5ac06864f420dd0ae1fcf
4
+ data.tar.gz: 4924ec21b6dc5c39efd835550d022df3555e0625
5
5
  SHA512:
6
- metadata.gz: 5e0bcd3c9823245148fe74fbeefe0cd3014727243f2faec5e22fec2a727434fc19c67fc171520488d09ea4e44a1df2dc328b110ddff3bd43f6fad651b0e3d15f
7
- data.tar.gz: cc4d1bcc23f499b3acbbde229b46bccc6fa1997435967918d62af16a315da4b64d15ed12e318fd55d15fb9040dbd7824b9251963f757ac2bcd3ac6edc965ef0b
6
+ metadata.gz: c2fbec33c4d7f638e18f55021bb13f9accfe0e5dfedd1c25b0c0cf7f9d04518949ba1ea39ac48422eb00fd8cbfad91661e7704b457aba4c2ebaf0988cc76e58e
7
+ data.tar.gz: 279f3af2f42c46c910215a5580032e7c90edde23ee9af3bc017ae58b66596fe3c160e3f222d29c27d16b133f4d38d36da5bdbe73762672a19f4e8e0c1ba70f18
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.add_dependency "mixlib-config", "~> 2.0"
20
20
  spec.add_dependency "fuzzyurl"
21
21
  spec.add_dependency "addressable"
22
+ spec.add_dependency "tomlrb", "~> 1.2"
22
23
 
23
24
  spec.add_development_dependency "rake", "~> 10.0"
24
25
 
@@ -592,6 +592,12 @@ module ChefConfig
592
592
  # If chef-zero is enabled, this defaults to nil (no authentication).
593
593
  default(:client_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/client.pem") }
594
594
 
595
+ # A credentials file may contain a complete client key, rather than the path
596
+ # to one.
597
+ #
598
+ # We'll use this preferentially.
599
+ default :client_key_contents, nil
600
+
595
601
  # When registering the client, should we allow the client key location to
596
602
  # be a symlink? eg: /etc/chef/client.pem -> /etc/chef/prod-client.pem
597
603
  # If the path of the key goes through a directory like /tmp this should
@@ -631,6 +637,7 @@ module ChefConfig
631
637
  default(:validation_key) { chef_zero.enabled ? nil : platform_specific_path("/etc/chef/validation.pem") }
632
638
  default :validation_client_name, "chef-validator"
633
639
 
640
+ default :validation_key_contents, nil
634
641
  # When creating a new client via the validation_client account, Chef 11
635
642
  # servers allow the client to generate a key pair locally and send the
636
643
  # public key to the server. This is more secure and helps offload work from
@@ -691,6 +698,9 @@ module ChefConfig
691
698
  # on running chef-client
692
699
  default :count_log_resource_updates, true
693
700
 
701
+ # The selected profile when using credentials.
702
+ default :profile, nil
703
+
694
704
  # knife configuration data
695
705
  config_context :knife do
696
706
  # XXX: none of these default values are applied to knife (and would create a backcompat
@@ -0,0 +1,57 @@
1
+ #
2
+ # Copyright:: Copyright 2017, Chef Software, Inc.
3
+ # License:: Apache License, Version 2.0
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+ require "tomlrb"
19
+ require "chef-config/path_helper"
20
+
21
+ module ChefConfig
22
+ module Mixin
23
+ module Credentials
24
+
25
+ def load_credentials(profile = nil)
26
+ credentials_file = PathHelper.home(".chef", "credentials").freeze
27
+ context_file = PathHelper.home(".chef", "context").freeze
28
+
29
+ return unless File.file?(credentials_file)
30
+
31
+ context = File.read(context_file) if File.file?(context_file)
32
+
33
+ environment = ENV.fetch("CHEF_PROFILE", nil)
34
+
35
+ profile = if !profile.nil?
36
+ profile
37
+ elsif !environment.nil?
38
+ environment
39
+ elsif !context.nil?
40
+ context
41
+ else
42
+ "default"
43
+ end
44
+
45
+ config = Tomlrb.load_file(credentials_file)
46
+ apply_credentials(config[profile], profile)
47
+ rescue ChefConfig::ConfigurationError
48
+ raise
49
+ rescue => e
50
+ # TOML's error messages are mostly rubbish, so we'll just give a generic one
51
+ message = "Unable to parse Credentials file: #{credentials_file}\n"
52
+ message << e.message
53
+ raise ChefConfig::ConfigurationError, message
54
+ end
55
+ end
56
+ end
57
+ end
@@ -235,7 +235,7 @@ module ChefConfig
235
235
  paths = paths.map { |home_path| home_path.gsub(path_separator, ::File::SEPARATOR) if home_path }
236
236
 
237
237
  # Filter out duplicate paths and paths that don't exist.
238
- valid_paths = paths.select { |home_path| home_path && Dir.exists?(home_path.force_encoding("utf-8")) }
238
+ valid_paths = paths.select { |home_path| home_path && Dir.exist?(home_path.force_encoding("utf-8")) }
239
239
  valid_paths = valid_paths.uniq
240
240
 
241
241
  # Join all optional path elements at the end.
@@ -21,7 +21,7 @@
21
21
 
22
22
  module ChefConfig
23
23
  CHEFCONFIG_ROOT = File.expand_path("../..", __FILE__)
24
- VERSION = "13.6.4"
24
+ VERSION = "13.7.16"
25
25
  end
26
26
 
27
27
  #
@@ -22,24 +22,31 @@ require "chef-config/logger"
22
22
  require "chef-config/path_helper"
23
23
  require "chef-config/windows"
24
24
  require "chef-config/mixin/dot_d"
25
+ require "chef-config/mixin/credentials"
25
26
 
26
27
  module ChefConfig
27
28
  class WorkstationConfigLoader
28
29
  include ChefConfig::Mixin::DotD
30
+ include ChefConfig::Mixin::Credentials
29
31
 
30
32
  # Path to a config file requested by user, (e.g., via command line option). Can be nil
31
33
  attr_accessor :explicit_config_file
34
+ # The name of a credentials profile. Can be nil
35
+ attr_accessor :profile
36
+ attr_reader :credentials_found
32
37
 
33
38
  # TODO: initialize this with a logger for Chef and Knife
34
- def initialize(explicit_config_file, logger = nil)
39
+ def initialize(explicit_config_file, logger = nil, profile: nil)
35
40
  @explicit_config_file = explicit_config_file
36
41
  @chef_config_dir = nil
37
42
  @config_location = nil
43
+ @profile = profile
38
44
  @logger = logger || NullLogger.new
45
+ @credentials_found = false
39
46
  end
40
47
 
41
48
  def no_config_found?
42
- config_location.nil?
49
+ config_location.nil? && !credentials_found
43
50
  end
44
51
 
45
52
  def config_location
@@ -62,6 +69,7 @@ module ChefConfig
62
69
  end
63
70
 
64
71
  def load
72
+ load_credentials(profile)
65
73
  # Ignore it if there's no explicit_config_file and can't find one at a
66
74
  # default path.
67
75
  if !config_location.nil?
@@ -138,6 +146,38 @@ module ChefConfig
138
146
  a
139
147
  end
140
148
 
149
+ def apply_credentials(creds, profile)
150
+ Config.profile ||= profile
151
+ if creds.key?("node_name") && creds.key?("client_name")
152
+ raise ChefConfig::ConfigurationError, "Do not specify both node_name and client_name. You should prefer client_name."
153
+ end
154
+ Config.node_name = creds.fetch("node_name") if creds.key?("node_name")
155
+ Config.node_name = creds.fetch("client_name") if creds.key?("client_name")
156
+ Config.chef_server_url = creds.fetch("chef_server_url") if creds.key?("chef_server_url")
157
+ Config.validation_client_name = creds.fetch("validation_client_name") if creds.key?("validation_client_name")
158
+
159
+ extract_key(creds, "validation_key", :validation_key, :validation_key_contents)
160
+ extract_key(creds, "validator_key", :validation_key, :validation_key_contents)
161
+ extract_key(creds, "client_key", :client_key, :client_key_contents)
162
+ @credentials_found = true
163
+ end
164
+
165
+ def extract_key(creds, name, config_path, config_contents)
166
+ return unless creds.has_key?(name)
167
+
168
+ val = creds.fetch(name)
169
+ if val.start_with?("-----BEGIN RSA PRIVATE KEY-----")
170
+ Config.send(config_contents, val)
171
+ else
172
+ abs_path = Pathname.new(val).expand_path(home_chef_dir)
173
+ Config.send(config_path, abs_path)
174
+ end
175
+ end
176
+
177
+ def home_chef_dir
178
+ @home_chef_dir ||= PathHelper.home(".chef")
179
+ end
180
+
141
181
  def apply_config(config_content, config_file_path)
142
182
  Config.from_string(config_content, config_file_path)
143
183
  rescue SignalException
@@ -38,6 +38,7 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
38
38
  before do
39
39
  # We set this to nil so that a dev workstation will
40
40
  # not interfere with the tests.
41
+ ChefConfig::Config.reset
41
42
  ChefConfig::Config[:config_d_dir] = nil
42
43
  end
43
44
 
@@ -363,4 +364,147 @@ RSpec.describe ChefConfig::WorkstationConfigLoader do
363
364
  end
364
365
  end
365
366
  end
367
+
368
+ describe "when loading a credentials file" do
369
+ if ChefConfig.windows?
370
+ let(:home) { "C:/Users/example.user" }
371
+ else
372
+ let(:home) { "/Users/example.user" }
373
+ end
374
+ let(:credentials_file) { "#{home}/.chef/credentials" }
375
+ let(:context_file) { "#{home}/.chef/context" }
376
+
377
+ before do
378
+ allow(ChefConfig::PathHelper).to receive(:home).with(".chef").and_return(File.join(home, ".chef"))
379
+ allow(ChefConfig::PathHelper).to receive(:home).with(".chef", "credentials").and_return(credentials_file)
380
+ allow(ChefConfig::PathHelper).to receive(:home).with(".chef", "context").and_return(context_file)
381
+ allow(File).to receive(:file?).with(context_file).and_return false
382
+ end
383
+
384
+ context "when the file exists" do
385
+ before do
386
+ expect(File).to receive(:read).with(credentials_file, { encoding: "utf-8" }).and_return(content)
387
+ allow(File).to receive(:file?).with(credentials_file).and_return true
388
+ end
389
+
390
+ context "and has a default profile" do
391
+ let(:content) do
392
+ content = <<EOH
393
+ [default]
394
+ node_name = 'barney'
395
+ client_key = "barney_rubble.pem"
396
+ chef_server_url = "https://api.chef.io/organizations/bedrock"
397
+ EOH
398
+ content
399
+ end
400
+
401
+ it "applies the expected config" do
402
+ expect { config_loader.load_credentials }.not_to raise_error
403
+ expect(ChefConfig::Config.chef_server_url).to eq("https://api.chef.io/organizations/bedrock")
404
+ expect(ChefConfig::Config.client_key.to_s).to eq("#{home}/.chef/barney_rubble.pem")
405
+ expect(ChefConfig::Config.profile.to_s).to eq("default")
406
+ end
407
+ end
408
+
409
+ context "and has a profile containing a full key" do
410
+ let(:content) do
411
+ content = <<EOH
412
+ [default]
413
+ client_key = """
414
+ -----BEGIN RSA PRIVATE KEY-----
415
+ foo
416
+ """
417
+ EOH
418
+ content
419
+ end
420
+
421
+ it "applies the expected config" do
422
+ expect { config_loader.load_credentials }.not_to raise_error
423
+ expect(ChefConfig::Config.client_key_contents).to eq(<<EOH
424
+ -----BEGIN RSA PRIVATE KEY-----
425
+ foo
426
+ EOH
427
+ )
428
+ end
429
+ end
430
+
431
+ context "and has several profiles" do
432
+ let(:content) do
433
+ content = <<EOH
434
+ [default]
435
+ client_name = "default"
436
+ [environment]
437
+ client_name = "environment"
438
+ [explicit]
439
+ client_name = "explicit"
440
+ [context]
441
+ client_name = "context"
442
+ EOH
443
+ content
444
+ end
445
+
446
+ let(:env) { {} }
447
+ before do
448
+ stub_const("ENV", env)
449
+ end
450
+
451
+ it "selects the correct profile explicitly" do
452
+ expect { config_loader.load_credentials("explicit") }.not_to raise_error
453
+ expect(ChefConfig::Config.node_name).to eq("explicit")
454
+ end
455
+
456
+ context "with an environment variable" do
457
+ let(:env) { { "CHEF_PROFILE" => "environment" } }
458
+
459
+ it "selects the correct profile" do
460
+ expect { config_loader.load_credentials }.not_to raise_error
461
+ expect(ChefConfig::Config.node_name).to eq("environment")
462
+ end
463
+ end
464
+
465
+ it "selects the correct profile with a context file" do
466
+ allow(File).to receive(:file?).with(context_file).and_return true
467
+ expect(File).to receive(:read).with(context_file).and_return "context"
468
+ expect { config_loader.load_credentials }.not_to raise_error
469
+ expect(ChefConfig::Config.node_name).to eq("context")
470
+ end
471
+
472
+ it "falls back to the default" do
473
+ expect { config_loader.load_credentials }.not_to raise_error
474
+ expect(ChefConfig::Config.node_name).to eq("default")
475
+ end
476
+ end
477
+
478
+ context "and contains both node_name and client_name" do
479
+ let(:content) do
480
+ content = <<EOH
481
+ [default]
482
+ node_name = 'barney'
483
+ client_name = 'barney'
484
+ EOH
485
+ content
486
+ end
487
+
488
+ it "raises a ConfigurationError" do
489
+ expect { config_loader.load_credentials }.to raise_error(ChefConfig::ConfigurationError)
490
+ end
491
+ end
492
+
493
+ context "and has a syntax error" do
494
+ let(:content) { "<<<<<" }
495
+
496
+ it "raises a ConfigurationError" do
497
+ expect { config_loader.load_credentials }.to raise_error(ChefConfig::ConfigurationError)
498
+ end
499
+ end
500
+ end
501
+
502
+ context "when the file does not exist" do
503
+ it "does not load anything" do
504
+ allow(File).to receive(:file?).with(credentials_file).and_return false
505
+ expect(Tomlrb).not_to receive(:load_file)
506
+ config_loader.load_credentials
507
+ end
508
+ end
509
+ end
366
510
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chef-config
3
3
  version: !ruby/object:Gem::Version
4
- version: 13.6.4
4
+ version: 13.7.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adam Jacob
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-06 00:00:00.000000000 Z
11
+ date: 2018-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-shellout
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: tomlrb
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -138,6 +152,7 @@ files:
138
152
  - lib/chef-config/exceptions.rb
139
153
  - lib/chef-config/fips.rb
140
154
  - lib/chef-config/logger.rb
155
+ - lib/chef-config/mixin/credentials.rb
141
156
  - lib/chef-config/mixin/dot_d.rb
142
157
  - lib/chef-config/mixin/fuzzy_hostname_matcher.rb
143
158
  - lib/chef-config/package_task.rb