Convert replication to use the new cert infrastructure and

correctly issue certs from the same authority. Also remove
support for read-only replicas since that work will not
be finished and tested for 1.0.
This commit is contained in:
Karl MacMillan 0001-01-01 00:00:00 +00:00
parent 6d9974dd95
commit ac0fb8ea52
7 changed files with 114 additions and 71 deletions

View File

@ -21,13 +21,13 @@
import sys
sys.path.append("/usr/share/ipa")
import tempfile
import tempfile, os, pwd, traceback, logging
from ConfigParser import SafeConfigParser
from ipa import ipautil
from ipaserver import dsinstance, replication, installutils, krbinstance, service
from ipaserver import httpinstance, webguiinstance, radiusinstance, ntpinstance
from ipaserver import httpinstance, webguiinstance, radiusinstance, ntpinstance, certs
class ReplicaConfig:
def __init__(self):
@ -42,8 +42,8 @@ class ReplicaConfig:
def parse_options():
from optparse import OptionParser
parser = OptionParser()
parser.add_option("-r", "--read-only", dest="master", action="store_false",
default=True, help="create read-only replica - default is master")
parser.add_option("-d", "--debug", dest="debug", action="store_true",
default=False, help="gather extra debugging information")
options, args = parser.parse_args()
@ -82,12 +82,25 @@ def get_host_name():
return hostname
def set_owner(config, dir):
pw = pwd.getpwnam(config.ds_user)
os.chown(dir, pw.pw_uid, pw.pw_gid)
def install_ds(config):
dsinstance.check_existing_installation()
dsinstance.check_ports()
# if we have a pkcs12 file, create the cert db from
# that. Otherwise the ds setup will create the CA
# cert
pkcs12_info = None
if ipautil.file_exists(config.dir + "/cacert.p12"):
pkcs12_info = (config.dir + "/cacert.p12",
config.dir + "/pwdfile.txt")
ds = dsinstance.DsInstance()
ds.create_instance(config.ds_user, config.realm_name, config.host_name, config.dirman_password)
ds.create_instance(config.ds_user, config.realm_name, config.host_name, config.dirman_password,
pkcs12_info)
def install_krb(config):
krb = krbinstance.KrbInstance()
@ -101,6 +114,8 @@ def install_http(config):
def main():
options, filename = parse_options()
installutils.standard_logging_setup("ipareplica-install.log", options.debug)
top_dir, dir = expand_info(filename)
config = ReplicaConfig()
@ -115,7 +130,9 @@ def main():
install_ds(config)
repl = replication.ReplicationManager(config.host_name, config.dirman_password)
repl.setup_replication(config.master_host_name, config.realm_name, options.master)
ret = repl.setup_replication(config.master_host_name, config.realm_name)
if ret != 0:
raise RuntimeError("failed to start replication")
install_krb(config)
install_http(config)
@ -124,11 +141,6 @@ def main():
webgui = webguiinstance.WebGuiInstance()
webgui.create_instance()
# Create a radius instance
radius = radiusinstance.RadiusInstance()
# FIXME: ldap_server should be derived, not hardcoded to localhost, also should it be a URL?
radius.create_instance(config.realm_name, config.host_name, 'localhost')
# Configure ntpd
ntp = ntpinstance.NTPInstance()
ntp.create_instance()
@ -137,6 +149,13 @@ def main():
service.restart("dirsrv")
service.restart("krb5kdc")
main()
try:
main()
except Exception, e:
print "creation of replica failed: %s" % str(e)
message = str(e)
for str in traceback.format_tb(sys.exc_info()[2]):
message = message + "\n" + str
logging.debug(message)
sys.exit(1)

View File

@ -26,10 +26,7 @@ from ConfigParser import SafeConfigParser
import krbV
from ipa import ipautil
from ipaserver import dsinstance
from ipaserver import installutils
certutil = "/usr/bin/certutil"
from ipaserver import dsinstance, installutils, certs
def get_host_name():
hostname = installutils.get_fqdn()
@ -51,18 +48,25 @@ def check_ipa_configuration(realm_name):
logging.error("could not find directory instance: %s" % config_dir)
sys.exit(1)
def create_certdb(ds_dir, dir):
# copy the passwd, noise, and pin files
shutil.copyfile(ds_dir + "/pwdfile.txt", dir + "/pwdfile.txt")
shutil.copyfile(ds_dir + "/noise.txt", dir + "/noise.txt")
shutil.copyfile(ds_dir + "/pin.txt", dir + "/pin.txt")
def export_certdb(ds_dir, dir):
ds_cdb = certs.CertDB(ds_dir)
pkcs12_fname = dir + "/cacert.p12"
passwd_fname = dir + "/pwdfile.txt"
fd = open(passwd_fname, "w")
fd.write("\n")
fd.close()
# create a new cert db
ipautil.run([certutil, "-N", "-d", dir, "-f", dir + "/pwdfile.txt"])
try:
ds_cdb.export_pkcs12(pkcs12_fname, passwd_fname)
except ipautil.CalledProcessError, e:
print "error exporting CA certificate: " + str(e)
try:
os.unlink(pkcs12_fname)
os.unlink(passwd_fname)
except:
pass
# Add the CA cert
ipautil.run([certutil, "-A", "-d", dir, "-n", "CA certificate", "-t", "CT,CT", "-a", "-i",
ds_dir + "/cacert.asc"])
def get_ds_user(ds_dir):
uid = os.stat(ds_dir).st_uid
@ -70,10 +74,6 @@ def get_ds_user(ds_dir):
return user
def copy_files(realm_name, dir):
shutil.copy("/var/kerberos/krb5kdc/ldappwd", dir + "/ldappwd")
def save_config(dir, realm_name, host_name, ds_user):
config = SafeConfigParser()
config.add_section("realm")
@ -82,7 +82,9 @@ def save_config(dir, realm_name, host_name, ds_user):
config.set("realm", "ds_user", ds_user)
fd = open(dir + "/realm_info", "w")
config.write(fd)
def copy_files(realm_name, dir):
shutil.copy("/var/kerberos/krb5kdc/ldappwd", dir + "/ldappwd")
def main():
realm_name = get_realm_name()
@ -96,10 +98,8 @@ def main():
dir = top_dir + "/realm_info"
os.mkdir(dir, 0700)
create_certdb(ds_dir, dir)
export_certdb(ds_dir, dir)
copy_files(realm_name, dir)
save_config(dir, realm_name, host_name, ds_user)
ipautil.run(["/bin/tar", "cfz", "replica-info-" + realm_name, "-C", top_dir, "realm_info"])

View File

@ -119,6 +119,7 @@ class CertDB(object):
"-z", self.noise_fname,
"-f", self.passwd_fname])
def export_ca_cert(self):
# export the CA cert for use with other apps
ipautil.backup_file(self.cacert_fname)
self.run_certutil(["-L", "-n", "CA certificate",
@ -274,21 +275,33 @@ class CertDB(object):
return server_certs
def import_pkcs12(self, pkcs12_fname):
def import_pkcs12(self, pkcs12_fname, passwd_fname=None):
args = ["/usr/bin/pk12util", "-d", self.secdir,
"-i", pkcs12_fname,
"-k", self.passwd_fname]
if passwd_fname:
args = args + ["-w", passwd_fname]
try:
ipautil.run(["/usr/bin/pk12util", "-d", self.secdir,
"-i", pkcs12_fname])
ipautil.run(args)
except ipautil.CalledProcessError, e:
if e.returncode == 17:
raise RuntimeError("incorrect password")
else:
raise RuntimeError("unknown error import pkcs#12 file")
def export_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname="CA certificate"):
ipautil.run(["/usr/bin/pk12util", "-d", self.secdir,
"-o", pkcs12_fname,
"-n", nickname,
"-k", self.passwd_fname,
"-w", pkcs12_pwd_fname])
def create_self_signed(self, passwd=True):
self.create_noise_file()
self.create_passwd_file(passwd)
self.create_certdbs()
self.create_ca_cert()
self.export_ca_cert()
self.create_pin_file()
def create_from_cacert(self, cacert_fname, passwd=False):
@ -296,3 +309,13 @@ class CertDB(object):
self.create_passwd_file(passwd)
self.create_certdbs()
self.load_cacert(cacert_fname)
def create_from_pkcs12(self, pkcs12_fname, pkcs12_pwd_fname, nickname="CA certificate", passwd=True):
self.create_noise_file()
self.create_passwd_file(passwd)
self.create_certdbs()
self.import_pkcs12(pkcs12_fname, pkcs12_pwd_fname)
self.trust_root_cert(nickname)
self.create_pin_file()
self.export_ca_cert()

View File

@ -125,7 +125,7 @@ class DsInstance(service.Service):
self.sub_dict = None
self.domain = None
def create_instance(self, ds_user, realm_name, host_name, dm_password, ro_replica=False):
def create_instance(self, ds_user, realm_name, host_name, dm_password, pkcs12_info=None):
self.ds_user = ds_user
self.realm_name = realm_name.upper()
self.serverid = realm_to_serverid(self.realm_name)
@ -133,13 +133,13 @@ class DsInstance(service.Service):
self.host_name = host_name
self.dm_password = dm_password
self.domain = host_name[host_name.find(".")+1:]
self.pkcs12_info = pkcs12_info
self.__setup_sub_dict()
self.step("creating directory server user", self.__create_ds_user)
self.step("creating directory server instance", self.__create_instance)
self.step("adding default schema", self.__add_default_schemas)
if not ro_replica:
self.step("enabling memberof plugin", self.__add_memberof_module)
self.step("enabling memberof plugin", self.__add_memberof_module)
self.step("enabling referential integrity plugin", self.__add_referint_module)
self.step("enabling distributed numeric assignment plugin", self.__add_dna_module)
self.step("creating indeces", self.__create_indeces)
@ -147,13 +147,12 @@ class DsInstance(service.Service):
self.step("configuring certmap.conf", self.__certmap_conf)
self.step("restarting directory server", self.__restart_instance)
self.step("adding default layout", self.__add_default_layout)
if not ro_replica:
self.step("configuring Posix uid/gid generation as first master",
self.__config_uidgid_gen_first_master)
self.step("adding master entry as first master",
self.__add_master_entry_first_master)
self.step("initializing group membership",
self.__init_memberof)
self.step("configuring Posix uid/gid generation as first master",
self.__config_uidgid_gen_first_master)
self.step("adding master entry as first master",
self.__add_master_entry_first_master)
self.step("initializing group membership",
self.__init_memberof)
self.step("configuring directory to start on boot", self.chkconfig_on)
@ -261,7 +260,11 @@ class DsInstance(service.Service):
def __enable_ssl(self):
dirname = config_dirname(self.realm_name)
ca = certs.CertDB(dirname)
ca.create_self_signed()
if self.pkcs12_info:
ca.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1])
ca.cur_serial = 2000
else:
ca.create_self_signed()
ca.create_server_cert("Server-Cert", "cn=%s,ou=Fedora Directory Server" % self.host_name)
conn = ipaldap.IPAdmin("127.0.0.1")

View File

@ -724,9 +724,12 @@ def notfound(args):
search returns no results.
This just returns whatever is after the equals sign"""
filter = args[2]
try:
target = re.match(r'\(.*=(.*)\)', filter).group(1)
except:
target = filter
return "%s not found" % str(target)
if len(args) > 2:
filter = args[2]
try:
target = re.match(r'\(.*=(.*)\)', filter).group(1)
except:
target = filter
return "%s not found" % str(target)
else:
return args[0]

View File

@ -257,7 +257,7 @@ class KrbInstance(service.Service):
self.__ldap_mod("default-aci.ldif")
def __create_replica_instance(self):
self.__create_instance(replace=True)
self.__create_instance(replica=True)
def __create_instance(self, replica=False):
kdc_conf = ipautil.template_file(ipautil.SHARE_DIR+"kdc.conf.template", self.sub_dict)

View File

@ -77,7 +77,7 @@ class ReplicationManager:
except ldap.NO_SUCH_OBJECT:
pass
def get_replica_type(self, master):
def get_replica_type(self, master=True):
if master:
return "3"
else:
@ -87,7 +87,7 @@ class ReplicationManager:
return 'cn=replica, cn="%s", cn=mapping tree, cn=config' % self.suffix
def local_replica_config(self, conn, master, replica_id):
def local_replica_config(self, conn, replica_id):
dn = self.replica_dn()
try:
@ -97,7 +97,7 @@ class ReplicationManager:
except ipaerror.exception_for(ipaerror.LDAP_NOT_FOUND):
pass
replica_type = self.get_replica_type(master)
replica_type = self.get_replica_type()
entry = ipaldap.Entry(dn)
entry.setValues('objectclass', "top", "nsds5replica", "extensibleobject")
@ -284,13 +284,12 @@ class ReplicationManager:
return self.wait_for_repl_init(other_conn, dn)
def basic_replication_setup(self, conn, master, replica_id):
def basic_replication_setup(self, conn, replica_id):
self.add_replication_manager(conn)
self.local_replica_config(conn, master, replica_id)
if master:
self.setup_changelog(conn)
self.local_replica_config(conn, replica_id)
self.setup_changelog(conn)
def setup_replication(self, other_hostname, realm_name, master=True):
def setup_replication(self, other_hostname, realm_name):
"""
NOTES:
- the directory manager password needs to be the same on
@ -300,15 +299,11 @@ class ReplicationManager:
other_conn.do_simple_bind(bindpw=self.dirman_passwd)
self.suffix = ipaldap.IPAdmin.normalizeDN(dsinstance.realm_to_suffix(realm_name))
self.basic_replication_setup(self.conn, master, 1)
self.basic_replication_setup(other_conn, True, 2)
self.basic_replication_setup(self.conn, 1)
self.basic_replication_setup(other_conn, 2)
self.setup_agreement(other_conn, self.conn)
if master:
self.setup_agreement(self.conn, other_conn)
else:
self.setup_chaining_farm(other_conn)
self.setup_chain_on_update(other_conn)
self.setup_agreement(self.conn, other_conn)
return self.start_replication(other_conn)