mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
install: Migrate ipa-server-install to the install framework
https://fedorahosted.org/freeipa/ticket/4468 Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
parent
9e9c01fba2
commit
eb959221e1
@ -20,369 +20,18 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
|
||||
# requires the following packages:
|
||||
# fedora-ds-base
|
||||
# openldap-clients
|
||||
# nss-tools
|
||||
|
||||
import sys
|
||||
import os
|
||||
import signal
|
||||
import random
|
||||
from optparse import OptionGroup, OptionValueError, SUPPRESS_HELP
|
||||
|
||||
from ipaserver.install import bindinstance
|
||||
from ipaserver.install import installutils
|
||||
from ipaserver.install import server
|
||||
from ipaserver.install.server import (
|
||||
validate_dm_password, validate_admin_password)
|
||||
from ipapython import version
|
||||
|
||||
from ipalib import constants
|
||||
from ipapython.config import IPAOptionParser
|
||||
from ipalib.util import validate_domain_name
|
||||
from ipapython.ipa_log_manager import root_logger, standard_logging_setup
|
||||
from ipapython.dn import DN
|
||||
|
||||
from ipapython.install import cli
|
||||
from ipaplatform.paths import paths
|
||||
|
||||
VALID_SUBJECT_ATTRS = ['st', 'o', 'ou', 'dnqualifier', 'c',
|
||||
'serialnumber', 'l', 'title', 'sn', 'givenname',
|
||||
'initials', 'generationqualifier', 'dc', 'mail',
|
||||
'uid', 'postaladdress', 'postalcode', 'postofficebox',
|
||||
'houseidentifier', 'e', 'street', 'pseudonym',
|
||||
'incorporationlocality', 'incorporationstate',
|
||||
'incorporationcountry', 'businesscategory']
|
||||
from ipaserver.install.server import Server
|
||||
|
||||
|
||||
def subject_callback(option, opt_str, value, parser):
|
||||
"""
|
||||
Make sure the certificate subject base is a valid DN
|
||||
"""
|
||||
v = unicode(value, 'utf-8')
|
||||
if any(ord(c) < 0x20 for c in v):
|
||||
raise OptionValueError("Subject base must not contain control characters")
|
||||
if '&' in v:
|
||||
raise OptionValueError("Subject base must not contain an ampersand (\"&\")")
|
||||
try:
|
||||
dn = DN(v)
|
||||
for rdn in dn:
|
||||
if rdn.attr.lower() not in VALID_SUBJECT_ATTRS:
|
||||
raise OptionValueError('%s=%s has invalid attribute: "%s"' % (opt_str, value, rdn.attr))
|
||||
except ValueError, e:
|
||||
raise OptionValueError('%s=%s has invalid subject base format: %s' % (opt_str, value, e))
|
||||
parser.values.subject = dn
|
||||
ServerInstall = cli.install_tool(
|
||||
Server,
|
||||
command_name='ipa-server-install',
|
||||
log_file_name=paths.IPASERVER_INSTALL_LOG,
|
||||
debug_option=True,
|
||||
uninstall_log_file_name=paths.IPASERVER_UNINSTALL_LOG,
|
||||
)
|
||||
|
||||
|
||||
def parse_options():
|
||||
# Guaranteed to give a random 200k range below the 2G mark (uint32_t limit)
|
||||
namespace = random.randint(1, 10000) * 200000
|
||||
parser = IPAOptionParser(version=version.VERSION)
|
||||
|
||||
basic_group = OptionGroup(parser, "basic options")
|
||||
basic_group.add_option("-r", "--realm", dest="realm_name",
|
||||
help="realm name")
|
||||
basic_group.add_option("-n", "--domain", dest="domain_name",
|
||||
help="domain name")
|
||||
basic_group.add_option("-p", "--ds-password", dest="dm_password",
|
||||
sensitive=True, help="Directory Manager password")
|
||||
basic_group.add_option("-P", "--master-password",
|
||||
dest="master_password", sensitive=True,
|
||||
help=SUPPRESS_HELP)
|
||||
basic_group.add_option("-a", "--admin-password",
|
||||
sensitive=True, dest="admin_password",
|
||||
help="admin user kerberos password")
|
||||
basic_group.add_option("--mkhomedir",
|
||||
dest="mkhomedir",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="create home directories for users "
|
||||
"on their first login")
|
||||
basic_group.add_option("--hostname", dest="host_name", help="fully qualified name of server")
|
||||
basic_group.add_option("--domain-level", dest="domainlevel", help="IPA domain level",
|
||||
default=constants.MAX_DOMAIN_LEVEL, type=int)
|
||||
basic_group.add_option("--ip-address", dest="ip_addresses",
|
||||
type="ip", ip_local=True, action="append", default=[],
|
||||
help="Master Server IP Address. This option can be used multiple times",
|
||||
metavar="IP_ADDRESS")
|
||||
basic_group.add_option("-N", "--no-ntp", dest="conf_ntp", action="store_false",
|
||||
help="do not configure ntp", default=True)
|
||||
basic_group.add_option("--idstart", dest="idstart", default=namespace, type=int,
|
||||
help="The starting value for the IDs range (default random)")
|
||||
basic_group.add_option("--idmax", dest="idmax", default=0, type=int,
|
||||
help="The max value value for the IDs range (default: idstart+199999)")
|
||||
basic_group.add_option("--no_hbac_allow", dest="hbac_allow", default=False,
|
||||
action="store_true",
|
||||
help="Don't install allow_all HBAC rule")
|
||||
basic_group.add_option("--no-ui-redirect", dest="ui_redirect", action="store_false",
|
||||
default=True, help="Do not automatically redirect to the Web UI")
|
||||
basic_group.add_option("--ssh-trust-dns", dest="trust_sshfp", default=False, action="store_true",
|
||||
help="configure OpenSSH client to trust DNS SSHFP records")
|
||||
basic_group.add_option("--no-ssh", dest="conf_ssh", default=True, action="store_false",
|
||||
help="do not configure OpenSSH client")
|
||||
basic_group.add_option("--no-sshd", dest="conf_sshd", default=True, action="store_false",
|
||||
help="do not configure OpenSSH server")
|
||||
basic_group.add_option("-d", "--debug", dest="debug", action="store_true",
|
||||
default=False, help="print debugging information")
|
||||
basic_group.add_option("-U", "--unattended", dest="unattended", action="store_true",
|
||||
default=False, help="unattended (un)installation never prompts the user")
|
||||
parser.add_option_group(basic_group)
|
||||
|
||||
cert_group = OptionGroup(parser, "certificate system options")
|
||||
cert_group.add_option("", "--external-ca", dest="external_ca", action="store_true",
|
||||
default=False, help="Generate a CSR for the IPA CA certificate to be signed by an external CA")
|
||||
cert_group.add_option("--external-ca-type", dest="external_ca_type",
|
||||
type="choice", choices=("generic", "ms-cs"),
|
||||
help="Type of the external CA")
|
||||
cert_group.add_option("--external-cert-file", dest="external_cert_files",
|
||||
action="append", metavar="FILE",
|
||||
help="File containing the IPA CA certificate and the external CA certificate chain")
|
||||
cert_group.add_option("--external_cert_file", dest="external_cert_files",
|
||||
action="append",
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--external_ca_file", dest="external_cert_files",
|
||||
action="append",
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--no-pkinit", dest="setup_pkinit", action="store_false",
|
||||
default=True, help="disables pkinit setup steps")
|
||||
cert_group.add_option("--dirsrv-cert-file", dest="dirsrv_cert_files",
|
||||
action="append", metavar="FILE",
|
||||
help="File containing the Directory Server SSL certificate and private key")
|
||||
cert_group.add_option("--dirsrv_pkcs12", dest="dirsrv_cert_files",
|
||||
action="append",
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--http-cert-file", dest="http_cert_files",
|
||||
action="append", metavar="FILE",
|
||||
help="File containing the Apache Server SSL certificate and private key")
|
||||
cert_group.add_option("--http_pkcs12", dest="http_cert_files",
|
||||
action="append",
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--pkinit-cert-file", dest="pkinit_cert_files",
|
||||
action="append", metavar="FILE",
|
||||
help="File containing the Kerberos KDC SSL certificate and private key")
|
||||
cert_group.add_option("--pkinit_pkcs12", dest="pkinit_cert_files",
|
||||
action="append",
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--dirsrv-pin", dest="dirsrv_pin", sensitive=True,
|
||||
metavar="PIN",
|
||||
help="The password to unlock the Directory Server private key")
|
||||
cert_group.add_option("--dirsrv_pin", dest="dirsrv_pin", sensitive=True,
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--http-pin", dest="http_pin", sensitive=True,
|
||||
metavar="PIN",
|
||||
help="The password to unlock the Apache Server private key")
|
||||
cert_group.add_option("--http_pin", dest="http_pin", sensitive=True,
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--pkinit-pin", dest="pkinit_pin", sensitive=True,
|
||||
metavar="PIN",
|
||||
help="The password to unlock the Kerberos KDC private key")
|
||||
cert_group.add_option("--pkinit_pin", dest="pkinit_pin", sensitive=True,
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--dirsrv-cert-name", dest="dirsrv_cert_name",
|
||||
metavar="NAME",
|
||||
help="Name of the Directory Server SSL certificate to install")
|
||||
cert_group.add_option("--http-cert-name", dest="http_cert_name",
|
||||
metavar="NAME",
|
||||
help="Name of the Apache Server SSL certificate to install")
|
||||
cert_group.add_option("--pkinit-cert-name", dest="pkinit_cert_name",
|
||||
metavar="NAME",
|
||||
help="Name of the Kerberos KDC SSL certificate to install")
|
||||
cert_group.add_option("--ca-cert-file", dest="ca_cert_files",
|
||||
action="append", metavar="FILE",
|
||||
help="File containing CA certificates for the service certificate files")
|
||||
cert_group.add_option("--root-ca-file", dest="ca_cert_files",
|
||||
action="append",
|
||||
help=SUPPRESS_HELP)
|
||||
cert_group.add_option("--subject", action="callback", callback=subject_callback,
|
||||
type="string",
|
||||
help="The certificate subject base (default O=<realm-name>)")
|
||||
cert_group.add_option("--ca-signing-algorithm", dest="ca_signing_algorithm",
|
||||
type="choice",
|
||||
choices=('SHA1withRSA', 'SHA256withRSA', 'SHA512withRSA'),
|
||||
help="Signing algorithm of the IPA CA certificate")
|
||||
parser.add_option_group(cert_group)
|
||||
|
||||
dns_group = OptionGroup(parser, "DNS options")
|
||||
dns_group.add_option("--setup-dns", dest="setup_dns", action="store_true",
|
||||
default=False, help="configure bind with our zone")
|
||||
dns_group.add_option("--forwarder", dest="forwarders", action="append",
|
||||
type="ip", help="Add a DNS forwarder. This option can be used multiple times")
|
||||
dns_group.add_option("--no-forwarders", dest="no_forwarders", action="store_true",
|
||||
default=False, help="Do not add any DNS forwarders, use root servers instead")
|
||||
dns_group.add_option("--reverse-zone", dest="reverse_zones",
|
||||
help="The reverse DNS zone to use. This option can be used multiple times",
|
||||
action="append", default=[], metavar="REVERSE_ZONE")
|
||||
dns_group.add_option("--no-reverse", dest="no_reverse", action="store_true",
|
||||
default=False, help="Do not create reverse DNS zone")
|
||||
dns_group.add_option("--no-dnssec-validation", dest="no_dnssec_validation", action="store_true",
|
||||
default=False, help="Disable DNSSEC validation")
|
||||
dns_group.add_option("--zonemgr", action="callback", callback=bindinstance.zonemgr_callback,
|
||||
type="string",
|
||||
help="DNS zone manager e-mail address. Defaults to hostmaster@DOMAIN")
|
||||
dns_group.add_option("--no-host-dns", dest="no_host_dns", action="store_true",
|
||||
default=False,
|
||||
help="Do not use DNS for hostname lookup during installation")
|
||||
dns_group.add_option("--no-dns-sshfp", dest="create_sshfp", default=True, action="store_false",
|
||||
help="Do not automatically create DNS SSHFP records")
|
||||
parser.add_option_group(dns_group)
|
||||
|
||||
uninstall_group = OptionGroup(parser, "uninstall options")
|
||||
uninstall_group.add_option("", "--uninstall", dest="uninstall", action="store_true",
|
||||
default=False, help="uninstall an existing installation. The uninstall can " \
|
||||
"be run with --unattended option")
|
||||
parser.add_option_group(uninstall_group)
|
||||
|
||||
options, args = parser.parse_args()
|
||||
safe_options = parser.get_safe_opts(options)
|
||||
|
||||
if options.dm_password is not None:
|
||||
try:
|
||||
validate_dm_password(options.dm_password)
|
||||
except ValueError, e:
|
||||
parser.error("DS admin password: " + str(e))
|
||||
if options.admin_password is not None:
|
||||
try:
|
||||
validate_admin_password(options.admin_password)
|
||||
except ValueError, e:
|
||||
parser.error("Admin user password: " + str(e))
|
||||
|
||||
if options.domain_name is not None:
|
||||
try:
|
||||
validate_domain_name(options.domain_name)
|
||||
except ValueError, e:
|
||||
parser.error("invalid domain: " + unicode(e))
|
||||
|
||||
# Check that Domain Level is within the allowed range
|
||||
if not options.uninstall:
|
||||
if options.domainlevel < constants.MIN_DOMAIN_LEVEL:
|
||||
parser.error("Domain Level cannot be lower than {0}"
|
||||
.format(constants.MIN_DOMAIN_LEVEL))
|
||||
elif options.domainlevel > constants.MAX_DOMAIN_LEVEL:
|
||||
parser.error("Domain Level cannot be higher than {0}"
|
||||
.format(constants.MAX_DOMAIN_LEVEL))
|
||||
|
||||
if not options.setup_dns:
|
||||
if options.forwarders:
|
||||
parser.error("You cannot specify a --forwarder option without the --setup-dns option")
|
||||
if options.no_forwarders:
|
||||
parser.error("You cannot specify a --no-forwarders option without the --setup-dns option")
|
||||
if options.reverse_zones:
|
||||
parser.error("You cannot specify a --reverse-zone option without the --setup-dns option")
|
||||
if options.no_reverse:
|
||||
parser.error("You cannot specify a --no-reverse option without the --setup-dns option")
|
||||
if options.no_dnssec_validation:
|
||||
parser.error("You cannot specify a --no-dnssec-validation option without the --setup-dns option")
|
||||
elif options.forwarders and options.no_forwarders:
|
||||
parser.error("You cannot specify a --forwarder option together with --no-forwarders")
|
||||
elif options.reverse_zones and options.no_reverse:
|
||||
parser.error("You cannot specify a --reverse-zone option together with --no-reverse")
|
||||
|
||||
if options.uninstall:
|
||||
if (options.realm_name or
|
||||
options.admin_password or options.master_password):
|
||||
parser.error("In uninstall mode, -a, -r and -P options are not allowed")
|
||||
elif options.unattended:
|
||||
if (not options.realm_name or
|
||||
not options.dm_password or not options.admin_password):
|
||||
parser.error("In unattended mode you need to provide at least -r, -p and -a options")
|
||||
if options.setup_dns:
|
||||
if not options.forwarders and not options.no_forwarders:
|
||||
parser.error("You must specify at least one --forwarder option or --no-forwarders option")
|
||||
|
||||
# If any of the key file options are selected, all are required.
|
||||
cert_file_req = (options.dirsrv_cert_files, options.http_cert_files)
|
||||
cert_file_opt = (options.pkinit_cert_files,)
|
||||
if any(cert_file_req + cert_file_opt) and not all(cert_file_req):
|
||||
parser.error("--dirsrv-cert-file and --http-cert-file are required if "
|
||||
"any key file options are used.")
|
||||
|
||||
if options.unattended:
|
||||
if options.dirsrv_cert_files and options.dirsrv_pin is None:
|
||||
parser.error(
|
||||
"You must specify --dirsrv-pin with --dirsrv-cert-file")
|
||||
if options.http_cert_files and options.http_pin is None:
|
||||
parser.error(
|
||||
"You must specify --http-pin with --http-cert-file")
|
||||
if options.pkinit_cert_files and options.pkinit_pin is None:
|
||||
parser.error(
|
||||
"You must specify --pkinit-pin with --pkinit-cert-file")
|
||||
|
||||
if options.external_cert_files and options.dirsrv_cert_files:
|
||||
parser.error("Service certificate file options cannot be used with "
|
||||
"the external CA options.")
|
||||
|
||||
if options.external_ca:
|
||||
if options.external_cert_files:
|
||||
parser.error("You cannot specify --external-cert-file "
|
||||
"together with --external-ca")
|
||||
if options.dirsrv_cert_files:
|
||||
parser.error("You cannot specify service certificate file options "
|
||||
"together with --external-ca")
|
||||
|
||||
if options.external_ca_type and not options.external_ca:
|
||||
parser.error(
|
||||
"You cannot specify --external-ca-type without --external-ca")
|
||||
|
||||
if (options.external_cert_files and
|
||||
any(not os.path.isabs(path) for path in options.external_cert_files)):
|
||||
parser.error("--external-cert-file must use an absolute path")
|
||||
|
||||
if options.idmax == 0:
|
||||
options.idmax = int(options.idstart) + 200000 - 1
|
||||
|
||||
if options.idmax < options.idstart:
|
||||
parser.error("idmax (%u) cannot be smaller than idstart (%u)" %
|
||||
(options.idmax, options.idstart))
|
||||
|
||||
#Automatically disable pkinit w/ dogtag until that is supported
|
||||
options.setup_pkinit = False
|
||||
|
||||
options.dnssec_master = False
|
||||
|
||||
return safe_options, options
|
||||
|
||||
|
||||
def signal_handler(signum, frame):
|
||||
raise KeyboardInterrupt
|
||||
|
||||
|
||||
def main():
|
||||
safe_options, options = parse_options()
|
||||
|
||||
if os.getegid() != 0:
|
||||
sys.exit("Must be root to set up server")
|
||||
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
if not options.uninstall:
|
||||
standard_logging_setup(paths.IPASERVER_INSTALL_LOG,
|
||||
debug=options.debug)
|
||||
else:
|
||||
standard_logging_setup(paths.IPASERVER_UNINSTALL_LOG,
|
||||
debug=options.debug)
|
||||
|
||||
root_logger.debug('%s was invoked with options: %s' % (sys.argv[0], safe_options))
|
||||
root_logger.debug("missing options might be asked for interactively later\n")
|
||||
root_logger.debug('IPA version %s' % version.VENDOR_VERSION)
|
||||
|
||||
if not options.uninstall:
|
||||
server.install_check(options)
|
||||
server.install(options)
|
||||
else:
|
||||
server.uninstall_check(options)
|
||||
server.uninstall(options)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# FIXME: Common option parsing, logging setup, etc should be factored
|
||||
# out from all install scripts
|
||||
safe_options, options = parse_options()
|
||||
if options.uninstall:
|
||||
log_file_name = paths.IPASERVER_UNINSTALL_LOG
|
||||
else:
|
||||
log_file_name = paths.IPASERVER_INSTALL_LOG
|
||||
|
||||
installutils.run_script(main, log_file_name=log_file_name,
|
||||
operation_name='ipa-server-install')
|
||||
ServerInstall.run_cli()
|
||||
|
@ -2,9 +2,8 @@
|
||||
# Copyright (C) 2015 FreeIPA Contributors see COPYING for license
|
||||
#
|
||||
|
||||
from .install import install_check, install, uninstall_check, uninstall
|
||||
from .install import Server
|
||||
|
||||
from .replicainstall import install_check as replica_install_check
|
||||
from .replicainstall import install as replica_install
|
||||
from .upgrade import upgrade_check, upgrade
|
||||
|
||||
from .install import validate_dm_password, validate_admin_password
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -10,6 +10,7 @@ import os
|
||||
import shutil
|
||||
import socket
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from ipapython import dogtag, ipautil, sysrestore
|
||||
from ipapython.dn import DN
|
||||
@ -25,8 +26,6 @@ from ipaserver.install import (
|
||||
from ipaserver.install.installutils import create_replica_config
|
||||
from ipaserver.install.replication import (
|
||||
ReplicationManager, replica_conn_check)
|
||||
from ipaserver.install.server.install import (
|
||||
init_private_ccache, destroy_private_ccache)
|
||||
|
||||
DIRMAN_DN = DN(('cn', 'directory manager'))
|
||||
REPLICA_INFO_TOP_DIR = None
|
||||
@ -286,6 +285,31 @@ def remove_replica_info_dir():
|
||||
pass
|
||||
|
||||
|
||||
def init_private_ccache():
|
||||
global original_ccache
|
||||
global temp_ccache
|
||||
|
||||
(desc, temp_ccache) = tempfile.mkstemp(prefix='krbcc')
|
||||
os.close(desc)
|
||||
|
||||
original_ccache = os.environ.get('KRB5CCNAME')
|
||||
|
||||
os.environ['KRB5CCNAME'] = temp_ccache
|
||||
|
||||
|
||||
def destroy_private_ccache():
|
||||
global original_ccache
|
||||
global temp_ccache
|
||||
|
||||
if original_ccache is not None:
|
||||
os.environ['KRB5CCNAME'] = original_ccache
|
||||
else:
|
||||
os.environ.pop('KRB5CCNAME', None)
|
||||
|
||||
if os.path.exists(temp_ccache):
|
||||
os.remove(temp_ccache)
|
||||
|
||||
|
||||
def common_cleanup(func):
|
||||
def decorated(*args, **kwargs):
|
||||
try:
|
||||
|
Loading…
Reference in New Issue
Block a user