puppetserver-ca 0.0.1.pre.dev1 → 0.1.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
  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