Changes of Revision 6
[-] | Changed | certmaster.spec |
x 1
2 3 %{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 4 5 -Summary: Remote certificate distribution framework 6 -Name: certmaster 7 -Source1: version 8 -Version: %(echo `awk '{ print $1 }' %{SOURCE1}`) 9 -Release: %(echo `awk '{ print $2 }' %{SOURCE1}`)%{?dist} 10 -Source0: %{name}-%{version}.tar.gz 11 -Patch0: %{name}-init.patch 12 -License: GPLv2+ 13 -Group: Applications/System 14 -Requires: python >= 2.3 15 -Requires: pyOpenSSL 16 -BuildRequires: python-devel 17 +Summary: Remote certificate distribution framework 18 +Name: certmaster 19 +Version: 0.28 20 +Release: 1 21 +Source0: %{name}-%{version}.tar.bz2 22 +Patch0: %{name}-init.patch 23 +License: GPLv2+ 24 +Group: Applications/System 25 +Requires: python >= 2.3 26 +%if 0%{?rhel_version} || 0%{?fedora_version} || 0%{?redhat_version} || 0%{?centos_version} 27 +Requires: pyOpenSSL 28 +%endif 29 +BuildRequires: python-devel 30 %if 0%{?suse_version} 31 -BuildRequires: gettext-devel 32 +Requires: python-openssl 33 +BuildRequires: gettext-devel 34 %else 35 %if 0%{?fedora_version} >= 8 36 -BuildRequires: python-setuptools-devel 37 +BuildRequires: python-setuptools-devel 38 %else 39 -BuildRequires: python-setuptools 40 +BuildRequires: python-setuptools 41 %endif 42 -BuildArch: noarch 43 +BuildArch: noarch 44 %endif 45 -BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot 46 -Url: https://fedorahosted.org/certmaster 47 +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot 48 +Url: https://fedorahosted.org/certmaster 49 50 %description 51 52 |
||
Deleted | certmaster-0.24.tar.gz/etc/.minion.conf.swp ^ | |
[+] | Deleted | certmaster-0.24.tar.gz/version ^ |
@@ -1 +0,0 @@ -0.24 1 | ||
[+] | Changed | certmaster-0.28.tar.bz2/PKG-INFO ^ |
@@ -1,10 +1,10 @@ Metadata-Version: 1.0 Name: certmaster -Version: 0.24 +Version: 0.28 Summary: certmaster remote configuration and management api -Home-page: https://hosted.fedoraproject.org/projects/certmaster/ +Home-page: https://fedorahosted.org/certmaster/ Author: Lots -Author-email: certmaster-list@redhat.com +Author-email: func-list@redhat.com License: GPL Description: A small pluggable xml-rpc daemon used by certmaster to implement various web services hooks | ||
[+] | Changed | certmaster-0.28.tar.bz2/README ^ |
@@ -2,7 +2,7 @@ read more at: -https://hosted.fedoraproject.org/projects/certmaster +https://fedorahosted.org/certmaster/ -Source: http://git.fedoraproject.org/git/certmaster.git +Source: http://git.fedorahosted.org/git/?p=certmaster.git;a=summary | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/CommonErrors.py ^ |
@@ -67,4 +67,3 @@ self.value = value def __str__(self): return "%s" %(self.value,) - | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/SSLCommon.py ^ |
@@ -29,13 +29,16 @@ return preverifyOK -def CreateSSLContext(pkey, cert, ca_cert): +def CreateSSLContext(pkey, cert, ca_cert, passwd_callback=None): for f in pkey, cert, ca_cert: if f and not os.access(f, os.R_OK): print "%s does not exist or is not readable." % f os._exit(1) ctx = SSL.Context(SSL.SSLv3_METHOD) # SSLv3 only + if passwd_callback: + ctx.set_passwd_cb = passwd_callback + ctx.use_certificate_file(cert) ctx.use_privatekey_file(pkey) ctx.load_client_ca(ca_cert) @@ -118,4 +121,3 @@ def __init__(self, host='', port=None, ssl_context=None, strict=None, timeout=None): self._setup(self._connection_class(host, port, ssl_context, strict, timeout)) - | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/SSLConnection.py ^ |
@@ -62,7 +62,7 @@ c, a = self.__dict__["conn"].accept() return (SSLConnection(c), a) - def makefile(self, mode, bufsize): + def makefile(self, mode='r', bufsize=-1): """ We need to use socket._fileobject Because SSL.Connection doesn't have a 'dup'. Not exactly sure WHY this is, but @@ -97,6 +97,9 @@ if not con in write: raise socket.timeout((110, "Operation timed out.")) + if hasattr(data, 'tobytes'): + data = data.tobytes() + starttime = time.time() origlen = len(data) sent = -1 | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/certmaster.py ^ |
@@ -16,11 +16,25 @@ # standard modules import SimpleXMLRPCServer +import string import sys +import traceback import os import os.path from OpenSSL import crypto -import sha + +try: + import hashlib +except ImportError: + # Python-2.4.z ... gah! (or even 2.3!) + import sha + class hashlib: + @staticmethod + def new(algo): + if algo == 'sha1': + return sha.new() + raise ValueError, "Bad checksum type" + import glob import socket import exceptions @@ -50,6 +64,10 @@ self.logger = logger.Logger().logger self.audit_logger = logger.AuditLogger() + # if ca_key_file exists and ca_cert_file is missing == minion only setup + if os.path.exists(self.ca_key_file) and not os.path.exists(self.ca_cert_file): + return + try: if not os.path.exists(self.cfg.cadir): os.makedirs(self.cfg.cadir) @@ -59,11 +77,11 @@ 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) @@ -73,7 +91,7 @@ 'wait_for_cert': self.wait_for_cert, } - + def _dispatch(self, method, params): if method == 'trait_names' or method == '_getAttributeNames': return self.handlers.keys() @@ -84,54 +102,54 @@ else: self.logger.info("Unhandled method call for method: %s " % method) raise codes.InvalidMethodException - + def _sanitize_cn(self, commonname): commonname = commonname.replace('/', '') - commonname = commonname.replace('\\', '') + commonname = commonname.replace('\\', '') return commonname - + def wait_for_cert(self, csrbuf, with_triggers=True): """ 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) if with_triggers: - self._run_triggers(requesting_host, '/var/lib/certmaster/triggers/request/pre/*') + self._run_triggers(requesting_host, '/var/lib/certmaster/triggers/request/pre/*') self.logger.info("%s requested signing of cert %s" % (requesting_host,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 self.logger.debug("csrfile: %s certfile: %s" % (csrfile, certfile)) - + if os.path.exists(csrfile): oldfo = open(csrfile) oldcsrbuf = oldfo.read() - oldsha = sha.new() + oldsha = hashlib.new('sha1') oldsha.update(oldcsrbuf) olddig = oldsha.hexdigest() - newsha = sha.new() + newsha = hashlib.new('sha1') newsha.update(csrbuf) newdig = newsha.hexdigest() if not newdig == olddig: self.logger.info("A cert for %s already exists and does not match the requesting cert" % (requesting_host)) # XXX raise a proper fault return False, '', '' - + # look for a cert: # if we have it, then return True, etc, etc @@ -142,21 +160,21 @@ if with_triggers: self._run_triggers(requesting_host,'/var/lib/certmaster/triggers/request/post/*') 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 = 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) self.logger.info("cert for %s was autosigned" % (requesting_host)) if with_triggers: self._run_triggers(None,'/var/lib/certmaster/triggers/request/post/*') 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') @@ -171,7 +189,7 @@ return False, '', '' def get_csrs_waiting(self): - hosts = [] + hosts = [] csrglob = '%s/*.csr' % self.cfg.csrroot csr_list = glob.glob(csrglob) for f in csr_list: @@ -179,7 +197,7 @@ hn = hn[:-4] hosts.append(hn) return hosts - + def remove_this_cert(self, hn, with_triggers=True): """ removes cert for hostname using unlink """ cm = self @@ -199,32 +217,32 @@ os.unlink(fn) if with_triggers: self._run_triggers(hn,'/var/lib/certmaster/triggers/remove/post/*') - + def sign_this_csr(self, csr, with_triggers=True): """returns the path to the signed cert file""" csr_unlink_file = None - if type(csr) is type(''): + 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) + csrreq = crypto.load_certificate_request(crypto.FILETYPE_PEM, csr_buf) except crypto.Error, e: self.logger.info("Unable to sign %s: Bad CSR" % (csr)) raise exceptions.Exception("Bad CSR: %s" % csr) - + else: # assume we got a bare csr req csrreq = csr @@ -248,10 +266,10 @@ if with_triggers: self._run_triggers(requesting_host,'/var/lib/certmaster/triggers/sign/post/*') - + if csr_unlink_file and os.path.exists(csr_unlink_file): os.unlink(csr_unlink_file) - + return certfile # return a list of already signed certs @@ -274,6 +292,13 @@ return signed_certs + def get_peer_certs(self): + """ + Returns a list of all certs under peerroot + """ + myglob = os.path.join(self.cfg.peerroot, '*.%s' % self.cfg.cert_extension) + return glob.glob(myglob) + # return a list of the cert hash string we use to identify systems def get_cert_hashes(self, hostglobs=None): certglob = "%s/*.cert" % (self.cfg.certroot) @@ -286,12 +311,12 @@ for hostglob in globs: certglob = "%s/%s.cert" % (self.cfg.certroot, hostglob) certfiles = certfiles + glob.glob(certglob) - + cert_hashes = [] for certfile in certfiles: cert = certs.retrieve_cert_from_file(certfile) cert_hashes.append("%s-%s" % (cert.get_subject().CN, cert.subject_name_hash())) - + return cert_hashes def _run_triggers(self, ref, globber): @@ -302,7 +327,7 @@ def __init__(self, addr): self.allow_reuse_address = True SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, addr) - + def serve(xmlrpcinstance): @@ -315,7 +340,7 @@ listen_addr = config.listen_addr listen_port = config.listen_port if listen_port == '': - listen_port = CERTMASTER_LISTEN_PORT + listen_port = CERTMASTER_LISTEN_PORT server = CertmasterXMLRPCServer((listen_addr,listen_port)) server.logRequests = 0 # don't print stuff to console server.register_instance(xmlrpcinstance) @@ -323,21 +348,39 @@ xmlrpcinstance.audit_logger.logger.info("certmaster started") server.serve_forever() +def excepthook(exctype, value, tracebackobj): + exctype_blurb = "Exception occured: %s" % exctype + excvalue_blurb = "Exception value: %s" % value + exctb_blurb = "Exception Info:\n%s" % string.join(traceback.format_list(traceback.extract_tb(tracebackobj))) + + print exctype_blurb + print excvalue_blurb + print exctb_blurb + + log = logger.Logger().logger + log.info(exctype_blurb) + log.info(excvalue_blurb) + log.info(exctb_blurb) + def main(argv): - + + sys.excepthook = excepthook cm = CertMaster('/etc/certmaster/certmaster.conf') + if "--version" in sys.argv or "-v" in sys.argv: + print >> sys.stderr, file("/etc/certmaster/version").read().strip() + sys.exit(0) + 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) | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/certs.py ^ |
@@ -11,7 +11,7 @@ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# Copyright (c) 2007 Red Hat, inc +# Copyright (c) 2007 Red Hat, inc #- Written by Seth Vidal skvidal @ fedoraproject.org from OpenSSL import crypto @@ -33,11 +33,11 @@ destfd = os.open(dest, os.O_RDWR|os.O_CREAT, 0600) os.write(destfd, (crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))) os.close(destfd) - + return pkey -def make_csr(pkey, dest=None, cn=None): +def make_csr(pkey, dest=None, cn=None, hostname=None, emailaddr=None): req = crypto.X509Req() req.get_subject() subj = req.get_subject() @@ -48,10 +48,16 @@ subj.OU = def_ou if cn: subj.CN = cn + elif hostname: + subj.CN = hostname + else: + subj.CN = utils.gethostname() + + if emailaddr: + subj.emailAddress = emailaddr else: - subj.CN = utils.get_hostname() - subj.emailAddress = 'root@%s' % subj.CN - + subj.emailAddress = 'root@%s' % subj.CN + req.set_pubkey(pkey) req.sign(pkey, 'md5') if dest: @@ -68,7 +74,7 @@ keypair = crypto.load_privatekey(crypto.FILETYPE_PEM, buf) return keypair - + def retrieve_csr_from_file(csrfile): fo = open(csrfile, 'r') buf = fo.read() @@ -93,13 +99,17 @@ cacert.set_issuer(careq.get_subject()) cacert.set_subject(careq.get_subject()) cacert.set_pubkey(careq.get_pubkey()) - cacert.sign(cakey, 'md5') + cacert.set_version(2) + xt = crypto.X509Extension('basicConstraints',1,'CA:TRUE') + # FIXME - add subjectkeyidentifier and authoritykeyidentifier extensions, too) + cacert.add_extensions((xt,)) + cacert.sign(cakey, 'sha1') if ca_cert_file: destfo = open(ca_cert_file, 'w') destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cacert)) destfo.close() - - + + def _get_serial_number(cadir): serial = '%s/serial.txt' % cadir i = 1 @@ -108,11 +118,11 @@ f = f.replace('\n','') try: i = int(f) - i+=1 + i+=1 except ValueError, e: i = 1 - - _set_serial_number(cadir, i) + + _set_serial_number(cadir, i) return i @@ -121,8 +131,8 @@ f = open(serial, 'w') f.write(str(last) + '\n') f.close() - - + + def create_slave_certificate(csr, cakey, cacert, cadir, slave_cert_file=None): cert = crypto.X509() cert.set_serial_number(_get_serial_number(cadir)) @@ -131,9 +141,28 @@ cert.set_issuer(cacert.get_subject()) cert.set_subject(csr.get_subject()) cert.set_pubkey(csr.get_pubkey()) - cert.sign(cakey, 'md5') + cert.set_version(2) + xt = crypto.X509Extension('basicConstraints', False ,'CA:FALSE') + # FIXME - add subjectkeyidentifier and authoritykeyidentifier extensions, too) + cert.add_extensions((xt,)) + cert.sign(cakey, 'sha1') if slave_cert_file: destfo = open(slave_cert_file, 'w') destfo.write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) destfo.close() return cert + +def check_cert_key_match(cert, key): + if not isinstance(cert, crypto.X509Type): + cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert) + if not isinstance(key, crypto.PKeyType): + key = crypto.load_privatekey(crypto.FILETYPE_PEM, key) + + from OpenSSL import SSL + context = SSL.Context(SSL.SSLv3_METHOD) + try: + context.use_certificate(cert) + context.use_privatekey(key) + return True + except: + return False | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/codes.py ^ |
@@ -25,4 +25,3 @@ pass # FIXME: more sub-exceptions maybe - | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/commonconfig.py ^ |
@@ -26,10 +26,12 @@ csrroot = Option('/var/lib/certmaster/certmaster/csrs') cert_extension = Option('cert') autosign = BoolOption(False) + sync_certs = BoolOption(False) + peering = BoolOption(True) + peerroot = Option('/var/lib/certmaster/peers') class MinionConfig(BaseConfig): log_level = Option('INFO') certmaster = Option('certmaster') certmaster_port = IntOption(51235) cert_dir = Option('/etc/pki/certmaster') - | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/config.py ^ |
@@ -11,7 +11,7 @@ # 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# Copyright 2002 Duke University +# Copyright 2002 Duke University # filched from yum - menno smits wrote this - he rocks @@ -32,13 +32,13 @@ self.value = value def __str__(self): return "%s" %(self.value,) - - + + class Option(object): ''' This class handles a single Yum configuration file option. Create subclasses for each type of supported configuration option. - + Python descriptor foo (__get__ and __set__) is used to make option definition easy and consise. ''' @@ -55,7 +55,7 @@ self._attrname = '__opt%d' % id(self) def __get__(self, obj, objtype): - '''Called when the option is read (via the descriptor protocol). + '''Called when the option is read (via the descriptor protocol). @param obj: The configuration instance to modify. @param objtype: The type of the config instance (not used). @@ -68,7 +68,7 @@ return getattr(obj, self._attrname, None) def __set__(self, obj, value): - '''Called when the option is set (via the descriptor protocol). + '''Called when the option is set (via the descriptor protocol). @param obj: The configuration instance to modify. @param value: The value to set the option to. @@ -85,8 +85,8 @@ setattr(obj, self._attrname, value) def setup(self, obj, name): - '''Initialise the option for a config instance. - This must be called before the option can be set or retrieved. + '''Initialise the option for a config instance. + This must be called before the option can be set or retrieved. @param obj: BaseConfig (or subclass) instance. @param name: Name of the option. @@ -105,7 +105,7 @@ @param s: Raw string value to parse. @return: Validated native value. - + Will raise ValueError if there was a problem parsing the string. Subclasses should override this. ''' @@ -164,7 +164,7 @@ This option handles lists of URLs with validation of the URL scheme. ''' - def __init__(self, default=None, schemes=('http', 'ftp', 'file', 'https'), + def __init__(self, default=None, schemes=('http', 'ftp', 'file', 'https'), allow_none=False): super(UrlOption, self).__init__(default) self.schemes = schemes @@ -208,7 +208,7 @@ # Hold a UrlOption instance to assist with parsing self._urloption = UrlOption(schemes=schemes) - + def parse(self, s): out = [] for url in super(UrlListOption, self).parse(s): @@ -255,7 +255,7 @@ def __init__(self, default=None, allowed=()): super(SelectionOption, self).__init__(default) self._allowed = allowed - + def parse(self, s): if s not in self._allowed: raise ValueError('"%s" is not an allowed value' % s) @@ -276,7 +276,7 @@ The input should be a string containing a (possibly floating point) number followed by an optional single character unit. Valid units are 'k', 'M', 'G'. Case is ignored. - + Valid inputs: 100, 123M, 45.6k, 12.4G, 100K, 786.3, 0 Invalid inputs: -10, -0.1, 45.6L, 123Mb @@ -298,7 +298,7 @@ else: n = s mult = 1 - + try: n = float(n) except ValueError: @@ -313,7 +313,7 @@ class ThrottleOption(BytesOption): def parse(self, s): - """Get a throttle option. + """Get a throttle option. Input may either be a percentage or a "friendly bandwidth value" as accepted by the BytesOption. @@ -382,7 +382,7 @@ # No matching option in this section, try inheriting if parent and option.inherit: value = getattr(parent, name) - + if value is not None: setattr(self, name, value) @@ -397,7 +397,7 @@ optionobj = classmethod(optionobj) def isoption(cls, name): - '''Return True if the given name refers to a defined option + '''Return True if the given name refers to a defined option ''' try: cls.optionobj(name) @@ -438,7 +438,7 @@ raise ValueError("not populated, don't know section") section = self._section - # Updated the ConfigParser with the changed values + # Updated the ConfigParser with the changed values cfgOptions = self.cfg.options(section) for name,value in self.iteritems(): option = self.optionobj(name) | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/logger.py ^ |
@@ -33,12 +33,12 @@ def __init__(self, logfilepath ="/var/log/certmaster/certmaster.log"): config_file = '/etc/certmaster/minion.conf' - self.config = read_config(config_file, CMConfig) + self.config = read_config(config_file, CMConfig) self.loglevel = logging._levelNames[self.config.log_level] self._setup_logging() if self._no_handlers: self._setup_handlers(logfilepath=logfilepath) - + def _setup_logging(self): self.logger = logging.getLogger("certmaster") | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/requester.py ^ |
@@ -15,8 +15,8 @@ import utils -def request_cert(): - # this should be enough, but do we want to allow parameters - # for overriding the server and port from the config file? - # maybe not. -- mpd - utils.create_minion_keys() +def request_cert(hostname=None): + # this should be enough, but do we want to allow parameters + # for overriding the server and port from the config file? + # maybe not. -- mpd + utils.create_minion_keys(hostname) | ||
[+] | Changed | certmaster-0.28.tar.bz2/certmaster/utils.py ^ |
@@ -57,7 +57,7 @@ sys.exit(0) os.chdir("/") os.setsid() - os.umask(0) + os.umask(077) pid = os.fork() os.close(0) @@ -65,10 +65,10 @@ os.close(2) # based on http://code.activestate.com/recipes/278731/ - os.open(REDIRECT_TO, os.O_RDWR) # standard input (0) + os.open(REDIRECT_TO, os.O_RDWR) # standard input (0) - os.dup2(0, 1) # standard output (1) - os.dup2(0, 2) # standard error (2) + os.dup2(0, 1) # standard output (1) + os.dup2(0, 2) # standard error (2) @@ -87,7 +87,7 @@ except: nicetype = etype nicestack = string.join(traceback.format_list(traceback.extract_tb(etb))) - return [ REMOTE_ERROR, nicetype, str(evalue), nicestack ] + return [ REMOTE_ERROR, nicetype, str(evalue), nicestack ] def is_error(result): # FIXME: I believe we can remove this function @@ -104,64 +104,42 @@ "localhost" is a lame hostname to use for a key, so try to get a more meaningful hostname. We do this by connecting to the certmaster and seeing what interface/ip it uses to make that connection, and looking - up the hostname for that. + up the hostname for that. """ # FIXME: this code ignores http proxies (which granted, we don't - # support elsewhere either. It also hardcodes the port number - # for the certmaster for now + # support elsewhere either. hostname = None hostname = socket.gethostname() # print "DEBUG: HOSTNAME TRY1: %s" % hostname try: ip = socket.gethostbyname(hostname) - # print "DEBUG: IP TRY2: %s" % ip except: - # print "DEBUG: ERROR: returning" return hostname if ip != "127.0.0.1": - # print "DEBUG: ERROR: returning 2" return hostname - if talk_to_certmaster: - config_file = '/etc/certmaster/minion.conf' - config = read_config(config_file, MinionConfig) - - server = config.certmaster - port = config.certmaster_port - - try: - s = socket.socket() - s.settimeout(5) - s.connect((server, port)) - (intf, port) = s.getsockname() - remote_hostname = socket.gethostbyaddr(intf)[0] - if remote_hostname != "localhost": - hostname = remote_hostname - # print "DEBUG: HOSTNAME FROM CERTMASTER == %s" % hostname - s.close() - except: - s.close() - raise - - # print "DEBUG: final hostname=%s" % hostname - return hostname - # FIXME: move to requestor module and also create a verbose mode # prints to the screen for usage by /usr/bin/certmaster-request -def create_minion_keys(): +def create_minion_keys(hostname=None): + log = logger.Logger().logger + # FIXME: paths should not be hard coded here, move to settings universally config_file = '/etc/certmaster/minion.conf' config = read_config(config_file, MinionConfig) cert_dir = config.cert_dir master_uri = 'http://%s:%s/' % (config.certmaster, config.certmaster_port) - # print "DEBUG: acquiring hostname" - hn = get_hostname() - # print "DEBUG: hostname = %s\n" % hn + + hn = hostname + if hn is None: + hn = get_hostname() if hn is None: raise codes.CMException("Could not determine a hostname other than localhost") + else: + # use lowercase letters for hostnames + hn = hn.lower() key_file = '%s/%s.pem' % (cert_dir, hn) csr_file = '%s/%s.csr' % (cert_dir, hn) @@ -182,20 +160,20 @@ 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) + csr = certs.make_csr(keypair, dest=csr_file, hostname=hn) except Exception, e: traceback.print_exc() raise codes.CMException, "Could not create local keypair or csr for session" result = False - log = logger.Logger().logger + while not result: try: # print "DEBUG: submitting CSR to certmaster: %s" % master_uri - log.debug("submitting CSR to certmaster %s" % master_uri) + log.debug("submitting CSR: %s to certmaster %s" % (csr_file, master_uri)) result, cert_string, ca_cert_string = submit_csr_to_master(csr_file, master_uri) - except socket.gaierror, e: - raise codes.CMException, "Could not locate certmaster at %s" % master_uri + except socket.error, e: + log.warning("Could not locate certmaster at %s" % master_uri) # logging here would be nice if not result: @@ -207,6 +185,13 @@ if result: # print "DEBUG: recieved certificate from certmaster" log.debug("received certificate from certmaster %s, storing to %s" % (master_uri, cert_file)) + if not keypair: + keypair = certs.retrieve_key_from_file(key_file) + valid = certs.check_cert_key_match(cert_string, keypair) + if not valid: + log.info("certificate does not match key (run certmaster-ca --clean first?)") + sys.stderr.write("certificate does not match key (run certmaster-ca --clean first?)\n") + return cert_fd = os.open(cert_file, os.O_RDWR|os.O_CREAT, 0644) os.write(cert_fd, cert_string) os.close(cert_fd) @@ -259,4 +244,3 @@ # print "DEBUG: waiting for cert" return s.wait_for_cert(csr) - | ||
[+] | Changed | certmaster-0.28.tar.bz2/docs/certmaster-ca.1.gz ^ |
@@ -1,15 +1,7 @@ -.\" Automatically generated by Pod::Man 2.16 (Pod::Simple 3.07) +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) .\" .\" Standard preamble: .\" ======================================================================== -.de Sh \" Subsection heading -.br -.if t .Sp -.ne 5 -.PP -\fB\\$1\fR -.PP -.. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp @@ -53,7 +45,7 @@ .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ @@ -132,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "CERTMASTER-CA 1" -.TH CERTMASTER-CA 1 "2008-09-19" "" "certmaster-ca" +.TH CERTMASTER-CA 1 "2009-11-24" "" "certmaster-ca" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -162,8 +154,9 @@ .SH "ADDITONAL RESOURCES" .IX Header "ADDITONAL RESOURCES" See https://fedorahosted.org/certmaster. It's a Wiki. -.PP +See also https://fedorahosted.org/func See also the manpages for \*(L"certmaster\*(R" and \*(L"certmaster-request\*(R". .SH "AUTHOR" .IX Header "AUTHOR" Various. See https://fedorahosted.org/certmaster +and https://fedorahosted.org/func | ||
[+] | Changed | certmaster-0.28.tar.bz2/docs/certmaster-ca.pod ^ |
@@ -28,11 +28,11 @@ =head1 ADDITONAL RESOURCES See https://fedorahosted.org/certmaster. It's a Wiki. - +See also https://fedorahosted.org/func See also the manpages for "certmaster" and "certmaster-request". =head1 AUTHOR Various. See https://fedorahosted.org/certmaster - +and https://fedorahosted.org/func | ||
[+] | Changed | certmaster-0.28.tar.bz2/docs/certmaster-request.1.gz ^ |
@@ -0,0 +1,159 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "CERTMASTER-REQUEST 1" +.TH CERTMASTER-REQUEST 1 "2010-02-16" "" "certmaster-request" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +certmaster\-request \-\- requests SSL certs from a certmaster +Fedora Unified Network Controller. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +certmaster-request [\-\-server certmaster.example.com] [\-\-port port] +[ \-\-wait infinite/seconds ] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\s-1FIXME:\s0 To be added later once we split this out from func. +.SH "API" +.IX Header "API" +Note: Many applications will want to use the \s-1XMLRPC\s0 \s-1API\s0 (see source) or import +the Python code to request certs. For those that don't want to do that, +this command line tool is available. Explore the other options if they +make more sense for your application. +.SH "EXIT_STATUS" +.IX Header "EXIT_STATUS" +non-zero upon failure. +.SH "ADDITONAL RESOURCES" +.IX Header "ADDITONAL RESOURCES" +See https://fedorahosted.org/certmaster for more information +.PP +See also the manpages for \*(L"certmaster\*(R", and \*(L"certmaster-ca\*(R". +.SH "AUTHOR" +.IX Header "AUTHOR" +Various. See https://fedorahosted.org/func and +https://fedorahosted.org/certmaster | ||
[+] | Changed | certmaster-0.28.tar.bz2/docs/certmaster-request.pod ^ |
@@ -1,6 +1,6 @@ =head1 NAME -certmaster-request -- requests SSL certs from a certmasster +certmaster-request -- requests SSL certs from a certmaster Fedora Unified Network Controller. =head1 SYNOPSIS @@ -31,6 +31,7 @@ =head1 AUTHOR -Various. See https://fedorahosted.org/func +Various. See https://fedorahosted.org/func and +https://fedorahosted.org/certmaster | ||
[+] | Added | certmaster-0.28.tar.bz2/docs/certmaster-sync.1.gz ^ |
@@ -0,0 +1,160 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "CERTMASTER-SYNC 1" +.TH CERTMASTER-SYNC 1 "2010-03-04" "" "certmaster-sync" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +certmaster\-sync \-\- synchronize client certificates with Func. +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +certmaster-sync [\-f|\-\-force] +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +certmaster-sync synchronizes client certificates amongst certmaster clients via Func. It is assumed that the hosts who have requested certificates are reachable via Func for synchronization operations. +.PP +certmaster-sync by default is called as a post-sign and post-clean trigger. In order to enable synchronization you must set \fBsync_certs\fR to \fBTrue\fR, see \fB\s-1CONFIGURATION\s0 \s-1VALUES\s0\fR below. +.PP +The synchronization occurs by querying remote Func methods in \fBcertmastermod\fR on the minion hosts. This will gather information, copy any new certificates, and remove any certificates that have been cleaned. +.SH "OPTIONS" +.IX Header "OPTIONS" +.IP "\-f, \-\-force" 4 +.IX Item "-f, --force" +Override the configuration value for \fBsync_certs\fR in \fI/etc/certmaster/certmaster.conf\fR +.SH "CONFIGURATION VALUES" +.IX Header "CONFIGURATION VALUES" +.IP "sync_certs" 4 +.IX Item "sync_certs" +\&\fBsync_certs\fR determines whether or not the script will actually synchronize or if it will exit with no operation. You can use \-f|\-\-force to override this configuration value. (Default: False) +.SH "ADDITONAL RESOURCES" +.IX Header "ADDITONAL RESOURCES" +See https://fedorahosted.org/certmaster. It's a Wiki. +See also https://fedorahosted.org/func +.SH "AUTHOR" +.IX Header "AUTHOR" +John Eckersberg <jeckersb@redhat.com> | ||
[+] | Added | certmaster-0.28.tar.bz2/docs/certmaster-sync.pod ^ |
@@ -0,0 +1,44 @@ +=head1 NAME + +certmaster-sync -- synchronize client certificates with Func. + +=head1 SYNOPSIS + +certmaster-sync [-f|--force] + +=head1 DESCRIPTION + +certmaster-sync synchronizes client certificates amongst certmaster clients via Func. It is assumed that the hosts who have requested certificates are reachable via Func for synchronization operations. + +certmaster-sync by default is called as a post-sign and post-clean trigger. In order to enable synchronization you must set B<sync_certs> to B<True>, see B<CONFIGURATION VALUES> below. + +The synchronization occurs by querying remote Func methods in B<certmastermod> on the minion hosts. This will gather information, copy any new certificates, and remove any certificates that have been cleaned. + +=head1 OPTIONS + +=over + +=item -f, --force + +Override the configuration value for B<sync_certs> in F</etc/certmaster/certmaster.conf> + +=back + +=head1 CONFIGURATION VALUES + +=over + +=item sync_certs + +B<sync_certs> determines whether or not the script will actually synchronize or if it will exit with no operation. You can use -f|--force to override this configuration value. (Default: False) + +=back + +=head1 ADDITONAL RESOURCES + +See https://fedorahosted.org/certmaster. It's a Wiki. +See also https://fedorahosted.org/func + +=head1 AUTHOR + +John Eckersberg <jeckersb@redhat.com> | ||
[+] | Changed | certmaster-0.28.tar.bz2/docs/certmaster.1.gz ^ |
@@ -1,15 +1,7 @@ -.\" Automatically generated by Pod::Man 2.16 (Pod::Simple 3.07) +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) .\" .\" Standard preamble: .\" ======================================================================== -.de Sh \" Subsection heading -.br -.if t .Sp -.ne 5 -.PP -\fB\\$1\fR -.PP -.. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp @@ -53,7 +45,7 @@ .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for -.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .ie \nF \{\ @@ -132,7 +124,7 @@ .\" ======================================================================== .\" .IX Title "CERTMASTER 1" -.TH CERTMASTER 1 "2008-09-19" "" "certmaster" +.TH CERTMASTER 1 "2009-11-24" "" "certmaster" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -153,8 +145,9 @@ .SH "ADDITONAL RESOURCES" .IX Header "ADDITONAL RESOURCES" See https://fedorahosted.org/certmaster/. It's a Wiki. -.PP +See also See also the manpages for \*(L"certmaster-request\*(R" and \*(L"certmaster-ca\*(R". .SH "AUTHOR" .IX Header "AUTHOR" -Various. See https://hosted.fedoraproject.org/projects/func +Various. See https://fedorahosted.org/certmaster and +https://fedorahosted.org/func | ||
[+] | Changed | certmaster-0.28.tar.bz2/docs/certmaster.pod ^ |
@@ -18,11 +18,12 @@ =head1 ADDITONAL RESOURCES See https://fedorahosted.org/certmaster/. It's a Wiki. - +See also See also the manpages for "certmaster-request" and "certmaster-ca". =head1 AUTHOR -Various. See https://hosted.fedoraproject.org/projects/func +Various. See https://fedorahosted.org/certmaster and +https://fedorahosted.org/func | ||
[+] | Changed | certmaster-0.28.tar.bz2/etc/certmaster.conf ^ |
@@ -9,4 +9,4 @@ certroot = /var/lib/certmaster/certmaster/certs csrroot = /var/lib/certmaster/certmaster/csrs cert_extension = cert - +sync_certs = False | ||
[+] | Added | certmaster-0.28.tar.bz2/etc/version ^ |
@@ -0,0 +1,5 @@ +version: 0.28 +release: 1 +source build date: +git commit: 224352b0208b651c951d386bdbf9293c3365d531 +git date: Thu Apr 7 13:39:36 2011 -0400 | ||
[+] | Added | certmaster-0.28.tar.bz2/etc/version~ ^ |
@@ -0,0 +1,5 @@ +version: 0.27.1 +release: 1 +source build date: +git commit: f33325800add0c2ca5886cc78c05e007a5be5e8e +git date: Wed Jun 10 13:40:44 2009 -0400 | ||
[+] | Changed | certmaster-0.28.tar.bz2/init-scripts/certmaster ^ |
@@ -39,6 +39,7 @@ RVAL=3 echo "certmaster is not running" fi + return $RVAL } if [ -f /lib/lsb/init-functions ]; then | ||
[+] | Changed | certmaster-0.28.tar.bz2/scripts/certmaster-ca ^ |
@@ -7,6 +7,7 @@ import sys import glob +import optparse import os import certmaster @@ -15,15 +16,17 @@ -from optparse import OptionParser def errorprint(stuff): print >> sys.stderr, stuff +class CertmasterCAOptionParser(optparse.OptionParser): + def get_version(self): + return file("/etc/func/version").read().strip() def parseargs(args): usage = 'certmaster-ca <option> [args]' - parser = OptionParser(usage=usage) + parser = CertmasterCAOptionParser(usage=usage,version=True) parser.add_option('-l', '--list', default=False, action="store_true", help='list signing requests remaining') @@ -60,7 +63,7 @@ if opts.list: hns = cm.get_csrs_waiting() if hns: - for hn in cm.get_csrs_waiting(): + for hn in sorted(hns): print hn else: print 'No certificates to sign' @@ -101,7 +104,7 @@ signed_certs = cm.get_signed_certs(args) - for i in signed_certs: + for i in sorted(signed_certs): print i return 0 @@ -113,7 +116,7 @@ cert_hashes = cm.get_cert_hashes(hostglobs) - for i in cert_hashes: + for i in sorted(cert_hashes): print i return 0 | ||
[+] | Added | certmaster-0.28.tar.bz2/scripts/certmaster-sync ^ |
@@ -0,0 +1,151 @@ +#!/usr/bin/python -tt + +# Syncs the valid CA-signed certificates from certmaster to all known +# hosts via func. To be called during the post-sign hook to copy new +# certificates and from the post-clean hook in order to purge stale +# certificates. Requires 'sync_certs' to be set in certmaster.conf. + +import os +import sys +try: + import hashlib +except ImportError: + # Python-2.4.z ... gah! (or even 2.3!) + import sha + class hashlib: + @staticmethod + def new(algo): + if algo == 'sha1': + return sha.new() + raise ValueError, "Bad checksum type" + + +import xmlrpclib +from glob import glob +from time import sleep +from certmaster import certmaster as certmaster +from func.overlord.client import Client +from func.CommonErrors import Func_Client_Exception +import func.jobthing as jobthing + +def syncable(cert_list): + """ + Calls out to known hosts to find out who is configured for + peering. Returns a list of hostnames who support peering. + """ + try: + fc = Client('*', async=True, nforks=len(cert_list)) + except Func_Client_Exception: + # we are either: + # - signing the first minion + # - cleaning the only minion + # so there's nothing to hit. This shouldn't happen + # when we get called from the 'post-fetch' trigger + # (future work) + return None + + # Only wait for a few seconds. Assume anything that doesn't get + # back by then is a lost cause. Don't want this trigger to spin + # too long. + ticks = 0 + return_code = jobthing.JOB_ID_RUNNING + results = None + job_id = fc.certmastermod.peering_enabled() + while return_code != jobthing.JOB_ID_FINISHED and ticks < 3: + sleep(1) + (return_code, results) = fc.job_status(job_id) + ticks += 1 + + hosts = [] + for host, result in results.iteritems(): + if result == True: + hosts.append(host) + return hosts + +def remote_peers(hosts): + """ + Calls out to hosts to collect peer information + """ + fc = Client(';'.join(hosts)) + return fc.certmastermod.known_peers() + +def local_certs(): + """ + Returns (hostname, sha1) hash of local certs + """ + globby = '*.%s' % cm.cfg.cert_extension + globby = os.path.join(cm.cfg.certroot, globby) + files = glob(globby) + results = [] + for f in files: + hostname = os.path.basename(f).replace('.' + cm.cfg.cert_extension, '') + digest = checksum(f) + results.append([hostname, digest]) + return results + +def checksum(f): + thissum = hashlib.new('sha1') + if os.path.exists(f): + fo = open(f, 'r') + data = fo.read() + fo.close() + thissum.update(data) + + return thissum.hexdigest() + +def remove_stale_certs(local, remote): + """ + For each cert on each remote host, make sure it exists locally. + If not then it has been cleaned locally and needs unlinked + remotely. + """ + local = [foo[0] for foo in local] # don't care about checksums + for host, peers in remote.iteritems(): + fc = Client(host) + die = [] + for peer in peers: + if peer[0] not in local: + die.append(peer[0]) + if die != []: + fc.certmastermod.remove_peer_certs(die) + +def copy_updated_certs(local, remote): + """ + For each local cert, make sure it exists on the remote with the + correct hash. If not, copy it over! + """ + for host, peers in remote.iteritems(): + fc = Client(host) + for cert in local: + if cert not in peers: + cert_name = '%s.%s' % (cert[0], cm.cfg.cert_extension) + full_path = os.path.join(cm.cfg.certroot, cert_name) + fd = open(full_path) + certblob = fd.read() + fd.close() + fc.certmastermod.copy_peer_cert(cert[0], xmlrpclib.Binary(certblob)) + +def main(): + forced = False + try: + if sys.argv[1] in ['-f', '--force']: + forced = True + except IndexError: + pass + + if not cm.cfg.sync_certs and not forced: + sys.exit(0) + + certs = glob(os.path.join(cm.cfg.certroot, + '*.%s' % cm.cfg.cert_extension)) + hosts = syncable(certs) + if not hosts: + return 0 + remote = remote_peers(hosts) + local = local_certs() + remove_stale_certs(local, remote) + copy_updated_certs(local, remote) + +if __name__ == "__main__": + cm = certmaster.CertMaster() + main() | ||
[+] | Changed | certmaster-0.28.tar.bz2/setup.py ^ |
@@ -4,7 +4,7 @@ #from setuptools import setup,find_packages NAME = "certmaster" -VERSION = open("version", "r+").read().split()[0] +VERSION = "0.28" SHORT_DESC = "%s remote configuration and management api" % NAME LONG_DESC = """ A small pluggable xml-rpc daemon used by %s to implement various web services hooks @@ -18,6 +18,9 @@ initpath = "/etc/init.d/" logpath = "/var/log/%s/" % NAME certdir = "/var/lib/%s/" % NAME + certmaster_cert_dir = "/var/lib/%s/%s" % (NAME,NAME) + certmaster_cert_certs_dir = "/var/lib/%s/%s/certs" % (NAME, NAME) + certmaster_cert_csrs_dir = "/var/lib/%s/%s/csrs" % (NAME, NAME) trigpath = "/var/lib/%s/triggers/"% NAME pkipath = "/etc/pki/%s" % NAME rotpath = "/etc/logrotate.d" @@ -26,12 +29,12 @@ name="%s" % NAME, version = VERSION, author = "Lots", - author_email = "certmaster-list@redhat.com", - url = "https://hosted.fedoraproject.org/projects/certmaster/", + author_email = "func-list@redhat.com", + url = "https://fedorahosted.org/certmaster/", license = "GPL", scripts = [ "scripts/certmaster", "scripts/certmaster-ca", - "scripts/certmaster-request", + "scripts/certmaster-request", "scripts/certmaster-sync", ], # package_data = { '' : ['*.*'] }, package_dir = {"%s" % NAME: "%s" % NAME @@ -39,17 +42,23 @@ packages = ["%s" % NAME, ], data_files = [(initpath, ["init-scripts/certmaster"]), - (etcpath, ["etc/minion.conf"]), - (etcpath, ["etc/certmaster.conf"]), + (etcpath, ["etc/minion.conf", + "etc/certmaster.conf", + "etc/version"]), (manpath, ["docs/certmaster.1.gz"]), (manpath, ["docs/certmaster-request.1.gz"]), (manpath, ["docs/certmaster-ca.1.gz"]), + (manpath, ["docs/certmaster-sync.1.gz"]), (rotpath, ['etc/certmaster_rotate']), (logpath, []), (certdir, []), + (certmaster_cert_dir, []), + (certmaster_cert_certs_dir, []), + (certmaster_cert_csrs_dir, []), (etcpath, []), (pkipath, []), (aclpath, []), + ("%s/peers" % certdir, []), ("%s/sign/pre/" % trigpath, []), ("%s/sign/post/" % trigpath, []), ("%s/remove/pre/" % trigpath, []), | ||
[+] | Changed | version ^ |
@@ -1 +1 @@ -0.24 1 +0.28.1 |