puppet 0.9.2 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- data/CHANGELOG +58 -0
- data/README +21 -18
- data/Rakefile +176 -36
- data/bin/puppet +34 -48
- data/bin/puppetca +41 -28
- data/bin/puppetd +87 -65
- data/bin/puppetdoc +99 -23
- data/bin/puppetmasterd +72 -91
- data/conf/redhat/client.init +80 -0
- data/conf/redhat/client.sysconfig +11 -0
- data/conf/redhat/fileserver.conf +12 -0
- data/conf/redhat/puppet.spec +130 -0
- data/conf/redhat/server.init +89 -0
- data/conf/redhat/server.sysconfig +9 -0
- data/examples/code/allatonce +2 -2
- data/examples/code/assignments +1 -1
- data/examples/code/classing +2 -2
- data/examples/code/components +2 -2
- data/examples/code/file.bl +5 -5
- data/examples/code/filedefaults +2 -2
- data/examples/code/fileparsing +1 -1
- data/examples/code/filerecursion +1 -1
- data/examples/code/functions +1 -1
- data/examples/code/groups +1 -1
- data/examples/code/importing +1 -1
- data/examples/code/nodes +1 -1
- data/examples/code/one +1 -1
- data/examples/code/relationships +2 -2
- data/examples/code/simpletests +5 -5
- data/examples/code/snippets/argumentdefaults +2 -2
- data/examples/code/snippets/casestatement +16 -8
- data/examples/code/snippets/classheirarchy.pp +4 -4
- data/examples/code/snippets/classincludes.pp +4 -4
- data/examples/code/snippets/classpathtest +2 -2
- data/examples/code/snippets/componentmetaparams.pp +11 -0
- data/examples/code/snippets/dirchmod +5 -5
- data/examples/code/snippets/emptyclass.pp +9 -0
- data/examples/code/snippets/failmissingexecpath.pp +1 -1
- data/examples/code/snippets/falsevalues.pp +1 -1
- data/examples/code/snippets/filecreate +5 -5
- data/examples/code/snippets/implicititeration +5 -5
- data/examples/code/snippets/multipleinstances +4 -4
- data/examples/code/snippets/namevartest +3 -3
- data/examples/code/snippets/scopetest +1 -1
- data/examples/code/snippets/selectorvalues.pp +3 -3
- data/examples/code/snippets/simpledefaults +2 -2
- data/examples/code/snippets/simpleselector +5 -5
- data/examples/code/snippets/singleary.pp +19 -0
- data/examples/root/etc/init.d/sleeper +3 -2
- data/ext/emacs/puppet-mode-init.el +6 -0
- data/ext/emacs/puppet-mode.el +189 -0
- data/ext/ldap/puppet.schema +17 -0
- data/ext/{module:puppet → module_puppet} +30 -31
- data/ext/vim/filetype.vim +9 -0
- data/ext/vim/puppet.vim +87 -0
- data/install.rb +63 -30
- data/lib/puppet.rb +216 -122
- data/lib/puppet/client.rb +51 -416
- data/lib/puppet/client/ca.rb +17 -0
- data/lib/puppet/client/dipper.rb +78 -0
- data/lib/puppet/client/file.rb +20 -0
- data/lib/puppet/client/log.rb +17 -0
- data/lib/puppet/client/master.rb +246 -0
- data/lib/puppet/client/proxy.rb +27 -0
- data/lib/puppet/client/status.rb +7 -0
- data/lib/puppet/config.rb +563 -13
- data/lib/puppet/daemon.rb +50 -22
- data/lib/puppet/element.rb +4 -4
- data/lib/puppet/event-loop.rb +1 -0
- data/lib/puppet/event-loop/better-definers.rb +367 -0
- data/lib/puppet/event-loop/event-loop.rb +355 -0
- data/lib/puppet/event-loop/signal-system.rb +220 -0
- data/lib/puppet/event.rb +9 -11
- data/lib/puppet/filetype.rb +195 -0
- data/lib/puppet/log.rb +35 -12
- data/lib/puppet/metric.rb +2 -2
- data/lib/puppet/networkclient.rb +145 -0
- data/lib/puppet/parameter.rb +335 -0
- data/lib/puppet/parser/ast.rb +42 -1453
- data/lib/puppet/parser/ast/astarray.rb +88 -0
- data/lib/puppet/parser/ast/branch.rb +47 -0
- data/lib/puppet/parser/ast/caseopt.rb +66 -0
- data/lib/puppet/parser/ast/casestatement.rb +78 -0
- data/lib/puppet/parser/ast/classdef.rb +78 -0
- data/lib/puppet/parser/ast/compdef.rb +111 -0
- data/lib/puppet/parser/ast/component.rb +105 -0
- data/lib/puppet/parser/ast/hostclass.rb +82 -0
- data/lib/puppet/parser/ast/leaf.rb +86 -0
- data/lib/puppet/parser/ast/node.rb +103 -0
- data/lib/puppet/parser/ast/nodedef.rb +68 -0
- data/lib/puppet/parser/ast/objectdef.rb +336 -0
- data/lib/puppet/parser/ast/objectparam.rb +30 -0
- data/lib/puppet/parser/ast/objectref.rb +76 -0
- data/lib/puppet/parser/ast/selector.rb +60 -0
- data/lib/puppet/parser/ast/typedefaults.rb +45 -0
- data/lib/puppet/parser/ast/vardef.rb +44 -0
- data/lib/puppet/parser/interpreter.rb +31 -14
- data/lib/puppet/parser/lexer.rb +2 -4
- data/lib/puppet/parser/parser.rb +332 -242
- data/lib/puppet/parser/scope.rb +55 -38
- data/lib/puppet/server.rb +43 -44
- data/lib/puppet/server/authstore.rb +3 -6
- data/lib/puppet/server/ca.rb +5 -2
- data/lib/puppet/server/filebucket.rb +2 -4
- data/lib/puppet/server/fileserver.rb +28 -12
- data/lib/puppet/server/logger.rb +15 -4
- data/lib/puppet/server/master.rb +62 -7
- data/lib/puppet/sslcertificates.rb +41 -607
- data/lib/puppet/sslcertificates/ca.rb +291 -0
- data/lib/puppet/sslcertificates/certificate.rb +283 -0
- data/lib/puppet/statechange.rb +6 -1
- data/lib/puppet/storage.rb +67 -56
- data/lib/puppet/transaction.rb +25 -9
- data/lib/puppet/transportable.rb +102 -22
- data/lib/puppet/type.rb +1096 -315
- data/lib/puppet/type/component.rb +30 -21
- data/lib/puppet/type/cron.rb +409 -448
- data/lib/puppet/type/exec.rb +234 -174
- data/lib/puppet/type/group.rb +65 -82
- data/lib/puppet/type/nameservice.rb +247 -3
- data/lib/puppet/type/nameservice/netinfo.rb +29 -40
- data/lib/puppet/type/nameservice/objectadd.rb +52 -66
- data/lib/puppet/type/nameservice/posix.rb +6 -194
- data/lib/puppet/type/package.rb +447 -295
- data/lib/puppet/type/package/apt.rb +51 -50
- data/lib/puppet/type/package/bsd.rb +82 -0
- data/lib/puppet/type/package/dpkg.rb +85 -88
- data/lib/puppet/type/package/rpm.rb +67 -63
- data/lib/puppet/type/package/sun.rb +119 -98
- data/lib/puppet/type/package/yum.rb +41 -37
- data/lib/puppet/type/parsedtype.rb +295 -0
- data/lib/puppet/type/parsedtype/host.rb +143 -0
- data/lib/puppet/type/parsedtype/port.rb +232 -0
- data/lib/puppet/type/parsedtype/sshkey.rb +129 -0
- data/lib/puppet/type/pfile.rb +484 -460
- data/lib/puppet/type/pfile/checksum.rb +237 -181
- data/lib/puppet/type/pfile/content.rb +67 -0
- data/lib/puppet/type/pfile/ensure.rb +212 -0
- data/lib/puppet/type/pfile/group.rb +106 -105
- data/lib/puppet/type/pfile/mode.rb +98 -101
- data/lib/puppet/type/pfile/source.rb +228 -209
- data/lib/puppet/type/pfile/type.rb +18 -21
- data/lib/puppet/type/pfile/uid.rb +127 -130
- data/lib/puppet/type/pfilebucket.rb +68 -63
- data/lib/puppet/type/schedule.rb +341 -0
- data/lib/puppet/type/service.rb +351 -255
- data/lib/puppet/type/service/base.rb +9 -14
- data/lib/puppet/type/service/debian.rb +32 -38
- data/lib/puppet/type/service/init.rb +130 -130
- data/lib/puppet/type/service/smf.rb +48 -20
- data/lib/puppet/type/state.rb +229 -16
- data/lib/puppet/type/symlink.rb +51 -63
- data/lib/puppet/type/tidy.rb +105 -102
- data/lib/puppet/type/user.rb +118 -180
- data/lib/puppet/util.rb +100 -6
- data/test/certmgr/certmgr.rb +0 -1
- data/test/client/client.rb +4 -4
- data/test/executables/puppetbin.rb +7 -14
- data/test/executables/puppetca.rb +18 -24
- data/test/executables/puppetd.rb +7 -16
- data/test/executables/puppetmasterd.rb +7 -9
- data/test/executables/puppetmodule.rb +11 -16
- data/test/language/ast.rb +11 -7
- data/test/language/interpreter.rb +1 -1
- data/test/language/scope.rb +2 -0
- data/test/language/snippets.rb +30 -5
- data/test/language/transportable.rb +77 -0
- data/test/other/config.rb +316 -0
- data/test/other/events.rb +22 -21
- data/test/other/log.rb +14 -14
- data/test/other/metrics.rb +4 -8
- data/test/other/overrides.rb +5 -5
- data/test/other/relationships.rb +4 -2
- data/test/other/storage.rb +64 -3
- data/test/other/transactions.rb +20 -20
- data/test/parser/parser.rb +7 -4
- data/test/puppet/conffiles.rb +12 -12
- data/test/puppet/defaults.rb +13 -11
- data/test/puppet/utiltest.rb +14 -11
- data/test/puppettest.rb +156 -48
- data/test/server/bucket.rb +2 -2
- data/test/server/fileserver.rb +6 -6
- data/test/server/logger.rb +19 -11
- data/test/server/master.rb +33 -4
- data/test/server/server.rb +2 -7
- data/test/types/basic.rb +5 -7
- data/test/types/component.rb +22 -18
- data/test/types/cron.rb +111 -44
- data/test/types/exec.rb +116 -59
- data/test/types/file.rb +262 -137
- data/test/types/filebucket.rb +13 -15
- data/test/types/fileignoresource.rb +12 -16
- data/test/types/filesources.rb +73 -48
- data/test/types/filetype.rb +13 -15
- data/test/types/group.rb +15 -13
- data/test/types/host.rb +146 -0
- data/test/types/package.rb +74 -63
- data/test/types/port.rb +139 -0
- data/test/types/query.rb +8 -8
- data/test/types/schedule.rb +335 -0
- data/test/types/service.rb +137 -21
- data/test/types/sshkey.rb +140 -0
- data/test/types/symlink.rb +3 -5
- data/test/types/tidy.rb +5 -14
- data/test/types/type.rb +67 -11
- data/test/types/user.rb +25 -23
- metadata +186 -122
- data/lib/puppet/type/pfile/create.rb +0 -108
- data/lib/puppet/type/pprocess.rb +0 -97
- data/lib/puppet/type/typegen.rb +0 -149
- data/lib/puppet/type/typegen/filerecord.rb +0 -243
- data/lib/puppet/type/typegen/filetype.rb +0 -316
- data/test/other/state.rb +0 -106
@@ -0,0 +1,291 @@
|
|
1
|
+
class Puppet::SSLCertificates::CA
|
2
|
+
Certificate = Puppet::SSLCertificates::Certificate
|
3
|
+
attr_accessor :keyfile, :file, :config, :dir, :cert
|
4
|
+
|
5
|
+
Puppet.setdefaults("ca",
|
6
|
+
[:certdir, "$ssldir/certs", "The certificate directory."],
|
7
|
+
[:publickeydir, "$ssldir/public_keys", "The public key directory."],
|
8
|
+
[:privatekeydir, "$ssldir/private_keys", "The private key directory."],
|
9
|
+
[:cadir, "$ssldir/ca",
|
10
|
+
"The root directory for the certificate authority."],
|
11
|
+
[:cacert, "$cadir/ca_crt.pem", "The CA certificate."],
|
12
|
+
[:cakey, "$cadir/ca_key.pem", "The CA private key."],
|
13
|
+
[:capub, "$cadir/ca_pub.pem", "The CA public key."],
|
14
|
+
[:caprivatedir, "$cadir/private",
|
15
|
+
"Where the CA stores private certificate information."],
|
16
|
+
[:csrdir, "$cadir/requests",
|
17
|
+
"Where the CA stores certificate requests"],
|
18
|
+
[:signeddir, "$cadir/signed",
|
19
|
+
"Where the CA stores signed certificates."],
|
20
|
+
[:capass, "$caprivatedir/ca.pass",
|
21
|
+
"Where the CA stores the password for the private key"],
|
22
|
+
[:serial, "$cadir/serial",
|
23
|
+
"Where the serial number for certificates is stored."],
|
24
|
+
[:privatedir, "$ssldir/private",
|
25
|
+
"Where the client stores private certificate information."],
|
26
|
+
[:passfile, "$privatedir/password",
|
27
|
+
"Where puppetd stores the password for its private key. Generally
|
28
|
+
unused."],
|
29
|
+
[:autosign, "$confdir/autosign.conf",
|
30
|
+
"Whether to enable autosign. Valid values are true (which autosigns
|
31
|
+
any key request, and is a very bad idea), false (which never autosigns
|
32
|
+
any key request), and the path to a file, which uses that configuration
|
33
|
+
file to determine which keys to sign."],
|
34
|
+
[:ca_days, 1825, "How long a certificate should be valid."],
|
35
|
+
[:ca_md, "md5", "The type of hash used in certificates."],
|
36
|
+
[:req_bits, 2048, "The bit length of the certificates."],
|
37
|
+
[:keylength, 1024, "The bit length of keys."]
|
38
|
+
)
|
39
|
+
|
40
|
+
#@@params.each { |param|
|
41
|
+
# Puppet.setdefault(param,@@defaults[param])
|
42
|
+
#}
|
43
|
+
|
44
|
+
def certfile
|
45
|
+
@config[:cacert]
|
46
|
+
end
|
47
|
+
|
48
|
+
def host2csrfile(hostname)
|
49
|
+
File.join(Puppet[:csrdir], [hostname, "pem"].join("."))
|
50
|
+
end
|
51
|
+
|
52
|
+
# this stores signed certs in a directory unrelated to
|
53
|
+
# normal client certs
|
54
|
+
def host2certfile(hostname)
|
55
|
+
File.join(Puppet[:signeddir], [hostname, "pem"].join("."))
|
56
|
+
end
|
57
|
+
|
58
|
+
def thing2name(thing)
|
59
|
+
thing.subject.to_a.find { |ary|
|
60
|
+
ary[0] == "CN"
|
61
|
+
}[1]
|
62
|
+
end
|
63
|
+
|
64
|
+
def initialize(hash = {})
|
65
|
+
self.setconfig(hash)
|
66
|
+
|
67
|
+
if Puppet[:capass]
|
68
|
+
if FileTest.exists?(Puppet[:capass])
|
69
|
+
#puts "Reading %s" % Puppet[:capass]
|
70
|
+
#system "ls -al %s" % Puppet[:capass]
|
71
|
+
#File.read Puppet[:capass]
|
72
|
+
Puppet.info "Getting pass"
|
73
|
+
@config[:password] = self.getpass
|
74
|
+
else
|
75
|
+
# Don't create a password if the cert already exists
|
76
|
+
unless FileTest.exists?(@config[:cacert])
|
77
|
+
Puppet.info "Genning pass"
|
78
|
+
@config[:password] = self.genpass
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
self.getcert
|
84
|
+
unless FileTest.exists?(@config[:serial])
|
85
|
+
File.open(@config[:serial], "w") { |f|
|
86
|
+
f << "%04X" % 1
|
87
|
+
}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def genpass
|
92
|
+
pass = ""
|
93
|
+
20.times { pass += (rand(74) + 48).chr }
|
94
|
+
|
95
|
+
Puppet.recmkdir(File.dirname(@config[:capass]))
|
96
|
+
begin
|
97
|
+
File.open(@config[:capass], "w", 0600) { |f| f.print pass }
|
98
|
+
rescue Errno::EACCES => detail
|
99
|
+
raise Puppet::Error, detail.to_s
|
100
|
+
end
|
101
|
+
return pass
|
102
|
+
end
|
103
|
+
|
104
|
+
def getpass
|
105
|
+
if @config[:capass] and File.readable?(@config[:capass])
|
106
|
+
return File.read(@config[:capass])
|
107
|
+
else
|
108
|
+
raise Puppet::Error, "Could not read CA passfile %s" % @config[:capass]
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def getcert
|
113
|
+
if FileTest.exists?(@config[:cacert])
|
114
|
+
@cert = OpenSSL::X509::Certificate.new(
|
115
|
+
File.read(@config[:cacert])
|
116
|
+
)
|
117
|
+
else
|
118
|
+
self.mkrootcert
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def getclientcsr(host)
|
123
|
+
csrfile = host2csrfile(host)
|
124
|
+
unless File.exists?(csrfile)
|
125
|
+
return nil
|
126
|
+
end
|
127
|
+
|
128
|
+
return OpenSSL::X509::Request.new(File.read(csrfile))
|
129
|
+
end
|
130
|
+
|
131
|
+
def getclientcert(host)
|
132
|
+
certfile = host2certfile(host)
|
133
|
+
unless File.exists?(certfile)
|
134
|
+
return [nil, nil]
|
135
|
+
end
|
136
|
+
|
137
|
+
return [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert]
|
138
|
+
end
|
139
|
+
|
140
|
+
def list
|
141
|
+
return Dir.entries(Puppet[:csrdir]).reject { |file|
|
142
|
+
file =~ /^\.+$/
|
143
|
+
}.collect { |file|
|
144
|
+
file.sub(/\.pem$/, '')
|
145
|
+
}
|
146
|
+
end
|
147
|
+
|
148
|
+
def mkrootcert
|
149
|
+
cert = Certificate.new(
|
150
|
+
:name => "CAcert",
|
151
|
+
:cert => @config[:cacert],
|
152
|
+
:encrypt => @config[:capass],
|
153
|
+
:key => @config[:cakey],
|
154
|
+
:selfsign => true,
|
155
|
+
:length => 1825,
|
156
|
+
:type => :ca
|
157
|
+
)
|
158
|
+
@cert = cert.mkselfsigned
|
159
|
+
File.open(@config[:cacert], "w", 0660) { |f|
|
160
|
+
f.puts @cert.to_pem
|
161
|
+
}
|
162
|
+
@key = cert.key
|
163
|
+
return cert
|
164
|
+
end
|
165
|
+
|
166
|
+
def removeclientcsr(host)
|
167
|
+
csrfile = host2csrfile(host)
|
168
|
+
unless File.exists?(csrfile)
|
169
|
+
raise Puppet::Error, "No certificate request for %s" % host
|
170
|
+
end
|
171
|
+
|
172
|
+
File.unlink(csrfile)
|
173
|
+
end
|
174
|
+
|
175
|
+
def setconfig(hash)
|
176
|
+
@config = {}
|
177
|
+
Puppet.config.params("ca").each { |param|
|
178
|
+
param = param.intern if param.is_a? String
|
179
|
+
if hash.include?(param)
|
180
|
+
@config[param] = hash[param]
|
181
|
+
Puppet[param] = hash[param]
|
182
|
+
hash.delete(param)
|
183
|
+
else
|
184
|
+
@config[param] = Puppet[param]
|
185
|
+
end
|
186
|
+
}
|
187
|
+
|
188
|
+
if hash.include?(:password)
|
189
|
+
@config[:password] = hash[:password]
|
190
|
+
hash.delete(:password)
|
191
|
+
end
|
192
|
+
|
193
|
+
if hash.length > 0
|
194
|
+
raise ArgumentError, "Unknown parameters %s" % hash.keys.join(",")
|
195
|
+
end
|
196
|
+
|
197
|
+
[:cadir, :csrdir, :signeddir].each { |dir|
|
198
|
+
unless @config[dir]
|
199
|
+
raise Puppet::DevError, "%s is undefined" % dir
|
200
|
+
end
|
201
|
+
unless FileTest.exists?(@config[dir])
|
202
|
+
Puppet.recmkdir(@config[dir])
|
203
|
+
end
|
204
|
+
}
|
205
|
+
end
|
206
|
+
|
207
|
+
def sign(csr)
|
208
|
+
unless csr.is_a?(OpenSSL::X509::Request)
|
209
|
+
raise Puppet::Error,
|
210
|
+
"CA#sign only accepts OpenSSL::X509::Request objects, not %s" %
|
211
|
+
csr.class
|
212
|
+
end
|
213
|
+
|
214
|
+
unless csr.verify(csr.public_key)
|
215
|
+
raise Puppet::Error, "CSR sign verification failed"
|
216
|
+
end
|
217
|
+
|
218
|
+
# i should probably check key length...
|
219
|
+
|
220
|
+
# read the ca cert in
|
221
|
+
cacert = OpenSSL::X509::Certificate.new(
|
222
|
+
File.read(@config[:cacert])
|
223
|
+
)
|
224
|
+
|
225
|
+
cakey = nil
|
226
|
+
if @config[:password]
|
227
|
+
cakey = OpenSSL::PKey::RSA.new(
|
228
|
+
File.read(@config[:cakey]), @config[:password]
|
229
|
+
)
|
230
|
+
else
|
231
|
+
system("ls -al %s" % Puppet[:capass])
|
232
|
+
cakey = OpenSSL::PKey::RSA.new(
|
233
|
+
File.read(@config[:cakey])
|
234
|
+
)
|
235
|
+
end
|
236
|
+
|
237
|
+
unless cacert.check_private_key(cakey)
|
238
|
+
raise Puppet::Error, "CA Certificate is invalid"
|
239
|
+
end
|
240
|
+
|
241
|
+
serial = File.read(@config[:serial]).chomp.hex
|
242
|
+
newcert = Puppet::SSLCertificates.mkcert(
|
243
|
+
:type => :server,
|
244
|
+
:name => csr.subject,
|
245
|
+
:days => @config[:ca_days],
|
246
|
+
:issuer => cacert,
|
247
|
+
:serial => serial,
|
248
|
+
:publickey => csr.public_key
|
249
|
+
)
|
250
|
+
|
251
|
+
# increment the serial
|
252
|
+
File.open(@config[:serial], "w") { |f|
|
253
|
+
f << "%04X" % (serial + 1)
|
254
|
+
}
|
255
|
+
|
256
|
+
newcert.sign(cakey, OpenSSL::Digest::SHA1.new)
|
257
|
+
|
258
|
+
self.storeclientcert(newcert)
|
259
|
+
|
260
|
+
return [newcert, cacert]
|
261
|
+
end
|
262
|
+
|
263
|
+
def storeclientcsr(csr)
|
264
|
+
host = thing2name(csr)
|
265
|
+
|
266
|
+
csrfile = host2csrfile(host)
|
267
|
+
if File.exists?(csrfile)
|
268
|
+
raise Puppet::Error, "Certificate request for %s already exists" % host
|
269
|
+
end
|
270
|
+
|
271
|
+
File.open(csrfile, "w", 0660) { |f|
|
272
|
+
f.print csr.to_pem
|
273
|
+
}
|
274
|
+
end
|
275
|
+
|
276
|
+
def storeclientcert(cert)
|
277
|
+
host = thing2name(cert)
|
278
|
+
|
279
|
+
certfile = host2certfile(host)
|
280
|
+
if File.exists?(certfile)
|
281
|
+
Puppet.notice "Overwriting signed certificate %s for %s" %
|
282
|
+
[certfile, host]
|
283
|
+
end
|
284
|
+
|
285
|
+
File.open(certfile, "w", 0660) { |f|
|
286
|
+
f.print cert.to_pem
|
287
|
+
}
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
# $Id: ca.rb 873 2006-02-07 23:12:33Z luke $
|
@@ -0,0 +1,283 @@
|
|
1
|
+
class Puppet::SSLCertificates::Certificate
|
2
|
+
SSLCertificates = Puppet::SSLCertificates
|
3
|
+
|
4
|
+
attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type
|
5
|
+
attr_accessor :key, :cert, :csr, :cacert
|
6
|
+
|
7
|
+
@@params2names = {
|
8
|
+
:name => "CN",
|
9
|
+
:state => "ST",
|
10
|
+
:country => "C",
|
11
|
+
:email => "emailAddress",
|
12
|
+
:org => "O",
|
13
|
+
:city => "L",
|
14
|
+
:ou => "OU"
|
15
|
+
}
|
16
|
+
|
17
|
+
def certname
|
18
|
+
OpenSSL::X509::Name.new self.subject
|
19
|
+
end
|
20
|
+
|
21
|
+
def delete
|
22
|
+
[@certfile,@keyfile].each { |file|
|
23
|
+
if FileTest.exists?(file)
|
24
|
+
File.unlink(file)
|
25
|
+
end
|
26
|
+
}
|
27
|
+
|
28
|
+
if defined? @hash and @hash
|
29
|
+
if FileTest.symlink?(@hash)
|
30
|
+
File.unlink(@hash)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def exists?
|
36
|
+
return FileTest.exists?(@certfile)
|
37
|
+
end
|
38
|
+
|
39
|
+
def getkey
|
40
|
+
unless FileTest.exists?(@keyfile)
|
41
|
+
self.mkkey()
|
42
|
+
end
|
43
|
+
if @password
|
44
|
+
@key = OpenSSL::PKey::RSA.new(
|
45
|
+
File.read(@keyfile),
|
46
|
+
@password
|
47
|
+
)
|
48
|
+
else
|
49
|
+
@key = OpenSSL::PKey::RSA.new(
|
50
|
+
File.read(@keyfile)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(hash)
|
56
|
+
unless hash.include?(:name)
|
57
|
+
raise Puppet::Error, "You must specify the common name for the certificate"
|
58
|
+
end
|
59
|
+
@name = hash[:name]
|
60
|
+
|
61
|
+
# init a few variables
|
62
|
+
@cert = @key = @csr = nil
|
63
|
+
|
64
|
+
if hash.include?(:cert)
|
65
|
+
@certfile = hash[:cert]
|
66
|
+
@dir = File.dirname(@certfile)
|
67
|
+
else
|
68
|
+
@dir = hash[:dir] || Puppet[:certdir]
|
69
|
+
@certfile = File.join(@dir, @name)
|
70
|
+
end
|
71
|
+
|
72
|
+
@cacertfile ||= File.join(Puppet[:certdir], "ca.pem")
|
73
|
+
|
74
|
+
unless FileTest.directory?(@dir)
|
75
|
+
Puppet.recmkdir(@dir)
|
76
|
+
end
|
77
|
+
|
78
|
+
unless @certfile =~ /\.pem$/
|
79
|
+
@certfile += ".pem"
|
80
|
+
end
|
81
|
+
@keyfile = hash[:key] || File.join(
|
82
|
+
Puppet[:privatekeydir], [@name,"pem"].join(".")
|
83
|
+
)
|
84
|
+
unless FileTest.directory?(@dir)
|
85
|
+
Puppet.recmkdir(@dir)
|
86
|
+
end
|
87
|
+
|
88
|
+
[@keyfile].each { |file|
|
89
|
+
dir = File.dirname(file)
|
90
|
+
|
91
|
+
unless FileTest.directory?(dir)
|
92
|
+
Puppet.recmkdir(dir)
|
93
|
+
end
|
94
|
+
}
|
95
|
+
|
96
|
+
@days = hash[:length] || 365
|
97
|
+
@selfsign = hash[:selfsign] || false
|
98
|
+
@encrypt = hash[:encrypt] || false
|
99
|
+
@replace = hash[:replace] || false
|
100
|
+
@issuer = hash[:issuer] || nil
|
101
|
+
|
102
|
+
if hash.include?(:type)
|
103
|
+
case hash[:type]
|
104
|
+
when :ca, :client, :server: @type = hash[:type]
|
105
|
+
else
|
106
|
+
raise "Invalid Cert type %s" % hash[:type]
|
107
|
+
end
|
108
|
+
else
|
109
|
+
@type = :client
|
110
|
+
end
|
111
|
+
|
112
|
+
@params = {:name => @name}
|
113
|
+
[:state, :country, :email, :org, :ou].each { |param|
|
114
|
+
if hash.include?(param)
|
115
|
+
@params[param] = hash[param]
|
116
|
+
end
|
117
|
+
}
|
118
|
+
|
119
|
+
if @encrypt
|
120
|
+
if @encrypt =~ /^\//
|
121
|
+
File.open(@encrypt) { |f|
|
122
|
+
@password = f.read.chomp
|
123
|
+
}
|
124
|
+
else
|
125
|
+
raise Puppet::Error, ":encrypt must be a path to a pass phrase file"
|
126
|
+
end
|
127
|
+
else
|
128
|
+
@password = nil
|
129
|
+
end
|
130
|
+
|
131
|
+
if hash.include?(:selfsign)
|
132
|
+
@selfsign = hash[:selfsign]
|
133
|
+
else
|
134
|
+
@selfsign = false
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# this only works for servers, not for users
|
139
|
+
def mkcsr
|
140
|
+
unless defined? @key and @key
|
141
|
+
self.getkey
|
142
|
+
end
|
143
|
+
|
144
|
+
name = OpenSSL::X509::Name.new self.subject
|
145
|
+
|
146
|
+
@csr = OpenSSL::X509::Request.new
|
147
|
+
@csr.version = 0
|
148
|
+
@csr.subject = name
|
149
|
+
@csr.public_key = @key.public_key
|
150
|
+
@csr.sign(@key, OpenSSL::Digest::SHA1.new)
|
151
|
+
|
152
|
+
#File.open(@csrfile, "w") { |f|
|
153
|
+
# f << @csr.to_pem
|
154
|
+
#}
|
155
|
+
|
156
|
+
unless @csr.verify(@key.public_key)
|
157
|
+
raise Puppet::Error, "CSR sign verification failed"
|
158
|
+
end
|
159
|
+
|
160
|
+
return @csr
|
161
|
+
end
|
162
|
+
|
163
|
+
def mkkey
|
164
|
+
# @key is the file
|
165
|
+
|
166
|
+
@key = OpenSSL::PKey::RSA.new(1024)
|
167
|
+
# { |p,n|
|
168
|
+
# case p
|
169
|
+
# when 0; Puppet.info "key info: ." # BN_generate_prime
|
170
|
+
# when 1; Puppet.info "key info: +" # BN_generate_prime
|
171
|
+
# when 2; Puppet.info "key info: *" # searching good prime,
|
172
|
+
# # n = #of try,
|
173
|
+
# # but also data from BN_generate_prime
|
174
|
+
# when 3; Puppet.info "key info: \n" # found good prime, n==0 - p, n==1 - q,
|
175
|
+
# # but also data from BN_generate_prime
|
176
|
+
# else; Puppet.info "key info: *" # BN_generate_prime
|
177
|
+
# end
|
178
|
+
# }
|
179
|
+
|
180
|
+
if @password
|
181
|
+
#passwdproc = proc { @password }
|
182
|
+
keytext = @key.export(
|
183
|
+
OpenSSL::Cipher::DES.new(:EDE3, :CBC),
|
184
|
+
@password
|
185
|
+
)
|
186
|
+
File.open(@keyfile, "w", 0400) { |f|
|
187
|
+
f << keytext
|
188
|
+
}
|
189
|
+
else
|
190
|
+
File.open(@keyfile, "w", 0400) { |f|
|
191
|
+
f << @key.to_pem
|
192
|
+
}
|
193
|
+
end
|
194
|
+
|
195
|
+
#cmd = "#{ossl} genrsa -out #{@key} 1024"
|
196
|
+
end
|
197
|
+
|
198
|
+
def mkselfsigned
|
199
|
+
unless defined? @key and @key
|
200
|
+
self.getkey
|
201
|
+
end
|
202
|
+
|
203
|
+
if defined? @cert and @cert
|
204
|
+
raise Puppet::Error, "Cannot replace existing certificate"
|
205
|
+
end
|
206
|
+
|
207
|
+
args = {
|
208
|
+
:name => self.certname,
|
209
|
+
:days => @days,
|
210
|
+
:issuer => nil,
|
211
|
+
:serial => 0x0,
|
212
|
+
:publickey => @key.public_key
|
213
|
+
}
|
214
|
+
if @type
|
215
|
+
args[:type] = @type
|
216
|
+
else
|
217
|
+
args[:type] = :server
|
218
|
+
end
|
219
|
+
@cert = SSLCertificates.mkcert(args)
|
220
|
+
|
221
|
+
@cert.sign(@key, OpenSSL::Digest::SHA1.new) if @selfsign
|
222
|
+
|
223
|
+
return @cert
|
224
|
+
end
|
225
|
+
|
226
|
+
def subject(string = false)
|
227
|
+
subj = @@params2names.collect { |param, name|
|
228
|
+
if @params.include?(param)
|
229
|
+
[name, @params[param]]
|
230
|
+
end
|
231
|
+
}.reject { |ary| ary.nil? }
|
232
|
+
|
233
|
+
if string
|
234
|
+
return "/" + subj.collect { |ary|
|
235
|
+
"%s=%s" % ary
|
236
|
+
}.join("/") + "/"
|
237
|
+
else
|
238
|
+
return subj
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# verify that we can track down the cert chain or whatever
|
243
|
+
def verify
|
244
|
+
"openssl verify -verbose -CAfile /home/luke/.puppet/ssl/certs/ca.pem -purpose sslserver culain.madstop.com.pem"
|
245
|
+
end
|
246
|
+
|
247
|
+
def write
|
248
|
+
files = {
|
249
|
+
@certfile => @cert,
|
250
|
+
@keyfile => @key,
|
251
|
+
}
|
252
|
+
if defined? @cacert
|
253
|
+
files[@cacertfile] = @cacert
|
254
|
+
end
|
255
|
+
|
256
|
+
files.each { |file,thing|
|
257
|
+
if defined? thing and thing
|
258
|
+
if FileTest.exists?(file)
|
259
|
+
next
|
260
|
+
end
|
261
|
+
|
262
|
+
text = nil
|
263
|
+
|
264
|
+
if thing.is_a?(OpenSSL::PKey::RSA) and @password
|
265
|
+
text = thing.export(
|
266
|
+
OpenSSL::Cipher::DES.new(:EDE3, :CBC),
|
267
|
+
@password
|
268
|
+
)
|
269
|
+
else
|
270
|
+
text = thing.to_pem
|
271
|
+
end
|
272
|
+
|
273
|
+
File.open(file, "w", 0660) { |f| f.print text }
|
274
|
+
end
|
275
|
+
}
|
276
|
+
|
277
|
+
if defined? @cacert
|
278
|
+
SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
# $Id: certificate.rb 873 2006-02-07 23:12:33Z luke $
|