leap_cli 1.5.6 → 1.6.2
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.
- data/bin/leap +29 -6
- data/lib/leap/platform.rb +36 -1
- data/lib/leap_cli/commands/ca.rb +97 -20
- data/lib/leap_cli/commands/compile.rb +49 -8
- data/lib/leap_cli/commands/db.rb +13 -4
- data/lib/leap_cli/commands/deploy.rb +138 -29
- data/lib/leap_cli/commands/env.rb +76 -0
- data/lib/leap_cli/commands/facts.rb +10 -3
- data/lib/leap_cli/commands/inspect.rb +2 -2
- data/lib/leap_cli/commands/list.rb +10 -10
- data/lib/leap_cli/commands/node.rb +7 -132
- data/lib/leap_cli/commands/node_init.rb +169 -0
- data/lib/leap_cli/commands/pre.rb +4 -27
- data/lib/leap_cli/commands/ssh.rb +152 -0
- data/lib/leap_cli/commands/test.rb +22 -13
- data/lib/leap_cli/commands/user.rb +12 -4
- data/lib/leap_cli/commands/vagrant.rb +4 -4
- data/lib/leap_cli/config/filter.rb +175 -0
- data/lib/leap_cli/config/manager.rb +130 -61
- data/lib/leap_cli/config/node.rb +32 -0
- data/lib/leap_cli/config/object.rb +69 -44
- data/lib/leap_cli/config/object_list.rb +44 -39
- data/lib/leap_cli/config/secrets.rb +24 -12
- data/lib/leap_cli/config/tag.rb +7 -0
- data/lib/{core_ext → leap_cli/core_ext}/boolean.rb +0 -0
- data/lib/{core_ext → leap_cli/core_ext}/hash.rb +0 -0
- data/lib/{core_ext → leap_cli/core_ext}/json.rb +0 -0
- data/lib/{core_ext → leap_cli/core_ext}/nil.rb +0 -0
- data/lib/{core_ext → leap_cli/core_ext}/string.rb +0 -0
- data/lib/leap_cli/core_ext/yaml.rb +29 -0
- data/lib/leap_cli/exceptions.rb +24 -0
- data/lib/leap_cli/leapfile.rb +60 -10
- data/lib/{lib_ext → leap_cli/lib_ext}/capistrano_connections.rb +0 -0
- data/lib/{lib_ext → leap_cli/lib_ext}/gli.rb +0 -0
- data/lib/leap_cli/log.rb +1 -1
- data/lib/leap_cli/logger.rb +18 -1
- data/lib/leap_cli/markdown_document_listener.rb +1 -1
- data/lib/leap_cli/override/json.rb +11 -0
- data/lib/leap_cli/path.rb +20 -6
- data/lib/leap_cli/remote/leap_plugin.rb +2 -2
- data/lib/leap_cli/remote/puppet_plugin.rb +1 -1
- data/lib/leap_cli/remote/rsync_plugin.rb +1 -1
- data/lib/leap_cli/remote/tasks.rb +1 -1
- data/lib/leap_cli/ssh_key.rb +63 -1
- data/lib/leap_cli/util/remote_command.rb +19 -2
- data/lib/leap_cli/util/secret.rb +1 -1
- data/lib/leap_cli/util/x509.rb +3 -2
- data/lib/leap_cli/util.rb +11 -3
- data/lib/leap_cli/version.rb +2 -2
- data/lib/leap_cli.rb +24 -14
- data/vendor/certificate_authority/lib/certificate_authority/certificate.rb +85 -29
- data/vendor/certificate_authority/lib/certificate_authority/distinguished_name.rb +5 -0
- data/vendor/certificate_authority/lib/certificate_authority/extensions.rb +406 -41
- data/vendor/certificate_authority/lib/certificate_authority/key_material.rb +0 -34
- data/vendor/certificate_authority/lib/certificate_authority/serial_number.rb +6 -0
- data/vendor/certificate_authority/lib/certificate_authority/signing_request.rb +36 -1
- metadata +25 -24
- data/lib/leap_cli/commands/shell.rb +0 -89
- data/lib/leap_cli/config/macros.rb +0 -430
- data/lib/leap_cli/constants.rb +0 -7
- data/lib/leap_cli/requirements.rb +0 -19
- data/lib/lib_ext/markdown_document_listener.rb +0 -122
@@ -33,7 +33,7 @@ module CertificateAuthority
|
|
33
33
|
self.serial_number = SerialNumber.new
|
34
34
|
self.key_material = MemoryKeyMaterial.new
|
35
35
|
self.not_before = Time.now
|
36
|
-
self.not_after = Time.now + 60 * 60 * 24 * 365 #One year
|
36
|
+
self.not_after = Time.now + 60 * 60 * 24 * 365 # One year
|
37
37
|
self.parent = self
|
38
38
|
self.extensions = load_extensions()
|
39
39
|
|
@@ -41,12 +41,31 @@ module CertificateAuthority
|
|
41
41
|
|
42
42
|
end
|
43
43
|
|
44
|
+
=begin
|
45
|
+
def self.from_openssl openssl_cert
|
46
|
+
unless openssl_cert.is_a? OpenSSL::X509::Certificate
|
47
|
+
raise "Can only construct from an OpenSSL::X509::Certificate"
|
48
|
+
end
|
49
|
+
|
50
|
+
certificate = Certificate.new
|
51
|
+
# Only subject, key_material, and body are used for signing
|
52
|
+
certificate.distinguished_name = DistinguishedName.from_openssl openssl_cert.subject
|
53
|
+
certificate.key_material.public_key = openssl_cert.public_key
|
54
|
+
certificate.openssl_body = openssl_cert
|
55
|
+
certificate.serial_number.number = openssl_cert.serial.to_i
|
56
|
+
certificate.not_before = openssl_cert.not_before
|
57
|
+
certificate.not_after = openssl_cert.not_after
|
58
|
+
# TODO extensions
|
59
|
+
certificate
|
60
|
+
end
|
61
|
+
=end
|
62
|
+
|
44
63
|
def sign!(signing_profile={})
|
45
64
|
raise "Invalid certificate #{self.errors.full_messages}" unless valid?
|
46
65
|
merge_profile_with_extensions(signing_profile)
|
47
66
|
|
48
67
|
openssl_cert = OpenSSL::X509::Certificate.new
|
49
|
-
openssl_cert.version
|
68
|
+
openssl_cert.version = 2
|
50
69
|
openssl_cert.not_before = self.not_before
|
51
70
|
openssl_cert.not_after = self.not_after
|
52
71
|
openssl_cert.public_key = self.key_material.public_key
|
@@ -58,7 +77,6 @@ module CertificateAuthority
|
|
58
77
|
|
59
78
|
require 'tempfile'
|
60
79
|
t = Tempfile.new("bullshit_conf")
|
61
|
-
# t = File.new("/tmp/openssl.cnf")
|
62
80
|
## The config requires a file even though we won't use it
|
63
81
|
openssl_config = OpenSSL::Config.new(t.path)
|
64
82
|
|
@@ -85,7 +103,7 @@ module CertificateAuthority
|
|
85
103
|
self.extensions.keys.sort{|a,b| b<=>a}.each do |k|
|
86
104
|
e = extensions[k]
|
87
105
|
next if e.to_s.nil? or e.to_s == "" ## If the extension returns an empty string we won't include it
|
88
|
-
ext = factory.create_ext(e.openssl_identifier, e.to_s)
|
106
|
+
ext = factory.create_ext(e.openssl_identifier, e.to_s, e.critical)
|
89
107
|
openssl_cert.add_extension(ext)
|
90
108
|
end
|
91
109
|
|
@@ -94,9 +112,10 @@ module CertificateAuthority
|
|
94
112
|
else
|
95
113
|
digest = OpenSSL::Digest::Digest.new(signing_profile["digest"])
|
96
114
|
end
|
97
|
-
|
98
|
-
|
99
|
-
|
115
|
+
|
116
|
+
self.openssl_body = openssl_cert.sign(parent.key_material.private_key, digest)
|
117
|
+
ensure
|
118
|
+
t.close! if t # We can get rid of the ridiculous temp file
|
100
119
|
end
|
101
120
|
|
102
121
|
def is_signing_entity?
|
@@ -116,6 +135,34 @@ module CertificateAuthority
|
|
116
135
|
self.openssl_body.to_pem
|
117
136
|
end
|
118
137
|
|
138
|
+
def to_csr
|
139
|
+
csr = SigningRequest.new
|
140
|
+
csr.distinguished_name = self.distinguished_name
|
141
|
+
csr.key_material = self.key_material
|
142
|
+
factory = OpenSSL::X509::ExtensionFactory.new
|
143
|
+
exts = []
|
144
|
+
self.extensions.keys.each do |k|
|
145
|
+
## Don't copy over key identifiers for CSRs
|
146
|
+
next if k == "subjectKeyIdentifier" || k == "authorityKeyIdentifier"
|
147
|
+
e = extensions[k]
|
148
|
+
## If the extension returns an empty string we won't include it
|
149
|
+
next if e.to_s.nil? or e.to_s == ""
|
150
|
+
exts << factory.create_ext(e.openssl_identifier, e.to_s, e.critical)
|
151
|
+
end
|
152
|
+
attrval = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)])
|
153
|
+
attrs = [
|
154
|
+
OpenSSL::X509::Attribute.new("extReq", attrval),
|
155
|
+
OpenSSL::X509::Attribute.new("msExtReq", attrval)
|
156
|
+
]
|
157
|
+
csr.attributes = attrs
|
158
|
+
csr
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.from_x509_cert(raw_cert)
|
162
|
+
openssl_cert = OpenSSL::X509::Certificate.new(raw_cert)
|
163
|
+
Certificate.from_openssl(openssl_cert)
|
164
|
+
end
|
165
|
+
|
119
166
|
def is_root_entity?
|
120
167
|
self.parent == self && is_signing_entity?
|
121
168
|
end
|
@@ -134,6 +181,16 @@ module CertificateAuthority
|
|
134
181
|
items = signing_config[k]
|
135
182
|
items.keys.each do |profile_item_key|
|
136
183
|
if extension.respond_to?("#{profile_item_key}=".to_sym)
|
184
|
+
if k == 'subjectAltName' && profile_item_key == 'emails'
|
185
|
+
items[profile_item_key].map do |email|
|
186
|
+
if email == 'email:copy'
|
187
|
+
fail "no email address provided for subject: #{subject.to_x509_name}" unless subject.email_address
|
188
|
+
"email:#{subject.email_address}"
|
189
|
+
else
|
190
|
+
email
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
137
194
|
extension.send("#{profile_item_key}=".to_sym, items[profile_item_key] )
|
138
195
|
else
|
139
196
|
p "Tried applying '#{profile_item_key}' to #{extension.class} but it doesn't respond!"
|
@@ -142,30 +199,25 @@ module CertificateAuthority
|
|
142
199
|
end
|
143
200
|
end
|
144
201
|
|
202
|
+
# Enumeration of the extensions. Not the worst option since
|
203
|
+
# the likelihood of these needing to be updated is low at best.
|
204
|
+
EXTENSIONS = [
|
205
|
+
CertificateAuthority::Extensions::BasicConstraints,
|
206
|
+
CertificateAuthority::Extensions::CrlDistributionPoints,
|
207
|
+
CertificateAuthority::Extensions::SubjectKeyIdentifier,
|
208
|
+
CertificateAuthority::Extensions::AuthorityKeyIdentifier,
|
209
|
+
CertificateAuthority::Extensions::AuthorityInfoAccess,
|
210
|
+
CertificateAuthority::Extensions::KeyUsage,
|
211
|
+
CertificateAuthority::Extensions::ExtendedKeyUsage,
|
212
|
+
CertificateAuthority::Extensions::SubjectAlternativeName,
|
213
|
+
CertificateAuthority::Extensions::CertificatePolicies
|
214
|
+
]
|
215
|
+
|
145
216
|
def load_extensions
|
146
217
|
extension_hash = {}
|
147
218
|
|
148
|
-
|
149
|
-
|
150
|
-
temp_extensions << basic_constraints
|
151
|
-
crl_distribution_points = CertificateAuthority::Extensions::CrlDistributionPoints.new
|
152
|
-
temp_extensions << crl_distribution_points
|
153
|
-
subject_key_identifier = CertificateAuthority::Extensions::SubjectKeyIdentifier.new
|
154
|
-
temp_extensions << subject_key_identifier
|
155
|
-
authority_key_identifier = CertificateAuthority::Extensions::AuthorityKeyIdentifier.new
|
156
|
-
temp_extensions << authority_key_identifier
|
157
|
-
authority_info_access = CertificateAuthority::Extensions::AuthorityInfoAccess.new
|
158
|
-
temp_extensions << authority_info_access
|
159
|
-
key_usage = CertificateAuthority::Extensions::KeyUsage.new
|
160
|
-
temp_extensions << key_usage
|
161
|
-
extended_key_usage = CertificateAuthority::Extensions::ExtendedKeyUsage.new
|
162
|
-
temp_extensions << extended_key_usage
|
163
|
-
subject_alternative_name = CertificateAuthority::Extensions::SubjectAlternativeName.new
|
164
|
-
temp_extensions << subject_alternative_name
|
165
|
-
certificate_policies = CertificateAuthority::Extensions::CertificatePolicies.new
|
166
|
-
temp_extensions << certificate_policies
|
167
|
-
|
168
|
-
temp_extensions.each do |extension|
|
219
|
+
EXTENSIONS.each do |klass|
|
220
|
+
extension = klass.new
|
169
221
|
extension_hash[extension.openssl_identifier] = extension
|
170
222
|
end
|
171
223
|
|
@@ -192,7 +244,11 @@ module CertificateAuthority
|
|
192
244
|
certificate.serial_number.number = openssl_cert.serial.to_i
|
193
245
|
certificate.not_before = openssl_cert.not_before
|
194
246
|
certificate.not_after = openssl_cert.not_after
|
195
|
-
|
247
|
+
EXTENSIONS.each do |klass|
|
248
|
+
_,v,c = (openssl_cert.extensions.detect { |e| e.to_a.first == klass::OPENSSL_IDENTIFIER } || []).to_a
|
249
|
+
certificate.extensions[klass::OPENSSL_IDENTIFIER] = klass.parse(v, c) if v
|
250
|
+
end
|
251
|
+
|
196
252
|
certificate
|
197
253
|
end
|
198
254
|
|
@@ -32,11 +32,16 @@ module CertificateAuthority
|
|
32
32
|
alias :emailAddress :email_address
|
33
33
|
alias :emailAddress= :email_address=
|
34
34
|
|
35
|
+
attr_accessor :serial_number
|
36
|
+
alias :serialNumber :serial_number
|
37
|
+
alias :serialNumber= :serial_number=
|
38
|
+
|
35
39
|
def to_x509_name
|
36
40
|
raise "Invalid Distinguished Name" unless valid?
|
37
41
|
|
38
42
|
# NB: the capitalization in the strings counts
|
39
43
|
name = OpenSSL::X509::Name.new
|
44
|
+
name.add_entry("serialNumber", serial_number) unless serial_number.blank?
|
40
45
|
name.add_entry("C", country) unless country.blank?
|
41
46
|
name.add_entry("ST", state) unless state.blank?
|
42
47
|
name.add_entry("L", locality) unless locality.blank?
|