puppetserver-ca 1.11.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +5 -15
- data/lib/puppetserver/ca/action/clean.rb +3 -3
- data/lib/puppetserver/ca/action/enable.rb +1 -1
- data/lib/puppetserver/ca/action/generate.rb +8 -27
- data/lib/puppetserver/ca/action/import.rb +15 -12
- data/lib/puppetserver/ca/action/list.rb +20 -87
- data/lib/puppetserver/ca/action/migrate.rb +1 -9
- data/lib/puppetserver/ca/action/revoke.rb +3 -3
- data/lib/puppetserver/ca/action/setup.rb +16 -13
- data/lib/puppetserver/ca/action/sign.rb +1 -1
- data/lib/puppetserver/ca/certificate_authority.rb +9 -9
- data/lib/puppetserver/ca/cli.rb +7 -14
- data/lib/puppetserver/ca/config/puppet.rb +45 -40
- data/lib/puppetserver/ca/host.rb +2 -2
- data/lib/puppetserver/ca/local_certificate_authority.rb +9 -9
- data/lib/puppetserver/ca/logger.rb +1 -9
- data/lib/puppetserver/ca/utils/config.rb +17 -0
- data/lib/puppetserver/ca/utils/file_system.rb +5 -0
- data/lib/puppetserver/ca/utils/http_client.rb +10 -22
- data/lib/puppetserver/ca/version.rb +1 -1
- metadata +3 -4
- data/lib/puppetserver/ca/action/prune.rb +0 -137
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6523b5628cc4d83aa2627326400a2fb493a18f28d7e4da4b8046eac41e09c555
|
4
|
+
data.tar.gz: 6e8cfbeb2a63ad443f22b196d9cdf2749242ef552c6376fd55b723aa699ceefd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 82c62889b706bad66349d5efd8469969b919d8d90741c57c12827eccdedf2de80597ea923509c66de6d6f317da365d860705d556441ce817167d323ad6e80325
|
7
|
+
data.tar.gz: 72cca87e22e38e8c6b2b7975d4920057f5364c7a9499bcf30553894b9285468a0cb1d3fd93aace8974a889a0e0a0ed35f348d902139a07d0f588957e61f479f4
|
data/README.md
CHANGED
@@ -55,30 +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 remove duplicated entries from Puppet's CRL:
|
59
|
-
```
|
60
|
-
puppetserver ca prune
|
61
|
-
```
|
62
|
-
|
63
|
-
To enable verbose mode:
|
64
|
-
```
|
65
|
-
puppetserver ca --verbose <action>
|
66
|
-
```
|
67
|
-
|
68
58
|
For more details, see the help output:
|
69
59
|
```
|
70
60
|
puppetserver ca --help
|
71
61
|
```
|
72
62
|
|
73
63
|
This code in this project is licensed under the Apache Software License v2,
|
74
|
-
please see the included [License](https://github.com/puppetlabs/puppetserver-ca-cli/blob/
|
64
|
+
please see the included [License](https://github.com/puppetlabs/puppetserver-ca-cli/blob/master/LICENSE.md)
|
75
65
|
for more details.
|
76
66
|
|
77
67
|
|
78
68
|
## Development
|
79
69
|
|
80
70
|
After checking out the repo, run `bin/setup` to install dependencies. Then,
|
81
|
-
run `
|
71
|
+
run `rake spec` to run the tests. You can also run `bin/console` for an
|
82
72
|
interactive prompt that will allow you to experiment.
|
83
73
|
|
84
74
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
@@ -102,7 +92,7 @@ To test your changes on a VM:
|
|
102
92
|
1. To confirm that installation was successful, run `puppetserver ca --help`
|
103
93
|
|
104
94
|
### Releasing
|
105
|
-
To release a new version, run the [release pipeline](https://jenkins-
|
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.
|
106
96
|
|
107
97
|
|
108
98
|
## Contributing & Support
|
@@ -115,9 +105,9 @@ Freenode, or the Puppet Community Slack channel.
|
|
115
105
|
|
116
106
|
Contributions are welcome at https://github.com/puppetlabs/puppetserver-ca-cli/pulls.
|
117
107
|
Contributors should both be sure to read the
|
118
|
-
[contributing document](https://github.com/puppetlabs/puppetserver-ca-cli/blob/
|
108
|
+
[contributing document](https://github.com/puppetlabs/puppetserver-ca-cli/blob/master/CONTRIBUTING.md)
|
119
109
|
and sign the [contributor license agreement](https://cla.puppet.com/).
|
120
110
|
|
121
111
|
Everyone interacting with the project’s codebase, issue tracker, etc is expected
|
122
112
|
to follow the
|
123
|
-
[code of conduct](https://github.com/puppetlabs/puppetserver-ca-cli/blob/
|
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
|
-
|
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
|
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)
|
@@ -18,7 +18,7 @@ module Puppetserver
|
|
18
18
|
|
19
19
|
# Only allow printing ascii characters, excluding /
|
20
20
|
VALID_CERTNAME = /\A[ -.0-~]+\Z/
|
21
|
-
|
21
|
+
CERTNAME_BLACKLIST = %w{--all --config}
|
22
22
|
|
23
23
|
SUMMARY = "Generate a new certificate signed by the CA"
|
24
24
|
BANNER = <<-BANNER
|
@@ -26,7 +26,7 @@ Usage:
|
|
26
26
|
puppetserver ca generate [--help]
|
27
27
|
puppetserver ca generate --certname NAME[,NAME] [--config PATH]
|
28
28
|
[--subject-alt-names NAME[,NAME]]
|
29
|
-
[--ca-client
|
29
|
+
[--ca-client]
|
30
30
|
|
31
31
|
Description:
|
32
32
|
Generates a new certificate signed by the intermediate CA
|
@@ -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
|
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).
|
@@ -75,10 +75,6 @@ BANNER
|
|
75
75
|
'Causes the cert to be generated offline.') do |ca_client|
|
76
76
|
parsed['ca-client'] = true
|
77
77
|
end
|
78
|
-
opts.on('--force', 'Suppress errors when signing cert offline.',
|
79
|
-
"To be used with '--ca-client'") do |force|
|
80
|
-
parsed['force'] = true
|
81
|
-
end
|
82
78
|
opts.on('--ttl TTL', 'The time-to-live for each cert generated and signed') do |ttl|
|
83
79
|
parsed['ttl'] = ttl
|
84
80
|
end
|
@@ -95,7 +91,7 @@ BANNER
|
|
95
91
|
errors << ' At least one certname is required to generate'
|
96
92
|
else
|
97
93
|
results['certnames'].each do |certname|
|
98
|
-
if
|
94
|
+
if CERTNAME_BLACKLIST.include?(certname)
|
99
95
|
errors << " Cannot manage cert named `#{certname}` from " +
|
100
96
|
"the CLI, if needed use the HTTP API directly"
|
101
97
|
end
|
@@ -130,7 +126,7 @@ BANNER
|
|
130
126
|
# Load, resolve, and validate puppet config settings
|
131
127
|
settings_overrides = {}
|
132
128
|
puppet = Config::Puppet.new(config_path)
|
133
|
-
puppet.load(settings_overrides)
|
129
|
+
puppet.load(settings_overrides, @logger)
|
134
130
|
return 1 if Errors.handle_with_usage(@logger, puppet.errors)
|
135
131
|
|
136
132
|
# We don't want generate to respect the alt names setting, since it is usually
|
@@ -143,21 +139,8 @@ BANNER
|
|
143
139
|
|
144
140
|
# Generate and save certs and associated keys
|
145
141
|
if input['ca-client']
|
146
|
-
#
|
147
|
-
|
148
|
-
return 1 if HttpClient.check_server_online(puppet.settings, @logger)
|
149
|
-
rescue Puppetserver::Ca::ConnectionFailed => e
|
150
|
-
base_message = "Could not determine whether Puppet Server is online."
|
151
|
-
if input['force']
|
152
|
-
@logger.inform("#{base_message} Connection check failed with " \
|
153
|
-
"error: #{e.wrapped}\nContinuing with certificate signing.")
|
154
|
-
else
|
155
|
-
@logger.inform("#{base_message} If you are certain that the " \
|
156
|
-
"Puppetserver service is stopped, run this command again " \
|
157
|
-
"with the '--force' flag.")
|
158
|
-
raise e
|
159
|
-
end
|
160
|
-
end
|
142
|
+
# Refused to generate certs offfline if the CA service is running
|
143
|
+
return 1 if HttpClient.check_server_online(puppet.settings, @logger)
|
161
144
|
all_passed = generate_authorized_certs(certnames, alt_names, puppet.settings, signer.digest)
|
162
145
|
else
|
163
146
|
all_passed = generate_certs(certnames, alt_names, puppet.settings, signer.digest, input['ttl'])
|
@@ -313,9 +296,7 @@ BANNER
|
|
313
296
|
end
|
314
297
|
|
315
298
|
def process_alt_names(alt_names, certname)
|
316
|
-
|
317
|
-
# the certname as a SAN, see RFC 2818 https://tools.ietf.org/html/rfc2818#section-3.1.
|
318
|
-
return "DNS:#{certname}" if alt_names.empty?
|
299
|
+
return '' if alt_names.empty?
|
319
300
|
|
320
301
|
current_alt_names = alt_names.dup
|
321
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
|
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
|
-
|
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],
|
92
|
-
[settings[:hostcert],
|
93
|
-
[settings[:cert_inventory], ca.inventory_entry(
|
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"),
|
99
|
+
[File.join(settings[:signeddir], "#{settings[:certname]}.pem"), master_cert]
|
99
100
|
]
|
100
101
|
|
101
102
|
private_files = [
|
102
|
-
[settings[:hostprivkey],
|
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
|
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
|
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
|
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
|
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,16 +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
|
-
missing = []
|
66
|
-
|
67
|
-
unless VALID_FORMAT.include?(output_format)
|
68
|
-
Errors.handle_with_usage(@logger, ["Unknown format flag '#{output_format}'. Valid formats are '#{VALID_FORMAT.join("', '")}'."])
|
69
|
-
return 1
|
70
|
-
end
|
71
60
|
|
72
61
|
if all && certnames.any?
|
73
|
-
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'])
|
74
63
|
return 1
|
75
64
|
end
|
76
65
|
|
@@ -79,74 +68,27 @@ Options:
|
|
79
68
|
return 1 if Errors.handle_with_usage(@logger, errors)
|
80
69
|
end
|
81
70
|
|
82
|
-
puppet = Config::Puppet.parse(config)
|
71
|
+
puppet = Config::Puppet.parse(config, @logger)
|
83
72
|
return 1 if Errors.handle_with_usage(@logger, puppet.errors)
|
84
73
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
filter_names = lambda { |x| true }
|
89
|
-
end
|
90
|
-
|
91
|
-
if (all || certnames.any?)
|
92
|
-
found_certs = get_certs_or_csrs(puppet.settings)
|
93
|
-
if found_certs.nil?
|
94
|
-
# nil is different from no certs found
|
95
|
-
@logger.err('Error while getting certificates')
|
96
|
-
return 1
|
97
|
-
end
|
98
|
-
all_certs = found_certs.select { |cert| filter_names.call(cert) }
|
99
|
-
requested, signed, revoked = separate_certs(all_certs)
|
100
|
-
missing = certnames - all_certs.map { |cert| cert['name'] }
|
101
|
-
output_certs_by_state(all, output_format, requested, signed, revoked, missing)
|
102
|
-
else
|
103
|
-
all_csrs = get_certs_or_csrs(puppet.settings, "requested")
|
104
|
-
if all_csrs.nil?
|
105
|
-
# nil is different from no certs found
|
106
|
-
@logger.err('Error while getting certificate requests')
|
107
|
-
return 1
|
108
|
-
end
|
109
|
-
output_certs_by_state(all, output_format, all_csrs)
|
110
|
-
end
|
74
|
+
filter_names = certnames.any? \
|
75
|
+
? lambda { |x| certnames.include?(x['name']) }
|
76
|
+
: lambda { |x| true }
|
111
77
|
|
112
|
-
|
113
|
-
|
78
|
+
all_certs = get_all_certs(puppet.settings).select { |cert| filter_names.call(cert) }
|
79
|
+
requested, signed, revoked = separate_certs(all_certs)
|
80
|
+
missing = certnames - all_certs.map { |cert| cert['name'] }
|
114
81
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
else
|
119
|
-
output_certs_text_format(requested, signed, revoked, missing)
|
120
|
-
end
|
121
|
-
end
|
82
|
+
(all || certnames.any?) \
|
83
|
+
? output_certs_by_state(requested, signed, revoked, missing)
|
84
|
+
: output_certs_by_state(requested)
|
122
85
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
if all
|
127
|
-
grouped_cert = { "requested" => requested,
|
128
|
-
"signed" => signed,
|
129
|
-
"revoked" => revoked }.to_json
|
130
|
-
@logger.inform(grouped_cert)
|
131
|
-
else
|
132
|
-
grouped_cert["requested"] = requested unless requested.empty?
|
133
|
-
grouped_cert["signed"] = signed unless signed.empty?
|
134
|
-
grouped_cert["revoked"] = revoked unless revoked.empty?
|
135
|
-
grouped_cert["missing"] = missing unless missing.empty?
|
136
|
-
|
137
|
-
# If neither the '--all' flag or the '--certname' flag was passed in
|
138
|
-
# and the requested cert array is empty, we output a JSON object
|
139
|
-
# with an empty 'requested' key. Otherwise, we display
|
140
|
-
# any of the classes that are currently in grouped_cert
|
141
|
-
if grouped_cert.empty?
|
142
|
-
@logger.inform({ "requested" => requested }.to_json)
|
143
|
-
else
|
144
|
-
@logger.inform(grouped_cert.to_json)
|
145
|
-
end
|
146
|
-
end
|
86
|
+
return missing.any? \
|
87
|
+
? 1
|
88
|
+
: 0
|
147
89
|
end
|
148
90
|
|
149
|
-
def
|
91
|
+
def output_certs_by_state(requested, signed = [], revoked = [], missing = [])
|
150
92
|
if revoked.empty? && signed.empty? && requested.empty? && missing.empty?
|
151
93
|
@logger.inform "No certificates to list"
|
152
94
|
return
|
@@ -221,15 +163,9 @@ Options:
|
|
221
163
|
return requested, signed, revoked
|
222
164
|
end
|
223
165
|
|
224
|
-
def
|
225
|
-
|
226
|
-
result
|
227
|
-
|
228
|
-
if result
|
229
|
-
return JSON.parse(result.body)
|
230
|
-
else
|
231
|
-
return nil
|
232
|
-
end
|
166
|
+
def get_all_certs(settings)
|
167
|
+
result = Puppetserver::Ca::CertificateAuthority.new(@logger, settings).get_certificate_statuses
|
168
|
+
result ? JSON.parse(result.body) : []
|
233
169
|
end
|
234
170
|
|
235
171
|
def parse(args)
|
@@ -240,11 +176,8 @@ Options:
|
|
240
176
|
|
241
177
|
errors_were_handled = Errors.handle_with_usage(@logger, errors, parser.help)
|
242
178
|
|
243
|
-
|
244
|
-
|
245
|
-
else
|
246
|
-
exit_code = nil
|
247
|
-
end
|
179
|
+
exit_code = errors_were_handled ? 1 : nil
|
180
|
+
|
248
181
|
return results, exit_code
|
249
182
|
end
|
250
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
|
-
|
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
|
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
|
-
|
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
|
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
|
-
|
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],
|
94
|
+
[settings[:hostcert], master_cert],
|
94
95
|
[settings[:localcacert], [ca.cert, root_cert]],
|
95
96
|
[settings[:hostcrl], [ca.crl, root_crl]],
|
96
|
-
[settings[:hostpubkey],
|
97
|
+
[settings[:hostpubkey], master_key.public_key],
|
97
98
|
[settings[:capub], ca.key.public_key],
|
98
|
-
[settings[:cert_inventory], ca.inventory_entry(
|
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"),
|
103
|
+
[File.join(settings[:signeddir], "#{settings[:certname]}.pem"), master_cert],
|
103
104
|
]
|
104
105
|
|
105
106
|
private_files = [
|
106
|
-
[settings[:hostprivkey],
|
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
|
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
|
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
|
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
|
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(
|
26
|
+
@client = HttpClient.new(settings)
|
27
27
|
@ca_server = settings[:ca_server]
|
28
28
|
@ca_port = settings[:ca_port]
|
29
29
|
end
|
@@ -41,8 +41,8 @@ module Puppetserver
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Returns a URI-like wrapper around CA specific urls
|
44
|
-
def make_ca_url(resource_type = nil, certname = nil
|
45
|
-
HttpClient::URL.new('https', @ca_server, @ca_port, 'puppet-ca', 'v1', resource_type, certname
|
44
|
+
def make_ca_url(resource_type = nil, certname = nil)
|
45
|
+
HttpClient::URL.new('https', @ca_server, @ca_port, 'puppet-ca', 'v1', resource_type, certname)
|
46
46
|
end
|
47
47
|
|
48
48
|
def process_ttl_input(ttl)
|
@@ -141,7 +141,7 @@ module Puppetserver
|
|
141
141
|
when :revoke
|
142
142
|
case result.code
|
143
143
|
when '200', '204'
|
144
|
-
@logger.inform "
|
144
|
+
@logger.inform "Revoked certificate for #{certname}"
|
145
145
|
return :success
|
146
146
|
when '404'
|
147
147
|
@logger.err 'Error:'
|
@@ -215,7 +215,7 @@ module Puppetserver
|
|
215
215
|
def check_revocation(certname, result)
|
216
216
|
case result.code
|
217
217
|
when '200', '204'
|
218
|
-
@logger.inform "
|
218
|
+
@logger.inform "Revoked certificate for #{certname}"
|
219
219
|
return :success
|
220
220
|
when '409'
|
221
221
|
return :invalid
|
@@ -250,8 +250,8 @@ module Puppetserver
|
|
250
250
|
end
|
251
251
|
|
252
252
|
# Returns nil for errors, else the result of the GET request
|
253
|
-
def get_certificate_statuses
|
254
|
-
result = get('certificate_statuses', 'any_key'
|
253
|
+
def get_certificate_statuses
|
254
|
+
result = get('certificate_statuses', 'any_key')
|
255
255
|
|
256
256
|
unless result.code == '200'
|
257
257
|
@logger.err 'Error:'
|
@@ -287,8 +287,8 @@ module Puppetserver
|
|
287
287
|
# @param resource_type [String] the resource type of url
|
288
288
|
# @param resource_name [String] the resource name of url
|
289
289
|
# @return [Struct] an instance of the Result struct with :code, :body
|
290
|
-
def get(resource_type, resource_name
|
291
|
-
url = make_ca_url(resource_type, resource_name
|
290
|
+
def get(resource_type, resource_name)
|
291
|
+
url = make_ca_url(resource_type, resource_name)
|
292
292
|
@client.with_connection(url) do |connection|
|
293
293
|
connection.get(url)
|
294
294
|
end
|