As discussed offline, I will resend this patch with an addition about the upgrades, so disregard this for now.
On Thu, Jan 23, 2014 at 5:33 PM, Helga Velroyen <[email protected]> wrote: > This patch temporarily disables the usage of the client > SSL certificates. The handling of RPC connections had a > conceptional flaw, because the certificates lack a proper > signature. For this, Ganeti needs to implement a CA, > which is already designed (see design-x509-ca.rst) but > not implemented yet. This patch keeps most of the > client certificate infrastructure intact which was already > created and and can be reused, but just disables the > actual usage of the certificates in RPC calls till the CA > is in place. > > Signed-off-by: Helga Velroyen <[email protected]> > --- > My apologies for identifying this problem only now. For some > reason, it worked perfectly on debian machines and was only > discovered on fedora machines. I will investigate this > further to find out why the debian machines completely > ignored the signatures so far. > > lib/cmdlib/cluster.py | 1 - > lib/http/__init__.py | 2 +- > lib/rpc/node.py | 12 +--- > man/gnt-cluster.rst | 7 +- > src/Ganeti/Rpc.hs | 12 +--- > test/py/cmdlib/cluster_unittest.py | 134 > ------------------------------------- > 6 files changed, 6 insertions(+), 162 deletions(-) > > diff --git a/lib/cmdlib/cluster.py b/lib/cmdlib/cluster.py > index d04bd69..5f18205 100644 > --- a/lib/cmdlib/cluster.py > +++ b/lib/cmdlib/cluster.py > @@ -3182,7 +3182,6 @@ class LUClusterVerifyGroup(LogicalUnit, > _VerifyErrors): > > feedback_fn("* Verifying configuration file consistency") > > - self._VerifyClientCertificates(self.my_node_info.values(), all_nvinfo) > # If not all nodes are being checked, we need to make sure the master > node > # and a non-checked vm_capable node are in the list. > absent_node_uuids = > set(self.all_node_info).difference(self.my_node_info) > diff --git a/lib/http/__init__.py b/lib/http/__init__.py > index 614d6ba..5ae981f 100644 > --- a/lib/http/__init__.py > +++ b/lib/http/__init__.py > @@ -610,7 +610,7 @@ class HttpBase(object): > if ssl_verify_peer: > ctx.set_verify(OpenSSL.SSL.VERIFY_PEER | > OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, > - ssl_verify_callback) > + self._SSLVerifyCallback) > > # Also add our certificate as a trusted CA to be sent to the client. > # This is required at least for GnuTLS clients to work. > diff --git a/lib/rpc/node.py b/lib/rpc/node.py > index 8c0f822..e3944aa 100644 > --- a/lib/rpc/node.py > +++ b/lib/rpc/node.py > @@ -98,23 +98,15 @@ def Shutdown(): > > def _ConfigRpcCurl(curl): > noded_cert = str(pathutils.NODED_CERT_FILE) > - noded_client_cert = str(pathutils.NODED_CLIENT_CERT_FILE) > - > - # FIXME: The next two lines are necessary to ensure upgradability from > - # 2.10 to 2.11. Remove in 2.12, because this slows down RPC calls. > - if not os.path.exists(noded_client_cert): > - logging.info("Using server certificate as client certificate for RPC" > - "call.") > - noded_client_cert = noded_cert > > curl.setopt(pycurl.FOLLOWLOCATION, False) > curl.setopt(pycurl.CAINFO, noded_cert) > curl.setopt(pycurl.SSL_VERIFYHOST, 0) > curl.setopt(pycurl.SSL_VERIFYPEER, True) > curl.setopt(pycurl.SSLCERTTYPE, "PEM") > - curl.setopt(pycurl.SSLCERT, noded_client_cert) > + curl.setopt(pycurl.SSLCERT, noded_cert) > curl.setopt(pycurl.SSLKEYTYPE, "PEM") > - curl.setopt(pycurl.SSLKEY, noded_client_cert) > + curl.setopt(pycurl.SSLKEY, noded_cert) > curl.setopt(pycurl.CONNECTTIMEOUT, constants.RPC_CONNECT_TIMEOUT) > > > diff --git a/man/gnt-cluster.rst b/man/gnt-cluster.rst > index 72756c2..eeb1b5a 100644 > --- a/man/gnt-cluster.rst > +++ b/man/gnt-cluster.rst > @@ -766,7 +766,7 @@ RENEW-CRYPTO > ~~~~~~~~~~~~ > > | **renew-crypto** [-f] > -| [\--new-cluster-certificate] | [\--new-node-certificates] > +| [\--new-cluster-certificate] > | [\--new-confd-hmac-key] > | [\--new-rapi-certificate] [\--rapi-certificate *rapi-cert*] > | [\--new-spice-certificate | \--spice-certificate *spice-cert* > @@ -779,11 +779,6 @@ options ``--new-cluster-certificate`` and > ``--new-confd-hmac-key`` > can be used to regenerate respectively the cluster-internal SSL > certificate and the HMAC key used by **ganeti-confd**\(8). > > -The option ``--new-node-certificates`` will generate new node SSL > -certificates for all nodes. Note that the regeneration of the node > -certificates takes place after the other certificates are created > -and distributed and the ganeti daemons are restarted again. > - > To generate a new self-signed RAPI certificate (used by > **ganeti-rapi**\(8)) specify ``--new-rapi-certificate``. If you want to > use your own certificate, e.g. one signed by a certificate > diff --git a/src/Ganeti/Rpc.hs b/src/Ganeti/Rpc.hs > index 598b76f..2526d2e 100644 > --- a/src/Ganeti/Rpc.hs > +++ b/src/Ganeti/Rpc.hs > @@ -90,7 +90,6 @@ import Data.Maybe (fromMaybe) > import qualified Text.JSON as J > import Text.JSON.Pretty (pp_value) > import qualified Data.ByteString.Base64.Lazy as Base64 > -import System.Directory > > import Network.Curl hiding (content) > import qualified Ganeti.Path as P > @@ -229,15 +228,8 @@ getOptionsForCall cert_path client_cert_path call = > executeRpcCalls :: (Rpc a b) => [(Node, a)] -> IO [(Node, ERpcError b)] > executeRpcCalls nodeCalls = do > cert_file <- P.nodedCertFile > - client_cert_file_name <- P.nodedClientCertFile > - client_file_exists <- doesFileExist client_cert_file_name > - -- FIXME: This is needed to ensure upgradability to 2.11 > - -- Remove in 2.12. > - let client_cert_file = if client_file_exists > - then client_cert_file_name > - else cert_file > - (nodes, calls) = unzip nodeCalls > - opts = map (getOptionsForCall cert_file client_cert_file) calls > + let (nodes, calls) = unzip nodeCalls > + opts = map (getOptionsForCall cert_file cert_file) calls > opts_urls = zipWith3 (\n c o -> > case prepareHttpRequest o n c of > Left v -> Left v > diff --git a/test/py/cmdlib/cluster_unittest.py > b/test/py/cmdlib/cluster_unittest.py > index 51aa3e0..fad9276 100644 > --- a/test/py/cmdlib/cluster_unittest.py > +++ b/test/py/cmdlib/cluster_unittest.py > @@ -1085,140 +1085,6 @@ class TestLUClusterVerifyGroup(CmdlibTestCase): > self.ExecOpCode(op) > > > -class TestLUClusterVerifyClientCerts(CmdlibTestCase): > - > - def _AddNormalNode(self): > - self.normalnode = copy.deepcopy(self.master) > - self.normalnode.master_candidate = False > - self.normalnode.uuid = "normal-node-uuid" > - self.cfg.AddNode(self.normalnode, None) > - > - def testVerifyMasterCandidate(self): > - client_cert = "client-cert-digest" > - self.cluster.candidate_certs = {self.master.uuid: client_cert} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (None, client_cert)}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - > - def testVerifyMasterCandidateInvalid(self): > - client_cert = "client-cert-digest" > - self.cluster.candidate_certs = {self.master.uuid: client_cert} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (666, "Invalid Certificate")}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - self.mcpu.assertLogContainsRegex("Client certificate") > - self.mcpu.assertLogContainsRegex("failed validation") > - > - def testVerifyNoMasterCandidateMap(self): > - client_cert = "client-cert-digest" > - self.cluster.candidate_certs = {} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (None, client_cert)}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - self.mcpu.assertLogContainsRegex( > - "list of master candidate certificates is empty") > - > - def testVerifyNoSharingMasterCandidates(self): > - client_cert = "client-cert-digest" > - self.cluster.candidate_certs = { > - self.master.uuid: client_cert, > - "some-other-master-candidate-uuid": client_cert} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (None, client_cert)}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - self.mcpu.assertLogContainsRegex( > - "two master candidates configured to use the same") > - > - def testVerifyMasterCandidateCertMismatch(self): > - client_cert = "client-cert-digest" > - self.cluster.candidate_certs = {self.master.uuid: > "different-cert-digest"} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (None, client_cert)}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - self.mcpu.assertLogContainsRegex("does not match its entry") > - > - def testVerifyMasterCandidateUnregistered(self): > - client_cert = "client-cert-digest" > - self.cluster.candidate_certs = {"other-node-uuid": > "different-cert-digest"} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (None, client_cert)}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - self.mcpu.assertLogContainsRegex("does not have an entry") > - > - def testVerifyMasterCandidateOtherNodesCert(self): > - client_cert = "client-cert-digest" > - self.cluster.candidate_certs = {"other-node-uuid": client_cert} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (None, client_cert)}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - self.mcpu.assertLogContainsRegex("using a certificate of another > node") > - > - def testNormalNodeStillInList(self): > - self._AddNormalNode() > - client_cert_master = "client-cert-digest-master" > - client_cert_normal = "client-cert-digest-normal" > - self.cluster.candidate_certs = { > - self.normalnode.uuid: client_cert_normal, > - self.master.uuid: client_cert_master} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.normalnode, > - {constants.NV_CLIENT_CERT: (None, client_cert_normal)}) \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (None, client_cert_master)}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - self.mcpu.assertLogContainsRegex("not a master candidate") > - self.mcpu.assertLogContainsRegex("still listed") > - > - def testNormalNodeStealingMasterCandidateCert(self): > - self._AddNormalNode() > - client_cert_master = "client-cert-digest-master" > - self.cluster.candidate_certs = { > - self.master.uuid: client_cert_master} > - self.rpc.call_node_verify.return_value = \ > - RpcResultsBuilder() \ > - .AddSuccessfulNode(self.normalnode, > - {constants.NV_CLIENT_CERT: (None, client_cert_master)}) \ > - .AddSuccessfulNode(self.master, > - {constants.NV_CLIENT_CERT: (None, client_cert_master)}) \ > - .Build() > - op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True) > - self.ExecOpCode(op) > - self.mcpu.assertLogContainsRegex("not a master candidate") > - self.mcpu.assertLogContainsRegex( > - "certificate of another node which is master candidate") > - > - > class TestLUClusterVerifyGroupMethods(CmdlibTestCase): > """Base class for testing individual methods in LUClusterVerifyGroup. > > -- > 1.8.5.3 > > -- -- Helga Velroyen | Software Engineer | [email protected] | Google Germany GmbH Dienerstr. 12 80331 München Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Geschäftsführer: Graham Law, Christine Elizabeth Flores
