puppet 2.7.5 → 2.7.6
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 +121 -0
- data/conf/redhat/puppet.spec +16 -7
- data/lib/puppet.rb +1 -1
- data/lib/puppet/application/cert.rb +17 -3
- data/lib/puppet/application/device.rb +1 -0
- data/lib/puppet/application/kick.rb +0 -2
- data/lib/puppet/application/resource.rb +73 -66
- data/lib/puppet/configurer/plugin_handler.rb +6 -2
- data/lib/puppet/defaults.rb +60 -5
- data/lib/puppet/face/ca.rb +11 -2
- data/lib/puppet/face/certificate.rb +33 -4
- data/lib/puppet/file_serving/fileset.rb +1 -1
- data/lib/puppet/file_serving/indirection_hooks.rb +2 -2
- data/lib/puppet/file_serving/metadata.rb +43 -4
- data/lib/puppet/indirector.rb +0 -1
- data/lib/puppet/indirector/request.rb +3 -4
- data/lib/puppet/indirector/resource/active_record.rb +3 -10
- data/lib/puppet/indirector/resource/ral.rb +2 -2
- data/lib/puppet/indirector/rest.rb +1 -1
- data/lib/puppet/network/handler/ca.rb +16 -106
- data/lib/puppet/network/handler/master.rb +0 -3
- data/lib/puppet/network/handler/runner.rb +1 -0
- data/lib/puppet/parser/scope.rb +10 -0
- data/lib/puppet/provider/file/posix.rb +72 -34
- data/lib/puppet/provider/file/windows.rb +100 -0
- data/lib/puppet/provider/group/windows_adsi.rb +2 -2
- data/lib/puppet/provider/user/windows_adsi.rb +19 -4
- data/lib/puppet/resource.rb +16 -0
- data/lib/puppet/resource/catalog.rb +1 -1
- data/lib/puppet/ssl/certificate.rb +2 -2
- data/lib/puppet/ssl/certificate_authority.rb +86 -10
- data/lib/puppet/ssl/certificate_authority/interface.rb +64 -19
- data/lib/puppet/ssl/certificate_factory.rb +112 -91
- data/lib/puppet/ssl/certificate_request.rb +88 -1
- data/lib/puppet/ssl/host.rb +20 -3
- data/lib/puppet/type/file.rb +15 -34
- data/lib/puppet/type/file/group.rb +11 -91
- data/lib/puppet/type/file/mode.rb +11 -41
- data/lib/puppet/type/file/owner.rb +18 -34
- data/lib/puppet/type/file/source.rb +22 -7
- data/lib/puppet/type/group.rb +4 -3
- data/lib/puppet/type/user.rb +4 -1
- data/lib/puppet/util.rb +59 -6
- data/lib/puppet/util/adsi.rb +11 -0
- data/lib/puppet/util/log.rb +4 -0
- data/lib/puppet/util/log/destinations.rb +7 -1
- data/lib/puppet/util/monkey_patches.rb +19 -0
- data/lib/puppet/util/network_device/config.rb +4 -5
- data/lib/puppet/util/settings.rb +5 -0
- data/lib/puppet/util/suidmanager.rb +0 -1
- data/lib/puppet/util/windows.rb +4 -0
- data/lib/puppet/util/windows/error.rb +16 -0
- data/lib/puppet/util/windows/security.rb +593 -0
- data/spec/integration/defaults_spec.rb +27 -0
- data/spec/integration/network/handler_spec.rb +1 -1
- data/spec/integration/type/file_spec.rb +382 -145
- data/spec/integration/util/windows/security_spec.rb +468 -0
- data/spec/shared_behaviours/file_serving.rb +4 -3
- data/spec/unit/application/agent_spec.rb +1 -0
- data/spec/unit/application/device_spec.rb +5 -0
- data/spec/unit/application/resource_spec.rb +62 -101
- data/spec/unit/configurer/downloader_spec.rb +2 -2
- data/spec/unit/configurer/plugin_handler_spec.rb +15 -8
- data/spec/unit/configurer_spec.rb +2 -2
- data/spec/unit/face/ca_spec.rb +34 -0
- data/spec/unit/face/certificate_spec.rb +168 -1
- data/spec/unit/file_serving/fileset_spec.rb +1 -1
- data/spec/unit/file_serving/indirection_hooks_spec.rb +1 -1
- data/spec/unit/file_serving/metadata_spec.rb +151 -107
- data/spec/unit/indirector/certificate_request/ca_spec.rb +0 -3
- data/spec/unit/indirector/direct_file_server_spec.rb +10 -9
- data/spec/unit/indirector/file_metadata/file_spec.rb +6 -4
- data/spec/unit/indirector/request_spec.rb +13 -3
- data/spec/unit/indirector/resource/active_record_spec.rb +4 -10
- data/spec/unit/indirector/resource/ral_spec.rb +6 -4
- data/spec/unit/indirector/rest_spec.rb +5 -6
- data/spec/unit/network/handler/ca_spec.rb +86 -0
- data/spec/unit/parser/collector_spec.rb +7 -7
- data/spec/unit/parser/scope_spec.rb +20 -0
- data/spec/unit/provider/file/posix_spec.rb +226 -0
- data/spec/unit/provider/file/windows_spec.rb +136 -0
- data/spec/unit/provider/group/windows_adsi_spec.rb +7 -2
- data/spec/unit/provider/user/windows_adsi_spec.rb +36 -3
- data/spec/unit/resource/catalog_spec.rb +20 -10
- data/spec/unit/resource_spec.rb +55 -8
- data/spec/unit/ssl/certificate_authority/interface_spec.rb +97 -54
- data/spec/unit/ssl/certificate_authority_spec.rb +133 -23
- data/spec/unit/ssl/certificate_factory_spec.rb +90 -70
- data/spec/unit/ssl/certificate_request_spec.rb +62 -1
- data/spec/unit/ssl/certificate_spec.rb +20 -14
- data/spec/unit/ssl/host_spec.rb +52 -6
- data/spec/unit/type/file/content_spec.rb +4 -4
- data/spec/unit/type/file/group_spec.rb +34 -96
- data/spec/unit/type/file/mode_spec.rb +88 -0
- data/spec/unit/type/file/owner_spec.rb +32 -123
- data/spec/unit/type/file/source_spec.rb +120 -41
- data/spec/unit/type/file_spec.rb +1033 -753
- data/spec/unit/type_spec.rb +19 -1
- data/spec/unit/util/adsi_spec.rb +19 -0
- data/spec/unit/util/log/destinations_spec.rb +75 -0
- data/spec/unit/util/log_spec.rb +15 -0
- data/spec/unit/util/network_device/config_spec.rb +7 -0
- data/spec/unit/util/settings_spec.rb +10 -0
- data/spec/unit/util_spec.rb +126 -13
- data/test/language/functions.rb +0 -1
- data/test/language/snippets.rb +0 -9
- data/test/lib/puppettest/exetest.rb +1 -1
- data/test/lib/puppettest/servertest.rb +0 -1
- data/test/rails/rails.rb +0 -1
- data/test/ral/type/filesources.rb +0 -60
- metadata +13 -33
- data/lib/puppet/network/client.rb +0 -174
- data/lib/puppet/network/client/ca.rb +0 -56
- data/lib/puppet/network/client/file.rb +0 -6
- data/lib/puppet/network/client/proxy.rb +0 -27
- data/lib/puppet/network/client/report.rb +0 -26
- data/lib/puppet/network/client/runner.rb +0 -10
- data/lib/puppet/network/client/status.rb +0 -4
- data/lib/puppet/network/http_server.rb +0 -3
- data/lib/puppet/network/http_server/mongrel.rb +0 -130
- data/lib/puppet/network/http_server/webrick.rb +0 -155
- data/lib/puppet/network/xmlrpc/client.rb +0 -211
- data/lib/puppet/provider/file/win32.rb +0 -72
- data/lib/puppet/sslcertificates.rb +0 -146
- data/lib/puppet/sslcertificates/ca.rb +0 -375
- data/lib/puppet/sslcertificates/certificate.rb +0 -255
- data/lib/puppet/sslcertificates/inventory.rb +0 -38
- data/lib/puppet/sslcertificates/support.rb +0 -146
- data/spec/integration/network/client_spec.rb +0 -18
- data/spec/unit/network/xmlrpc/client_spec.rb +0 -172
- data/spec/unit/sslcertificates/ca_spec.rb +0 -106
- data/test/certmgr/certmgr.rb +0 -308
- data/test/certmgr/inventory.rb +0 -69
- data/test/certmgr/support.rb +0 -105
- data/test/network/client/ca.rb +0 -69
- data/test/network/client/dipper.rb +0 -34
- data/test/network/handler/ca.rb +0 -273
- data/test/network/server/mongrel_test.rb +0 -99
- data/test/network/server/webrick.rb +0 -111
- data/test/network/xmlrpc/client.rb +0 -45
@@ -1,72 +0,0 @@
|
|
1
|
-
Puppet::Type.type(:file).provide :microsoft_windows do
|
2
|
-
desc "Uses Microsoft Windows functionality to manage file's users and rights."
|
3
|
-
|
4
|
-
confine :feature => :microsoft_windows
|
5
|
-
|
6
|
-
include Puppet::Util::Warnings
|
7
|
-
|
8
|
-
require 'sys/admin' if Puppet.features.microsoft_windows?
|
9
|
-
|
10
|
-
def id2name(id)
|
11
|
-
return id.to_s if id.is_a?(Symbol)
|
12
|
-
return nil if id > Puppet[:maximum_uid].to_i
|
13
|
-
# should translate ID numbers to usernames
|
14
|
-
id
|
15
|
-
end
|
16
|
-
|
17
|
-
def is_owner_insync?(current, should)
|
18
|
-
should.each do |value|
|
19
|
-
if value =~ /^\d+$/
|
20
|
-
uid = Integer(value)
|
21
|
-
elsif value.is_a?(String)
|
22
|
-
fail "Could not find user #{value}" unless uid = uid(value)
|
23
|
-
else
|
24
|
-
uid = value
|
25
|
-
end
|
26
|
-
|
27
|
-
return true if uid == current
|
28
|
-
end
|
29
|
-
|
30
|
-
unless Puppet.features.root?
|
31
|
-
warnonce "Cannot manage ownership unless running as root"
|
32
|
-
return true
|
33
|
-
end
|
34
|
-
|
35
|
-
false
|
36
|
-
end
|
37
|
-
|
38
|
-
# Determine if the user is valid, and if so, return the UID
|
39
|
-
def validuser?(value)
|
40
|
-
info "Is '#{value}' a valid user?"
|
41
|
-
return 0
|
42
|
-
begin
|
43
|
-
number = Integer(value)
|
44
|
-
return number
|
45
|
-
rescue ArgumentError
|
46
|
-
number = nil
|
47
|
-
end
|
48
|
-
(number = uid(value)) && number
|
49
|
-
end
|
50
|
-
|
51
|
-
def retrieve(resource)
|
52
|
-
unless stat = resource.stat
|
53
|
-
return :absent
|
54
|
-
end
|
55
|
-
|
56
|
-
currentvalue = stat.uid
|
57
|
-
|
58
|
-
# On OS X, files that are owned by -2 get returned as really
|
59
|
-
# large UIDs instead of negative ones. This isn't a Ruby bug,
|
60
|
-
# it's an OS X bug, since it shows up in perl, too.
|
61
|
-
if currentvalue > Puppet[:maximum_uid].to_i
|
62
|
-
self.warning "Apparently using negative UID (#{currentvalue}) on a platform that does not consistently handle them"
|
63
|
-
currentvalue = :silly
|
64
|
-
end
|
65
|
-
|
66
|
-
currentvalue
|
67
|
-
end
|
68
|
-
|
69
|
-
def sync(path, links, should)
|
70
|
-
info("should set '%s'%%owner to '%s'" % [path, should])
|
71
|
-
end
|
72
|
-
end
|
@@ -1,146 +0,0 @@
|
|
1
|
-
# The library for manipulating SSL certs.
|
2
|
-
|
3
|
-
require 'puppet'
|
4
|
-
|
5
|
-
raise Puppet::Error, "You must have the Ruby openssl library installed" unless Puppet.features.openssl?
|
6
|
-
|
7
|
-
module Puppet::SSLCertificates
|
8
|
-
#def self.mkcert(type, name, dnsnames, ttl, issuercert, issuername, serial, publickey)
|
9
|
-
def self.mkcert(hash)
|
10
|
-
[:type, :name, :ttl, :issuer, :serial, :publickey].each { |param|
|
11
|
-
raise ArgumentError, "mkcert called without #{param}" unless hash.include?(param)
|
12
|
-
}
|
13
|
-
|
14
|
-
cert = OpenSSL::X509::Certificate.new
|
15
|
-
# Make the certificate valid as of yesterday, because
|
16
|
-
# so many people's clocks are out of sync.
|
17
|
-
from = Time.now - (60*60*24)
|
18
|
-
|
19
|
-
cert.subject = hash[:name]
|
20
|
-
if hash[:issuer]
|
21
|
-
cert.issuer = hash[:issuer].subject
|
22
|
-
else
|
23
|
-
# we're a self-signed cert
|
24
|
-
cert.issuer = hash[:name]
|
25
|
-
end
|
26
|
-
cert.not_before = from
|
27
|
-
cert.not_after = from + hash[:ttl]
|
28
|
-
cert.version = 2 # X509v3
|
29
|
-
|
30
|
-
cert.public_key = hash[:publickey]
|
31
|
-
cert.serial = hash[:serial]
|
32
|
-
|
33
|
-
basic_constraint = nil
|
34
|
-
key_usage = nil
|
35
|
-
ext_key_usage = nil
|
36
|
-
subject_alt_name = []
|
37
|
-
|
38
|
-
ef = OpenSSL::X509::ExtensionFactory.new
|
39
|
-
|
40
|
-
ef.subject_certificate = cert
|
41
|
-
|
42
|
-
if hash[:issuer]
|
43
|
-
ef.issuer_certificate = hash[:issuer]
|
44
|
-
else
|
45
|
-
ef.issuer_certificate = cert
|
46
|
-
end
|
47
|
-
|
48
|
-
ex = []
|
49
|
-
case hash[:type]
|
50
|
-
when :ca
|
51
|
-
basic_constraint = "CA:TRUE"
|
52
|
-
key_usage = %w{cRLSign keyCertSign}
|
53
|
-
when :terminalsubca
|
54
|
-
basic_constraint = "CA:TRUE,pathlen:0"
|
55
|
-
key_usage = %w{cRLSign keyCertSign}
|
56
|
-
when :server
|
57
|
-
basic_constraint = "CA:FALSE"
|
58
|
-
dnsnames = Puppet[:certdnsnames]
|
59
|
-
name = hash[:name].to_s.sub(%r{/CN=},'')
|
60
|
-
if dnsnames != ""
|
61
|
-
dnsnames.split(':').each { |d| subject_alt_name << 'DNS:' + d }
|
62
|
-
subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
|
63
|
-
elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
|
64
|
-
subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
|
65
|
-
subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
|
66
|
-
subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
|
67
|
-
end
|
68
|
-
key_usage = %w{digitalSignature keyEncipherment}
|
69
|
-
ext_key_usage = %w{serverAuth clientAuth emailProtection}
|
70
|
-
when :ocsp
|
71
|
-
basic_constraint = "CA:FALSE"
|
72
|
-
key_usage = %w{nonRepudiation digitalSignature}
|
73
|
-
ext_key_usage = %w{serverAuth OCSPSigning}
|
74
|
-
when :client
|
75
|
-
basic_constraint = "CA:FALSE"
|
76
|
-
key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
|
77
|
-
ext_key_usage = %w{clientAuth emailProtection}
|
78
|
-
ex << ef.create_extension("nsCertType", "client,email")
|
79
|
-
else
|
80
|
-
raise Puppet::Error, "unknown cert type '#{hash[:type]}'"
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
ex << ef.create_extension(
|
85
|
-
"nsComment",
|
86
|
-
|
87
|
-
"Puppet Ruby/OpenSSL Generated Certificate")
|
88
|
-
ex << ef.create_extension("basicConstraints", basic_constraint, true)
|
89
|
-
ex << ef.create_extension("subjectKeyIdentifier", "hash")
|
90
|
-
|
91
|
-
ex << ef.create_extension("keyUsage", key_usage.join(",")) if key_usage
|
92
|
-
ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) if ext_key_usage
|
93
|
-
ex << ef.create_extension("subjectAltName", subject_alt_name.join(",")) if ! subject_alt_name.empty?
|
94
|
-
|
95
|
-
#if @ca_config[:cdp_location] then
|
96
|
-
# ex << ef.create_extension("crlDistributionPoints",
|
97
|
-
# @ca_config[:cdp_location])
|
98
|
-
#end
|
99
|
-
|
100
|
-
#if @ca_config[:ocsp_location] then
|
101
|
-
# ex << ef.create_extension("authorityInfoAccess",
|
102
|
-
# "OCSP;" << @ca_config[:ocsp_location])
|
103
|
-
#end
|
104
|
-
cert.extensions = ex
|
105
|
-
|
106
|
-
# for some reason this _must_ be the last extension added
|
107
|
-
ex << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if hash[:type] == :ca
|
108
|
-
|
109
|
-
cert
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.mkhash(dir, cert, certfile)
|
113
|
-
# Make sure the hash is zero-padded to 8 chars
|
114
|
-
hash = "%08x" % cert.issuer.hash
|
115
|
-
hashpath = nil
|
116
|
-
10.times { |i|
|
117
|
-
path = File.join(dir, "#{hash}.#{i}")
|
118
|
-
if FileTest.exists?(path)
|
119
|
-
if FileTest.symlink?(path)
|
120
|
-
dest = File.readlink(path)
|
121
|
-
if dest == certfile
|
122
|
-
# the correct link already exists
|
123
|
-
hashpath = path
|
124
|
-
break
|
125
|
-
else
|
126
|
-
next
|
127
|
-
end
|
128
|
-
else
|
129
|
-
next
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
File.symlink(certfile, path)
|
134
|
-
|
135
|
-
hashpath = path
|
136
|
-
break
|
137
|
-
}
|
138
|
-
|
139
|
-
|
140
|
-
hashpath
|
141
|
-
end
|
142
|
-
require 'puppet/sslcertificates/certificate'
|
143
|
-
require 'puppet/sslcertificates/inventory'
|
144
|
-
require 'puppet/sslcertificates/ca'
|
145
|
-
end
|
146
|
-
|
@@ -1,375 +0,0 @@
|
|
1
|
-
require 'sync'
|
2
|
-
|
3
|
-
class Puppet::SSLCertificates::CA
|
4
|
-
include Puppet::Util::Warnings
|
5
|
-
|
6
|
-
Certificate = Puppet::SSLCertificates::Certificate
|
7
|
-
attr_accessor :keyfile, :file, :config, :dir, :cert, :crl
|
8
|
-
|
9
|
-
def certfile
|
10
|
-
@config[:cacert]
|
11
|
-
end
|
12
|
-
|
13
|
-
# Remove all traces of a given host. This is kind of hackish, but, eh.
|
14
|
-
def clean(host)
|
15
|
-
host = host.downcase
|
16
|
-
[:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir].each do |name|
|
17
|
-
dir = Puppet[name]
|
18
|
-
|
19
|
-
file = File.join(dir, host + ".pem")
|
20
|
-
|
21
|
-
if FileTest.exists?(file)
|
22
|
-
begin
|
23
|
-
if Puppet[:name] == "cert"
|
24
|
-
puts "Removing #{file}"
|
25
|
-
else
|
26
|
-
Puppet.info "Removing #{file}"
|
27
|
-
end
|
28
|
-
File.unlink(file)
|
29
|
-
rescue => detail
|
30
|
-
raise Puppet::Error, "Could not delete #{file}: #{detail}"
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def host2csrfile(hostname)
|
38
|
-
File.join(Puppet[:csrdir], [hostname.downcase, "pem"].join("."))
|
39
|
-
end
|
40
|
-
|
41
|
-
# this stores signed certs in a directory unrelated to
|
42
|
-
# normal client certs
|
43
|
-
def host2certfile(hostname)
|
44
|
-
File.join(Puppet[:signeddir], [hostname.downcase, "pem"].join("."))
|
45
|
-
end
|
46
|
-
|
47
|
-
# Turn our hostname into a Name object
|
48
|
-
def thing2name(thing)
|
49
|
-
thing.subject.to_a.find { |ary|
|
50
|
-
ary[0] == "CN"
|
51
|
-
}[1]
|
52
|
-
end
|
53
|
-
|
54
|
-
def initialize(hash = {})
|
55
|
-
Puppet.settings.use(:main, :ca, :ssl)
|
56
|
-
self.setconfig(hash)
|
57
|
-
|
58
|
-
if Puppet[:capass]
|
59
|
-
if FileTest.exists?(Puppet[:capass])
|
60
|
-
#puts "Reading #{Puppet[:capass]}"
|
61
|
-
#system "ls -al #{Puppet[:capass]}"
|
62
|
-
#File.read Puppet[:capass]
|
63
|
-
@config[:password] = self.getpass
|
64
|
-
else
|
65
|
-
# Don't create a password if the cert already exists
|
66
|
-
@config[:password] = self.genpass unless FileTest.exists?(@config[:cacert])
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
self.getcert
|
71
|
-
init_crl
|
72
|
-
unless FileTest.exists?(@config[:serial])
|
73
|
-
Puppet.settings.write(:serial) do |f|
|
74
|
-
f << "%04X" % 1
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# Generate a new password for the CA.
|
80
|
-
def genpass
|
81
|
-
pass = ""
|
82
|
-
20.times { pass += (rand(74) + 48).chr }
|
83
|
-
|
84
|
-
begin
|
85
|
-
Puppet.settings.write(:capass) { |f| f.print pass }
|
86
|
-
rescue Errno::EACCES => detail
|
87
|
-
raise Puppet::Error, detail.to_s
|
88
|
-
end
|
89
|
-
pass
|
90
|
-
end
|
91
|
-
|
92
|
-
# Get the CA password.
|
93
|
-
def getpass
|
94
|
-
if @config[:capass] and File.readable?(@config[:capass])
|
95
|
-
return File.read(@config[:capass])
|
96
|
-
else
|
97
|
-
raise Puppet::Error, "Could not decrypt CA key with password: #{detail}"
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Get the CA cert.
|
102
|
-
def getcert
|
103
|
-
if FileTest.exists?(@config[:cacert])
|
104
|
-
@cert = OpenSSL::X509::Certificate.new(
|
105
|
-
File.read(@config[:cacert])
|
106
|
-
)
|
107
|
-
else
|
108
|
-
self.mkrootcert
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
# Retrieve a client's CSR.
|
113
|
-
def getclientcsr(host)
|
114
|
-
csrfile = host2csrfile(host)
|
115
|
-
return nil unless File.exists?(csrfile)
|
116
|
-
|
117
|
-
OpenSSL::X509::Request.new(File.read(csrfile))
|
118
|
-
end
|
119
|
-
|
120
|
-
# Retrieve a client's certificate.
|
121
|
-
def getclientcert(host)
|
122
|
-
certfile = host2certfile(host)
|
123
|
-
return [nil, nil] unless File.exists?(certfile)
|
124
|
-
|
125
|
-
[OpenSSL::X509::Certificate.new(File.read(certfile)), @cert]
|
126
|
-
end
|
127
|
-
|
128
|
-
# List certificates waiting to be signed. This returns a list of hostnames, not actual
|
129
|
-
# files -- the names can be converted to full paths with host2csrfile.
|
130
|
-
def list(dummy_argument=:work_arround_for_ruby_GC_bug)
|
131
|
-
return Dir.entries(Puppet[:csrdir]).find_all { |file|
|
132
|
-
file =~ /\.pem$/
|
133
|
-
}.collect { |file|
|
134
|
-
file.sub(/\.pem$/, '')
|
135
|
-
}
|
136
|
-
end
|
137
|
-
|
138
|
-
# List signed certificates. This returns a list of hostnames, not actual
|
139
|
-
# files -- the names can be converted to full paths with host2csrfile.
|
140
|
-
def list_signed(dummy_argument=:work_arround_for_ruby_GC_bug)
|
141
|
-
return Dir.entries(Puppet[:signeddir]).find_all { |file|
|
142
|
-
file =~ /\.pem$/
|
143
|
-
}.collect { |file|
|
144
|
-
file.sub(/\.pem$/, '')
|
145
|
-
}
|
146
|
-
end
|
147
|
-
|
148
|
-
# Create the root certificate.
|
149
|
-
def mkrootcert
|
150
|
-
# Make the root cert's name "Puppet CA: " plus the FQDN of the host running the CA.
|
151
|
-
name = "Puppet CA: #{Facter["hostname"].value}"
|
152
|
-
if domain = Facter["domain"].value
|
153
|
-
name += ".#{domain}"
|
154
|
-
end
|
155
|
-
|
156
|
-
cert = Certificate.new(
|
157
|
-
:name => name,
|
158
|
-
:cert => @config[:cacert],
|
159
|
-
:encrypt => @config[:capass],
|
160
|
-
:key => @config[:cakey],
|
161
|
-
:selfsign => true,
|
162
|
-
:ttl => ttl,
|
163
|
-
:type => :ca
|
164
|
-
)
|
165
|
-
|
166
|
-
# This creates the cakey file
|
167
|
-
Puppet::Util::SUIDManager.asuser(Puppet[:user], Puppet[:group]) do
|
168
|
-
@cert = cert.mkselfsigned
|
169
|
-
end
|
170
|
-
Puppet.settings.write(:cacert) do |f|
|
171
|
-
f.puts @cert.to_pem
|
172
|
-
end
|
173
|
-
Puppet.settings.write(:capub) do |f|
|
174
|
-
f.puts @cert.public_key
|
175
|
-
end
|
176
|
-
cert
|
177
|
-
end
|
178
|
-
|
179
|
-
def removeclientcsr(host)
|
180
|
-
csrfile = host2csrfile(host)
|
181
|
-
raise Puppet::Error, "No certificate request for #{host}" unless File.exists?(csrfile)
|
182
|
-
|
183
|
-
File.unlink(csrfile)
|
184
|
-
end
|
185
|
-
|
186
|
-
# Revoke the certificate with serial number SERIAL issued by this
|
187
|
-
# CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
|
188
|
-
def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
|
189
|
-
time = Time.now
|
190
|
-
revoked = OpenSSL::X509::Revoked.new
|
191
|
-
revoked.serial = serial
|
192
|
-
revoked.time = time
|
193
|
-
enum = OpenSSL::ASN1::Enumerated(reason)
|
194
|
-
ext = OpenSSL::X509::Extension.new("CRLReason", enum)
|
195
|
-
revoked.add_extension(ext)
|
196
|
-
@crl.add_revoked(revoked)
|
197
|
-
store_crl
|
198
|
-
end
|
199
|
-
|
200
|
-
# Take the Puppet config and store it locally.
|
201
|
-
def setconfig(hash)
|
202
|
-
@config = {}
|
203
|
-
Puppet.settings.params("ca").each { |param|
|
204
|
-
param = param.intern if param.is_a? String
|
205
|
-
if hash.include?(param)
|
206
|
-
@config[param] = hash[param]
|
207
|
-
Puppet[param] = hash[param]
|
208
|
-
hash.delete(param)
|
209
|
-
else
|
210
|
-
@config[param] = Puppet[param]
|
211
|
-
end
|
212
|
-
}
|
213
|
-
|
214
|
-
if hash.include?(:password)
|
215
|
-
@config[:password] = hash[:password]
|
216
|
-
hash.delete(:password)
|
217
|
-
end
|
218
|
-
|
219
|
-
raise ArgumentError, "Unknown parameters #{hash.keys.join(",")}" if hash.length > 0
|
220
|
-
|
221
|
-
[:cadir, :csrdir, :signeddir].each { |dir|
|
222
|
-
raise Puppet::DevError, "#{dir} is undefined" unless @config[dir]
|
223
|
-
}
|
224
|
-
end
|
225
|
-
|
226
|
-
# Sign a given certificate request.
|
227
|
-
def sign(csr)
|
228
|
-
unless csr.is_a?(OpenSSL::X509::Request)
|
229
|
-
raise Puppet::Error,
|
230
|
-
"CA#sign only accepts OpenSSL::X509::Request objects, not #{csr.class}"
|
231
|
-
end
|
232
|
-
|
233
|
-
raise Puppet::Error, "CSR sign verification failed" unless csr.verify(csr.public_key)
|
234
|
-
|
235
|
-
serial = nil
|
236
|
-
Puppet.settings.readwritelock(:serial) { |f|
|
237
|
-
serial = File.read(@config[:serial]).chomp.hex
|
238
|
-
# increment the serial
|
239
|
-
f << "%04X" % (serial + 1)
|
240
|
-
}
|
241
|
-
|
242
|
-
newcert = Puppet::SSLCertificates.mkcert(
|
243
|
-
:type => :server,
|
244
|
-
:name => csr.subject,
|
245
|
-
:ttl => ttl,
|
246
|
-
:issuer => @cert,
|
247
|
-
:serial => serial,
|
248
|
-
:publickey => csr.public_key
|
249
|
-
)
|
250
|
-
|
251
|
-
sign_with_key(newcert)
|
252
|
-
|
253
|
-
self.storeclientcert(newcert)
|
254
|
-
|
255
|
-
[newcert, @cert]
|
256
|
-
end
|
257
|
-
|
258
|
-
# Store the client's CSR for later signing. This is called from
|
259
|
-
# server/ca.rb, and the CSRs are deleted once the certificate is actually
|
260
|
-
# signed.
|
261
|
-
def storeclientcsr(csr)
|
262
|
-
host = thing2name(csr)
|
263
|
-
|
264
|
-
csrfile = host2csrfile(host)
|
265
|
-
raise Puppet::Error, "Certificate request for #{host} already exists" if File.exists?(csrfile)
|
266
|
-
|
267
|
-
Puppet.settings.writesub(:csrdir, csrfile) do |f|
|
268
|
-
f.print csr.to_pem
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
# Store the certificate that we generate.
|
273
|
-
def storeclientcert(cert)
|
274
|
-
host = thing2name(cert)
|
275
|
-
|
276
|
-
certfile = host2certfile(host)
|
277
|
-
Puppet.notice "Overwriting signed certificate #{certfile} for #{host}" if File.exists?(certfile)
|
278
|
-
|
279
|
-
Puppet::SSLCertificates::Inventory::add(cert)
|
280
|
-
Puppet.settings.writesub(:signeddir, certfile) do |f|
|
281
|
-
f.print cert.to_pem
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
# TTL for new certificates in seconds. If config param :ca_ttl is set,
|
286
|
-
# use that, otherwise use :ca_days for backwards compatibility
|
287
|
-
def ttl
|
288
|
-
days = @config[:ca_days]
|
289
|
-
if days && days.size > 0
|
290
|
-
warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead."
|
291
|
-
return @config[:ca_days] * 24 * 60 * 60
|
292
|
-
else
|
293
|
-
ttl = @config[:ca_ttl]
|
294
|
-
if ttl.is_a?(String)
|
295
|
-
unless ttl =~ /^(\d+)(y|d|h|s)$/
|
296
|
-
raise ArgumentError, "Invalid ca_ttl #{ttl}"
|
297
|
-
end
|
298
|
-
case $2
|
299
|
-
when 'y'
|
300
|
-
unit = 365 * 24 * 60 * 60
|
301
|
-
when 'd'
|
302
|
-
unit = 24 * 60 * 60
|
303
|
-
when 'h'
|
304
|
-
unit = 60 * 60
|
305
|
-
when 's'
|
306
|
-
unit = 1
|
307
|
-
else
|
308
|
-
raise ArgumentError, "Invalid unit for ca_ttl #{ttl}"
|
309
|
-
end
|
310
|
-
return $1.to_i * unit
|
311
|
-
else
|
312
|
-
return ttl
|
313
|
-
end
|
314
|
-
end
|
315
|
-
end
|
316
|
-
|
317
|
-
private
|
318
|
-
def init_crl
|
319
|
-
if FileTest.exists?(@config[:cacrl])
|
320
|
-
@crl = OpenSSL::X509::CRL.new(
|
321
|
-
File.read(@config[:cacrl])
|
322
|
-
)
|
323
|
-
else
|
324
|
-
# Create new CRL
|
325
|
-
@crl = OpenSSL::X509::CRL.new
|
326
|
-
@crl.issuer = @cert.subject
|
327
|
-
@crl.version = 1
|
328
|
-
store_crl
|
329
|
-
@crl
|
330
|
-
end
|
331
|
-
end
|
332
|
-
|
333
|
-
def store_crl
|
334
|
-
# Increment the crlNumber
|
335
|
-
e = @crl.extensions.find { |e| e.oid == 'crlNumber' }
|
336
|
-
ext = @crl.extensions.reject { |e| e.oid == 'crlNumber' }
|
337
|
-
crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0)
|
338
|
-
ext << OpenSSL::X509::Extension.new("crlNumber", crlNum)
|
339
|
-
@crl.extensions = ext
|
340
|
-
|
341
|
-
# Set last/next update
|
342
|
-
now = Time.now
|
343
|
-
@crl.last_update = now
|
344
|
-
# Keep CRL valid for 5 years
|
345
|
-
@crl.next_update = now + 5 * 365*24*60*60
|
346
|
-
|
347
|
-
sign_with_key(@crl)
|
348
|
-
Puppet.settings.write(:cacrl) do |f|
|
349
|
-
f.puts @crl.to_pem
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
def sign_with_key(signable, digest = OpenSSL::Digest::SHA1.new)
|
354
|
-
cakey = nil
|
355
|
-
if @config[:password]
|
356
|
-
begin
|
357
|
-
cakey = OpenSSL::PKey::RSA.new(
|
358
|
-
File.read(@config[:cakey]), @config[:password]
|
359
|
-
)
|
360
|
-
rescue
|
361
|
-
raise Puppet::Error,
|
362
|
-
"Decrypt of CA private key with password stored in @config[:capass] not possible"
|
363
|
-
end
|
364
|
-
else
|
365
|
-
cakey = OpenSSL::PKey::RSA.new(
|
366
|
-
File.read(@config[:cakey])
|
367
|
-
)
|
368
|
-
end
|
369
|
-
|
370
|
-
raise Puppet::Error, "CA Certificate is invalid" unless @cert.check_private_key(cakey)
|
371
|
-
|
372
|
-
signable.sign(cakey, digest)
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|