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

Reply via email to