puppetserver-ca 1.10.0 → 2.0.0

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
  SHA256:
3
- metadata.gz: 7200d67071717855a415f5b10ea96e2d008eb9e758b6c1bfcf367d41be1355c4
4
- data.tar.gz: 9b94632f35b636420a5bb80fe6e1878daefb77b4d113aed5122a116113e7ff20
3
+ metadata.gz: 6523b5628cc4d83aa2627326400a2fb493a18f28d7e4da4b8046eac41e09c555
4
+ data.tar.gz: 6e8cfbeb2a63ad443f22b196d9cdf2749242ef552c6376fd55b723aa699ceefd
5
5
  SHA512:
6
- metadata.gz: 82cca168aa2217dd81a68acb3acaabdaddcc06d494a783a04a27a03965110d0ca66fe5a3eee01e4d949073e4e8594d61a3203f83066e8e64b2e857344a723566
7
- data.tar.gz: 95708d9c5f670001c8c3018cf9804fd189d44cb52bcee4e0e86665c4b8d5fd114ebb7480a6576fcffe81fd2289ba28b1fe2c61a8d610d0733b6d6f947df0f04a
6
+ metadata.gz: 82c62889b706bad66349d5efd8469969b919d8d90741c57c12827eccdedf2de80597ea923509c66de6d6f317da365d860705d556441ce817167d323ad6e80325
7
+ data.tar.gz: 72cca87e22e38e8c6b2b7975d4920057f5364c7a9499bcf30553894b9285468a0cb1d3fd93aace8974a889a0e0a0ed35f348d902139a07d0f588957e61f479f4
data/README.md CHANGED
@@ -55,25 +55,20 @@ To create a new keypair and certificate for a certname:
55
55
  puppetserver ca generate --certname foo.example.com
56
56
  ```
57
57
 
58
- To enable verbose mode:
59
- ```
60
- puppetserver ca --verbose <action>
61
- ```
62
-
63
58
  For more details, see the help output:
64
59
  ```
65
60
  puppetserver ca --help
66
61
  ```
67
62
 
68
63
  This code in this project is licensed under the Apache Software License v2,
69
- please see the included [License](https://github.com/puppetlabs/puppetserver-ca-cli/blob/main/LICENSE.md)
64
+ please see the included [License](https://github.com/puppetlabs/puppetserver-ca-cli/blob/master/LICENSE.md)
70
65
  for more details.
71
66
 
72
67
 
73
68
  ## Development
74
69
 
75
70
  After checking out the repo, run `bin/setup` to install dependencies. Then,
76
- run `bundle exec rake spec` to run the tests. You can also run `bin/console` for an
71
+ run `rake spec` to run the tests. You can also run `bin/console` for an
77
72
  interactive prompt that will allow you to experiment.
78
73
 
79
74
  To install this gem onto your local machine, run `bundle exec rake install`.
@@ -97,7 +92,7 @@ To test your changes on a VM:
97
92
  1. To confirm that installation was successful, run `puppetserver ca --help`
98
93
 
99
94
  ### Releasing
100
- To release a new version, run the [release pipeline](https://jenkins-platform.delivery.puppetlabs.net/job/platform_puppetserver-ca_init-multijob_1.x/), which will bump the version, tag, build, and release the gem.
95
+ To release a new version, run the [release pipeline](https://jenkins-master-prod-1.delivery.puppetlabs.net/job/platform_puppetserver-ca_init-multijob_main/), which will bump the version, tag, build, and release the gem.
101
96
 
102
97
 
103
98
  ## Contributing & Support
@@ -110,9 +105,9 @@ Freenode, or the Puppet Community Slack channel.
110
105
 
111
106
  Contributions are welcome at https://github.com/puppetlabs/puppetserver-ca-cli/pulls.
112
107
  Contributors should both be sure to read the
113
- [contributing document](https://github.com/puppetlabs/puppetserver-ca-cli/blob/main/CONTRIBUTING.md)
108
+ [contributing document](https://github.com/puppetlabs/puppetserver-ca-cli/blob/master/CONTRIBUTING.md)
114
109
  and sign the [contributor license agreement](https://cla.puppet.com/).
115
110
 
116
111
  Everyone interacting with the project’s codebase, issue tracker, etc is expected
117
112
  to follow the
118
- [code of conduct](https://github.com/puppetlabs/puppetserver-ca-cli/blob/main/CODE_OF_CONDUCT.md).
113
+ [code of conduct](https://github.com/puppetlabs/puppetserver-ca-cli/blob/master/CODE_OF_CONDUCT.md).
@@ -14,7 +14,7 @@ module Puppetserver
14
14
 
15
15
  include Puppetserver::Ca::Utils
16
16
 
17
- CERTNAME_BLOCKLIST = %w{--all --config}
17
+ CERTNAME_BLACKLIST = %w{--all --config}
18
18
 
19
19
  SUMMARY = 'Revoke cert(s) and remove related files from CA'
20
20
  BANNER = <<-BANNER
@@ -59,7 +59,7 @@ BANNER
59
59
  errors = CliParsing.parse_with_errors(parser, args)
60
60
 
61
61
  results['certnames'].each do |certname|
62
- if CERTNAME_BLOCKLIST.include?(certname)
62
+ if CERTNAME_BLACKLIST.include?(certname)
63
63
  errors << " Cannot manage cert named `#{certname}` from " +
64
64
  "the CLI, if needed use the HTTP API directly"
65
65
  end
@@ -85,7 +85,7 @@ BANNER
85
85
  return 1 if Errors.handle_with_usage(@logger, errors)
86
86
  end
87
87
 
88
- puppet = Config::Puppet.parse(config)
88
+ puppet = Config::Puppet.parse(config, @logger)
89
89
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)
90
90
 
91
91
  result = clean_certs(certnames, puppet.settings)
@@ -45,7 +45,7 @@ BANNER
45
45
  end
46
46
 
47
47
  puppet = Config::Puppet.new(config_path)
48
- puppet.load
48
+ puppet.load({}, @logger)
49
49
  settings = puppet.settings
50
50
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)
51
51
 
@@ -18,7 +18,7 @@ module Puppetserver
18
18
 
19
19
  # Only allow printing ascii characters, excluding /
20
20
  VALID_CERTNAME = /\A[ -.0-~]+\Z/
21
- CERTNAME_BLOCKLIST = %w{--all --config}
21
+ CERTNAME_BLACKLIST = %w{--all --config}
22
22
 
23
23
  SUMMARY = "Generate a new certificate signed by the CA"
24
24
  BANNER = <<-BANNER
@@ -35,7 +35,7 @@ Description:
35
35
  If the `--ca-client` flag is passed, the cert will be generated
36
36
  offline, without using Puppet Server's signing code, and will add
37
37
  a special extension authorizing it to talk to the CA API. This can
38
- be used for regenerating the server's host cert, or for manually
38
+ be used for regenerating the master's host cert, or for manually
39
39
  setting up other nodes to be CA clients. Do not distribute certs
40
40
  generated this way to any node that you do not intend to have
41
41
  administrative access to the CA (e.g. the ability to sign a cert).
@@ -91,7 +91,7 @@ BANNER
91
91
  errors << ' At least one certname is required to generate'
92
92
  else
93
93
  results['certnames'].each do |certname|
94
- if CERTNAME_BLOCKLIST.include?(certname)
94
+ if CERTNAME_BLACKLIST.include?(certname)
95
95
  errors << " Cannot manage cert named `#{certname}` from " +
96
96
  "the CLI, if needed use the HTTP API directly"
97
97
  end
@@ -126,7 +126,7 @@ BANNER
126
126
  # Load, resolve, and validate puppet config settings
127
127
  settings_overrides = {}
128
128
  puppet = Config::Puppet.new(config_path)
129
- puppet.load(settings_overrides)
129
+ puppet.load(settings_overrides, @logger)
130
130
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)
131
131
 
132
132
  # We don't want generate to respect the alt names setting, since it is usually
@@ -296,9 +296,7 @@ BANNER
296
296
  end
297
297
 
298
298
  def process_alt_names(alt_names, certname)
299
- # It is recommended (and sometimes enforced) to always include
300
- # the certname as a SAN, see RFC 2818 https://tools.ietf.org/html/rfc2818#section-3.1.
301
- return "DNS:#{certname}" if alt_names.empty?
299
+ return '' if alt_names.empty?
302
300
 
303
301
  current_alt_names = alt_names.dup
304
302
  # When validating the cert, OpenSSL will ignore the CN field if
@@ -4,6 +4,7 @@ require 'puppetserver/ca/config/puppet'
4
4
  require 'puppetserver/ca/errors'
5
5
  require 'puppetserver/ca/local_certificate_authority'
6
6
  require 'puppetserver/ca/utils/cli_parsing'
7
+ require 'puppetserver/ca/utils/config'
7
8
  require 'puppetserver/ca/utils/file_system'
8
9
  require 'puppetserver/ca/utils/signing_digest'
9
10
  require 'puppetserver/ca/x509_loader'
@@ -14,7 +15,7 @@ module Puppetserver
14
15
  class Import
15
16
  include Puppetserver::Ca::Utils
16
17
 
17
- SUMMARY = "Import an external CA chain and generate server PKI"
18
+ SUMMARY = "Import an external CA chain and generate master PKI"
18
19
  BANNER = <<-BANNER
19
20
  Usage:
20
21
  puppetserver ca import [--help]
@@ -55,7 +56,7 @@ BANNER
55
56
  settings_overrides[:dns_alt_names] = input['subject-alt-names'] unless input['subject-alt-names'].empty?
56
57
 
57
58
  puppet = Config::Puppet.new(config_path)
58
- puppet.load(settings_overrides)
59
+ puppet.load(settings_overrides, @logger)
59
60
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)
60
61
 
61
62
  # Load most secure signing digest we can for cers/crl/csr signing.
@@ -72,7 +73,7 @@ BANNER
72
73
  def import(loader, settings, signing_digest)
73
74
  ca = Puppetserver::Ca::LocalCertificateAuthority.new(signing_digest, settings)
74
75
  ca.initialize_ssl_components(loader)
75
- server_key, server_cert = ca.create_server_cert
76
+ master_key, master_cert = ca.create_master_cert
76
77
  return ca.errors if ca.errors.any?
77
78
 
78
79
  FileSystem.ensure_dirs([settings[:ssldir],
@@ -88,25 +89,25 @@ BANNER
88
89
  [settings[:cadir] + '/infra_crl.pem', loader.crls],
89
90
  [settings[:localcacert], loader.certs],
90
91
  [settings[:hostcrl], loader.crls],
91
- [settings[:hostpubkey], server_key.public_key],
92
- [settings[:hostcert], server_cert],
93
- [settings[:cert_inventory], ca.inventory_entry(server_cert)],
92
+ [settings[:hostpubkey], master_key.public_key],
93
+ [settings[:hostcert], master_cert],
94
+ [settings[:cert_inventory], ca.inventory_entry(master_cert)],
94
95
  [settings[:capub], loader.key.public_key],
95
96
  [settings[:cadir] + '/infra_inventory.txt', ''],
96
97
  [settings[:cadir] + '/infra_serials', ''],
97
98
  [settings[:serial], "002"],
98
- [File.join(settings[:signeddir], "#{settings[:certname]}.pem"), server_cert]
99
+ [File.join(settings[:signeddir], "#{settings[:certname]}.pem"), master_cert]
99
100
  ]
100
101
 
101
102
  private_files = [
102
- [settings[:hostprivkey], server_key],
103
+ [settings[:hostprivkey], master_key],
103
104
  [settings[:cakey], loader.key],
104
105
  ]
105
106
 
106
107
  files_to_check = public_files + private_files
107
- # We don't want to error if server's keys exist. Certain workflows
108
+ # We don't want to error if master's keys exist. Certain workflows
108
109
  # allow the agent to have already be installed with keys and then
109
- # upgraded to be a server. The host class will honor keys, if both
110
+ # upgraded to be a master. The host class will honor keys, if both
110
111
  # public and private exist, and error if only one exists - as is
111
112
  # previous behavior.
112
113
  files_to_check = files_to_check.map(&:first) - [settings[:hostpubkey], settings[:hostprivkey]]
@@ -130,6 +131,8 @@ ERR
130
131
  FileSystem.write_file(location, content, 0640)
131
132
  end
132
133
 
134
+ Puppetserver::Ca::Utils::Config.symlink_to_old_cadir(settings[:cadir], settings[:confdir])
135
+
133
136
  return []
134
137
  end
135
138
 
@@ -178,11 +181,11 @@ ERR
178
181
  parsed['crl-chain'] = chain
179
182
  end
180
183
  opts.on('--certname NAME',
181
- 'Common name to use for the server cert') do |name|
184
+ 'Common name to use for the master cert') do |name|
182
185
  parsed['certname'] = name
183
186
  end
184
187
  opts.on('--subject-alt-names NAME[,NAME]',
185
- 'Subject alternative names for the server cert') do |sans|
188
+ 'Subject alternative names for the master cert') do |sans|
186
189
  parsed['subject-alt-names'] = sans
187
190
  end
188
191
  end
@@ -30,7 +30,6 @@ Options:
30
30
  BANNER
31
31
 
32
32
  BODY = JSON.dump({desired_state: 'signed'})
33
- VALID_FORMAT = ['text', 'json']
34
33
 
35
34
  def initialize(logger)
36
35
  @logger = logger
@@ -48,9 +47,6 @@ Options:
48
47
  opts.on('--all', 'List all certificates') do |a|
49
48
  parsed['all'] = true
50
49
  end
51
- opts.on('--format FORMAT', "Valid formats are: 'text' (default), 'json'") do |f|
52
- parsed['format'] = f
53
- end
54
50
  opts.on('--certname NAME[,NAME]', Array, 'List the specified cert(s)') do |cert|
55
51
  parsed['certname'] = cert
56
52
  end
@@ -61,15 +57,9 @@ Options:
61
57
  config = input['config']
62
58
  certnames = input['certname'] || []
63
59
  all = input['all']
64
- output_format = input['format'] || "text"
65
-
66
- unless VALID_FORMAT.include?(output_format)
67
- Errors.handle_with_usage(@logger, ["Unknown format flag '#{output_format}'. Valid formats are '#{VALID_FORMAT.join("', '")}'."])
68
- return 1
69
- end
70
60
 
71
61
  if all && certnames.any?
72
- Errors.handle_with_usage(@logger, ['Cannot combine use of --all and --certname.'])
62
+ Errors.handle_with_usage(@logger, ['Cannot combine use of --all and --certname'])
73
63
  return 1
74
64
  end
75
65
 
@@ -78,63 +68,27 @@ Options:
78
68
  return 1 if Errors.handle_with_usage(@logger, errors)
79
69
  end
80
70
 
81
- puppet = Config::Puppet.parse(config)
71
+ puppet = Config::Puppet.parse(config, @logger)
82
72
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)
83
73
 
84
- if certnames.any?
85
- filter_names = lambda { |x| certnames.include?(x['name']) }
86
- else
87
- filter_names = lambda { |x| true }
88
- end
74
+ filter_names = certnames.any? \
75
+ ? lambda { |x| certnames.include?(x['name']) }
76
+ : lambda { |x| true }
89
77
 
90
78
  all_certs = get_all_certs(puppet.settings).select { |cert| filter_names.call(cert) }
91
79
  requested, signed, revoked = separate_certs(all_certs)
92
80
  missing = certnames - all_certs.map { |cert| cert['name'] }
93
81
 
94
- if (all || certnames.any?)
95
- output_certs_by_state(all, output_format, requested, signed, revoked, missing)
96
- else
97
- output_certs_by_state(all, output_format, requested)
98
- end
99
-
100
- return missing.any? ? 1 : 0
101
- end
82
+ (all || certnames.any?) \
83
+ ? output_certs_by_state(requested, signed, revoked, missing)
84
+ : output_certs_by_state(requested)
102
85
 
103
- def output_certs_by_state(all, output_format, requested, signed = [], revoked = [], missing = [])
104
- if output_format == 'json'
105
- output_certs_json_format(all, requested, signed, revoked, missing)
106
- else
107
- output_certs_text_format(requested, signed, revoked, missing)
108
- end
86
+ return missing.any? \
87
+ ? 1
88
+ : 0
109
89
  end
110
90
 
111
- def output_certs_json_format(all, requested, signed, revoked, missing)
112
- grouped_cert = {}
113
-
114
- if all
115
- grouped_cert = { "requested" => requested,
116
- "signed" => signed,
117
- "revoked" => revoked }.to_json
118
- @logger.inform(grouped_cert)
119
- else
120
- grouped_cert["requested"] = requested unless requested.empty?
121
- grouped_cert["signed"] = signed unless signed.empty?
122
- grouped_cert["revoked"] = revoked unless revoked.empty?
123
- grouped_cert["missing"] = missing unless missing.empty?
124
-
125
- # If neither the '--all' flag or the '--certname' flag was passed in
126
- # and the requested cert array is empty, we output a JSON object
127
- # with an empty 'requested' key. Otherwise, we display
128
- # any of the classes that are currently in grouped_cert
129
- if grouped_cert.empty?
130
- @logger.inform({ "requested" => requested }.to_json)
131
- else
132
- @logger.inform(grouped_cert.to_json)
133
- end
134
- end
135
- end
136
-
137
- def output_certs_text_format(requested, signed, revoked, missing)
91
+ def output_certs_by_state(requested, signed = [], revoked = [], missing = [])
138
92
  if revoked.empty? && signed.empty? && requested.empty? && missing.empty?
139
93
  @logger.inform "No certificates to list"
140
94
  return
@@ -211,12 +165,7 @@ Options:
211
165
 
212
166
  def get_all_certs(settings)
213
167
  result = Puppetserver::Ca::CertificateAuthority.new(@logger, settings).get_certificate_statuses
214
-
215
- if result
216
- return JSON.parse(result.body)
217
- else
218
- return []
219
- end
168
+ result ? JSON.parse(result.body) : []
220
169
  end
221
170
 
222
171
  def parse(args)
@@ -227,11 +176,8 @@ Options:
227
176
 
228
177
  errors_were_handled = Errors.handle_with_usage(@logger, errors, parser.help)
229
178
 
230
- if errors_were_handled
231
- exit_code = 1
232
- else
233
- exit_code = nil
234
- end
179
+ exit_code = errors_were_handled ? 1 : nil
180
+
235
181
  return results, exit_code
236
182
  end
237
183
  end
@@ -29,7 +29,7 @@ BANNER
29
29
  def run(input)
30
30
  config_path = input['config']
31
31
  puppet = Config::Puppet.new(config_path)
32
- puppet.load
32
+ puppet.load({}, @logger)
33
33
  return 1 if HttpClient.check_server_online(puppet.settings, @logger)
34
34
 
35
35
  errors = FileSystem.check_for_existing_files(PUPPETSERVER_CA_DIR)
@@ -66,14 +66,6 @@ SUCCESS_MESSAGE
66
66
  def migrate(old_cadir, new_cadir=PUPPETSERVER_CA_DIR)
67
67
  FileUtils.mv(old_cadir, new_cadir)
68
68
  FileUtils.symlink(new_cadir, old_cadir)
69
- # Ensure the symlink has the same ownership as the actual cadir.
70
- # This requires using `FileUtils.chown` rather than `File.chown`, as
71
- # the latter will update the ownership of the target rather than the
72
- # link itself.
73
- # Symlink permissions are ignored in favor of the target's permissions,
74
- # so we don't have to change those.
75
- cadir = File.stat(new_cadir)
76
- FileUtils.chown(cadir.uid, cadir.gid, old_cadir)
77
69
  end
78
70
 
79
71
  def parse(args)
@@ -12,7 +12,7 @@ module Puppetserver
12
12
 
13
13
  include Puppetserver::Ca::Utils
14
14
 
15
- CERTNAME_BLOCKLIST = %w{--all --config}
15
+ CERTNAME_BLACKLIST = %w{--all --config}
16
16
 
17
17
  SUMMARY = 'Revoke certificate(s)'
18
18
  BANNER = <<-BANNER
@@ -55,7 +55,7 @@ BANNER
55
55
  errors = CliParsing.parse_with_errors(parser, args)
56
56
 
57
57
  results['certnames'].each do |certname|
58
- if CERTNAME_BLOCKLIST.include?(certname)
58
+ if CERTNAME_BLACKLIST.include?(certname)
59
59
  errors << " Cannot manage cert named `#{certname}` from " +
60
60
  "the CLI, if needed use the HTTP API directly"
61
61
  end
@@ -83,7 +83,7 @@ BANNER
83
83
  return 1 if Errors.handle_with_usage(@logger, errors)
84
84
  end
85
85
 
86
- puppet = Config::Puppet.parse(config)
86
+ puppet = Config::Puppet.parse(config, @logger)
87
87
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)
88
88
 
89
89
  result = revoke_certs(certnames, puppet.settings)
@@ -3,6 +3,7 @@ require 'optparse'
3
3
  require 'puppetserver/ca/config/puppet'
4
4
  require 'puppetserver/ca/errors'
5
5
  require 'puppetserver/ca/local_certificate_authority'
6
+ require 'puppetserver/ca/utils/config'
6
7
  require 'puppetserver/ca/utils/cli_parsing'
7
8
  require 'puppetserver/ca/utils/file_system'
8
9
  require 'puppetserver/ca/utils/signing_digest'
@@ -23,10 +24,10 @@ Usage:
23
24
  Description:
24
25
  Setup a root and intermediate signing CA for Puppet Server
25
26
  and store generated CA keys, certs, crls, and associated
26
- server related files on disk.
27
+ master related files on disk.
27
28
 
28
29
  The `--subject-alt-names` flag can be used to add SANs to the
29
- certificate generated for the Puppet server. Multiple names can be
30
+ certificate generated for the Puppet master. Multiple names can be
30
31
  listed as a comma separated string. These can be either DNS names or
31
32
  IP addresses, differentiated by prefixes: `DNS:foo.bar.com,IP:123.456.789`.
32
33
  Names with no prefix will be treated as DNS names.
@@ -55,7 +56,7 @@ BANNER
55
56
  settings_overrides[:dns_alt_names] = input['subject-alt-names'] unless input['subject-alt-names'].empty?
56
57
 
57
58
  puppet = Config::Puppet.new(config_path)
58
- puppet.load(settings_overrides)
59
+ puppet.load(settings_overrides, @logger)
59
60
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)
60
61
 
61
62
  # Load most secure signing digest we can for cers/crl/csr signing.
@@ -76,7 +77,7 @@ BANNER
76
77
 
77
78
  root_key, root_cert, root_crl = ca.create_root_cert
78
79
  ca.create_intermediate_cert(root_key, root_cert)
79
- server_key, server_cert = ca.create_server_cert
80
+ master_key, master_cert = ca.create_master_cert
80
81
  return ca.errors if ca.errors.any?
81
82
 
82
83
  FileSystem.ensure_dirs([settings[:ssldir],
@@ -90,28 +91,28 @@ BANNER
90
91
  [settings[:cacert], [ca.cert, root_cert]],
91
92
  [settings[:cacrl], [ca.crl, root_crl]],
92
93
  [settings[:cadir] + '/infra_crl.pem', [ca.crl, root_crl]],
93
- [settings[:hostcert], server_cert],
94
+ [settings[:hostcert], master_cert],
94
95
  [settings[:localcacert], [ca.cert, root_cert]],
95
96
  [settings[:hostcrl], [ca.crl, root_crl]],
96
- [settings[:hostpubkey], server_key.public_key],
97
+ [settings[:hostpubkey], master_key.public_key],
97
98
  [settings[:capub], ca.key.public_key],
98
- [settings[:cert_inventory], ca.inventory_entry(server_cert)],
99
+ [settings[:cert_inventory], ca.inventory_entry(master_cert)],
99
100
  [settings[:cadir] + '/infra_inventory.txt', ''],
100
101
  [settings[:cadir] + '/infra_serials', ''],
101
102
  [settings[:serial], "002"],
102
- [File.join(settings[:signeddir], "#{settings[:certname]}.pem"), server_cert],
103
+ [File.join(settings[:signeddir], "#{settings[:certname]}.pem"), master_cert],
103
104
  ]
104
105
 
105
106
  private_files = [
106
- [settings[:hostprivkey], server_key],
107
+ [settings[:hostprivkey], master_key],
107
108
  [settings[:rootkey], root_key],
108
109
  [settings[:cakey], ca.key],
109
110
  ]
110
111
 
111
112
  files_to_check = public_files + private_files
112
- # We don't want to error if server's keys exist. Certain workflows
113
+ # We don't want to error if master's keys exist. Certain workflows
113
114
  # allow the agent to have already be installed with keys and then
114
- # upgraded to be a server. The host class will honor keys, if both
115
+ # upgraded to be a master. The host class will honor keys, if both
115
116
  # public and private exist, and error if only one exists - as is
116
117
  # previous behavior.
117
118
  files_to_check = files_to_check.map(&:first) - [settings[:hostpubkey], settings[:hostprivkey]]
@@ -135,6 +136,8 @@ ERR
135
136
  FileSystem.write_file(location, content, 0640)
136
137
  end
137
138
 
139
+ Puppetserver::Ca::Utils::Config.symlink_to_old_cadir(settings[:cadir], settings[:confdir])
140
+
138
141
  return []
139
142
  end
140
143
 
@@ -160,7 +163,7 @@ ERR
160
163
  parsed['config'] = conf
161
164
  end
162
165
  opts.on('--subject-alt-names NAME[,NAME]',
163
- 'Subject alternative names for the server cert') do |sans|
166
+ 'Subject alternative names for the master cert') do |sans|
164
167
  parsed['subject-alt-names'] = sans
165
168
  end
166
169
  opts.on('--ca-name NAME',
@@ -168,7 +171,7 @@ ERR
168
171
  parsed['ca-name'] = name
169
172
  end
170
173
  opts.on('--certname NAME',
171
- 'Common name to use for the server cert') do |name|
174
+ 'Common name to use for the master cert') do |name|
172
175
  parsed['certname'] = name
173
176
  end
174
177
  end
@@ -62,7 +62,7 @@ Options:
62
62
  return 1 if Errors.handle_with_usage(@logger, errors)
63
63
  end
64
64
 
65
- puppet = Config::Puppet.parse(config)
65
+ puppet = Config::Puppet.parse(config, @logger)
66
66
  return 1 if Errors.handle_with_usage(@logger, puppet.errors)
67
67
 
68
68
  ca = Puppetserver::Ca::CertificateAuthority.new(@logger, puppet.settings)
@@ -23,7 +23,7 @@ module Puppetserver
23
23
 
24
24
  def initialize(logger, settings)
25
25
  @logger = logger
26
- @client = HttpClient.new(@logger, settings)
26
+ @client = HttpClient.new(settings)
27
27
  @ca_server = settings[:ca_server]
28
28
  @ca_port = settings[:ca_port]
29
29
  end
@@ -64,10 +64,8 @@ BANNER
64
64
 
65
65
 
66
66
  def self.run(cli_args = ARGV, out = STDOUT, err = STDERR)
67
+ logger = Puppetserver::Ca::Logger.new(:info, out, err)
67
68
  parser, general_options, unparsed = parse_general_inputs(cli_args)
68
- level = general_options.delete('verbose') ? :debug : :info
69
-
70
- logger = Puppetserver::Ca::Logger.new(level, out, err)
71
69
 
72
70
  if general_options['version']
73
71
  logger.inform Puppetserver::Ca::VERSION
@@ -123,9 +121,6 @@ BANNER
123
121
  opts.on('--version', 'Display the version') do |v|
124
122
  parsed['version'] = true
125
123
  end
126
- opts.on('--verbose', 'Display low-level information') do |verbose|
127
- parsed['verbose'] = true
128
- end
129
124
 
130
125
  opts.separator ACTION_OPTIONS
131
126
  opts.separator "\nSee `puppetserver ca <action> --help` for detailed info"
@@ -23,9 +23,9 @@ module Puppetserver
23
23
  # A regex describing valid formats with groups for capturing the value and units
24
24
  TTL_FORMAT = /^(\d+)(y|d|h|m|s)?$/
25
25
 
26
- def self.parse(config_path)
26
+ def self.parse(config_path, logger)
27
27
  instance = new(config_path)
28
- instance.load
28
+ instance.load({}, logger)
29
29
 
30
30
  return instance
31
31
  end
@@ -34,7 +34,7 @@ module Puppetserver
34
34
 
35
35
  def initialize(supplied_config_path = nil)
36
36
  @using_default_location = !supplied_config_path
37
- @config_path = supplied_config_path || user_specific_conf_file
37
+ @config_path = supplied_config_path || user_specific_puppet_config
38
38
 
39
39
  @settings = nil
40
40
  @errors = []
@@ -46,55 +46,45 @@ module Puppetserver
46
46
  # on Windows are unsupported.
47
47
  # Note that Puppet Server runs as the [pe-]puppet user but to
48
48
  # start/stop it you must be root.
49
- def user_specific_conf_dir
50
- @user_specific_conf_dir ||=
51
- if Puppetserver::Ca::Utils::Config.running_as_root?
52
- '/etc/puppetlabs/puppet'
53
- else
54
- "#{ENV['HOME']}/.puppetlabs/etc/puppet"
55
- end
49
+ def user_specific_puppet_confdir
50
+ @user_specific_puppet_confdir ||= Puppetserver::Ca::Utils::Config.puppet_confdir
56
51
  end
57
52
 
58
- def user_specific_conf_file
59
- user_specific_conf_dir + '/puppet.conf'
53
+ def user_specific_puppet_config
54
+ user_specific_puppet_confdir + '/puppet.conf'
60
55
  end
61
56
 
62
- def load(cli_overrides = {})
57
+ def load(cli_overrides = {}, logger)
63
58
  if explicitly_given_config_file_or_default_config_exists?
64
59
  results = parse_text(File.read(@config_path))
65
60
  end
66
61
 
67
62
  results ||= {}
68
63
  results[:main] ||= {}
69
- # The [master] config section is deprecated
70
- # We now favor [server], but support both for backwards compatibility
71
64
  results[:master] ||= {}
72
- results[:server] ||= {}
73
65
  results[:agent] ||= {}
74
66
 
75
- overrides = results[:agent].merge(results[:main]).merge(results[:master]).merge(results[:server])
67
+ overrides = results[:agent].merge(results[:main]).merge(results[:master])
76
68
  overrides.merge!(cli_overrides)
77
- if overrides[:masterport]
78
- overrides[:serverport] ||= overrides.delete(:masterport)
79
- end
80
69
 
81
- @settings = resolve_settings(overrides).freeze
70
+ @settings = resolve_settings(overrides, logger).freeze
82
71
  end
83
72
 
84
73
  def default_certname
85
- hostname = Facter.value(:hostname)
86
- domain = Facter.value(:domain)
87
- if domain and domain != ''
88
- fqdn = [hostname, domain].join('.')
89
- else
90
- fqdn = hostname
91
- end
92
- fqdn.chomp('.')
74
+ @certname ||=
75
+ hostname = Facter.value(:hostname)
76
+ domain = Facter.value(:domain)
77
+ if domain and domain != ''
78
+ fqdn = [hostname, domain].join('.')
79
+ else
80
+ fqdn = hostname
81
+ end
82
+ fqdn.chomp('.')
93
83
  end
94
84
 
95
85
  # Resolve settings from default values, with any overrides for the
96
86
  # specific settings or their dependent settings (ssldir, cadir) taken into account.
97
- def resolve_settings(overrides = {})
87
+ def resolve_settings(overrides = {}, logger)
98
88
  unresolved_setting = /\$[a-z_]+/
99
89
 
100
90
  # Returning the key for unknown keys (rather than nil) is required to
@@ -106,12 +96,12 @@ module Puppetserver
106
96
  # These need to be evaluated before we can construct their dependent
107
97
  # defaults below
108
98
  base_defaults = [
109
- [:confdir, user_specific_conf_dir],
99
+ [:confdir, user_specific_puppet_confdir],
110
100
  [:ssldir,'$confdir/ssl'],
111
101
  [:certdir, '$ssldir/certs'],
112
102
  [:certname, default_certname],
113
103
  [:server, 'puppet'],
114
- [:serverport, '8140'],
104
+ [:masterport, '8140'],
115
105
  [:privatekeydir, '$ssldir/private_keys'],
116
106
  [:publickeydir, '$ssldir/public_keys'],
117
107
  ]
@@ -129,7 +119,7 @@ module Puppetserver
129
119
  :serial => '$cadir/serial',
130
120
  :cert_inventory => '$cadir/inventory.txt',
131
121
  :ca_server => '$server',
132
- :ca_port => '$serverport',
122
+ :ca_port => '$masterport',
133
123
  :localcacert => '$certdir/ca.pem',
134
124
  :hostcrl => '$ssldir/crl.pem',
135
125
  :hostcert => '$certdir/$certname.pem',
@@ -153,9 +143,12 @@ module Puppetserver
153
143
  end
154
144
 
155
145
  cadir = find_cadir(overrides.fetch(:cadir, false),
156
- settings[:confdir])
146
+ settings[:confdir],
147
+ settings[:ssldir],
148
+ logger)
157
149
  settings[:cadir] = substitutions['$cadir'] = cadir
158
150
 
151
+
159
152
  dependent_defaults.each do |setting_name, default_value|
160
153
  setting_value = overrides.fetch(setting_name, default_value)
161
154
  settings[setting_name] = setting_value
@@ -218,17 +211,29 @@ module Puppetserver
218
211
 
219
212
  private
220
213
 
221
- def find_cadir(configured_cadir, confdir)
214
+
215
+ def find_cadir(configured_cadir, confdir, ssldir, logger)
216
+ warning = 'The cadir is currently configured to be inside the ' +
217
+ '%{ssldir} directory. This config setting and the directory ' +
218
+ 'location will not be used in a future version of puppet. ' +
219
+ 'Please run the puppetserver ca tool to migrate out from the ' +
220
+ 'puppet confdir to the /etc/puppetlabs/puppetserver/ca directory. ' +
221
+ 'Use `puppetserver ca migrate --help` for more info.'
222
+
222
223
  if configured_cadir
224
+ if configured_cadir.start_with?(ssldir)
225
+ logger.warn(warning % {ssldir: ssldir})
226
+ end
223
227
  configured_cadir
228
+
224
229
  else
225
230
  old_cadir = Puppetserver::Ca::Utils::Config.old_default_cadir(confdir)
226
231
  new_cadir = Puppetserver::Ca::Utils::Config.new_default_cadir(confdir)
227
-
228
- if File.exist?("#{new_cadir}/ca_crt.pem")
229
- new_cadir
230
- else
232
+ if File.exist?(old_cadir) && !File.symlink?(old_cadir)
233
+ logger.warn(warning % {ssldir: ssldir})
231
234
  old_cadir
235
+ else
236
+ new_cadir
232
237
  end
233
238
  end
234
239
  end
@@ -279,7 +284,7 @@ module Puppetserver
279
284
  end
280
285
 
281
286
  if settings.dig(:server_list, 0, 1) &&
282
- settings[:ca_port] == '$serverport'
287
+ settings[:ca_port] == '$masterport'
283
288
 
284
289
  settings[:ca_port] = settings.dig(:server_list, 0, 1)
285
290
  end
@@ -58,10 +58,10 @@ module Puppetserver
58
58
  @errors = []
59
59
  end
60
60
 
61
- # If both the private and public keys exist for a server then we want
61
+ # If both the private and public keys exist for a master then we want
62
62
  # to honor them here, if only one key exists we want to surface an error,
63
63
  # and if neither exist we generate a new key. This logic is necessary for
64
- # proper bootstrapping for certain server workflows.
64
+ # proper bootstrapping for certain master workflows.
65
65
  def create_private_key(keylength, private_path = '', public_path = '')
66
66
  if File.exists?(private_path) && File.exists?(public_path)
67
67
  return OpenSSL::PKey.read(File.read(private_path))
@@ -20,7 +20,7 @@ module Puppetserver
20
20
 
21
21
  CLI_AUTH_EXT_OID = "1.3.6.1.4.1.34380.1.3.39"
22
22
 
23
- SERVER_EXTENSIONS = [
23
+ MASTER_EXTENSIONS = [
24
24
  ["basicConstraints", "CA:FALSE", true],
25
25
  ["nsComment", "Puppet Server Internal Certificate", false],
26
26
  ["authorityKeyIdentifier", "keyid:always", false],
@@ -132,23 +132,23 @@ module Puppetserver
132
132
  time.strftime('%Y-%m-%dT%H:%M:%S%Z')
133
133
  end
134
134
 
135
- def create_server_cert
136
- server_cert = nil
137
- server_key = @host.create_private_key(@settings[:keylength],
135
+ def create_master_cert
136
+ master_cert = nil
137
+ master_key = @host.create_private_key(@settings[:keylength],
138
138
  @settings[:hostprivkey],
139
139
  @settings[:hostpubkey])
140
- if server_key
141
- server_csr = @host.create_csr(name: @settings[:certname], key: server_key)
140
+ if master_key
141
+ master_csr = @host.create_csr(name: @settings[:certname], key: master_key)
142
142
  if @settings[:subject_alt_names].empty?
143
143
  alt_names = "DNS:puppet, DNS:#{@settings[:certname]}"
144
144
  else
145
145
  alt_names = @settings[:subject_alt_names]
146
146
  end
147
147
 
148
- server_cert = sign_authorized_cert(server_csr, alt_names)
148
+ master_cert = sign_authorized_cert(master_csr, alt_names)
149
149
  end
150
150
 
151
- return server_key, server_cert
151
+ return master_key, master_cert
152
152
  end
153
153
 
154
154
  def sign_authorized_cert(csr, alt_names = '')
@@ -176,7 +176,7 @@ module Puppetserver
176
176
  end
177
177
 
178
178
  def add_authorized_extensions(cert, ef)
179
- SERVER_EXTENSIONS.each do |ext|
179
+ MASTER_EXTENSIONS.each do |ext|
180
180
  extension = ef.create_extension(*ext)
181
181
  cert.add_extension(extension)
182
182
  end
@@ -13,10 +13,6 @@ module Puppetserver
13
13
  @err = err
14
14
  end
15
15
 
16
- def level
17
- @level
18
- end
19
-
20
16
  def debug(text)
21
17
  if @level >= LEVELS[:debug]
22
18
  @out.puts(text)
@@ -1,3 +1,5 @@
1
+ require 'puppetserver/ca/utils/file_system'
2
+
1
3
  module Puppetserver
2
4
  module Ca
3
5
  module Utils
@@ -31,6 +33,10 @@ module Puppetserver
31
33
  File.join(File.dirname(puppet_confdir), 'puppetserver')
32
34
  end
33
35
 
36
+ def self.default_ssldir(confdir = puppet_confdir)
37
+ File.join(confdir, 'ssl')
38
+ end
39
+
34
40
  def self.old_default_cadir(confdir = puppet_confdir)
35
41
  File.join(confdir, 'ssl', 'ca')
36
42
  end
@@ -38,6 +44,17 @@ module Puppetserver
38
44
  def self.new_default_cadir(confdir = puppet_confdir)
39
45
  File.join(puppetserver_confdir(confdir), 'ca')
40
46
  end
47
+
48
+ def self.symlink_to_old_cadir(current_cadir, puppet_confdir)
49
+ old_cadir = old_default_cadir(puppet_confdir)
50
+ new_cadir = new_default_cadir(puppet_confdir)
51
+ return if current_cadir != new_cadir
52
+ # This is only run on setup/import, so there should be no files in the
53
+ # old cadir, so it should be safe to forcibly remove it (which we need
54
+ # to do in order to create a symlink).
55
+ Puppetserver::Ca::Utils::FileSystem.forcibly_symlink(new_cadir, old_cadir)
56
+ end
57
+
41
58
  end
42
59
  end
43
60
  end
@@ -50,6 +50,11 @@ module Puppetserver
50
50
  errors
51
51
  end
52
52
 
53
+ def self.forcibly_symlink(source, link_target)
54
+ FileUtils.remove_dir(link_target, true)
55
+ FileUtils.symlink(source, link_target)
56
+ end
57
+
53
58
  def initialize
54
59
  @user, @group = find_user_and_group
55
60
  end
@@ -19,8 +19,7 @@ module Puppetserver
19
19
 
20
20
  # Not all connections require a client cert to be present.
21
21
  # For example, when querying the status endpoint.
22
- def initialize(logger, settings, with_client_cert: true)
23
- @logger = logger
22
+ def initialize(settings, with_client_cert: true)
24
23
  @store = make_store(settings[:localcacert],
25
24
  settings[:certificate_revocation],
26
25
  settings[:hostcrl])
@@ -51,7 +50,7 @@ module Puppetserver
51
50
  # The Connection object should have HTTP verbs defined on it that take
52
51
  # a body (and optional overrides). Returns whatever the block given returned.
53
52
  def with_connection(url, &block)
54
- request = ->(conn) { block.call(Connection.new(conn, url, @logger)) }
53
+ request = ->(conn) { block.call(Connection.new(conn, url)) }
55
54
 
56
55
  begin
57
56
  Net::HTTP.start(url.host, url.port,
@@ -86,35 +85,29 @@ module Puppetserver
86
85
  # and defines methods named after HTTP verbs that are called on the
87
86
  # saved connection, returning a Result.
88
87
  class Connection
89
- def initialize(net_http_connection, url_struct, logger)
88
+ def initialize(net_http_connection, url_struct)
90
89
  @conn = net_http_connection
91
90
  @url = url_struct
92
- @logger = logger
93
91
  end
94
92
 
95
93
  def get(url_overide = nil, headers = {})
96
94
  url = url_overide || @url
97
95
  headers = DEFAULT_HEADERS.merge(headers)
98
96
 
99
- @logger.debug("Making a GET request at #{url.full_url}")
100
-
101
97
  request = Net::HTTP::Get.new(url.to_uri, headers)
102
98
  result = @conn.request(request)
103
- Result.new(result.code, result.body)
104
99
 
100
+ Result.new(result.code, result.body)
105
101
  end
106
102
 
107
103
  def put(body, url_override = nil, headers = {})
108
104
  url = url_override || @url
109
105
  headers = DEFAULT_HEADERS.merge(headers)
110
106
 
111
- @logger.debug("Making a PUT request at #{url.full_url}")
112
-
113
107
  request = Net::HTTP::Put.new(url.to_uri, headers)
114
108
  request.body = body
115
109
  result = @conn.request(request)
116
110
 
117
-
118
111
  Result.new(result.code, result.body)
119
112
  end
120
113
 
@@ -122,8 +115,6 @@ module Puppetserver
122
115
  url = url_override || @url
123
116
  headers = DEFAULT_HEADERS.merge(headers)
124
117
 
125
- @logger.debug("Making a DELETE request at #{url.full_url}")
126
-
127
118
  result = @conn.request(Net::HTTP::Delete.new(url.to_uri, headers))
128
119
 
129
120
  Result.new(result.code, result.body)
@@ -175,15 +166,15 @@ module Puppetserver
175
166
  def self.check_server_online(settings, logger)
176
167
  status_url = URL.new('https', settings[:ca_server], settings[:ca_port], 'status', 'v1', 'simple', 'ca')
177
168
  begin
178
- # Generating certs offline is necessary if the server cert has been destroyed
169
+ # Generating certs offline is necessary if the master cert has been destroyed
179
170
  # or compromised. Since querying the status endpoint does not require a client cert, and
180
171
  # we commonly won't have one, don't require one for creating the connection.
181
172
  # Additionally, we want to ensure the server is stopped before migrating the CA dir to
182
173
  # avoid issues with writing to the CA dir and moving it.
183
- self.new(logger, settings, with_client_cert: false).with_connection(status_url) do |conn|
174
+ self.new(settings, with_client_cert: false).with_connection(status_url) do |conn|
184
175
  result = conn.get
185
176
  if result.body == "running"
186
- logger.err "Puppetserver service is running. Please stop it before attempting to run this command."
177
+ logger.err "CA service is running. Please stop it before attempting to run this command."
187
178
  true
188
179
  else
189
180
  false
@@ -1,5 +1,5 @@
1
1
  module Puppetserver
2
2
  module Ca
3
- VERSION = "1.10.0"
3
+ VERSION = "2.0.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppetserver-ca
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet, Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-07-06 00:00:00.000000000 Z
11
+ date: 2020-11-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: facter