Import Upstream version 4.12.4
This commit is contained in:
@@ -9,6 +9,7 @@ import logging
|
||||
|
||||
import dns.exception as dnsexception
|
||||
import dns.name as dnsname
|
||||
import itertools
|
||||
import os
|
||||
import shutil
|
||||
import socket
|
||||
@@ -22,8 +23,8 @@ import six
|
||||
|
||||
from ipaclient.install.client import check_ldap_conf, sssd_enable_ifp
|
||||
import ipaclient.install.timeconf
|
||||
from ipalib.install import certstore, sysrestore
|
||||
from ipalib.install.kinit import kinit_keytab
|
||||
from ipalib.install import sysrestore
|
||||
from ipalib.kinit import kinit_keytab
|
||||
from ipapython import ipaldap, ipautil
|
||||
from ipapython.dn import DN
|
||||
from ipapython.dnsutil import DNSResolver
|
||||
@@ -32,14 +33,17 @@ from ipapython.ipachangeconf import IPAChangeConf
|
||||
from ipaplatform import services
|
||||
from ipaplatform.tasks import tasks
|
||||
from ipaplatform.paths import paths
|
||||
from ipalib import api, constants, create_api, errors, rpc, x509
|
||||
from ipalib import api, constants, create_api, errors, rpc
|
||||
from ipalib.config import Env
|
||||
from ipalib.facts import is_ipa_configured, is_ipa_client_configured
|
||||
from ipalib.util import no_matching_interface_for_ip_address_warning
|
||||
from ipaclient.install.client import configure_krb5_conf, purge_host_keytab
|
||||
from ipaserver.install.dogtaginstance import INTERNAL_TOKEN
|
||||
from ipaserver.install import (
|
||||
adtrust, bindinstance, ca, dns, dsinstance, httpinstance,
|
||||
installutils, kra, krbinstance, otpdinstance, custodiainstance, service)
|
||||
adtrust, bindinstance, ca, cainstance, dns, dsinstance, httpinstance,
|
||||
installutils, kra, krainstance, krbinstance, otpdinstance,
|
||||
custodiainstance, service,)
|
||||
from ipaserver.install import certs
|
||||
from ipaserver.install.installutils import (
|
||||
ReplicaConfig, load_pkcs12, validate_mask)
|
||||
from ipaserver.install.replication import (
|
||||
@@ -132,24 +136,6 @@ def install_krb(config, setup_pkinit=False, pkcs12_info=None, fstore=None):
|
||||
return krb
|
||||
|
||||
|
||||
def install_ca_cert(ldap, base_dn, realm, cafile, destfile=paths.IPA_CA_CRT):
|
||||
try:
|
||||
try:
|
||||
certs = certstore.get_ca_certs(ldap, base_dn, realm, False)
|
||||
except errors.NotFound:
|
||||
try:
|
||||
shutil.copy(cafile, destfile)
|
||||
except shutil.Error:
|
||||
# cafile == IPA_CA_CRT
|
||||
pass
|
||||
else:
|
||||
certs = [c[0] for c in certs if c[2] is not False]
|
||||
x509.write_certificate_list(certs, destfile, mode=0o644)
|
||||
except Exception as e:
|
||||
raise ScriptError("error copying files: " + str(e))
|
||||
return destfile
|
||||
|
||||
|
||||
def install_http(config, auto_redirect, ca_is_configured, ca_file,
|
||||
pkcs12_info=None, fstore=None):
|
||||
# if we have a pkcs12 file, create the cert db from
|
||||
@@ -623,7 +609,7 @@ def check_domain_level_is_supported(current):
|
||||
above_upper_bound = current > constants.MAX_DOMAIN_LEVEL
|
||||
|
||||
if under_lower_bound or above_upper_bound:
|
||||
message = ("This version of FreeIPA does not support "
|
||||
message = ("This version of IPA does not support "
|
||||
"the Domain Level which is currently set for "
|
||||
"this domain. The Domain Level needs to be "
|
||||
"raised before installing a replica with "
|
||||
@@ -720,6 +706,8 @@ def ensure_enrolled(installer):
|
||||
args.append("--no-sshd")
|
||||
if installer.mkhomedir:
|
||||
args.append("--mkhomedir")
|
||||
if installer.subid:
|
||||
args.append("--subid")
|
||||
if installer.force_join:
|
||||
args.append("--force-join")
|
||||
if installer.no_ntp:
|
||||
@@ -770,6 +758,101 @@ def promotion_check_ipa_domain(master_ldap_conn, basedn):
|
||||
))
|
||||
|
||||
|
||||
def promotion_check_host_principal_auth_ind(conn, hostdn):
|
||||
entry = conn.get_entry(hostdn, ['krbprincipalauthind'])
|
||||
if 'krbprincipalauthind' in entry:
|
||||
raise RuntimeError(
|
||||
"Client cannot be promoted to a replica if the host principal "
|
||||
"has an authentication indicator set."
|
||||
)
|
||||
|
||||
|
||||
def clean_up_hsm_nicknames(api):
|
||||
"""Ensure that all of the nicknames on the token are visible on
|
||||
the NSS softoken.
|
||||
"""
|
||||
# Hardcode the token names. NSS tooling does not provide a
|
||||
# public way to determine it other than scraping modutil
|
||||
# output.
|
||||
if tasks.is_fips_enabled():
|
||||
dbname = 'NSS FIPS 140-2 Certificate DB'
|
||||
else:
|
||||
dbname = 'NSS Certificate DB'
|
||||
|
||||
api.Backend.ldap2.connect()
|
||||
(token_name, _unused) = ca.lookup_hsm_configuration(api)
|
||||
api.Backend.ldap2.disconnect()
|
||||
if not token_name:
|
||||
return
|
||||
|
||||
cai = cainstance.CAInstance(api.env.realm, host_name=api.env.host)
|
||||
dogtag_reqs = cai.tracking_reqs.items()
|
||||
kra = krainstance.KRAInstance(api.env.realm)
|
||||
if kra.is_installed():
|
||||
dogtag_reqs = itertools.chain(dogtag_reqs,
|
||||
kra.tracking_reqs.items())
|
||||
|
||||
try:
|
||||
tmpdir = tempfile.mkdtemp(prefix="tmp-")
|
||||
pwd_file = os.path.join(tmpdir, "pwd_file")
|
||||
with open(pwd_file, "w") as pwd:
|
||||
with open(paths.PKI_TOMCAT_PASSWORD_CONF, 'r') as fd:
|
||||
for line in fd:
|
||||
(token, pin) = line.split('=', 1)
|
||||
if token.startswith('hardware-'):
|
||||
token = token.replace('hardware-', '')
|
||||
pwd.write(f'{token}:{pin}')
|
||||
elif token == INTERNAL_TOKEN:
|
||||
pwd.write(f'{dbname}:{pin}')
|
||||
pwd.flush()
|
||||
db = certs.CertDB(api.env.realm,
|
||||
nssdir=paths.PKI_TOMCAT_ALIAS_DIR,
|
||||
pwd_file=pwd_file)
|
||||
for (nickname, _unused) in dogtag_reqs:
|
||||
try:
|
||||
if nickname in (
|
||||
'caSigningCert cert-pki-ca',
|
||||
'Server-Cert cert-pki-ca'
|
||||
):
|
||||
continue
|
||||
if nickname in (
|
||||
'auditSigningCert cert-pki-ca',
|
||||
'auditSigningCert cert-pki-kra',
|
||||
):
|
||||
trust = ',,P'
|
||||
else:
|
||||
trust = ',,'
|
||||
db.run_certutil(['-M',
|
||||
'-n', f"{token_name}:{nickname}",
|
||||
'-t', trust])
|
||||
except CalledProcessError as e:
|
||||
logger.debug("Modifying trust on %s failed: %s",
|
||||
nickname, e)
|
||||
|
||||
if db.has_nickname('Directory Server CA certificate'):
|
||||
db.run_certutil(['--rename',
|
||||
'-n', 'Directory Server CA certificate',
|
||||
'--new-n', 'caSigningCert cert-pki-ca'],
|
||||
raiseonerr=False)
|
||||
finally:
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
||||
def remote_connection(config):
|
||||
logger.debug("Creating LDAP connection to %s", config.master_host_name)
|
||||
ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name)
|
||||
xmlrpc_uri = 'https://{}/ipa/xml'.format(
|
||||
ipautil.format_netloc(config.master_host_name))
|
||||
remote_api = create_api(mode=None)
|
||||
remote_api.bootstrap(in_server=True,
|
||||
context='installer',
|
||||
confdir=paths.ETC_IPA,
|
||||
ldap_uri=ldapuri,
|
||||
xmlrpc_uri=xmlrpc_uri)
|
||||
remote_api.finalize()
|
||||
return remote_api
|
||||
|
||||
|
||||
@common_cleanup
|
||||
@preserve_enrollment_state
|
||||
def promote_check(installer):
|
||||
@@ -786,7 +869,8 @@ def promote_check(installer):
|
||||
raise ScriptError("--setup-ca and --*-cert-file options are "
|
||||
"mutually exclusive")
|
||||
|
||||
if not is_ipa_client_configured(on_master=True):
|
||||
ipa_client_installed = is_ipa_client_configured(on_master=True)
|
||||
if not ipa_client_installed:
|
||||
# One-step replica installation
|
||||
if options.password and options.admin_password:
|
||||
raise ScriptError("--password and --admin-password options are "
|
||||
@@ -814,14 +898,12 @@ def promote_check(installer):
|
||||
env._bootstrap(context='installer', confdir=paths.ETC_IPA, log=None)
|
||||
env._finalize_core(**dict(constants.DEFAULT_CONFIG))
|
||||
|
||||
# pylint: disable=no-member
|
||||
xmlrpc_uri = 'https://{}/ipa/xml'.format(ipautil.format_netloc(env.host))
|
||||
api.bootstrap(in_server=True,
|
||||
context='installer',
|
||||
confdir=paths.ETC_IPA,
|
||||
ldap_uri=ipaldap.realm_to_ldapi_uri(env.realm),
|
||||
xmlrpc_uri=xmlrpc_uri)
|
||||
# pylint: enable=no-member
|
||||
api.finalize()
|
||||
|
||||
config = ReplicaConfig()
|
||||
@@ -921,26 +1003,23 @@ def promote_check(installer):
|
||||
installutils.verify_fqdn(config.master_host_name, options.no_host_dns,
|
||||
local_hostname=not container_environment)
|
||||
|
||||
if config.host_name.lower() == config.domain_name.lower():
|
||||
raise ScriptError("hostname cannot be the same as the domain name")
|
||||
|
||||
ccache = os.environ['KRB5CCNAME']
|
||||
kinit_keytab('host/{env.host}@{env.realm}'.format(env=api.env),
|
||||
paths.KRB5_KEYTAB,
|
||||
ccache)
|
||||
|
||||
cafile = paths.IPA_CA_CRT
|
||||
if not os.path.isfile(cafile):
|
||||
raise RuntimeError("CA cert file is not available! Please reinstall"
|
||||
"the client and try again.")
|
||||
if ipa_client_installed:
|
||||
# host was already an IPA client, refresh client cert stores to
|
||||
# ensure we have up to date CA certs.
|
||||
try:
|
||||
ipautil.run([paths.IPA_CERTUPDATE])
|
||||
except ipautil.CalledProcessError:
|
||||
raise RuntimeError("ipa-certupdate failed to refresh certs.")
|
||||
|
||||
ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name)
|
||||
xmlrpc_uri = 'https://{}/ipa/xml'.format(
|
||||
ipautil.format_netloc(config.master_host_name))
|
||||
remote_api = create_api(mode=None)
|
||||
remote_api.bootstrap(in_server=True,
|
||||
context='installer',
|
||||
confdir=paths.ETC_IPA,
|
||||
ldap_uri=ldapuri,
|
||||
xmlrpc_uri=xmlrpc_uri)
|
||||
remote_api.finalize()
|
||||
remote_api = remote_connection(config)
|
||||
installer._remote_api = remote_api
|
||||
|
||||
with rpc_client(remote_api) as client:
|
||||
@@ -956,6 +1035,10 @@ def promote_check(installer):
|
||||
config.master_host_name, None)
|
||||
|
||||
promotion_check_ipa_domain(conn, remote_api.env.basedn)
|
||||
hostdn = DN(('fqdn', api.env.host),
|
||||
api.env.container_host,
|
||||
api.env.basedn)
|
||||
promotion_check_host_principal_auth_ind(conn, hostdn)
|
||||
|
||||
# Make sure that domain fulfills minimal domain level
|
||||
# requirement
|
||||
@@ -981,7 +1064,7 @@ def promote_check(installer):
|
||||
raise errors.ACIError(info="Not authorized")
|
||||
|
||||
if installer._ccache is None:
|
||||
del os.environ['KRB5CCNAME']
|
||||
os.environ.pop('KRB5CCNAME', None)
|
||||
else:
|
||||
os.environ['KRB5CCNAME'] = installer._ccache
|
||||
|
||||
@@ -1012,8 +1095,8 @@ def promote_check(installer):
|
||||
if replman.get_replication_agreement(config.host_name):
|
||||
msg = ("A replication agreement for this host already exists. "
|
||||
"It needs to be removed.\n"
|
||||
"Run this command:\n"
|
||||
" %% ipa-replica-manage del {host} --force"
|
||||
"Run this command on any working server:\n"
|
||||
" %% ipa server-del {host} --force"
|
||||
.format(host=config.host_name))
|
||||
raise ScriptError(msg, rval=3)
|
||||
|
||||
@@ -1066,8 +1149,16 @@ def promote_check(installer):
|
||||
'CA', conn, preferred_cas
|
||||
)
|
||||
if ca_host is not None:
|
||||
if options.setup_ca and config.master_host_name != ca_host:
|
||||
conn.disconnect()
|
||||
del remote_api
|
||||
config.master_host_name = ca_host
|
||||
remote_api = remote_connection(config)
|
||||
installer._remote_api = remote_api
|
||||
conn = remote_api.Backend.ldap2
|
||||
conn.connect(ccache=installer._ccache)
|
||||
config.ca_host_name = ca_host
|
||||
ca_enabled = True
|
||||
ca_enabled = True # There is a CA somewhere in the topology
|
||||
if options.dirsrv_cert_files:
|
||||
logger.error("Certificates could not be provided when "
|
||||
"CA is present on some master.")
|
||||
@@ -1105,8 +1196,18 @@ def promote_check(installer):
|
||||
'KRA', conn, preferred_kras
|
||||
)
|
||||
if kra_host is not None:
|
||||
if options.setup_kra and config.master_host_name != kra_host:
|
||||
conn.disconnect()
|
||||
del remote_api
|
||||
config.master_host_name = kra_host
|
||||
remote_api = remote_connection(config)
|
||||
installer._remote_api = remote_api
|
||||
conn = remote_api.Backend.ldap2
|
||||
conn.connect(ccache=installer._ccache)
|
||||
config.kra_host_name = kra_host
|
||||
kra_enabled = True
|
||||
if options.setup_kra: # only reset ca_host if KRA is requested
|
||||
config.ca_host_name = kra_host
|
||||
kra_enabled = True # There is a KRA somewhere in the topology
|
||||
if options.setup_kra and options.server and \
|
||||
kra_host != options.server:
|
||||
# Installer was provided with a specific master
|
||||
@@ -1145,8 +1246,9 @@ def promote_check(installer):
|
||||
# check addresses here, dns module is doing own check
|
||||
no_matching_interface_for_ip_address_warning(config.ips)
|
||||
|
||||
if options.setup_adtrust:
|
||||
adtrust.install_check(False, options, remote_api)
|
||||
# Always call adtrust.install_check
|
||||
# if --setup-adtrust is not specified, only the SID part is executed
|
||||
adtrust.install_check(False, options, remote_api)
|
||||
|
||||
except errors.ACIError:
|
||||
logger.debug("%s", traceback.format_exc())
|
||||
@@ -1170,7 +1272,7 @@ def promote_check(installer):
|
||||
if add_to_ipaservers:
|
||||
# use user's credentials when the server host is not ipaservers
|
||||
if installer._ccache is None:
|
||||
del os.environ['KRB5CCNAME']
|
||||
os.environ.pop('KRB5CCNAME', None)
|
||||
else:
|
||||
os.environ['KRB5CCNAME'] = installer._ccache
|
||||
|
||||
@@ -1179,14 +1281,14 @@ def promote_check(installer):
|
||||
config.master_host_name, config.host_name, config.realm_name,
|
||||
options.setup_ca, 389,
|
||||
options.admin_password, principal=options.principal,
|
||||
ca_cert_file=cafile)
|
||||
ca_cert_file=paths.IPA_CA_CRT)
|
||||
finally:
|
||||
if add_to_ipaservers:
|
||||
os.environ['KRB5CCNAME'] = ccache
|
||||
|
||||
installer._ca_enabled = ca_enabled
|
||||
installer._kra_enabled = kra_enabled
|
||||
installer._ca_file = cafile
|
||||
installer._ca_file = paths.IPA_CA_CRT
|
||||
installer._fstore = fstore
|
||||
installer._sstore = sstore
|
||||
installer._config = config
|
||||
@@ -1207,7 +1309,6 @@ def install(installer):
|
||||
fstore = installer._fstore
|
||||
sstore = installer._sstore
|
||||
config = installer._config
|
||||
cafile = installer._ca_file
|
||||
dirsrv_pkcs12_info = installer._dirsrv_pkcs12_info
|
||||
http_pkcs12_info = installer._http_pkcs12_info
|
||||
pkinit_pkcs12_info = installer._pkinit_pkcs12_info
|
||||
@@ -1222,6 +1323,24 @@ def install(installer):
|
||||
if tasks.configure_pkcs11_modules(fstore):
|
||||
print("Disabled p11-kit-proxy")
|
||||
|
||||
_hostname, _sep, host_domain = config.host_name.partition('.')
|
||||
fstore.backup_file(paths.KRB5_CONF)
|
||||
|
||||
# Write a new krb5.conf in case any values changed finding the
|
||||
# right server to configure against (for CA, KRA).
|
||||
logger.debug("Installing against server %s", config.master_host_name)
|
||||
configure_krb5_conf(
|
||||
cli_realm=api.env.realm,
|
||||
cli_domain=api.env.domain,
|
||||
cli_server=[config.master_host_name],
|
||||
cli_kdc=[config.master_host_name],
|
||||
dnsok=False,
|
||||
filename=paths.KRB5_CONF,
|
||||
client_domain=host_domain,
|
||||
client_hostname=config.host_name,
|
||||
configure_sssd=False
|
||||
)
|
||||
|
||||
if installer._add_to_ipaservers:
|
||||
try:
|
||||
conn.connect(ccache=installer._ccache)
|
||||
@@ -1241,18 +1360,10 @@ def install(installer):
|
||||
|
||||
try:
|
||||
conn.connect(ccache=ccache)
|
||||
|
||||
# Update and istall updated CA file
|
||||
cafile = install_ca_cert(conn, api.env.basedn, api.env.realm, cafile)
|
||||
install_ca_cert(conn, api.env.basedn, api.env.realm, cafile,
|
||||
destfile=paths.KDC_CA_BUNDLE_PEM)
|
||||
install_ca_cert(conn, api.env.basedn, api.env.realm, cafile,
|
||||
destfile=paths.CA_BUNDLE_PEM)
|
||||
|
||||
# Configure dirsrv
|
||||
ds = install_replica_ds(config, options, ca_enabled,
|
||||
remote_api,
|
||||
ca_file=cafile,
|
||||
ca_file=paths.IPA_CA_CRT,
|
||||
pkcs12_info=dirsrv_pkcs12_info,
|
||||
fstore=fstore)
|
||||
|
||||
@@ -1303,7 +1414,7 @@ def install(installer):
|
||||
auto_redirect=not options.no_ui_redirect,
|
||||
pkcs12_info=http_pkcs12_info,
|
||||
ca_is_configured=ca_enabled,
|
||||
ca_file=cafile,
|
||||
ca_file=paths.IPA_CA_CRT,
|
||||
fstore=fstore)
|
||||
|
||||
# Need to point back to ourself after the cert for HTTP is obtained
|
||||
@@ -1313,10 +1424,10 @@ def install(installer):
|
||||
otpd.create_instance('OTPD', config.host_name,
|
||||
ipautil.realm_to_suffix(config.realm_name))
|
||||
|
||||
if kra_enabled:
|
||||
if options.setup_kra and kra_enabled:
|
||||
# A KRA peer always provides a CA, too.
|
||||
mode = custodiainstance.CustodiaModes.KRA_PEER
|
||||
elif ca_enabled:
|
||||
elif options.setup_ca and ca_enabled:
|
||||
mode = custodiainstance.CustodiaModes.CA_PEER
|
||||
else:
|
||||
mode = custodiainstance.CustodiaModes.MASTER_PEER
|
||||
@@ -1328,6 +1439,8 @@ def install(installer):
|
||||
options.domain_name = config.domain_name
|
||||
options.host_name = config.host_name
|
||||
options.dm_password = config.dirman_password
|
||||
# Always call ca.install() if there is a CA in the topology
|
||||
# to ensure the RA agent is present.
|
||||
ca.install(False, config, options, custodia=custodia)
|
||||
|
||||
# configure PKINIT now that all required services are in place
|
||||
@@ -1340,6 +1453,7 @@ def install(installer):
|
||||
ds.finalize_replica_config()
|
||||
|
||||
if kra_enabled:
|
||||
# The KRA installer checks for itself the status of setup_kra
|
||||
kra.install(api, config, options, custodia=custodia)
|
||||
|
||||
service.print_msg("Restarting the KDC")
|
||||
@@ -1352,8 +1466,9 @@ def install(installer):
|
||||
if options.setup_dns:
|
||||
dns.install(False, True, options, api)
|
||||
|
||||
if options.setup_adtrust:
|
||||
adtrust.install(False, options, fstore, api)
|
||||
# Always call adtrust.install
|
||||
# if --setup-adtrust is not specified, only the SID part is executed
|
||||
adtrust.install(False, options, fstore, api)
|
||||
|
||||
if options.hidden_replica:
|
||||
# Set services to hidden
|
||||
@@ -1388,6 +1503,9 @@ def install(installer):
|
||||
'''.format(ca_servers[0]))
|
||||
print(msg, file=sys.stderr)
|
||||
|
||||
if options.setup_ca:
|
||||
clean_up_hsm_nicknames(api)
|
||||
|
||||
|
||||
def init(installer):
|
||||
installer.unattended = not installer.interactive
|
||||
|
||||
Reference in New Issue
Block a user