mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-26 08:51:50 -06:00
Use file to store the current CA serial number
No longer create a PKCS#12 file that contains the CA No longer send the entire CA to each replica, generate the SSL certs on master Fix number of bugs in ipa-replica-install and prepare Produce status output during replica creation
This commit is contained in:
parent
25057816a5
commit
5a96618f5d
@ -20,13 +20,13 @@
|
||||
|
||||
import sys
|
||||
|
||||
import tempfile, os, pwd, traceback, logging
|
||||
import tempfile, os, pwd, traceback, logging, shutil
|
||||
from ConfigParser import SafeConfigParser
|
||||
|
||||
from ipa import ipautil
|
||||
|
||||
from ipaserver import dsinstance, replication, installutils, krbinstance, service
|
||||
from ipaserver import httpinstance, webguiinstance, ntpinstance, certs
|
||||
from ipaserver import httpinstance, ntpinstance, certs
|
||||
|
||||
class ReplicaConfig:
|
||||
def __init__(self):
|
||||
@ -93,13 +93,12 @@ def install_ds(config):
|
||||
# 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",
|
||||
if ipautil.file_exists(config.dir + "/dscert.p12"):
|
||||
pkcs12_info = (config.dir + "/dscert.p12",
|
||||
config.dir + "/pwdfile.txt")
|
||||
|
||||
ds = dsinstance.DsInstance()
|
||||
ds.create_instance(config.ds_user, config.realm_name, config.host_name, config.dirman_password,
|
||||
pkcs12_info)
|
||||
ds.create_instance(config.ds_user, config.realm_name, config.host_name, config.dirman_password, pkcs12_info)
|
||||
|
||||
def install_krb(config):
|
||||
krb = krbinstance.KrbInstance()
|
||||
@ -108,8 +107,25 @@ def install_krb(config):
|
||||
config.dirman_password, ldappwd_filename)
|
||||
|
||||
def install_http(config):
|
||||
# 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 + "/httpcert.p12"):
|
||||
pkcs12_info = (config.dir + "/httpcert.p12",
|
||||
config.dir + "/pwdfile.txt")
|
||||
|
||||
http = httpinstance.HTTPInstance()
|
||||
http.create_instance(config.realm_name, config.host_name)
|
||||
http.create_instance(config.realm_name, config.host_name, False, pkcs12_info)
|
||||
|
||||
# Now copy the autoconfiguration files
|
||||
try:
|
||||
shutil.copy(config.dir + "/preferences.html", "/usr/share/ipa/html/preferences.html")
|
||||
shutil.copy(config.dir + "/configure.jar", "/usr/share/ipa/html/configure.jar")
|
||||
shutil.copy(config.dir + "/ca.crt", "/usr/share/ipa/html/ca.crt")
|
||||
except Exception, e:
|
||||
print "error copying files: " + str(e)
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
options, filename = parse_options()
|
||||
@ -137,18 +153,20 @@ def main():
|
||||
install_http(config)
|
||||
|
||||
# Create a Web Gui instance
|
||||
webgui = webguiinstance.WebGuiInstance()
|
||||
webgui = httpinstance.WebGuiInstance()
|
||||
webgui.create_instance()
|
||||
|
||||
# Configure ntpd
|
||||
ntp = ntpinstance.NTPInstance()
|
||||
ntp.create_instance()
|
||||
|
||||
|
||||
service.restart("dirsrv")
|
||||
service.restart("krb5kdc")
|
||||
|
||||
try:
|
||||
if not os.geteuid()==0:
|
||||
sys.exit("\nYou must be root to run this script.\n")
|
||||
|
||||
main()
|
||||
except Exception, e:
|
||||
print "creation of replica failed: %s" % str(e)
|
||||
@ -157,4 +175,3 @@ except Exception, e:
|
||||
message = message + "\n" + str
|
||||
logging.debug(message)
|
||||
sys.exit(1)
|
||||
|
||||
|
@ -21,12 +21,30 @@
|
||||
import sys
|
||||
|
||||
import logging, tempfile, shutil, os, pwd
|
||||
import traceback
|
||||
from ConfigParser import SafeConfigParser
|
||||
import krbV
|
||||
from optparse import OptionParser
|
||||
|
||||
import ipa.config
|
||||
from ipa import ipautil
|
||||
from ipaserver import dsinstance, installutils, certs
|
||||
|
||||
def usage():
|
||||
print "ipa-replica-prepate FQDN (e.g. replica.example.com)"
|
||||
sys.exit(1)
|
||||
|
||||
def parse_options():
|
||||
parser = OptionParser()
|
||||
|
||||
args = ipa.config.init_config(sys.argv)
|
||||
options, args = parser.parse_args(args)
|
||||
|
||||
if len(args) != 2:
|
||||
parser.error("must provide the fully-qualified name of the replica")
|
||||
|
||||
return options, args
|
||||
|
||||
def get_host_name():
|
||||
hostname = installutils.get_fqdn()
|
||||
try:
|
||||
@ -42,22 +60,31 @@ def get_realm_name():
|
||||
return c.default_realm
|
||||
|
||||
def check_ipa_configuration(realm_name):
|
||||
config_dir = dsinstance.config_dirname(realm_name)
|
||||
config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
|
||||
if not ipautil.dir_exists(config_dir):
|
||||
logging.error("could not find directory instance: %s" % config_dir)
|
||||
sys.exit(1)
|
||||
|
||||
def export_certdb(ds_dir, dir):
|
||||
ds_cdb = certs.CertDB(ds_dir)
|
||||
|
||||
pkcs12_fname = dir + "/cacert.p12"
|
||||
def export_certdb(realm_name, ds_dir, dir, fname, subject):
|
||||
"""realm is the kerberos realm for the IPA server.
|
||||
ds_dir is the location of the master DS we are creating a replica for.
|
||||
dir is the location of the files for the replica we are creating.
|
||||
fname is the filename of the PKCS#12 file for this cert (minus the .p12).
|
||||
subject is the subject of the certificate we are creating
|
||||
"""
|
||||
ds_ca = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name)))
|
||||
ca = certs.CertDB(dir)
|
||||
ca.create_from_cacert(ds_ca.cacert_fname)
|
||||
ca.create_server_cert("Server-Cert", subject, ds_ca)
|
||||
|
||||
pkcs12_fname = dir + "/" + fname + ".p12"
|
||||
passwd_fname = dir + "/pwdfile.txt"
|
||||
fd = open(passwd_fname, "w")
|
||||
fd.write("\n")
|
||||
fd.close()
|
||||
|
||||
try:
|
||||
ds_cdb.export_pkcs12(pkcs12_fname, passwd_fname)
|
||||
ca.export_pkcs12(pkcs12_fname, passwd_fname, "Server-Cert")
|
||||
except ipautil.CalledProcessError, e:
|
||||
print "error exporting CA certificate: " + str(e)
|
||||
try:
|
||||
@ -66,6 +93,9 @@ def export_certdb(ds_dir, dir):
|
||||
except:
|
||||
pass
|
||||
|
||||
os.unlink(dir + "/cert8.db")
|
||||
os.unlink(dir + "/key3.db")
|
||||
os.unlink(dir + "/secmod.db")
|
||||
|
||||
def get_ds_user(ds_dir):
|
||||
uid = os.stat(ds_dir).st_uid
|
||||
@ -83,31 +113,60 @@ def save_config(dir, realm_name, host_name, ds_user):
|
||||
config.write(fd)
|
||||
|
||||
def copy_files(realm_name, dir):
|
||||
shutil.copy("/var/kerberos/krb5kdc/ldappwd", dir + "/ldappwd")
|
||||
config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
|
||||
try:
|
||||
shutil.copy("/var/kerberos/krb5kdc/ldappwd", dir + "/ldappwd")
|
||||
shutil.copy("/usr/share/ipa/html/preferences.html", dir + "/preferences.html")
|
||||
shutil.copy("/usr/share/ipa/html/configure.jar", dir + "/configure.jar")
|
||||
shutil.copy(config_dir + "/cacert.asc", dir + "/ca.crt")
|
||||
except Exception, e:
|
||||
print "error copying files: " + str(e)
|
||||
sys.exit(1)
|
||||
|
||||
def main():
|
||||
options, args = parse_options()
|
||||
|
||||
replica_fqdn = args[1]
|
||||
|
||||
realm_name = get_realm_name()
|
||||
check_ipa_configuration(realm_name)
|
||||
|
||||
host_name = get_host_name()
|
||||
ds_dir = dsinstance.config_dirname(realm_name)
|
||||
ds_user = get_ds_user(ds_dir)
|
||||
|
||||
check_ipa_configuration(realm_name)
|
||||
print "Preparing replica for %s from %s" % (replica_fqdn, host_name)
|
||||
|
||||
top_dir = tempfile.mkdtemp("ipa")
|
||||
dir = top_dir + "/realm_info"
|
||||
os.mkdir(dir, 0700)
|
||||
|
||||
export_certdb(ds_dir, dir)
|
||||
print "Creating SSL certificate for the Directory Server"
|
||||
export_certdb(realm_name, ds_dir, dir, "dscert", "cn=%s,ou=Fedora Directory Server" % replica_fqdn)
|
||||
print "Creating SSL certificate for the Web Server"
|
||||
export_certdb(realm_name, ds_dir, dir, "httpcert", "cn=%s,ou=Apache Web Server" % replica_fqdn)
|
||||
print "Copying additional files"
|
||||
copy_files(realm_name, dir)
|
||||
print "Finalizing configuration"
|
||||
save_config(dir, realm_name, host_name, ds_user)
|
||||
|
||||
print "Packaging the replica into %s" % "replica-info-" + realm_name
|
||||
ipautil.run(["/bin/tar", "cfz", "replica-info-" + realm_name, "-C", top_dir, "realm_info"])
|
||||
|
||||
shutil.rmtree(dir)
|
||||
|
||||
main()
|
||||
|
||||
try:
|
||||
if not os.geteuid()==0:
|
||||
sys.exit("\nYou must be root to run this script.\n")
|
||||
if not ipautil.file_exists("/usr/share/ipa/serial"):
|
||||
sys.exist("The replica must be created on the primary IPA server.")
|
||||
|
||||
|
||||
|
||||
|
||||
main()
|
||||
except Exception, e:
|
||||
print "preparation 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)
|
||||
print message
|
||||
sys.exit(1)
|
||||
|
@ -496,7 +496,7 @@ def main():
|
||||
print "\t\t * 88, 464: kerberos"
|
||||
print "\t\t * 123: ntp"
|
||||
print ""
|
||||
print "\t2. You can now obtain a kerberos ticket using the command: 'kinit admin'."
|
||||
print "\t2. You can now obtain a kerberos ticket using the command: 'kinit admin'"
|
||||
print "\t This ticket will allow you to use the IPA tools (e.g., ipa-adduser)"
|
||||
print "\t and the web user interface."
|
||||
|
||||
@ -504,7 +504,8 @@ def main():
|
||||
print "\t3. Kerberos requires time synchronization between clients"
|
||||
print "\t and servers for correct operation. You should consider enabling ntpd."
|
||||
|
||||
|
||||
print ""
|
||||
print "Be sure to back up the CA certificate stored in " + ipaserver.dsinstance.config_dirname(ds.serverid) + "cacert.p12"
|
||||
|
||||
return 0
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
import os, stat, subprocess, re
|
||||
import sha
|
||||
import errno
|
||||
|
||||
from ipa import ipautil
|
||||
|
||||
@ -42,7 +43,7 @@ class CertDB(object):
|
||||
# responsibility of the caller for now. In the
|
||||
# future we might automatically determine this
|
||||
# for a given db.
|
||||
self.cur_serial = 1000
|
||||
self.cur_serial = -1
|
||||
|
||||
self.cacert_name = "CA certificate"
|
||||
self.valid_months = "120"
|
||||
@ -57,10 +58,40 @@ class CertDB(object):
|
||||
self.uid = mode[stat.ST_UID]
|
||||
self.gid = mode[stat.ST_GID]
|
||||
|
||||
def set_serial_from_pkcs12(self):
|
||||
"""A CA cert was loaded from a PKCS#12 file. Set up our serial file"""
|
||||
|
||||
self.cur_serial = self.find_cacert_serial()
|
||||
try:
|
||||
f=open("/usr/share/ipa/serial","w")
|
||||
f.write(str(self.cur_serial))
|
||||
f.close()
|
||||
except IOError, e:
|
||||
raise RuntimeError("Unable to increment serial number: %s" % str(e))
|
||||
|
||||
def next_serial(self):
|
||||
r = self.cur_serial
|
||||
self.cur_serial += 1
|
||||
return str(r)
|
||||
try:
|
||||
f=open("/usr/share/ipa/serial","r")
|
||||
r = f.readline()
|
||||
self.cur_serial = int(r) + 1
|
||||
f.close()
|
||||
except IOError, e:
|
||||
if e.errno == errno.ENOENT:
|
||||
self.cur_serial = 1000
|
||||
f=open("/usr/share/ipa/serial","w")
|
||||
f.write(str(self.cur_serial))
|
||||
f.close()
|
||||
else:
|
||||
raise RuntimeError("Unable to determine serial number: %s" % str(e))
|
||||
|
||||
try:
|
||||
f=open("/usr/share/ipa/serial","w")
|
||||
f.write(str(self.cur_serial))
|
||||
f.close()
|
||||
except IOError, e:
|
||||
raise RuntimeError("Unable to increment serial number: %s" % str(e))
|
||||
|
||||
return str(self.cur_serial)
|
||||
|
||||
def set_perms(self, fname, write=False):
|
||||
os.chown(fname, self.uid, self.gid)
|
||||
@ -75,7 +106,7 @@ class CertDB(object):
|
||||
def run_certutil(self, args, stdin=None):
|
||||
new_args = ["/usr/bin/certutil", "-d", self.secdir]
|
||||
new_args = new_args + args
|
||||
ipautil.run(new_args, stdin)
|
||||
return ipautil.run(new_args, stdin)
|
||||
|
||||
def run_signtool(self, args, stdin=None):
|
||||
new_args = ["/usr/bin/signtool", "-d", self.secdir]
|
||||
@ -139,6 +170,16 @@ class CertDB(object):
|
||||
"-t", "CT,,C",
|
||||
"-a",
|
||||
"-i", cacert_fname])
|
||||
|
||||
def find_cacert_serial(self):
|
||||
(out,err) = self.run_certutil(["-L", "-n", self.cacert_name])
|
||||
data = out.split('\n')
|
||||
for line in data:
|
||||
x = re.match(r'\s+Serial Number: (\d+) .*', line)
|
||||
if x is not None:
|
||||
return x.group(1)
|
||||
|
||||
raise RuntimeError("Unable to find serial number")
|
||||
|
||||
def create_server_cert(self, nickname, name, other_certdb=None):
|
||||
cdb = other_certdb
|
||||
@ -330,5 +371,3 @@ class CertDB(object):
|
||||
sysrestore.backup_file(self.pin_fname)
|
||||
sysrestore.backup_file(self.certreq_fname)
|
||||
sysrestore.backup_file(self.certder_fname)
|
||||
|
||||
|
||||
|
@ -257,10 +257,9 @@ class DsInstance(service.Service):
|
||||
ca = certs.CertDB(dirname)
|
||||
if self.pkcs12_info:
|
||||
ca.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1])
|
||||
ca.cur_serial = 2100
|
||||
else:
|
||||
ca.create_self_signed()
|
||||
ca.create_server_cert("Server-Cert", "cn=%s,ou=Fedora Directory Server" % self.host_name)
|
||||
ca.create_server_cert("Server-Cert", "cn=%s,ou=Fedora Directory Server" % self.host_name)
|
||||
|
||||
conn = ipaldap.IPAdmin("127.0.0.1")
|
||||
conn.simple_bind_s("cn=directory manager", self.dm_password)
|
||||
|
@ -55,10 +55,11 @@ class HTTPInstance(service.Service):
|
||||
def __init__(self):
|
||||
service.Service.__init__(self, "httpd")
|
||||
|
||||
def create_instance(self, realm, fqdn):
|
||||
def create_instance(self, realm, fqdn, autoconfig=True, pkcs12_info=None):
|
||||
self.fqdn = fqdn
|
||||
self.realm = realm
|
||||
self.domain = fqdn[fqdn.find(".")+1:]
|
||||
self.pkcs12_info = pkcs12_info
|
||||
self.sub_dict = { "REALM" : realm, "FQDN": fqdn, "DOMAIN" : self.domain }
|
||||
|
||||
self.step("disabling mod_ssl in httpd", self.__disable_mod_ssl)
|
||||
@ -66,7 +67,8 @@ class HTTPInstance(service.Service):
|
||||
self.step("configuring httpd", self.__configure_http)
|
||||
self.step("creating a keytab for httpd", self.__create_http_keytab)
|
||||
self.step("Setting up ssl", self.__setup_ssl)
|
||||
self.step("Setting up browser autoconfig", self.__setup_autoconfig)
|
||||
if autoconfig:
|
||||
self.step("Setting up browser autoconfig", self.__setup_autoconfig)
|
||||
self.step("configuring SELinux for httpd", self.__selinux_config)
|
||||
self.step("restarting httpd", self.__start)
|
||||
self.step("configuring httpd to start on boot", self.__enable)
|
||||
@ -136,10 +138,12 @@ class HTTPInstance(service.Service):
|
||||
def __setup_ssl(self):
|
||||
ds_ca = certs.CertDB(dsinstance.config_dirname(dsinstance.realm_to_serverid(self.realm)))
|
||||
ca = certs.CertDB(NSS_DIR)
|
||||
ds_ca.cur_serial = 2000
|
||||
ca.create_from_cacert(ds_ca.cacert_fname)
|
||||
ca.create_server_cert("Server-Cert", "cn=%s,ou=Apache Web Server" % self.fqdn, ds_ca)
|
||||
ca.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ds_ca)
|
||||
if self.pkcs12_info:
|
||||
ca.create_from_pkcs12(self.pkcs12_info[0], self.pkcs12_info[1], passwd=False)
|
||||
else:
|
||||
ca.create_from_cacert(ds_ca.cacert_fname)
|
||||
ca.create_server_cert("Server-Cert", "cn=%s,ou=Apache Web Server" % self.fqdn, ds_ca)
|
||||
ca.create_signing_cert("Signing-Cert", "cn=%s,ou=Signing Certificate,o=Identity Policy Audit" % self.fqdn, ds_ca)
|
||||
|
||||
def __setup_autoconfig(self):
|
||||
prefs_txt = ipautil.template_file(ipautil.SHARE_DIR + "preferences.html.template", self.sub_dict)
|
||||
|
@ -279,7 +279,7 @@ class ReplicationManager:
|
||||
return haserror
|
||||
|
||||
def start_replication(self, other_conn):
|
||||
print "starting replication"
|
||||
print "Starting replication, please wait until this has completed."
|
||||
cn, dn = self.agreement_dn(self.conn)
|
||||
|
||||
mod = [(ldap.MOD_ADD, 'nsds5BeginReplicaRefresh', 'start')]
|
||||
|
Loading…
Reference in New Issue
Block a user