|
|
ac7d03 |
From 948ab2a1f44676769e1e8c9be439606d05672c9b Mon Sep 17 00:00:00 2001
|
|
|
ac7d03 |
From: Simo Sorce <simo@redhat.com>
|
|
|
ac7d03 |
Date: Fri, 31 Mar 2017 11:22:45 -0400
|
|
|
ac7d03 |
Subject: [PATCH] Make sure remote hosts have our keys
|
|
|
ac7d03 |
|
|
|
ac7d03 |
In complex replication setups a replica may try to obtain CA keys from a
|
|
|
ac7d03 |
host that is not the master we initially create the keys against.
|
|
|
ac7d03 |
In this case race conditions may happen due to replication. So we need
|
|
|
ac7d03 |
to make sure the server we are contacting to get the CA keys has our
|
|
|
ac7d03 |
keys in LDAP. We do this by waiting to positively fetch our encryption
|
|
|
ac7d03 |
public key (the last one we create) from the target host LDAP server.
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Fixes: https://pagure.io/freeipa/issue/6838
|
|
|
ac7d03 |
|
|
|
ac7d03 |
Signed-off-by: Simo Sorce <simo@redhat.com>
|
|
|
ac7d03 |
Reviewed-By: Stanislav Laznicka <slaznick@redhat.com>
|
|
|
ac7d03 |
Reviewed-By: Christian Heimes <cheimes@redhat.com>
|
|
|
ac7d03 |
---
|
|
|
ac7d03 |
ipaserver/install/custodiainstance.py | 28 +++++++++++++++++++++++++++-
|
|
|
ac7d03 |
ipaserver/secrets/kem.py | 12 ++++++++++++
|
|
|
ac7d03 |
2 files changed, 39 insertions(+), 1 deletion(-)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
diff --git a/ipaserver/install/custodiainstance.py b/ipaserver/install/custodiainstance.py
|
|
|
ac7d03 |
index 6a613923163bccd1b59e0c3b3672905715a8de7c..390576bc0c0edfb7d8f8895eca9df30079526aa8 100644
|
|
|
ac7d03 |
--- a/ipaserver/install/custodiainstance.py
|
|
|
ac7d03 |
+++ b/ipaserver/install/custodiainstance.py
|
|
|
ac7d03 |
@@ -1,6 +1,6 @@
|
|
|
ac7d03 |
# Copyright (C) 2015 FreeIPa Project Contributors, see 'COPYING' for license.
|
|
|
ac7d03 |
|
|
|
ac7d03 |
-from ipaserver.secrets.kem import IPAKEMKeys
|
|
|
ac7d03 |
+from ipaserver.secrets.kem import IPAKEMKeys, KEMLdap
|
|
|
ac7d03 |
from ipaserver.secrets.client import CustodiaClient
|
|
|
ac7d03 |
from ipaplatform.paths import paths
|
|
|
ac7d03 |
from ipaplatform.constants import constants
|
|
|
ac7d03 |
@@ -18,6 +18,7 @@ import shutil
|
|
|
ac7d03 |
import os
|
|
|
ac7d03 |
import stat
|
|
|
ac7d03 |
import tempfile
|
|
|
ac7d03 |
+import time
|
|
|
ac7d03 |
import pwd
|
|
|
ac7d03 |
|
|
|
ac7d03 |
|
|
|
ac7d03 |
@@ -122,6 +123,27 @@ class CustodiaInstance(SimpleServiceInstance):
|
|
|
ac7d03 |
cli = self.__CustodiaClient(server=master_host_name)
|
|
|
ac7d03 |
cli.fetch_key('dm/DMHash')
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+ def __wait_keys(self, host, timeout=300):
|
|
|
ac7d03 |
+ ldap_uri = 'ldap://%s' % host
|
|
|
ac7d03 |
+ deadline = int(time.time()) + timeout
|
|
|
ac7d03 |
+ root_logger.info("Waiting up to {} seconds to see our keys "
|
|
|
ac7d03 |
+ "appear on host: {}".format(timeout, host))
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ konn = KEMLdap(ldap_uri)
|
|
|
ac7d03 |
+ saved_e = None
|
|
|
ac7d03 |
+ while True:
|
|
|
ac7d03 |
+ try:
|
|
|
ac7d03 |
+ return konn.check_host_keys(self.fqdn)
|
|
|
ac7d03 |
+ except Exception as e:
|
|
|
ac7d03 |
+ # log only once for the same error
|
|
|
ac7d03 |
+ if not isinstance(e, type(saved_e)):
|
|
|
ac7d03 |
+ root_logger.debug(
|
|
|
ac7d03 |
+ "Transient error getting keys: '{err}'".format(err=e))
|
|
|
ac7d03 |
+ saved_e = e
|
|
|
ac7d03 |
+ if int(time.time()) > deadline:
|
|
|
ac7d03 |
+ raise RuntimeError("Timed out trying to obtain keys.")
|
|
|
ac7d03 |
+ time.sleep(1)
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
def __get_keys(self, ca_host, cacerts_file, cacerts_pwd, data):
|
|
|
ac7d03 |
# Fecth all needed certs one by one, then combine them in a single
|
|
|
ac7d03 |
# p12 file
|
|
|
ac7d03 |
@@ -129,6 +151,10 @@ class CustodiaInstance(SimpleServiceInstance):
|
|
|
ac7d03 |
prefix = data['prefix']
|
|
|
ac7d03 |
certlist = data['list']
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+ # Before we attempt to fetch keys from this host, make sure our public
|
|
|
ac7d03 |
+ # keys have been replicated there.
|
|
|
ac7d03 |
+ self.__wait_keys(ca_host)
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
cli = self.__CustodiaClient(server=ca_host)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
# Temporary nssdb
|
|
|
ac7d03 |
diff --git a/ipaserver/secrets/kem.py b/ipaserver/secrets/kem.py
|
|
|
ac7d03 |
index 28fb4d31b35fc96c77ddd3f09cb3927efb4000fa..c1991c6b2ae00ed7147b2ec18389e463784b9f98 100644
|
|
|
ac7d03 |
--- a/ipaserver/secrets/kem.py
|
|
|
ac7d03 |
+++ b/ipaserver/secrets/kem.py
|
|
|
ac7d03 |
@@ -24,6 +24,7 @@ import ldap
|
|
|
ac7d03 |
|
|
|
ac7d03 |
IPA_REL_BASE_DN = 'cn=custodia,cn=ipa,cn=etc'
|
|
|
ac7d03 |
IPA_KEYS_QUERY = '(&(ipaKeyUsage={usage:s})(memberPrincipal={princ:s}))'
|
|
|
ac7d03 |
+IPA_CHECK_QUERY = '(cn=enc/{host:s})'
|
|
|
ac7d03 |
RFC5280_USAGE_MAP = {KEY_USAGE_SIG: 'digitalSignature',
|
|
|
ac7d03 |
KEY_USAGE_ENC: 'dataEncipherment'}
|
|
|
ac7d03 |
|
|
|
ac7d03 |
@@ -78,6 +79,17 @@ class KEMLdap(iSecLdap):
|
|
|
ac7d03 |
jwk['use'] = KEY_USAGE_MAP[usage]
|
|
|
ac7d03 |
return json_encode(jwk)
|
|
|
ac7d03 |
|
|
|
ac7d03 |
+ def check_host_keys(self, host):
|
|
|
ac7d03 |
+ conn = self.connect()
|
|
|
ac7d03 |
+ scope = ldap.SCOPE_SUBTREE
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
+ ldap_filter = self.build_filter(IPA_CHECK_QUERY, {'host': host})
|
|
|
ac7d03 |
+ r = conn.search_s(self.keysbase, scope, ldap_filter)
|
|
|
ac7d03 |
+ if len(r) != 1:
|
|
|
ac7d03 |
+ raise ValueError("Incorrect number of results (%d) searching for"
|
|
|
ac7d03 |
+ "public key for %s" % (len(r), host))
|
|
|
ac7d03 |
+ return True
|
|
|
ac7d03 |
+
|
|
|
ac7d03 |
def _format_public_key(self, key):
|
|
|
ac7d03 |
if isinstance(key, str):
|
|
|
ac7d03 |
jwkey = json_decode(key)
|
|
|
ac7d03 |
--
|
|
|
ac7d03 |
2.12.2
|
|
|
ac7d03 |
|