mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-24 16:10:02 -06:00
efded2264f
hexlify returns bytes and needs to be casted to string before printing it out. Related: https://pagure.io/freeipa/issue/4985 Signed-off-by: Tomas Krizek <tkrizek@redhat.com> Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
178 lines
6.6 KiB
Python
Executable File
178 lines
6.6 KiB
Python
Executable File
#!/usr/bin/python2
|
|
#
|
|
# Copyright (C) 2014 FreeIPA Contributors see COPYING for license
|
|
#
|
|
"""
|
|
Download keys from LDAP to local HSM.
|
|
|
|
This program should be run only on replicas, not on DNSSEC masters.
|
|
"""
|
|
|
|
from gssapi.exceptions import GSSError
|
|
import logging
|
|
import os
|
|
import sys
|
|
|
|
import ipalib
|
|
from ipalib.constants import SOFTHSM_DNSSEC_TOKEN_LABEL
|
|
from ipalib.install.kinit import kinit_keytab
|
|
from ipapython.dn import DN
|
|
from ipapython.ipa_log_manager import standard_logging_setup
|
|
from ipapython import ipaldap
|
|
from ipaplatform.paths import paths
|
|
from ipaserver.dnssec.abshsm import (sync_pkcs11_metadata,
|
|
ldap2p11helper_api_params,
|
|
wrappingmech_name2id)
|
|
from ipaserver.dnssec.ldapkeydb import LdapKeyDB, str_hexlify
|
|
from ipaserver.dnssec.localhsm import LocalHSM
|
|
|
|
logger = logging.getLogger(os.path.basename(__file__))
|
|
|
|
DAEMONNAME = 'ipa-dnskeysyncd'
|
|
PRINCIPAL = None # not initialized yet
|
|
WORKDIR = '/tmp'
|
|
|
|
def hex_set(s):
|
|
out = set()
|
|
for i in s:
|
|
out.add("0x%s" % str_hexlify(i))
|
|
return out
|
|
|
|
def update_metadata_set(source_set, target_set):
|
|
"""sync metadata from source key set to target key set
|
|
|
|
Keys not present in both sets are left intact."""
|
|
name = 'sync_metadata'
|
|
matching_keys = set(source_set.keys()).intersection(set(target_set.keys()))
|
|
logger.info("%s: keys in local HSM & LDAP: %s",
|
|
name, hex_set(matching_keys))
|
|
for key_id in matching_keys:
|
|
sync_pkcs11_metadata(name, source_set[key_id], target_set[key_id])
|
|
|
|
|
|
def find_unwrapping_key(localhsm, wrapping_key_uri):
|
|
wrap_keys = localhsm.find_keys(uri=wrapping_key_uri)
|
|
# find usable unwrapping key with matching ID
|
|
for key_id in wrap_keys.keys():
|
|
unwrap_keys = localhsm.find_keys(id=key_id, cka_unwrap=True)
|
|
if len(unwrap_keys) > 0:
|
|
return unwrap_keys.popitem()[1]
|
|
|
|
def ldap2replica_master_keys_sync(ldapkeydb, localhsm):
|
|
## LDAP -> replica master key synchronization
|
|
# import new master keys from LDAP
|
|
new_keys = set(ldapkeydb.master_keys.keys()) \
|
|
- set(localhsm.master_keys.keys())
|
|
logger.debug("master keys in local HSM: %s",
|
|
hex_set(localhsm.master_keys.keys()))
|
|
logger.debug("master keys in LDAP HSM: %s",
|
|
hex_set(ldapkeydb.master_keys.keys()))
|
|
logger.debug("new master keys in LDAP HSM: %s",
|
|
hex_set(new_keys))
|
|
for mkey_id in new_keys:
|
|
mkey_ldap = ldapkeydb.master_keys[mkey_id]
|
|
assert mkey_ldap.wrapped_entries, ("Master key 0x%s in LDAP is " \
|
|
"missing key material referenced by ipaSecretKeyRefObject " \
|
|
"attribute") % str_hexlify(mkey_id)
|
|
for wrapped_ldap in mkey_ldap.wrapped_entries:
|
|
unwrapping_key = find_unwrapping_key(
|
|
localhsm, wrapped_ldap.single_value['ipaWrappingKey'])
|
|
if unwrapping_key:
|
|
break
|
|
|
|
# TODO: Could it happen in normal cases?
|
|
assert unwrapping_key is not None, ("Local HSM does not contain " \
|
|
"suitable unwrapping key for master key 0x%s") % \
|
|
str_hexlify(mkey_id)
|
|
|
|
params = ldap2p11helper_api_params(mkey_ldap)
|
|
params['data'] = wrapped_ldap.single_value['ipaSecretKey']
|
|
params['unwrapping_key'] = unwrapping_key.handle
|
|
params['wrapping_mech'] = wrappingmech_name2id[wrapped_ldap.single_value['ipaWrappingMech']]
|
|
logger.debug('Importing new master key: 0x%s %s',
|
|
str_hexlify(mkey_id), params)
|
|
localhsm.p11.import_wrapped_secret_key(**params)
|
|
|
|
# synchronize metadata about master keys in LDAP
|
|
update_metadata_set(ldapkeydb.master_keys, localhsm.master_keys)
|
|
|
|
def ldap2replica_zone_keys_sync(ldapkeydb, localhsm):
|
|
## LDAP -> replica zone key synchronization
|
|
# import new zone keys from LDAP
|
|
new_keys = set(ldapkeydb.zone_keypairs.keys()) \
|
|
- set(localhsm.zone_privkeys.keys())
|
|
|
|
logger.debug("zone keys in local HSM: %s",
|
|
hex_set(localhsm.master_keys.keys()))
|
|
logger.debug("zone keys in LDAP HSM: %s",
|
|
hex_set(ldapkeydb.master_keys.keys()))
|
|
logger.debug("new zone keys in LDAP HSM: %s",
|
|
hex_set(new_keys))
|
|
for zkey_id in new_keys:
|
|
zkey_ldap = ldapkeydb.zone_keypairs[zkey_id]
|
|
logger.debug('Looking for unwrapping key "%s" for zone key 0x%s',
|
|
zkey_ldap['ipaWrappingKey'], str_hexlify(zkey_id))
|
|
unwrapping_key = find_unwrapping_key(
|
|
localhsm, zkey_ldap['ipaWrappingKey'])
|
|
assert unwrapping_key is not None, \
|
|
"Local HSM does not contain suitable unwrapping key for ' \
|
|
'zone key 0x%s" % str_hexlify(zkey_id)
|
|
|
|
logger.debug('Importing zone key pair 0x%s', str_hexlify(zkey_id))
|
|
localhsm.import_private_key(zkey_ldap, zkey_ldap['ipaPrivateKey'],
|
|
unwrapping_key)
|
|
localhsm.import_public_key(zkey_ldap, zkey_ldap['ipaPublicKey'])
|
|
|
|
# synchronize metadata about zone keys in LDAP & local HSM
|
|
update_metadata_set(ldapkeydb.master_keys, localhsm.master_keys)
|
|
|
|
# delete keys removed from LDAP
|
|
deleted_keys = set(localhsm.zone_privkeys.keys()) \
|
|
- set(ldapkeydb.zone_keypairs.keys())
|
|
|
|
for zkey_id in deleted_keys:
|
|
localhsm.p11.delete_key(localhsm.zone_pubkeys[zkey_id].handle)
|
|
localhsm.p11.delete_key(localhsm.zone_privkeys[zkey_id].handle)
|
|
|
|
|
|
# IPA framework initialization
|
|
standard_logging_setup(verbose=True, debug=True)
|
|
ipalib.api.bootstrap(context='dns', confdir=paths.ETC_IPA, in_server=True)
|
|
ipalib.api.finalize()
|
|
|
|
# Kerberos initialization
|
|
PRINCIPAL = str('%s/%s' % (DAEMONNAME, ipalib.api.env.host))
|
|
logger.debug('Kerberos principal: %s', PRINCIPAL)
|
|
ccache_filename = os.path.join(WORKDIR, 'ipa-dnskeysync-replica.ccache')
|
|
|
|
try:
|
|
kinit_keytab(PRINCIPAL, paths.IPA_DNSKEYSYNCD_KEYTAB, ccache_filename,
|
|
attempts=5)
|
|
except GSSError as e:
|
|
logger.critical('Kerberos authentication failed: %s', e)
|
|
sys.exit(1)
|
|
|
|
os.environ['KRB5CCNAME'] = ccache_filename
|
|
logger.debug('Got TGT')
|
|
|
|
# LDAP initialization
|
|
ldap = ipaldap.LDAPClient(ipalib.api.env.ldap_uri)
|
|
logger.debug('Connecting to LDAP')
|
|
ldap.gssapi_bind()
|
|
logger.debug('Connected')
|
|
|
|
|
|
### DNSSEC master: key synchronization
|
|
ldapkeydb = LdapKeyDB(ldap, DN(('cn', 'keys'),
|
|
('cn', 'sec'),
|
|
ipalib.api.env.container_dns,
|
|
ipalib.api.env.basedn))
|
|
|
|
localhsm = LocalHSM(paths.LIBSOFTHSM2_SO, SOFTHSM_DNSSEC_TOKEN_LABEL,
|
|
open(paths.DNSSEC_SOFTHSM_PIN).read())
|
|
|
|
ldap2replica_master_keys_sync(ldapkeydb, localhsm)
|
|
ldap2replica_zone_keys_sync(ldapkeydb, localhsm)
|
|
|
|
sys.exit(0)
|