diff options
Diffstat (limited to 'daemons/dnssec/ipa-dnskeysync-replica')
-rwxr-xr-x | daemons/dnssec/ipa-dnskeysync-replica | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/daemons/dnssec/ipa-dnskeysync-replica b/daemons/dnssec/ipa-dnskeysync-replica new file mode 100755 index 000000000..4d3e660d7 --- /dev/null +++ b/daemons/dnssec/ipa-dnskeysync-replica @@ -0,0 +1,164 @@ +#!/usr/bin/python +# +# 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 binascii import hexlify +from datetime import datetime +import dns.dnssec +import fcntl +import logging +import os +from pprint import pprint +import subprocess +import socket +import sys +import systemd.daemon +import systemd.journal +import time + +import ipalib +from ipapython.dn import DN +from ipapython.ipa_log_manager import root_logger, standard_logging_setup +from ipapython import ipaldap +from ipapython import ipautil +from ipaserver.plugins.ldap2 import ldap2 +from ipaplatform.paths import paths + +from ipapython.dnssec.abshsm import sync_pkcs11_metadata, ldap2p11helper_api_params, wrappingmech_name2id +from ipapython.dnssec.ldapkeydb import LdapKeyDB +from ipapython.dnssec.localhsm import LocalHSM +import _ipap11helper + +DAEMONNAME = 'ipa-dnskeysyncd' +PRINCIPAL = None # not initialized yet +WORKDIR = '/tmp' + +def hex_set(s): + out = set() + for i in s: + out.add("0x%s" % hexlify(i)) + return out + +def update_metadata_set(log, source_set, target_set): + """sync metadata from source key set to target key set + + Keys not present in both sets are left intact.""" + log = log.getChild('sync_metadata') + matching_keys = set(source_set.keys()).intersection(set(target_set.keys())) + log.info("keys in local HSM & LDAP: %s", hex_set(matching_keys)) + for key_id in matching_keys: + sync_pkcs11_metadata(log, source_set[key_id], target_set[key_id]) + + +def find_unwrapping_key(log, localhsm, wrapping_key_uri): + wrap_keys = localhsm.find_keys(uri=wrapping_key_uri) + # find usable unwrapping key with matching ID + for key_id, key in wrap_keys.iteritems(): + 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(log, 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()) + log.debug("master keys in local HSM: %s", hex_set(localhsm.master_keys.keys())) + log.debug("master keys in LDAP HSM: %s", hex_set(ldapkeydb.master_keys.keys())) + log.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] + for wrapped_ldap in mkey_ldap.wrapped_entries: + unwrapping_key = find_unwrapping_key(log, 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" % 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']] + log.debug('Importing new master key: 0x%s %s', hexlify(mkey_id), params) + localhsm.p11.import_wrapped_secret_key(**params) + + # synchronize metadata about master keys in LDAP + update_metadata_set(log, ldapkeydb.master_keys, localhsm.master_keys) + +def ldap2replica_zone_keys_sync(log, 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()) + + log.debug("zone keys in local HSM: %s", hex_set(localhsm.master_keys.keys())) + log.debug("zone keys in LDAP HSM: %s", hex_set(ldapkeydb.master_keys.keys())) + log.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] + log.debug('Looking for unwrapping key "%s" for zone key 0x%s', + zkey_ldap['ipaWrappingKey'], hexlify(zkey_id)) + unwrapping_key = find_unwrapping_key(log, localhsm, + zkey_ldap['ipaWrappingKey']) + assert unwrapping_key is not None, \ + "Local HSM does not contain suitable unwrapping key for ' \ + 'zone key 0x%s" % hexlify(zkey_id) + + log.debug('Importing zone key pair 0x%s', 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(log, 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 +ipalib.api.bootstrap() +ipalib.api.finalize() +standard_logging_setup(verbose=True, debug = True) # debug=ipalib.api.env.debug) +log = root_logger +log.setLevel(level=logging.DEBUG) + +# Kerberos initialization +PRINCIPAL = str('%s/%s' % (DAEMONNAME, ipalib.api.env.host)) +log.debug('Kerberos principal: %s', PRINCIPAL) +ipautil.kinit_hostprincipal(paths.IPA_DNSKEYSYNCD_KEYTAB, WORKDIR, PRINCIPAL) +log.debug('Got TGT') + +# LDAP initialization +ldap = ipalib.api.Backend[ldap2] +# fixme +log.debug('Connecting to LDAP') +ldap.connect(ccache="%s/ccache" % WORKDIR) +log.debug('Connected') + + +### DNSSEC master: key synchronization +ldapkeydb = LdapKeyDB(log, ldap, + DN(ipalib.api.env.container_dnssec_keys, ipalib.api.env.basedn)) + +# TODO: slot number could be configurable +localhsm = LocalHSM(paths.LIBSOFTHSM2_SO, 0, + open(paths.DNSSEC_SOFTHSM_PIN).read()) + +ldap2replica_master_keys_sync(log, ldapkeydb, localhsm) +ldap2replica_zone_keys_sync(log, ldapkeydb, localhsm) + +sys.exit(0) |