From d6dfdb25c4e8be31d77ba8db7c3499e3f10e0c4b Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Mon, 25 Feb 2008 16:48:47 -0500 Subject: Pushing changes as part of certmaster split --- certmaster/codes.py | 2 + certmaster/commonconfig.py | 6 +- certmaster/logger.py | 6 +- certmaster/utils.py | 142 ++++++++++++++++++++++++++++++++++++++++++--- certs/master-keys.py | 44 -------------- certs/slave-keys.py | 92 ----------------------------- scripts/certmaster-request | 23 ++++++-- 7 files changed, 158 insertions(+), 157 deletions(-) delete mode 100644 certs/master-keys.py delete mode 100644 certs/slave-keys.py diff --git a/certmaster/codes.py b/certmaster/codes.py index a73c700..ace800c 100755 --- a/certmaster/codes.py +++ b/certmaster/codes.py @@ -18,6 +18,8 @@ import exceptions class CertMasterException(exceptions.Exception): pass +class CMException(CertMasterException): + pass class InvalidMethodException(CertMasterException): pass diff --git a/certmaster/commonconfig.py b/certmaster/commonconfig.py index baf6a88..f4e96be 100644 --- a/certmaster/commonconfig.py +++ b/certmaster/commonconfig.py @@ -1,15 +1,15 @@ from config import BaseConfig, BoolOption, IntOption, Option class CMConfig(BaseConfig): + log_level = Option('INFO') listen_addr = Option('') cadir = Option('/etc/pki/certmaster/ca') certroot = Option('/var/lib/certmaster/certmaster/certs') csrroot = Option('/var/lib/certmaster/certmaster/csrs') autosign = BoolOption(False) - -class FuncdConfig(BaseConfig): +class MinionConfig(BaseConfig): log_level = Option('INFO') certmaster = Option('certmaster') cert_dir = Option('/etc/pki/certmaster') - acl_dir = Option('/etc/certmaster/minion-acl.d') + # acl_dir = Option('/etc/certmaster/minion-acl.d') diff --git a/certmaster/logger.py b/certmaster/logger.py index bd35652..b2d14ed 100755 --- a/certmaster/logger.py +++ b/certmaster/logger.py @@ -14,8 +14,8 @@ import logging -from certmaster.config import read_config -from certmaster.commonconfig import CertmasterConfig +from config import read_config +from commonconfig import CMConfig # from the comments in http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531 @@ -33,7 +33,7 @@ class Logger(Singleton): def __init__(self, logfilepath ="/var/log/certmaster/certmaster.log"): config_file = '/etc/certmaster/minion.conf' - self.config = read_config(config_file, CertMasterConfig) + self.config = read_config(config_file, CMConfig) self.loglevel = logging._levelNames[self.config.log_level] self._setup_logging() if self._no_handlers: diff --git a/certmaster/utils.py b/certmaster/utils.py index 481faf5..7927c55 100755 --- a/certmaster/utils.py +++ b/certmaster/utils.py @@ -16,9 +16,22 @@ import sys import traceback import xmlrpclib import socket +import time +import glob +import codes +import certs +from config import read_config +from commonconfig import MinionConfig +import logger + +# FIXME: module needs better pydoc + + +# FIXME: can remove this constant? REMOTE_ERROR = "REMOTE_ERROR" + def trace_me(): x = traceback.extract_stack() bar = string.join(traceback.format_list(x)) @@ -44,6 +57,7 @@ def daemonize(pidfile=None): sys.exit(0) def nice_exception(etype, evalue, etb): + # FIXME: I believe we can remove this function etype = str(etype) lefti = etype.index("'") + 1 righti = etype.rindex("'") @@ -51,16 +65,8 @@ def nice_exception(etype, evalue, etb): nicestack = string.join(traceback.format_list(traceback.extract_tb(etb))) return [ REMOTE_ERROR, nicetype, str(evalue), nicestack ] -def get_hostname(): - fqdn = socket.getfqdn() - host = socket.gethostname() - if fqdn.find(host) != -1: - return fqdn - else: - return host - - def is_error(result): + # FIXME: I believe we can remove this function if type(result) != list: return False if len(result) == 0: @@ -69,5 +75,123 @@ def is_error(result): return True return False +def get_hostname(): + """ + "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. + """ + # 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 + hostname = None + hostname = socket.gethostname() + try: + ip = socket.gethostbyname(hostname) + except: + return hostname + if ip != "127.0.0.1": + return hostname + + + config_file = '/etc/certmaster/minion.conf' + config = read_config(config_file, MinionConfig) + + server = config.certmaster + port = 51235 + + try: + s = socket.socket() + s.settimeout(5) + s.connect((server, port)) + (intf, port) = s.getsockname() + hostname = socket.gethostbyaddr(intf)[0] + s.close() + except: + s.close() + raise + + return hostname + + + +def create_minion_keys(): + # 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:51235/' % config.certmaster + print "DEBUG: acquiring hostname" + hn = get_hostname() + print "DEBUG: hostname = %s\n" % hn + + if hn is None: + raise codes.CMException("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): + print "DEBUG: err, no 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 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) + 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: + print "DEBUG: no response from certmaster, sleeping 10 seconds" + log.warning("no response from certmaster %s, sleeping 10 seconds" % master_uri) + time.sleep(10) + + + if result: + print "DEBUG: recieved certificate from certmaster" + 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) + print "DEBUG: waiting for cert" + return s.wait_for_cert(csr) diff --git a/certs/master-keys.py b/certs/master-keys.py deleted file mode 100644 index 0ea24a8..0000000 --- a/certs/master-keys.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/python -tt -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Library General Public License for more details. -# -# 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-2008 Red Hat, inc -#- Written by Seth Vidal skvidal @ fedoraproject.org - -import sys -import os -import os.path -import certmaster.certs - - -cadir = '/etc/pki/certmaster/ca' -ca_key_file = '%s/certmaster.key' % cadir -ca_cert_file = '%s/certmaster.crt' % cadir - - -def main(): - keypair = None - try: - if not os.path.exists(cadir): - os.makedirs(cadir) - if not os.path.exists(ca_key_file): - func.certs.create_ca(ca_key_file=ca_key_file, ca_cert_file=ca_cert_file) - except: - return 1 - - return 0 - - -if __name__ == "__main__": - sys.exit(main()) - diff --git a/certs/slave-keys.py b/certs/slave-keys.py deleted file mode 100644 index b8cde7c..0000000 --- a/certs/slave-keys.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/python -tt -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Library General Public License for more details. -# -# 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-2008 Red Hat, inc -#- Written by Seth Vidal skvidal @ fedoraproject.org - -import sys -import os -import os.path -import xmlrpclib -import time - -from exceptions import Exception - -import certmaster.certs - - -def submit_csr_to_master(csr_file, master_uri): - # get csr_file - # submit buffer of file content to master_uri.wait_for_cert() - # wait for response and return - fo = open(csr_file) - csr = fo.read() - s = xmlrpclib.ServerProxy(master_uri) - - return s.wait_for_cert(csr) - - - -def main(cert_dir, master_uri): - keypair = None - key_file = '%s/slave.pem' % cert_dir - csr_file = '%s/slave.csr' % cert_dir - cert_file = '%s/slave.cert' % cert_dir - ca_cert_file = '%s/ca.cert' % cert_dir - - try: - if not os.path.exists(cert_dir): - os.makedirs(cert_dir) - if not os.path.exists(key_file): - keypair = certmaster.certs.make_keypair(dest=key_file) - if not os.path.exists(csr_file): - if not keypair: - keypair = certmaster.certs.retrieve_key_from_file(key_file) - csr = certmaster.certs.make_csr(keypair, dest=csr_file) - except Exception, e: # need a little more specificity here - print e - return 1 - - result = False - while not result: - result, cert_string, ca_cert_string = submit_csr_to_master(csr_file, master_uri) - print 'looping' - time.sleep(10) - - - if result: - cert_fo = open(cert_file, 'w') - cert_fo.write(cert_string) - cert_fo.close() - - ca_cert_fo = open(ca_cert_file, 'w') - ca_cert_fo.write(ca_cert_string) - ca_cert_fo.close() - - return 0 - - -if __name__ == "__main__": - if len(sys.argv[1:]) > 0: - cert_dir = sys.argv[1] - else: - cert_dir = '/etc/pki/certmaster' - - if len(sys.argv[1:]) > 1: - master_uri = sys.argv[2] - else: - master_uri = 'http://localhost:51235/' - - sys.exit(main(cert_dir, master_uri)) - diff --git a/scripts/certmaster-request b/scripts/certmaster-request index c731fdb..b40a66c 100755 --- a/scripts/certmaster-request +++ b/scripts/certmaster-request @@ -1,12 +1,23 @@ #!/usr/bin/python +""" +Application to request a cert from a certmaster. +Takes no arguments, uses /etc/certmaster/minion.conf + +Copyright 2008, Red Hat, Inc +Michael DeHaan + +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. +""" -import sys import distutils.sysconfig -print "This app is not implemented yet!" +from certmaster import requester -# from func.minion import server -# -#if __name__ == "__main__": -# server.main(sys.argv) +if __name__ == "__main__": + requester.request_cert() -- cgit