mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
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:
parent
6d9974dd95
commit
ac0fb8ea52
@ -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)
|
||||
|
||||
|
@ -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"])
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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]
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user