puppet 0.9.2
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 +0 -0
- data/COPYING +340 -0
- data/LICENSE +17 -0
- data/README +24 -0
- data/Rakefile +294 -0
- data/TODO +4 -0
- data/bin/cf2puppet +186 -0
- data/bin/puppet +176 -0
- data/bin/puppetca +213 -0
- data/bin/puppetd +246 -0
- data/bin/puppetdoc +184 -0
- data/bin/puppetmasterd +258 -0
- data/examples/code/allatonce +13 -0
- data/examples/code/assignments +11 -0
- data/examples/code/classing +35 -0
- data/examples/code/components +73 -0
- data/examples/code/execs +16 -0
- data/examples/code/failers/badclassnoparam +10 -0
- data/examples/code/failers/badclassparam +10 -0
- data/examples/code/failers/badcompnoparam +9 -0
- data/examples/code/failers/badcompparam +9 -0
- data/examples/code/failers/badtypeparam +3 -0
- data/examples/code/file.bl +11 -0
- data/examples/code/filedefaults +10 -0
- data/examples/code/fileparsing +116 -0
- data/examples/code/filerecursion +15 -0
- data/examples/code/functions +3 -0
- data/examples/code/groups +7 -0
- data/examples/code/head +30 -0
- data/examples/code/importing +8 -0
- data/examples/code/nodes +20 -0
- data/examples/code/one +8 -0
- data/examples/code/relationships +34 -0
- data/examples/code/selectors +28 -0
- data/examples/code/simpletests +11 -0
- data/examples/code/snippets/argumentdefaults +14 -0
- data/examples/code/snippets/casestatement +39 -0
- data/examples/code/snippets/classheirarchy.pp +15 -0
- data/examples/code/snippets/classincludes.pp +17 -0
- data/examples/code/snippets/classpathtest +11 -0
- data/examples/code/snippets/dirchmod +19 -0
- data/examples/code/snippets/failmissingexecpath.pp +13 -0
- data/examples/code/snippets/falsevalues.pp +3 -0
- data/examples/code/snippets/filecreate +11 -0
- data/examples/code/snippets/implicititeration +15 -0
- data/examples/code/snippets/multipleinstances +7 -0
- data/examples/code/snippets/namevartest +9 -0
- data/examples/code/snippets/scopetest +13 -0
- data/examples/code/snippets/selectorvalues.pp +22 -0
- data/examples/code/snippets/simpledefaults +5 -0
- data/examples/code/snippets/simpleselector +38 -0
- data/examples/code/svncommit +13 -0
- data/examples/root/bin/sleeper +69 -0
- data/examples/root/etc/configfile +0 -0
- data/examples/root/etc/debian-passwd +29 -0
- data/examples/root/etc/debian-syslog.conf +71 -0
- data/examples/root/etc/init.d/sleeper +65 -0
- data/examples/root/etc/otherfile +0 -0
- data/examples/root/etc/puppet/fileserver.conf +3 -0
- data/examples/root/etc/puppet/puppetmasterd.conf +10 -0
- data/ext/module:puppet +195 -0
- data/install.rb +270 -0
- data/lib/puppet.rb +249 -0
- data/lib/puppet/base64.rb +19 -0
- data/lib/puppet/client.rb +519 -0
- data/lib/puppet/config.rb +49 -0
- data/lib/puppet/daemon.rb +208 -0
- data/lib/puppet/element.rb +71 -0
- data/lib/puppet/event.rb +259 -0
- data/lib/puppet/log.rb +321 -0
- data/lib/puppet/metric.rb +250 -0
- data/lib/puppet/parsedfile.rb +38 -0
- data/lib/puppet/parser/ast.rb +1560 -0
- data/lib/puppet/parser/interpreter.rb +150 -0
- data/lib/puppet/parser/lexer.rb +226 -0
- data/lib/puppet/parser/parser.rb +1354 -0
- data/lib/puppet/parser/scope.rb +755 -0
- data/lib/puppet/server.rb +170 -0
- data/lib/puppet/server/authstore.rb +227 -0
- data/lib/puppet/server/ca.rb +140 -0
- data/lib/puppet/server/filebucket.rb +147 -0
- data/lib/puppet/server/fileserver.rb +477 -0
- data/lib/puppet/server/logger.rb +43 -0
- data/lib/puppet/server/master.rb +103 -0
- data/lib/puppet/server/servlet.rb +247 -0
- data/lib/puppet/sslcertificates.rb +737 -0
- data/lib/puppet/statechange.rb +150 -0
- data/lib/puppet/storage.rb +95 -0
- data/lib/puppet/transaction.rb +179 -0
- data/lib/puppet/transportable.rb +151 -0
- data/lib/puppet/type.rb +1354 -0
- data/lib/puppet/type/component.rb +141 -0
- data/lib/puppet/type/cron.rb +543 -0
- data/lib/puppet/type/exec.rb +316 -0
- data/lib/puppet/type/group.rb +152 -0
- data/lib/puppet/type/nameservice.rb +3 -0
- data/lib/puppet/type/nameservice/netinfo.rb +173 -0
- data/lib/puppet/type/nameservice/objectadd.rb +146 -0
- data/lib/puppet/type/nameservice/posix.rb +200 -0
- data/lib/puppet/type/package.rb +420 -0
- data/lib/puppet/type/package/apt.rb +70 -0
- data/lib/puppet/type/package/dpkg.rb +108 -0
- data/lib/puppet/type/package/rpm.rb +81 -0
- data/lib/puppet/type/package/sun.rb +117 -0
- data/lib/puppet/type/package/yum.rb +58 -0
- data/lib/puppet/type/pfile.rb +569 -0
- data/lib/puppet/type/pfile/checksum.rb +219 -0
- data/lib/puppet/type/pfile/create.rb +108 -0
- data/lib/puppet/type/pfile/group.rb +129 -0
- data/lib/puppet/type/pfile/mode.rb +131 -0
- data/lib/puppet/type/pfile/source.rb +264 -0
- data/lib/puppet/type/pfile/type.rb +31 -0
- data/lib/puppet/type/pfile/uid.rb +166 -0
- data/lib/puppet/type/pfilebucket.rb +80 -0
- data/lib/puppet/type/pprocess.rb +97 -0
- data/lib/puppet/type/service.rb +347 -0
- data/lib/puppet/type/service/base.rb +17 -0
- data/lib/puppet/type/service/debian.rb +50 -0
- data/lib/puppet/type/service/init.rb +145 -0
- data/lib/puppet/type/service/smf.rb +29 -0
- data/lib/puppet/type/state.rb +182 -0
- data/lib/puppet/type/symlink.rb +183 -0
- data/lib/puppet/type/tidy.rb +183 -0
- data/lib/puppet/type/typegen.rb +149 -0
- data/lib/puppet/type/typegen/filerecord.rb +243 -0
- data/lib/puppet/type/typegen/filetype.rb +316 -0
- data/lib/puppet/type/user.rb +290 -0
- data/lib/puppet/util.rb +138 -0
- data/test/certmgr/certmgr.rb +265 -0
- data/test/client/client.rb +203 -0
- data/test/executables/puppetbin.rb +53 -0
- data/test/executables/puppetca.rb +79 -0
- data/test/executables/puppetd.rb +71 -0
- data/test/executables/puppetmasterd.rb +153 -0
- data/test/executables/puppetmodule.rb +60 -0
- data/test/language/ast.rb +412 -0
- data/test/language/interpreter.rb +71 -0
- data/test/language/scope.rb +412 -0
- data/test/language/snippets.rb +445 -0
- data/test/other/events.rb +111 -0
- data/test/other/log.rb +195 -0
- data/test/other/metrics.rb +92 -0
- data/test/other/overrides.rb +115 -0
- data/test/other/parsedfile.rb +31 -0
- data/test/other/relationships.rb +113 -0
- data/test/other/state.rb +106 -0
- data/test/other/storage.rb +39 -0
- data/test/other/transactions.rb +235 -0
- data/test/parser/lexer.rb +120 -0
- data/test/parser/parser.rb +180 -0
- data/test/puppet/conffiles.rb +104 -0
- data/test/puppet/defaults.rb +100 -0
- data/test/puppet/error.rb +23 -0
- data/test/puppet/utiltest.rb +120 -0
- data/test/puppettest.rb +774 -0
- data/test/server/authstore.rb +209 -0
- data/test/server/bucket.rb +227 -0
- data/test/server/ca.rb +201 -0
- data/test/server/fileserver.rb +710 -0
- data/test/server/logger.rb +175 -0
- data/test/server/master.rb +150 -0
- data/test/server/server.rb +130 -0
- data/test/tagging/tagging.rb +80 -0
- data/test/test +51 -0
- data/test/types/basic.rb +119 -0
- data/test/types/component.rb +272 -0
- data/test/types/cron.rb +261 -0
- data/test/types/exec.rb +273 -0
- data/test/types/file.rb +616 -0
- data/test/types/filebucket.rb +167 -0
- data/test/types/fileignoresource.rb +287 -0
- data/test/types/filesources.rb +587 -0
- data/test/types/filetype.rb +162 -0
- data/test/types/group.rb +271 -0
- data/test/types/package.rb +205 -0
- data/test/types/query.rb +101 -0
- data/test/types/service.rb +100 -0
- data/test/types/symlink.rb +93 -0
- data/test/types/tidy.rb +124 -0
- data/test/types/type.rb +135 -0
- data/test/types/user.rb +371 -0
- metadata +243 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
# the server
|
2
|
+
#
|
3
|
+
# allow things to connect to us and communicate, and stuff
|
4
|
+
|
5
|
+
require 'puppet'
|
6
|
+
require 'puppet/daemon'
|
7
|
+
|
8
|
+
$noservernetworking = false
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'webrick'
|
12
|
+
require 'webrick/https'
|
13
|
+
require 'cgi'
|
14
|
+
require 'xmlrpc/server'
|
15
|
+
require 'xmlrpc/client'
|
16
|
+
rescue LoadError => detail
|
17
|
+
$noservernetworking = detail
|
18
|
+
end
|
19
|
+
|
20
|
+
module Puppet
|
21
|
+
class ServerError < RuntimeError; end
|
22
|
+
#---------------------------------------------------------------
|
23
|
+
if $noservernetworking
|
24
|
+
Puppet.err "Could not create server: %s" % $noservernetworking
|
25
|
+
class Server; end
|
26
|
+
else
|
27
|
+
class Server < WEBrick::HTTPServer
|
28
|
+
include Puppet::Daemon
|
29
|
+
|
30
|
+
def initialize(hash = {})
|
31
|
+
daemonize = nil
|
32
|
+
if hash.include?(:Daemonize)
|
33
|
+
daemonize = hash[:Daemonize]
|
34
|
+
end
|
35
|
+
|
36
|
+
if daemonize
|
37
|
+
self.daemonize
|
38
|
+
end
|
39
|
+
# FIXME we should have some kind of access control here, using
|
40
|
+
# :RequestHandler
|
41
|
+
hash[:Port] ||= Puppet[:masterport]
|
42
|
+
hash[:Logger] ||= self.httplog
|
43
|
+
hash[:AccessLog] ||= [
|
44
|
+
[ self.httplog, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
|
45
|
+
[ self.httplog, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
|
46
|
+
]
|
47
|
+
|
48
|
+
if hash.include?(:Handlers)
|
49
|
+
unless hash[:Handlers].is_a?(Hash)
|
50
|
+
raise ServerError, "Handlers must have arguments"
|
51
|
+
end
|
52
|
+
|
53
|
+
@handlers = hash[:Handlers].collect { |handler, args|
|
54
|
+
hclass = nil
|
55
|
+
unless hclass = Handler.handler(handler)
|
56
|
+
raise ServerError, "Invalid handler %s" % handler
|
57
|
+
end
|
58
|
+
hclass.new(args)
|
59
|
+
}
|
60
|
+
else
|
61
|
+
raise ServerError, "A server must have handlers"
|
62
|
+
end
|
63
|
+
|
64
|
+
# okay, i need to retrieve my cert and set it up, somehow
|
65
|
+
# the default case will be that i'm also the ca
|
66
|
+
if ca = @handlers.find { |handler| handler.is_a?(Puppet::Server::CA) }
|
67
|
+
@driver = ca
|
68
|
+
@secureinit = true
|
69
|
+
self.fqdn
|
70
|
+
end
|
71
|
+
|
72
|
+
unless self.readcert
|
73
|
+
unless self.requestcert
|
74
|
+
raise Puppet::Error, "Cannot start without certificates"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
hash[:SSLCertificate] = @cert
|
79
|
+
hash[:SSLPrivateKey] = @key
|
80
|
+
hash[:SSLStartImmediately] = true
|
81
|
+
hash[:SSLEnable] = true
|
82
|
+
hash[:SSLCACertificateFile] = @cacertfile
|
83
|
+
hash[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
|
84
|
+
hash[:SSLCertName] = nil
|
85
|
+
|
86
|
+
super(hash)
|
87
|
+
|
88
|
+
Puppet.info "Listening on port %s" % hash[:Port]
|
89
|
+
|
90
|
+
# this creates a new servlet for every connection,
|
91
|
+
# but all servlets have the same list of handlers
|
92
|
+
# thus, the servlets can have their own state -- passing
|
93
|
+
# around the requests and such -- but the handlers
|
94
|
+
# have a global state
|
95
|
+
|
96
|
+
# mount has to be called after the server is initialized
|
97
|
+
self.mount("/RPC2", Puppet::Server::Servlet, @handlers)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class Server
|
103
|
+
# the base class for the different handlers
|
104
|
+
class Handler
|
105
|
+
attr_accessor :server
|
106
|
+
@subclasses = []
|
107
|
+
|
108
|
+
def self.each
|
109
|
+
@subclasses.each { |c| yield c }
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.handler(name)
|
113
|
+
@subclasses.find { |h|
|
114
|
+
h.name == name
|
115
|
+
}
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.inherited(sub)
|
119
|
+
@subclasses << sub
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.interface
|
123
|
+
if defined? @interface
|
124
|
+
return @interface
|
125
|
+
else
|
126
|
+
raise Puppet::DevError, "Handler %s has no defined interface" %
|
127
|
+
self
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.name
|
132
|
+
unless defined? @name
|
133
|
+
@name = self.to_s.sub(/.+::/, '').intern
|
134
|
+
end
|
135
|
+
|
136
|
+
return @name
|
137
|
+
end
|
138
|
+
|
139
|
+
def initialize(hash = {})
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
class ServerStatus < Handler
|
144
|
+
|
145
|
+
@interface = XMLRPC::Service::Interface.new("status") { |iface|
|
146
|
+
iface.add_method("int status()")
|
147
|
+
}
|
148
|
+
|
149
|
+
@name = :Status
|
150
|
+
|
151
|
+
def status(status = nil, client = nil, clientip = nil)
|
152
|
+
return 1
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
#---------------------------------------------------------------
|
159
|
+
end
|
160
|
+
|
161
|
+
require 'puppet/server/authstore'
|
162
|
+
require 'puppet/server/servlet'
|
163
|
+
require 'puppet/server/master'
|
164
|
+
require 'puppet/server/ca'
|
165
|
+
require 'puppet/server/fileserver'
|
166
|
+
require 'puppet/server/filebucket'
|
167
|
+
require 'puppet/server/logger'
|
168
|
+
require 'puppet/client'
|
169
|
+
|
170
|
+
# $Id: server.rb 732 2005-10-28 05:39:59Z luke $
|
@@ -0,0 +1,227 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
|
3
|
+
#--------------------
|
4
|
+
# standard module for determining whether a given hostname or IP has access to
|
5
|
+
# the requested resource
|
6
|
+
#
|
7
|
+
# $Id: authstore.rb 742 2005-11-16 17:12:11Z luke $
|
8
|
+
|
9
|
+
require 'ipaddr'
|
10
|
+
|
11
|
+
module Puppet
|
12
|
+
class Server
|
13
|
+
class AuthStoreError < Puppet::Error; end
|
14
|
+
class AuthorizationError < Puppet::Error; end
|
15
|
+
|
16
|
+
class AuthStore
|
17
|
+
ORDER = {
|
18
|
+
:ip => [:ip],
|
19
|
+
:name => [:hostname, :domain]
|
20
|
+
}
|
21
|
+
|
22
|
+
Puppet::Util.logmethods(self, false)
|
23
|
+
|
24
|
+
def allow(pattern)
|
25
|
+
# a simple way to allow anyone at all to connect
|
26
|
+
if pattern == "*"
|
27
|
+
@globalallow = true
|
28
|
+
else
|
29
|
+
store(pattern, @allow)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def allowed?(name, ip)
|
34
|
+
if name or ip
|
35
|
+
unless name and ip
|
36
|
+
raise Puppet::DevError, "Name and IP must be passed to 'allowed?'"
|
37
|
+
end
|
38
|
+
# else, we're networked and such
|
39
|
+
else
|
40
|
+
# we're local
|
41
|
+
return true
|
42
|
+
end
|
43
|
+
|
44
|
+
# yay insecure overrides
|
45
|
+
if @globalallow
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
|
49
|
+
value = nil
|
50
|
+
ORDER.each { |nametype, array|
|
51
|
+
if nametype == :ip
|
52
|
+
value = IPAddr.new(ip)
|
53
|
+
else
|
54
|
+
value = name.split(".").reverse
|
55
|
+
end
|
56
|
+
|
57
|
+
array.each { |type|
|
58
|
+
[[@deny, false], [@allow, true]].each { |ary|
|
59
|
+
hash, retval = ary
|
60
|
+
if hash.include?(type)
|
61
|
+
hash[type].each { |pattern|
|
62
|
+
if match?(nametype, value, pattern)
|
63
|
+
return retval
|
64
|
+
end
|
65
|
+
}
|
66
|
+
end
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
self.info "Defaulting to false for %s" % name
|
72
|
+
# default to false
|
73
|
+
return false
|
74
|
+
end
|
75
|
+
|
76
|
+
def deny(pattern)
|
77
|
+
store(pattern, @deny)
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize
|
81
|
+
@globalallow = nil
|
82
|
+
@allow = Hash.new { |hash, key|
|
83
|
+
hash[key] = []
|
84
|
+
}
|
85
|
+
@deny = Hash.new { |hash, key|
|
86
|
+
hash[key] = []
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def match?(nametype, value, pattern)
|
93
|
+
if value == pattern # simplest shortcut
|
94
|
+
return true
|
95
|
+
end
|
96
|
+
|
97
|
+
case nametype
|
98
|
+
when :ip: matchip?(value, pattern)
|
99
|
+
when :name: matchname?(value, pattern)
|
100
|
+
else
|
101
|
+
raise Puppet::DevError, "Invalid match type %s" % nametype
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def matchip?(value, pattern)
|
106
|
+
# we're just using builtin stuff for this, thankfully
|
107
|
+
if pattern.include?(value)
|
108
|
+
return true
|
109
|
+
else
|
110
|
+
return false
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def matchname?(value, pattern)
|
115
|
+
# yay, horribly inefficient
|
116
|
+
if pattern[-1] != '*' # the pattern has no metachars and is not equal
|
117
|
+
# thus, no match
|
118
|
+
#Puppet.info "%s is not equal with no * in %s" % [value, pattern]
|
119
|
+
return false
|
120
|
+
else
|
121
|
+
# we know the last field of the pattern is '*'
|
122
|
+
# if everything up to that doesn't match, we're definitely false
|
123
|
+
if pattern[0..-2] != value[0..pattern.length-2]
|
124
|
+
#Puppet.notice "subpatterns didn't match; %s vs %s" %
|
125
|
+
# [pattern[0..-2], value[0..pattern.length-2]]
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
|
129
|
+
case value.length <=> pattern.length
|
130
|
+
when -1: # value is shorter than pattern
|
131
|
+
if pattern.length - value.length == 1
|
132
|
+
# only ever allowed when the value is the domain of a
|
133
|
+
# splatted pattern
|
134
|
+
#Puppet.info "allowing splatted domain %s" % [value]
|
135
|
+
return true
|
136
|
+
else
|
137
|
+
return false
|
138
|
+
end
|
139
|
+
when 0: # value is the same length as pattern
|
140
|
+
if pattern[-1] == "*"
|
141
|
+
#Puppet.notice "same length with *"
|
142
|
+
return true
|
143
|
+
else
|
144
|
+
return false
|
145
|
+
end
|
146
|
+
when 1: # value is longer than pattern
|
147
|
+
# at this point we've already verified that everything up to
|
148
|
+
# the '*' in the pattern matches, so we are true
|
149
|
+
return true
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def store(pattern, hash)
|
155
|
+
type, value = type(pattern)
|
156
|
+
|
157
|
+
if type and value
|
158
|
+
# this won't work once we get beyond simple stuff...
|
159
|
+
hash[type] << value
|
160
|
+
else
|
161
|
+
raise AuthStoreError, "Invalid pattern %s" % pattern
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def type(pattern)
|
166
|
+
type = value = nil
|
167
|
+
case pattern
|
168
|
+
when /^(\d+\.){3}\d+$/:
|
169
|
+
type = :ip
|
170
|
+
begin
|
171
|
+
value = IPAddr.new(pattern)
|
172
|
+
rescue ArgumentError => detail
|
173
|
+
raise AuthStoreError, "Invalid IP address pattern %s" % pattern
|
174
|
+
end
|
175
|
+
when /^(\d+\.){3}\d+\/(\d+)$/:
|
176
|
+
mask = Integer($2)
|
177
|
+
if mask < 1 or mask > 32
|
178
|
+
raise AuthStoreError, "Invalid IP mask %s" % mask
|
179
|
+
end
|
180
|
+
type = :ip
|
181
|
+
begin
|
182
|
+
value = IPAddr.new(pattern)
|
183
|
+
rescue ArgumentError => detail
|
184
|
+
raise AuthStoreError, "Invalid IP address pattern %s" % pattern
|
185
|
+
end
|
186
|
+
when /^(\d+\.){1,3}\*$/: # an ip address with a '*' at the end
|
187
|
+
type = :ip
|
188
|
+
match = $1
|
189
|
+
match.sub!(".", '')
|
190
|
+
ary = pattern.split(".")
|
191
|
+
|
192
|
+
mask = case ary.index(match)
|
193
|
+
when 0: 8
|
194
|
+
when 1: 16
|
195
|
+
when 2: 24
|
196
|
+
else
|
197
|
+
raise AuthStoreError, "Invalid IP pattern %s" % pattern
|
198
|
+
end
|
199
|
+
|
200
|
+
ary.pop
|
201
|
+
while ary.length < 4
|
202
|
+
ary.push("0")
|
203
|
+
end
|
204
|
+
|
205
|
+
begin
|
206
|
+
value = IPAddr.new(ary.join(".") + "/" + mask.to_s)
|
207
|
+
rescue ArgumentError => detail
|
208
|
+
raise AuthStoreError, "Invalid IP address pattern %s" % pattern
|
209
|
+
end
|
210
|
+
when /^[\d.]+$/: # necessary so incomplete IP addresses can't look
|
211
|
+
# like hostnames
|
212
|
+
raise AuthStoreError, "Invalid IP address pattern %s" % pattern
|
213
|
+
when /^([a-zA-Z][-\w]*\.)+[-\w]+$/: # a full hostname
|
214
|
+
type = :hostname
|
215
|
+
value = pattern.split(".").reverse
|
216
|
+
when /^\*\.([a-zA-Z][-\w]*\.)+[-\w]+$/: # this doesn't match TLDs
|
217
|
+
type = :domain
|
218
|
+
value = pattern.split(".").reverse
|
219
|
+
else
|
220
|
+
raise AuthStoreError, "Invalid pattern %s" % pattern
|
221
|
+
end
|
222
|
+
|
223
|
+
return [type, value]
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'puppet'
|
3
|
+
require 'puppet/sslcertificates'
|
4
|
+
require 'xmlrpc/server'
|
5
|
+
|
6
|
+
# Much of this was taken from QuickCert:
|
7
|
+
# http://segment7.net/projects/ruby/QuickCert/
|
8
|
+
|
9
|
+
module Puppet
|
10
|
+
class Server
|
11
|
+
class CAError < Puppet::Error; end
|
12
|
+
class CA < Handler
|
13
|
+
attr_reader :ca
|
14
|
+
|
15
|
+
@interface = XMLRPC::Service::Interface.new("puppetca") { |iface|
|
16
|
+
iface.add_method("array getcert(csr)")
|
17
|
+
}
|
18
|
+
|
19
|
+
# FIXME autosign? should probably accept both hostnames and IP addresses
|
20
|
+
def autosign?(hostname)
|
21
|
+
# simple values are easy
|
22
|
+
if @autosign == true or @autosign == false
|
23
|
+
return @autosign
|
24
|
+
end
|
25
|
+
|
26
|
+
# we only otherwise know how to handle files
|
27
|
+
unless @autosign =~ /^\//
|
28
|
+
raise Puppet::Error, "Invalid autosign value %s" %
|
29
|
+
@autosign
|
30
|
+
end
|
31
|
+
|
32
|
+
unless FileTest.exists?(@autosign)
|
33
|
+
Puppet.info "Autosign is enabled but %s is missing" % @autosign
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
auth = Puppet::Server::AuthStore.new
|
37
|
+
File.open(@autosign) { |f|
|
38
|
+
f.each { |line|
|
39
|
+
auth.allow(line.chomp)
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
# for now, just cheat and pass a fake IP address to allowed?
|
44
|
+
return auth.allowed?(hostname, "127.1.1.1")
|
45
|
+
end
|
46
|
+
|
47
|
+
def initialize(hash = {})
|
48
|
+
@autosign = hash[:autosign] || Puppet[:autosign]
|
49
|
+
@ca = Puppet::SSLCertificates::CA.new()
|
50
|
+
end
|
51
|
+
|
52
|
+
# our client sends us a csr, and we either store it for later signing,
|
53
|
+
# or we sign it right away
|
54
|
+
def getcert(csrtext, client = nil, clientip = nil)
|
55
|
+
csr = OpenSSL::X509::Request.new(csrtext)
|
56
|
+
|
57
|
+
# Use the hostname from the CSR, not from the network.
|
58
|
+
subject = csr.subject
|
59
|
+
|
60
|
+
nameary = subject.to_a.find { |ary|
|
61
|
+
ary[0] == "CN"
|
62
|
+
}
|
63
|
+
|
64
|
+
if nameary.nil?
|
65
|
+
Puppet.err(
|
66
|
+
"Invalid certificate request: could not retrieve server name"
|
67
|
+
)
|
68
|
+
return "invalid"
|
69
|
+
end
|
70
|
+
|
71
|
+
hostname = nameary[1]
|
72
|
+
|
73
|
+
unless @ca
|
74
|
+
Puppet.notice "Host %s asked for signing from non-CA master" % hostname
|
75
|
+
return ""
|
76
|
+
end
|
77
|
+
|
78
|
+
# okay, we're now going to store the public key if we don't already
|
79
|
+
# have it
|
80
|
+
public_key = csr.public_key
|
81
|
+
unless FileTest.directory?(Puppet[:publickeydir])
|
82
|
+
Puppet.recmkdir(Puppet[:publickeydir])
|
83
|
+
end
|
84
|
+
pkeyfile = File.join(Puppet[:publickeydir], [hostname, "pem"].join('.'))
|
85
|
+
|
86
|
+
if FileTest.exists?(pkeyfile)
|
87
|
+
currentkey = File.open(pkeyfile) { |k| k.read }
|
88
|
+
unless currentkey == public_key.to_s
|
89
|
+
raise Puppet::Error, "public keys for %s differ" % hostname
|
90
|
+
end
|
91
|
+
else
|
92
|
+
File.open(pkeyfile, "w", 0644) { |f|
|
93
|
+
f.print public_key.to_s
|
94
|
+
}
|
95
|
+
end
|
96
|
+
unless FileTest.directory?(Puppet[:certdir])
|
97
|
+
Puppet.recmkdir(Puppet[:certdir], 0770)
|
98
|
+
end
|
99
|
+
certfile = File.join(Puppet[:certdir], [hostname, "pem"].join("."))
|
100
|
+
|
101
|
+
#puts hostname
|
102
|
+
#puts certfile
|
103
|
+
|
104
|
+
unless FileTest.directory?(Puppet[:csrdir])
|
105
|
+
Puppet.recmkdir(Puppet[:csrdir], 0770)
|
106
|
+
end
|
107
|
+
# first check to see if we already have a signed cert for the host
|
108
|
+
cert, cacert = ca.getclientcert(hostname)
|
109
|
+
if cert and cacert
|
110
|
+
Puppet.info "Retrieving existing certificate for %s" % hostname
|
111
|
+
#Puppet.info "Cert: %s; Cacert: %s" % [cert.class, cacert.class]
|
112
|
+
return [cert.to_pem, cacert.to_pem]
|
113
|
+
elsif @ca
|
114
|
+
if self.autosign?(hostname) or client.nil?
|
115
|
+
if client.nil?
|
116
|
+
Puppet.info "Signing certificate for CA server"
|
117
|
+
end
|
118
|
+
# okay, we don't have a signed cert
|
119
|
+
# if we're a CA and autosign is turned on, then go ahead and sign
|
120
|
+
# the csr and return the results
|
121
|
+
Puppet.info "Signing certificate for %s" % hostname
|
122
|
+
cert, cacert = @ca.sign(csr)
|
123
|
+
Puppet.info "Cert: %s; Cacert: %s" % [cert.class, cacert.class]
|
124
|
+
return [cert.to_pem, cacert.to_pem]
|
125
|
+
else # just write out the csr for later signing
|
126
|
+
if @ca.getclientcsr(hostname)
|
127
|
+
Puppet.info "Not replacing existing request from %s" % hostname
|
128
|
+
else
|
129
|
+
Puppet.info "Storing certificate request for %s" % hostname
|
130
|
+
@ca.storeclientcsr(csr)
|
131
|
+
end
|
132
|
+
return ["", ""]
|
133
|
+
end
|
134
|
+
else
|
135
|
+
raise "huh?"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|