Imported Upstream version 4.7.2
This commit is contained in:
184
daemons/dnssec/ipa-dnskeysync-replica.in
Normal file
184
daemons/dnssec/ipa-dnskeysync-replica.in
Normal file
@@ -0,0 +1,184 @@
|
||||
@PYTHONSHEBANG@
|
||||
#
|
||||
# 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]
|
||||
if not mkey_ldap.wrapped_entries:
|
||||
raise ValueError(
|
||||
"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?
|
||||
if unwrapping_key is None:
|
||||
raise ValueError(
|
||||
"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'])
|
||||
if unwrapping_key is None:
|
||||
raise ValueError(
|
||||
"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)
|
||||
Reference in New Issue
Block a user