puppetserver-ca 0.0.1.pre.dev1 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29470ef5b2d156af3ab35e6b08bba8cf04f9ace7
4
- data.tar.gz: 9c194481163f5a9b5e9e7974b5929189141f2d1f
3
+ metadata.gz: 3ce9f1836cdf33c3a90c4ead5503c9e3bd77dd4c
4
+ data.tar.gz: 4c935b843c029cce7626c9b5ae5ec4d2e3d7a483
5
5
  SHA512:
6
- metadata.gz: 4a685288d88e4a2388736cef346d9c7d7d24f23bf4b5befc968f296b44443faf652fbe47702f9d1a10c999bfad089164cffc7b7525b9dd5cb6cf54c7abbe30ae
7
- data.tar.gz: '08f50143a3a5090ee5173fd27e0391d99eda1c56bfeff627804da40bb209a40f7bab095d479c8ef07791bd0a4ed2d00b48679a01c8dcaa8a1a8186ef84ec2b50'
6
+ metadata.gz: 136312e8f3183ba47e97d7e256c6887e22b044bc4b455cb0d7f7e635835b511a83e2a78d53c87b6c45f12c1b11ff149a82dd02346324fde2a75dcb656de4c688
7
+ data.tar.gz: 1bff6c715e519f6cc4fcb238059c318659b244a7fad493d8a4b446a7d204a9947464838adb76f213a80fbf7416088b49231dab4531013318c8703abf01b6b579
@@ -1,5 +1,11 @@
1
1
  sudo: false
2
2
  language: ruby
3
+ notifications:
4
+ email: false
3
5
  rvm:
4
- - 2.3.4
6
+ - 2.3
7
+ - 2.4
8
+ - 2.5
5
9
  before_install: gem install bundler -v 1.16.1
10
+ script:
11
+ - bundle exec rake spec
data/Gemfile CHANGED
@@ -4,3 +4,6 @@ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in puppetserver-ca.gemspec
6
6
  gemspec
7
+
8
+ gem 'pry'
9
+ gem 'pry-byebug'
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # This requires everything in our Gemfile, so when functionally testing
4
+ # our debugging tools are available without having to require them
5
+ require 'bundler/setup'
6
+ Bundler.require(:default)
7
+
8
+ require 'puppetserver/ca/cli'
9
+
10
+ exit Puppetserver::Ca::Cli.run(ARGV)
@@ -0,0 +1,105 @@
1
+ require 'optparse'
2
+ require 'puppetserver/ca/version'
3
+ require 'puppetserver/ca/setup_action'
4
+ require 'puppetserver/ca/logger'
5
+
6
+ module Puppetserver
7
+ module Ca
8
+ class Cli
9
+ BANNER= <<-BANNER
10
+ Usage: puppetserver ca <action> [options]
11
+
12
+ Manage the Private Key Infrastructure for
13
+ Puppet Server's built-in Certificate Authority
14
+ BANNER
15
+
16
+ VALID_ACTIONS = {'setup' => SetupAction}
17
+
18
+ ACTION_LIST = "\nAvailable Actions:\n" +
19
+ VALID_ACTIONS.map do |action, cls|
20
+ " #{action}\t#{cls::SUMMARY}"
21
+ end.join("\n")
22
+
23
+ ACTION_OPTIONS = "\nAction Options:\n" +
24
+ VALID_ACTIONS.map do |action, cls|
25
+ " #{action}:\n" +
26
+ cls.parser.summarize.
27
+ select{|line| line =~ /^\s*--/ }.
28
+ reject{|line| line =~ /--help|--version/ }.join('')
29
+ end.join("\n")
30
+
31
+
32
+ def self.run(cli_args = ARGV, out = STDOUT, err = STDERR)
33
+ logger = Puppetserver::Ca::Logger.new(:info, out, err)
34
+ parser, general_options, unparsed = parse_general_inputs(cli_args)
35
+
36
+ if general_options['version']
37
+ logger.inform Puppetserver::Ca::VERSION
38
+ return 0
39
+ end
40
+
41
+ action_argument = unparsed.shift
42
+ action_class = VALID_ACTIONS[action_argument]
43
+
44
+ if general_options['help']
45
+ if action_class
46
+ logger.inform action_class.parser.help
47
+ else
48
+ logger.inform parser.help
49
+ end
50
+
51
+ return 0
52
+ end
53
+
54
+ if action_class
55
+ action = action_class.new(logger)
56
+ input, exit_code = action.parse(unparsed)
57
+
58
+ if exit_code
59
+ return exit_code
60
+ else
61
+ return action.run(input)
62
+ end
63
+ else
64
+ logger.warn "Unknown action: #{action_argument}"
65
+ logger.warn parser.help
66
+ return 1
67
+ end
68
+ end
69
+
70
+ def self.parse_general_inputs(inputs)
71
+ parsed = {}
72
+ general_parser = OptionParser.new do |opts|
73
+ opts.banner = BANNER
74
+ opts.separator ACTION_LIST
75
+ opts.separator "\nGeneral Options:"
76
+
77
+ opts.on('--help', 'Display this general help output') do |help|
78
+ parsed['help'] = true
79
+ end
80
+ opts.on('--version', 'Display the version') do |v|
81
+ parsed['version'] = true
82
+ end
83
+
84
+ opts.separator ACTION_OPTIONS
85
+ opts.separator "\nSee `puppetserver ca <action> --help` for detailed info"
86
+
87
+ end
88
+
89
+ unparsed, nonopts = [], []
90
+
91
+ begin
92
+ general_parser.order!(inputs) do |nonopt|
93
+ nonopts << nonopt
94
+ end
95
+ rescue OptionParser::InvalidOption => e
96
+ unparsed += e.args
97
+ unparsed << inputs.shift unless inputs.first =~ /^-{1,2}/
98
+ retry
99
+ end
100
+
101
+ return general_parser, parsed, nonopts + unparsed
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,41 @@
1
+ module Puppetserver
2
+ module Ca
3
+ class Logger
4
+ LEVELS = {error: 1, warning: 2, info: 3, debug: 4}
5
+
6
+ def initialize(level = :info, out = STDOUT, err = STDERR)
7
+ @level = LEVELS[level]
8
+ if @level.nil?
9
+ raise ArgumentError, "Unknown log level #{level}"
10
+ end
11
+
12
+ @out = out
13
+ @err = err
14
+ end
15
+
16
+ def debug(text)
17
+ if @level >= LEVELS[:debug]
18
+ @out.puts(text)
19
+ end
20
+ end
21
+
22
+ def inform(text)
23
+ if @level >= LEVELS[:info]
24
+ @out.puts(text)
25
+ end
26
+ end
27
+
28
+ def warn(text)
29
+ if @level >= LEVELS[:warning]
30
+ @err.puts(text)
31
+ end
32
+ end
33
+
34
+ def err(text)
35
+ if @level >= LEVELS[:error]
36
+ @err.puts(text)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,134 @@
1
+
2
+ module Puppetserver
3
+ module Ca
4
+ # Provides an interface for asking for Puppet[ Server] settings w/o loading
5
+ # either Puppet or Puppet Server. Includes a simple ini parser that will
6
+ # ignore Puppet's more complicated conventions.
7
+ class PuppetConfig
8
+
9
+ def self.parse(config_path = nil)
10
+ instance = new(config_path)
11
+ instance.load
12
+
13
+ return instance
14
+ end
15
+
16
+ attr_reader :errors, :settings
17
+
18
+ def initialize(supplied_config_path = nil)
19
+ @using_default_location = !supplied_config_path
20
+ @config_path = supplied_config_path || user_specific_conf_file
21
+
22
+ @settings = nil
23
+ @errors = []
24
+ end
25
+
26
+ # Return the correct confdir. We check for being root on *nix,
27
+ # else the user path. We do not include a check for running
28
+ # as Adminstrator since non-development scenarios for Puppet Server
29
+ # on Windows are unsupported.
30
+ # Note that Puppet Server runs as the [pe-]puppet user but to
31
+ # start/stop it you must be root.
32
+ def user_specific_conf_dir
33
+ if running_as_root?
34
+ '/etc/puppetlabs/puppet'
35
+ else
36
+ "#{ENV['HOME']}/.puppetlabs/etc/puppet"
37
+ end
38
+ end
39
+
40
+ def user_specific_conf_file
41
+ user_specific_conf_dir + '/puppet.conf'
42
+ end
43
+
44
+ def load
45
+ if explicitly_given_config_file_or_default_config_exists?
46
+ results = parse_text(File.read(@config_path))
47
+ end
48
+
49
+ results ||= {}
50
+ results[:main] ||= {}
51
+ results[:master] ||= {}
52
+
53
+ overrides = results[:main].merge(results[:master])
54
+
55
+ @settings = resolve_settings(overrides).freeze
56
+ end
57
+
58
+ # Resolve the cacert, cakey, and cacrl settings from default values,
59
+ # with any overrides for the specific settings or their dependent
60
+ # settings (ssldir, cadir) taken into account.
61
+ def resolve_settings(overrides = {})
62
+ unresolved_setting = /\$[a-z_]+/
63
+
64
+ # Returning the key for unknown keys (rather than nil) is required to
65
+ # keep unknown settings in the string for later verification.
66
+ substitutions = Hash.new {|h, k| k }
67
+ settings = {}
68
+
69
+ confdir = user_specific_conf_dir
70
+ settings[:confdir] = substitutions['$confdir'] = confdir
71
+
72
+ ssldir = overrides.fetch(:ssldir, '$confdir/ssl')
73
+ settings[:ssldir] = substitutions['$ssldir'] = ssldir.sub('$confdir', confdir)
74
+
75
+ cadir = overrides.fetch(:cadir, '$ssldir/ca')
76
+ settings[:cadir] = substitutions['$cadir'] = cadir.sub(unresolved_setting, substitutions)
77
+
78
+ settings[:cacert] = overrides.fetch(:cacert, '$cadir/ca_crt.pem')
79
+ settings[:cakey] = overrides.fetch(:cakey, '$cadir/ca_key.pem')
80
+ settings[:cacrl] = overrides.fetch(:cacrl, '$cadir/ca_crl.pem')
81
+ settings[:serial] = overrides.fetch(:serial, '$cadir/serial')
82
+ settings[:cert_inventory] = overrides.fetch(:cert_inventory, '$cadir/inventory.txt')
83
+
84
+ settings.each_pair do |key, value|
85
+ settings[key] = value.sub(unresolved_setting, substitutions)
86
+
87
+ if match = settings[key].match(unresolved_setting)
88
+ @errors << "Could not parse #{match[0]} in #{value}, " +
89
+ 'valid settings to be interpolated are ' +
90
+ '$ssldir or $cadir'
91
+ end
92
+ end
93
+
94
+ return settings
95
+ end
96
+
97
+ # Parse an inifile formatted String. Only captures \word character
98
+ # class keys/section names but nearly any character values (excluding
99
+ # leading whitespace) up to one of whitespace, opening curly brace, or
100
+ # hash sign (Our concern being to capture filesystem path values).
101
+ # Put values without a section into :main.
102
+ #
103
+ # Return Hash of Symbol section names with Symbol setting keys and
104
+ # String values.
105
+ def parse_text(text)
106
+ res = {}
107
+ current_section = :main
108
+ text.each_line do |line|
109
+ case line
110
+ when /^\s*\[(\w+)\].*/
111
+ current_section = $1.to_sym
112
+ when /^\s*(\w+)\s*=\s*([^\s{#]+).*$/
113
+ # Using a Hash with a default key breaks RSpec expectations.
114
+ res[current_section] ||= {}
115
+ res[current_section][$1.to_sym] = $2
116
+ end
117
+ end
118
+
119
+ res
120
+ end
121
+
122
+
123
+ private
124
+
125
+ def explicitly_given_config_file_or_default_config_exists?
126
+ !@using_default_location || File.exist?(@config_path)
127
+ end
128
+
129
+ def running_as_root?
130
+ !Gem.win_platform? && Process::UID.eid == 0
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,211 @@
1
+ require 'etc'
2
+ require 'fileutils'
3
+ require 'optparse'
4
+ require 'puppetserver/ca/x509_loader'
5
+ require 'puppetserver/ca/puppet_config'
6
+
7
+ module Puppetserver
8
+ module Ca
9
+ class SetupAction
10
+
11
+ SUMMARY = "Set up the CA's key, certs, and crls"
12
+ BANNER = <<-BANNER
13
+ Usage:
14
+ puppetserver ca setup [--help|--version]
15
+ puppetserver ca setup [--config PATH]
16
+ --private-key PATH --cert-bundle PATH --crl-chain PATH
17
+
18
+ Description:
19
+ Given a private key, cert bundle, and a crl chain,
20
+ validate and import to the Puppet Server CA.
21
+
22
+ To determine the target location the default puppet.conf
23
+ is consulted for custom values. If using a custom puppet.conf
24
+ provide it with the --config flag
25
+
26
+ Options:
27
+ BANNER
28
+
29
+ def initialize(logger)
30
+ @logger = logger
31
+ end
32
+
33
+ def run(input)
34
+ bundle_path = input['cert-bundle']
35
+ key_path = input['private-key']
36
+ chain_path = input['crl-chain']
37
+ config_path = input['config']
38
+
39
+ files = [bundle_path, key_path, chain_path, config_path].compact
40
+
41
+ errors = validate_file_paths(files)
42
+ return 1 if log_possible_errors(errors)
43
+
44
+ loader = X509Loader.new(bundle_path, key_path, chain_path)
45
+ return 1 if log_possible_errors(loader.errors)
46
+
47
+ puppet = PuppetConfig.parse(config_path)
48
+ return 1 if log_possible_errors(puppet.errors)
49
+
50
+ user, group = find_user_and_group
51
+
52
+ if !File.exist?(puppet.settings[:cadir])
53
+ FileUtils.mkdir_p(puppet.settings[:cadir], mode: 0750)
54
+ FileUtils.chown(user, group, puppet.settings[:cadir])
55
+ end
56
+
57
+ write_file(puppet.settings[:cacert], loader.certs, user, group, 0640)
58
+
59
+ write_file(puppet.settings[:cakey], loader.key, user, group, 0640)
60
+
61
+ write_file(puppet.settings[:cacrl], loader.crls, user, group, 0640)
62
+
63
+ if !File.exist?(puppet.settings[:serial])
64
+ write_file(puppet.settings[:serial], "001", user, group, 0640)
65
+ end
66
+
67
+ if !File.exist?(puppet.settings[:cert_inventory])
68
+ write_file(puppet.settings[:cert_inventory],
69
+ "", user, group, 0640)
70
+ end
71
+
72
+ return 0
73
+ end
74
+
75
+ def find_user_and_group
76
+ if !running_as_root?
77
+ return Process.euid, Process.egid
78
+ else
79
+ if pe_puppet_exists?
80
+ return 'pe-puppet', 'pe-puppet'
81
+ else
82
+ return 'puppet', 'puppet'
83
+ end
84
+ end
85
+ end
86
+
87
+ def running_as_root?
88
+ !Gem.win_platform? && Process.euid == 0
89
+ end
90
+
91
+ def pe_puppet_exists?
92
+ !!(Etc.getpwnam('pe-puppet') rescue nil)
93
+ end
94
+
95
+ def write_file(path, one_or_more_objects, user, group, mode)
96
+ if File.exist?(path)
97
+ @logger.warn("#{path} exists, overwriting")
98
+ end
99
+
100
+ File.open(path, 'w', mode) do |f|
101
+ Array(one_or_more_objects).each do |object|
102
+ f.puts object.to_s
103
+ end
104
+ end
105
+
106
+ FileUtils.chown(user, group, path)
107
+ end
108
+
109
+ def log_possible_errors(maybe_errors)
110
+ errors = Array(maybe_errors).compact
111
+ unless errors.empty?
112
+ @logger.err "Error:"
113
+ errors.each do |message|
114
+ @logger.err " #{message}"
115
+ end
116
+ return true
117
+ end
118
+ end
119
+
120
+ def parse(cli_args)
121
+ parser, inputs, unparsed = parse_inputs(cli_args)
122
+
123
+ if !unparsed.empty?
124
+ @logger.err 'Error:'
125
+ @logger.err 'Unknown arguments or flags:'
126
+ unparsed.each do |arg|
127
+ @logger.err " #{arg}"
128
+ end
129
+
130
+ @logger.err ''
131
+ @logger.err parser.help
132
+
133
+ exit_code = 1
134
+ else
135
+ exit_code = validate_inputs(inputs, parser.help)
136
+ end
137
+
138
+ return inputs, exit_code
139
+ end
140
+
141
+ def validate_inputs(input, usage)
142
+ exit_code = nil
143
+
144
+ if input.values_at('cert-bundle', 'private-key', 'crl-chain').any?(&:nil?)
145
+ @logger.err 'Error:'
146
+ @logger.err 'Missing required argument'
147
+ @logger.err ' --cert-bundle, --private-key, --crl-chain are required'
148
+ @logger.err ''
149
+ @logger.err usage
150
+ exit_code = 1
151
+ end
152
+
153
+ exit_code
154
+ end
155
+
156
+ def parse_inputs(inputs)
157
+ parsed = {}
158
+ unparsed = []
159
+
160
+ parser = self.class.parser(parsed)
161
+
162
+ begin
163
+ parser.order!(inputs) do |nonopt|
164
+ unparsed << nonopt
165
+ end
166
+ rescue OptionParser::ParseError => e
167
+ unparsed += e.args
168
+ unparsed << inputs.shift unless inputs.first =~ /^-{1,2}/
169
+ retry
170
+ end
171
+
172
+ return parser, parsed, unparsed
173
+ end
174
+
175
+ def self.parser(parsed = {})
176
+ OptionParser.new do |opts|
177
+ opts.banner = BANNER
178
+ opts.on('--help', 'Display this setup specific help output') do |help|
179
+ parsed['help'] = true
180
+ end
181
+ opts.on('--version', 'Output the version') do |v|
182
+ parsed['version'] = true
183
+ end
184
+ opts.on('--config CONF', 'Path to puppet.conf') do |conf|
185
+ parsed['config'] = conf
186
+ end
187
+ opts.on('--private-key KEY', 'Path to PEM encoded key') do |key|
188
+ parsed['private-key'] = key
189
+ end
190
+ opts.on('--cert-bundle BUNDLE', 'Path to PEM encoded bundle') do |bundle|
191
+ parsed['cert-bundle'] = bundle
192
+ end
193
+ opts.on('--crl-chain CHAIN', 'Path to PEM encoded chain') do |chain|
194
+ parsed['crl-chain'] = chain
195
+ end
196
+ end
197
+ end
198
+
199
+ def validate_file_paths(one_or_more_paths)
200
+ errors = []
201
+ Array(one_or_more_paths).each do |path|
202
+ if !File.exist?(path) || !File.readable?(path)
203
+ errors << "Could not read file '#{path}'"
204
+ end
205
+ end
206
+
207
+ errors
208
+ end
209
+ end
210
+ end
211
+ end
@@ -1,5 +1,5 @@
1
1
  module Puppetserver
2
2
  module Ca
3
- VERSION = "0.0.1-dev1"
3
+ VERSION = "0.1.0"
4
4
  end
5
5
  end
@@ -0,0 +1,131 @@
1
+ require 'openssl'
2
+
3
+ module Puppetserver
4
+ module Ca
5
+ # Load, validate, and store x509 objects needed by the Puppet Server CA.
6
+ class X509Loader
7
+
8
+ attr_reader :errors, :certs, :key, :crls
9
+
10
+ def initialize(bundle_path, key_path, chain_path)
11
+ @errors = []
12
+
13
+ @certs = load_certs(bundle_path)
14
+ @key = load_key(key_path)
15
+ @crls = load_crls(chain_path)
16
+
17
+ validate(@certs, @key, @crls)
18
+ end
19
+
20
+ # Only do as much validation as is possible, assume whoever tried to
21
+ # load the objects wrote errors about any invalid ones, but that bundle
22
+ # and chain may be empty arrays and pkey may be nil.
23
+ def validate(bundle, pkey, chain)
24
+ if !chain.empty? && !bundle.empty?
25
+ validate_crl_and_cert(chain.first, bundle.first)
26
+ end
27
+
28
+ if pkey && !bundle.empty?
29
+ validate_cert_and_key(pkey, bundle.first)
30
+ end
31
+
32
+ unless bundle.empty?
33
+ validate_full_chain(bundle, chain)
34
+ end
35
+ end
36
+
37
+ def load_certs(bundle_path)
38
+ certs, errs = [], []
39
+
40
+ bundle_string = File.read(bundle_path)
41
+ cert_strings = bundle_string.scan(/-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m)
42
+ cert_strings.each do |cert_string|
43
+ begin
44
+ certs << OpenSSL::X509::Certificate.new(cert_string)
45
+ rescue OpenSSL::X509::CertificateError
46
+ errs << "Could not parse entry:\n#{cert_string}"
47
+ end
48
+ end
49
+
50
+ if certs.empty?
51
+ errs << "Could not detect any certs within #{bundle_path}"
52
+ end
53
+
54
+ unless errs.empty?
55
+ @errors << "Could not parse #{bundle_path}"
56
+ @errors += errs
57
+ end
58
+
59
+ return certs
60
+ end
61
+
62
+ def load_key(key_path)
63
+ begin
64
+ OpenSSL::PKey.read(File.read(key_path))
65
+ rescue ArgumentError, OpenSSL::PKey::PKeyError => e
66
+ @errors << "Could not parse #{key_path}"
67
+
68
+ return nil
69
+ end
70
+ end
71
+
72
+ def load_crls(chain_path)
73
+ errs, crls = [], []
74
+
75
+ chain_string = File.read(chain_path)
76
+ crl_strings = chain_string.scan(/-----BEGIN X509 CRL-----.*?-----END X509 CRL-----/m)
77
+ crl_strings.map do |crl_string|
78
+ begin
79
+ crls << OpenSSL::X509::CRL.new(crl_string)
80
+ rescue OpenSSL::X509::CRLError
81
+ errs << "Could not parse entry:\n#{crl_string}"
82
+ end
83
+ end
84
+
85
+ if crls.empty?
86
+ errs << "Could not detect any crls within #{chain_path}"
87
+ end
88
+
89
+ unless errs.empty?
90
+ @errors << "Could not parse #{chain_path}"
91
+ @errors += errs
92
+ end
93
+
94
+ return crls
95
+ end
96
+
97
+ def validate_cert_and_key(key, cert)
98
+ unless cert.check_private_key(key)
99
+ @errors << 'Private key and certificate do not match'
100
+ end
101
+ end
102
+
103
+ def validate_crl_and_cert(crl, cert)
104
+ unless crl.issuer == cert.subject
105
+ @errors << 'Leaf CRL was not issued by leaf certificate'
106
+ end
107
+ end
108
+
109
+ # By creating an X509::Store and validating the leaf cert with it we:
110
+ # - Ensure a full chain of trust (root to leaf) is within the bundle
111
+ # - If provided, there are CRLs for the CAs
112
+ # - If provided, no CAs within the chain of trust have been revoked
113
+ # However this does allow for:
114
+ # - Additional, ignored, certs and CRLs in the bundle/chain
115
+ # - certs and CRLs in any order (as long as the leaf cert is first)
116
+ def validate_full_chain(certs, crls)
117
+ store = OpenSSL::X509::Store.new
118
+ certs.each {|cert| store.add_cert(cert) }
119
+ if !crls.empty?
120
+ store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK | OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
121
+ crls.each {|crl| store.add_crl(crl) }
122
+ end
123
+
124
+ unless store.verify(certs.first)
125
+ @errors << 'Leaf certificate could not be validated'
126
+ @errors << "Validating cert store returned: #{store.error} - #{store.error_string}"
127
+ end
128
+ end
129
+ end
130
+ end
131
+ 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: 0.0.1.pre.dev1
4
+ version: 0.1.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: 2018-06-05 00:00:00.000000000 Z
11
+ date: 2018-07-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -55,7 +55,8 @@ dependencies:
55
55
  description:
56
56
  email:
57
57
  - release@puppet.com
58
- executables: []
58
+ executables:
59
+ - puppetserver-ca
59
60
  extensions: []
60
61
  extra_rdoc_files: []
61
62
  files:
@@ -70,9 +71,15 @@ files:
70
71
  - Rakefile
71
72
  - bin/console
72
73
  - bin/setup
74
+ - exe/puppetserver-ca
73
75
  - lib/puppetserver/ca.rb
76
+ - lib/puppetserver/ca/cli.rb
77
+ - lib/puppetserver/ca/logger.rb
78
+ - lib/puppetserver/ca/puppet_config.rb
79
+ - lib/puppetserver/ca/setup_action.rb
74
80
  - lib/puppetserver/ca/stub.rb
75
81
  - lib/puppetserver/ca/version.rb
82
+ - lib/puppetserver/ca/x509_loader.rb
76
83
  - puppetserver-ca.gemspec
77
84
  homepage: https://github.com/puppetlabs/puppetserver-ca-cli/
78
85
  licenses:
@@ -89,12 +96,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
89
96
  version: '0'
90
97
  required_rubygems_version: !ruby/object:Gem::Requirement
91
98
  requirements:
92
- - - ">"
99
+ - - ">="
93
100
  - !ruby/object:Gem::Version
94
- version: 1.3.1
101
+ version: '0'
95
102
  requirements: []
96
103
  rubyforge_project:
97
- rubygems_version: 2.5.2
104
+ rubygems_version: 2.5.1
98
105
  signing_key:
99
106
  specification_version: 4
100
107
  summary: A simple CLI tool for interacting with Puppet Server's Certificate Authority