diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 8eeb471829db2b56a7e238e1eea98331de72db8e..51514d7e00dc8cdf38beb533e5a6c574499545d3 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -8822,6 +8822,66 @@ class LUQueryExports(NoHooksLU):
     return result
 
 
+class LUPrepareExport(NoHooksLU):
+  """Prepares an instance for an export and returns useful information.
+
+  """
+  _OP_REQP = ["instance_name", "mode"]
+  REQ_BGL = False
+
+  def CheckArguments(self):
+    """Check the arguments.
+
+    """
+    if self.op.mode not in constants.EXPORT_MODES:
+      raise errors.OpPrereqError("Invalid export mode %r" % self.op.mode,
+                                 errors.ECODE_INVAL)
+
+  def ExpandNames(self):
+    self._ExpandAndLockInstance()
+
+  def CheckPrereq(self):
+    """Check prerequisites.
+
+    """
+    instance_name = self.op.instance_name
+
+    self.instance = self.cfg.GetInstanceInfo(instance_name)
+    assert self.instance is not None, \
+          "Cannot retrieve locked instance %s" % self.op.instance_name
+    _CheckNodeOnline(self, self.instance.primary_node)
+
+    self._cds = _GetClusterDomainSecret()
+
+  def Exec(self, feedback_fn):
+    """Prepares an instance for an export.
+
+    """
+    instance = self.instance
+
+    if self.op.mode == constants.EXPORT_MODE_REMOTE:
+      salt = utils.GenerateSecret(8)
+
+      feedback_fn("Generating X509 certificate on %s" % instance.primary_node)
+      result = self.rpc.call_x509_cert_create(instance.primary_node,
+                                              constants.RIE_CERT_VALIDITY)
+      result.Raise("Can't create X509 key and certificate on %s" % result.node)
+
+      (name, cert_pem) = result.payload
+
+      cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
+                                             cert_pem)
+
+      return {
+        "handshake": masterd.instance.ComputeRemoteExportHandshake(self._cds),
+        "x509_key_name": (name, utils.Sha1Hmac(self._cds, name, salt=salt),
+                          salt),
+        "x509_ca": utils.SignX509Certificate(cert, self._cds, salt),
+        }
+
+    return None
+
+
 class LUExportInstance(LogicalUnit):
   """Export an instance to an image in the cluster.
 
diff --git a/lib/constants.py b/lib/constants.py
index 02e1a10ed1946fc3e0df1431d243e24b9ea7407d..df9a534fa264489bcd251f61ad1400649dd30d0f 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -336,6 +336,13 @@ LOCKS_APPEND = 'append'
 INSTANCE_CREATE = "create"
 INSTANCE_IMPORT = "import"
 
+# Remote import/export handshake message and version
+RIE_VERSION = 0
+RIE_HANDSHAKE = "Hi, I'm Ganeti"
+
+# Remote import/export certificate validity in seconds
+RIE_CERT_VALIDITY = 24 * 60 * 60
+
 DISK_TEMPLATES = frozenset([DT_DISKLESS, DT_PLAIN,
                             DT_DRBD8, DT_FILE])
 
diff --git a/lib/masterd/instance.py b/lib/masterd/instance.py
index 7e95b0d5464d3fc99872f871075ff00338d9a71d..f48e01b13284ba51772be53ea7cae1c2c949209d 100644
--- a/lib/masterd/instance.py
+++ b/lib/masterd/instance.py
@@ -1105,3 +1105,50 @@ class ExportInstanceHelper:
     assert len(self._removed_snaps) == len(self._instance.disks)
     for idx in range(len(self._instance.disks)):
       self._RemoveSnapshot(idx)
+
+
+def _GetImportExportHandshakeMessage(version):
+  """Returns the handshake message for a RIE protocol version.
+
+  @type version: number
+
+  """
+  return "%s:%s" % (version, constants.RIE_HANDSHAKE)
+
+
+def ComputeRemoteExportHandshake(cds):
+  """Computes the remote import/export handshake.
+
+  @type cds: string
+  @param cds: Cluster domain secret
+
+  """
+  salt = utils.GenerateSecret(8)
+  msg = _GetImportExportHandshakeMessage(constants.RIE_VERSION)
+  return (constants.RIE_VERSION, utils.Sha1Hmac(cds, msg, salt=salt), salt)
+
+
+def CheckRemoteExportHandshake(cds, handshake):
+  """Checks the handshake of a remote import/export.
+
+  @type cds: string
+  @param cds: Cluster domain secret
+  @type handshake: sequence
+  @param handshake: Handshake sent by remote peer
+
+  """
+  try:
+    (version, hmac_digest, hmac_salt) = handshake
+  except (TypeError, ValueError), err:
+    return "Invalid data: %s" % err
+
+  if not utils.VerifySha1Hmac(cds, _GetImportExportHandshakeMessage(version),
+                              hmac_digest, salt=hmac_salt):
+    return "Hash didn't match, clusters don't share the same domain secret"
+
+  if version != constants.RIE_VERSION:
+    return ("Clusters don't have the same remote import/export protocol"
+            " (local=%s, remote=%s)" %
+            (constants.RIE_VERSION, version))
+
+  return None
diff --git a/lib/mcpu.py b/lib/mcpu.py
index c601c51dc28aa326c1d0d2b635ac03d9126169ca..319878006a920d62de2d86af848661ac6a50c287 100644
--- a/lib/mcpu.py
+++ b/lib/mcpu.py
@@ -210,6 +210,7 @@ class Processor(object):
     opcodes.OpDiagnoseOS: cmdlib.LUDiagnoseOS,
     # exports lu
     opcodes.OpQueryExports: cmdlib.LUQueryExports,
+    opcodes.OpPrepareExport: cmdlib.LUPrepareExport,
     opcodes.OpExportInstance: cmdlib.LUExportInstance,
     opcodes.OpRemoveExport: cmdlib.LURemoveExport,
     # tags lu
diff --git a/lib/opcodes.py b/lib/opcodes.py
index c7d00be0550c056be2384867ff814927dd764efa..149dbabaa033e12f9eb6dc402c59410bbe49247e 100644
--- a/lib/opcodes.py
+++ b/lib/opcodes.py
@@ -653,6 +653,20 @@ class OpQueryExports(OpCode):
   __slots__ = ["nodes", "use_locking"]
 
 
+class OpPrepareExport(OpCode):
+  """Prepares an instance export.
+
+  @ivar instance_name: Instance name
+  @ivar mode: Export mode (one of L{constants.EXPORT_MODES})
+
+  """
+  OP_ID = "OP_BACKUP_PREPARE"
+  OP_DSC_FIELD = "instance_name"
+  __slots__ = [
+    "instance_name", "mode",
+    ]
+
+
 class OpExportInstance(OpCode):
   """Export an instance."""
   OP_ID = "OP_BACKUP_EXPORT"
diff --git a/test/ganeti.masterd.instance_unittest.py b/test/ganeti.masterd.instance_unittest.py
index 05b0183ab5a5d98fdc37d0d60bd25717a99a2694..0c74defcf8871d9548df1c9882fa5f2d9506ba90 100755
--- a/test/ganeti.masterd.instance_unittest.py
+++ b/test/ganeti.masterd.instance_unittest.py
@@ -25,11 +25,13 @@ import os
 import sys
 import unittest
 
+from ganeti import constants
 from ganeti import utils
 from ganeti import masterd
 
 from ganeti.masterd.instance import \
-  ImportExportTimeouts, _TimeoutExpired, _DiskImportExportBase
+  ImportExportTimeouts, _TimeoutExpired, _DiskImportExportBase, \
+  ComputeRemoteExportHandshake, CheckRemoteExportHandshake
 
 import testutils
 
@@ -56,5 +58,33 @@ class TestMisc(unittest.TestCase):
                       None, None, None, None, None, None, None)
 
 
+class TestRieHandshake(unittest.TestCase):
+  def test(self):
+    cds = "cd-secret"
+    hs = ComputeRemoteExportHandshake(cds)
+    self.assertEqual(len(hs), 3)
+    self.assertEqual(hs[0], constants.RIE_VERSION)
+
+    self.assertEqual(CheckRemoteExportHandshake(cds, hs), None)
+
+  def testCheckErrors(self):
+    self.assert_(CheckRemoteExportHandshake(None, None))
+    self.assert_(CheckRemoteExportHandshake("", ""))
+    self.assert_(CheckRemoteExportHandshake("", ("xyz", "foo")))
+
+  def testCheckWrongHash(self):
+    cds = "cd-secret999"
+    self.assert_(CheckRemoteExportHandshake(cds, (0, "fakehash", "xyz")))
+
+  def testCheckWrongVersion(self):
+    version = 14887
+    self.assertNotEqual(version, constants.RIE_VERSION)
+    cds = "c28ac99"
+    salt = "a19cf8cc06"
+    msg = "%s:%s" % (version, constants.RIE_HANDSHAKE)
+    hs = (version, utils.Sha1Hmac(cds, msg, salt=salt), salt)
+    self.assert_(CheckRemoteExportHandshake(cds, hs))
+
+
 if __name__ == "__main__":
   testutils.GanetiTestProgram()