summaryrefslogtreecommitdiffstats
path: root/func
diff options
context:
space:
mode:
Diffstat (limited to 'func')
-rwxr-xr-xfunc/certmaster.py247
-rw-r--r--func/commonconfig.py25
-rwxr-xr-xfunc/minion/server.py20
-rwxr-xr-xfunc/minion/utils.py72
-rwxr-xr-xfunc/overlord/client.py14
-rw-r--r--func/overlord/command.py2
6 files changed, 38 insertions, 342 deletions
diff --git a/func/certmaster.py b/func/certmaster.py
deleted file mode 100755
index fe5dcbc..0000000
--- a/func/certmaster.py
+++ /dev/null
@@ -1,247 +0,0 @@
-# FIXME: more intelligent fault raises
-
-"""
-cert master listener
-
-Copyright 2007, Red Hat, Inc
-see AUTHORS
-
-This software may be freely redistributed under the terms of the GNU
-general public license.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-"""
-
-# standard modules
-import SimpleXMLRPCServer
-import sys
-import os
-import os.path
-from OpenSSL import crypto
-import sha
-import glob
-import socket
-import exceptions
-
-#from func.server import codes
-import certs
-import codes
-import utils
-from config import read_config
-from commonconfig import CMConfig
-
-CERTMASTER_LISTEN_PORT = 51235
-CERTMASTER_CONFIG = "/etc/func/certmaster.conf"
-
-class CertMaster(object):
- def __init__(self, conf_file=CERTMASTER_CONFIG):
- self.cfg = read_config(conf_file, CMConfig)
-
- usename = utils.get_hostname()
-
- mycn = '%s-CA-KEY' % usename
- self.ca_key_file = '%s/funcmaster.key' % self.cfg.cadir
- self.ca_cert_file = '%s/funcmaster.crt' % self.cfg.cadir
- try:
- if not os.path.exists(self.cfg.cadir):
- os.makedirs(self.cfg.cadir)
- if not os.path.exists(self.ca_key_file) and not os.path.exists(self.ca_cert_file):
- certs.create_ca(CN=mycn, ca_key_file=self.ca_key_file, ca_cert_file=self.ca_cert_file)
- except (IOError, OSError), e:
- print 'Cannot make certmaster certificate authority keys/certs, aborting: %s' % e
- sys.exit(1)
-
-
- # open up the cakey and cacert so we have them available
- self.cakey = certs.retrieve_key_from_file(self.ca_key_file)
- self.cacert = certs.retrieve_cert_from_file(self.ca_cert_file)
-
- for dirpath in [self.cfg.cadir, self.cfg.certroot, self.cfg.csrroot]:
- if not os.path.exists(dirpath):
- os.makedirs(dirpath)
-
- # setup handlers
- self.handlers = {
- 'wait_for_cert': self.wait_for_cert,
- }
-
- def _dispatch(self, method, params):
- if method == 'trait_names' or method == '_getAttributeNames':
- return self.handlers.keys()
-
- if method in self.handlers.keys():
- return self.handlers[method](*params)
- else:
- raise codes.InvalidMethodException
-
- def _sanitize_cn(self, commonname):
- commonname = commonname.replace('/', '')
- commonname = commonname.replace('\\', '')
- return commonname
-
- def wait_for_cert(self, csrbuf):
- """
- takes csr as a string
- returns True, caller_cert, ca_cert
- returns False, '', ''
- """
-
- try:
- csrreq = crypto.load_certificate_request(crypto.FILETYPE_PEM, csrbuf)
- except crypto.Error, e:
- #XXX need to raise a fault here and document it - but false is just as good
- return False, '', ''
-
- requesting_host = self._sanitize_cn(csrreq.get_subject().CN)
-
- # get rid of dodgy characters in the filename we're about to make
-
- certfile = '%s/%s.cert' % (self.cfg.certroot, requesting_host)
- csrfile = '%s/%s.csr' % (self.cfg.csrroot, requesting_host)
-
- # check for old csr on disk
- # if we have it - compare the two - if they are not the same - raise a fault
- if os.path.exists(csrfile):
- oldfo = open(csrfile)
- oldcsrbuf = oldfo.read()
- oldsha = sha.new()
- oldsha.update(oldcsrbuf)
- olddig = oldsha.hexdigest()
- newsha = sha.new()
- newsha.update(csrbuf)
- newdig = newsha.hexdigest()
- if not newdig == olddig:
- # XXX raise a proper fault
- return False, '', ''
-
- # look for a cert:
- # if we have it, then return True, etc, etc
- if os.path.exists(certfile):
- slavecert = certs.retrieve_cert_from_file(certfile)
- cert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, slavecert)
- cacert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, self.cacert)
- return True, cert_buf, cacert_buf
-
- # if we don't have a cert then:
- # if we're autosign then sign it, write out the cert and return True, etc, etc
- # else write out the csr
-
- if self.cfg.autosign:
- cert_fn = self.sign_this_csr(csrreq)
- cert = certs.retrieve_cert_from_file(cert_fn)
- cert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
- cacert_buf = crypto.dump_certificate(crypto.FILETYPE_PEM, self.cacert)
- return True, cert_buf, cacert_buf
-
- else:
- # write the csr out to a file to be dealt with by the admin
- destfo = open(csrfile, 'w')
- destfo.write(crypto.dump_certificate_request(crypto.FILETYPE_PEM, csrreq))
- destfo.close()
- del destfo
- return False, '', ''
-
- return False, '', ''
-
- def get_csrs_waiting(self):
- hosts = []
- csrglob = '%s/*.csr' % self.cfg.csrroot
- csr_list = glob.glob(csrglob)
- for f in csr_list:
- hn = os.path.basename(f)
- hn = hn[:-4]
- hosts.append(hn)
- return hosts
-
- def remove_this_cert(self, hn):
- """ removes cert for hostname using unlink """
- cm = self
- csrglob = '%s/%s.csr' % (cm.cfg.csrroot, hn)
- csrs = glob.glob(csrglob)
- certglob = '%s/%s.cert' % (cm.cfg.certroot, hn)
- certs = glob.glob(certglob)
- if not csrs and not certs:
- # FIXME: should be an exception?
- print 'No match for %s to clean up' % hn
- return
- for fn in csrs + certs:
- print 'Cleaning out %s for host matching %s' % (fn, hn)
- os.unlink(fn)
-
- def sign_this_csr(self, csr):
- """returns the path to the signed cert file"""
- csr_unlink_file = None
-
- if type(csr) is type(''):
- if csr.startswith('/') and os.path.exists(csr): # we have a full path to the file
- csrfo = open(csr)
- csr_buf = csrfo.read()
- csr_unlink_file = csr
-
- elif os.path.exists('%s/%s' % (self.cfg.csrroot, csr)): # we have a partial path?
- csrfo = open('%s/%s' % (self.cfg.csrroot, csr))
- csr_buf = csrfo.read()
- csr_unlink_file = '%s/%s' % (self.cfg.csrroot, csr)
-
- # we have a string of some kind
- else:
- csr_buf = csr
-
- try:
- csrreq = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr_buf)
- except crypto.Error, e:
- raise exceptions.Exception("Bad CSR: %s" % csr)
-
- else: # assume we got a bare csr req
- csrreq = csr
- requesting_host = self._sanitize_cn(csrreq.get_subject().CN)
-
- certfile = '%s/%s.cert' % (self.cfg.certroot, requesting_host)
- thiscert = certs.create_slave_certificate(csrreq, self.cakey, self.cacert, self.cfg.cadir)
- destfo = open(certfile, 'w')
- destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, thiscert))
- destfo.close()
- del destfo
- if csr_unlink_file and os.path.exists(csr_unlink_file):
- os.unlink(csr_unlink_file)
-
- return certfile
-
-
-class CertmasterXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
- def __init__(self, args):
- self.allow_reuse_address = True
- SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, args)
-
-
-def serve(xmlrpcinstance):
-
- """
- Code for starting the XMLRPC service.
- """
-
- server = CertmasterXMLRPCServer((xmlrpcinstance.cfg.listen_addr, CERTMASTER_LISTEN_PORT))
- server.logRequests = 0 # don't print stuff to console
- server.register_instance(xmlrpcinstance)
- server.serve_forever()
-
-
-def main(argv):
-
- cm = CertMaster('/etc/func/certmaster.conf')
-
- if "daemon" in argv or "--daemon" in argv:
- utils.daemonize("/var/run/certmaster.pid")
- else:
- print "serving...\n"
-
-
- # just let exceptions bubble up for now
- serve(cm)
-
-
-if __name__ == "__main__":
- #textdomain(I18N_DOMAIN)
- main(sys.argv)
diff --git a/func/commonconfig.py b/func/commonconfig.py
index 292eb45..66f4cfc 100644
--- a/func/commonconfig.py
+++ b/func/commonconfig.py
@@ -1,15 +1,22 @@
-from config import BaseConfig, BoolOption, Option
+#!/usr/bin/python
+"""
+func
+
+Copyright 2007, Red Hat, Inc
+see AUTHORS
+
+This software may be freely redistributed under the terms of the GNU
+general public license.
-class CMConfig(BaseConfig):
- listen_addr = Option('')
- cadir = Option('/etc/pki/func/ca')
- certroot = Option('/var/lib/certmaster/certmaster/certs')
- csrroot = Option('/var/lib/certmaster/certmaster/csrs')
- autosign = BoolOption(False)
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+
+from config import BaseConfig, BoolOption, Option
class FuncdConfig(BaseConfig):
log_level = Option('INFO')
- certmaster = Option('certmaster')
- cert_dir = Option('/etc/pki/func')
acl_dir = Option('/etc/func/minion-acl.d')
diff --git a/func/minion/server.py b/func/minion/server.py
index 2fa175a..c511598 100755
--- a/func/minion/server.py
+++ b/func/minion/server.py
@@ -25,17 +25,20 @@ I18N_DOMAIN = "func"
from func.config import read_config
from func.commonconfig import FuncdConfig
+from certmaster.commonconfig import CMConfig
from func import logger
from func import certs
import func.jobthing as jobthing
-import utils
# our modules
import AuthedXMLRPCServer
import codes
import module_loader
import func.utils as futils
+import func.minion.utils as fmutils
+from certmaster import utils
+from certmaster import requester
class XmlRpcInterface(object):
@@ -46,8 +49,11 @@ class XmlRpcInterface(object):
Constructor.
"""
- config_file = '/etc/func/minion.conf'
+ cm_config_file = '/etc/certmaster/minion.conf'
+ self.cm_config = read_config(cm_config_file, CMConfig)
+ config_file = "/etc/func/minion.conf"
self.config = read_config(config_file, FuncdConfig)
+
self.logger = logger.Logger().logger
self.audit_logger = logger.AuditLogger()
self.__setup_handlers()
@@ -172,9 +178,9 @@ class FuncSSLXMLRPCServer(AuthedXMLRPCServer.AuthedSSLXMLRPCServer,
XmlRpcInterface.__init__(self)
hn = utils.get_hostname()
- self.key = "%s/%s.pem" % (self.config.cert_dir, hn)
- self.cert = "%s/%s.cert" % (self.config.cert_dir, hn)
- self.ca = "%s/ca.cert" % self.config.cert_dir
+ self.key = "%s/%s.pem" % (self.cm_config.cert_dir, hn)
+ self.cert = "%s/%s.cert" % (self.cm_config.cert_dir, hn)
+ self.ca = "%s/ca.cert" % self.cm_config.cert_dir
self._our_ca = certs.retrieve_cert_from_file(self.ca)
@@ -234,7 +240,7 @@ class FuncSSLXMLRPCServer(AuthedXMLRPCServer.AuthedSSLXMLRPCServer,
return peer_cert.get_subject().CN
def _check_acl(self, cert, ip, method, params):
- acls = utils.get_acls_from_config(acldir=self.config.acl_dir)
+ acls = fmutils.get_acls_from_config(acldir=self.config.acl_dir)
# certmaster always gets to run things
ca_cn = self._our_ca.get_subject().CN
@@ -271,7 +277,7 @@ def main(argv):
print "serving...\n"
try:
- utils.create_minion_keys()
+ requester.request_cert()
serve()
except codes.FuncException, e:
print >> sys.stderr, 'error: %s' % e
diff --git a/func/minion/utils.py b/func/minion/utils.py
index ea8854c..1133866 100755
--- a/func/minion/utils.py
+++ b/func/minion/utils.py
@@ -65,78 +65,6 @@ def get_hostname():
-def create_minion_keys():
- config_file = '/etc/func/minion.conf'
- config = read_config(config_file, FuncdConfig)
- cert_dir = config.cert_dir
- master_uri = 'http://%s:51235/' % config.certmaster
- hn = get_hostname()
-
- if hn is None:
- raise codes.FuncException("Could not determine a hostname other than localhost")
-
- key_file = '%s/%s.pem' % (cert_dir, hn)
- csr_file = '%s/%s.csr' % (cert_dir, hn)
- cert_file = '%s/%s.cert' % (cert_dir, hn)
- ca_cert_file = '%s/ca.cert' % cert_dir
-
-
- if os.path.exists(cert_file) and os.path.exists(ca_cert_file):
- return
-
- keypair = None
- try:
- if not os.path.exists(cert_dir):
- os.makedirs(cert_dir)
- if not os.path.exists(key_file):
- keypair = certs.make_keypair(dest=key_file)
- if not os.path.exists(csr_file):
- if not keypair:
- keypair = certs.retrieve_key_from_file(key_file)
- csr = certs.make_csr(keypair, dest=csr_file)
- except Exception, e:
- traceback.print_exc()
- raise codes.FuncException, "Could not create local keypair or csr for minion funcd session"
-
- result = False
- log = logger.Logger().logger
- while not result:
- try:
- log.debug("submitting CSR to certmaster %s" % master_uri)
- result, cert_string, ca_cert_string = submit_csr_to_master(csr_file, master_uri)
- except socket.gaierror, e:
- raise codes.FuncException, "Could not locate certmaster at %s" % master_uri
-
- # logging here would be nice
- if not result:
- log.warning("no response from certmaster %s, sleeping 10 seconds" % master_uri)
- time.sleep(10)
-
-
- if result:
- log.debug("received certificate from certmaster %s, storing" % master_uri)
- cert_fd = os.open(cert_file, os.O_RDWR|os.O_CREAT, 0644)
- os.write(cert_fd, cert_string)
- os.close(cert_fd)
-
- ca_cert_fd = os.open(ca_cert_file, os.O_RDWR|os.O_CREAT, 0644)
- os.write(ca_cert_fd, ca_cert_string)
- os.close(ca_cert_fd)
-
-def submit_csr_to_master(csr_file, master_uri):
- """"
- gets us our cert back from the certmaster.wait_for_cert() method
- takes csr_file as path location and master_uri
- returns Bool, str(cert), str(ca_cert)
- """
-
- fo = open(csr_file)
- csr = fo.read()
- s = xmlrpclib.ServerProxy(master_uri)
-
- return s.wait_for_cert(csr)
-
-
# this is kind of handy, so keep it around for now
# but we really need to fix out server side logging and error
# reporting so we don't need it
diff --git a/func/overlord/client.py b/func/overlord/client.py
index fdcf875..26b1cca 100755
--- a/func/overlord/client.py
+++ b/func/overlord/client.py
@@ -17,7 +17,7 @@ import sys
import glob
import os
-from func.commonconfig import CMConfig
+from certmaster.commonconfig import CMConfig
from func.config import read_config, CONFIG_FILE
import sslclient
@@ -189,13 +189,15 @@ class Client(object):
# certmaster key, cert, ca
# funcd key, cert, ca
# raise FuncClientError
- ol_key = '%s/funcmaster.key' % self.config.cadir
- ol_crt = '%s/funcmaster.crt' % self.config.cadir
+ ol_key = '%s/certmaster.key' % self.config.cadir
+ ol_crt = '%s/certmaster.crt' % self.config.cadir
myname = utils.get_hostname()
+
+ # FIXME: should be config -akl?
# maybe /etc/pki/func is a variable somewhere?
- fd_key = '/etc/pki/func/%s.pem' % myname
- fd_crt = '/etc/pki/func/%s.cert' % myname
- self.ca = '%s/funcmaster.crt' % self.config.cadir
+ fd_key = '/etc/pki/certmaster/%s.pem' % myname
+ fd_crt = '/etc/pki/certmaster/%s.cert' % myname
+ self.ca = '%s/certmaster.crt' % self.config.cadir
if client_key and client_cert and ca:
if (os.access(client_key, os.R_OK) and os.access(client_cert, os.R_OK)
and os.access(ca, os.R_OK)):
diff --git a/func/overlord/command.py b/func/overlord/command.py
index 7fb7de4..7cf3623 100644
--- a/func/overlord/command.py
+++ b/func/overlord/command.py
@@ -15,7 +15,7 @@ import optparse
import sys
from func.config import read_config, CONFIG_FILE
-from func.commonconfig import CMConfig
+from certmaster.commonconfig import CMConfig
class CommandHelpFormatter(optparse.IndentedHelpFormatter):
"""