Import Upstream version 4.12.4

This commit is contained in:
geos_one
2025-08-12 22:28:56 +02:00
parent 03a8170b15
commit 9181ee2487
1629 changed files with 874094 additions and 554378 deletions

View File

@@ -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