diff --git a/lib/utils/__init__.py b/lib/utils/__init__.py
index 185d28b42e36db7b2530729980d4fc44d2460df1..a95cf7f159fbfd749231f472551ae51ed336d3da 100644
--- a/lib/utils/__init__.py
+++ b/lib/utils/__init__.py
@@ -155,6 +155,46 @@ def ValidateServiceName(name):
   return name
 
 
+def _ComputeMissingKeys(key_path, options, defaults):
+  """Helper functions to compute which keys a invalid.
+
+  @param key_path: The current key path (if any)
+  @param options: The user provided options
+  @param defaults: The default dictionary
+  @return: A list of invalid keys
+
+  """
+  defaults_keys = frozenset(defaults.keys())
+  invalid = []
+  for key, value in options.items():
+    if key_path:
+      new_path = "%s/%s" % (key_path, key)
+    else:
+      new_path = key
+
+    if key not in defaults_keys:
+      invalid.append(new_path)
+    elif isinstance(value, dict):
+      invalid.extend(_ComputeMissingKeys(new_path, value, defaults[key]))
+
+  return invalid
+
+
+def VerifyDictOptions(options, defaults):
+  """Verify a dict has only keys set which also are in the defaults dict.
+
+  @param options: The user provided options
+  @param defaults: The default dictionary
+  @raise error.OpPrereqError: If one of the keys is not supported
+
+  """
+  invalid = _ComputeMissingKeys("", options, defaults)
+
+  if invalid:
+    raise errors.OpPrereqError("Provided option keys not supported: %s" %
+                               CommaJoin(invalid), errors.ECODE_INVAL)
+
+
 def ListVolumeGroups():
   """List volume groups and their size
 
diff --git a/test/ganeti.utils_unittest.py b/test/ganeti.utils_unittest.py
index 80e737c771e5d2c034c5170e739d3cd5ae0ef72f..21316743b4cda891cb928753ead3140a8b2d25cf 100755
--- a/test/ganeti.utils_unittest.py
+++ b/test/ganeti.utils_unittest.py
@@ -315,5 +315,59 @@ class TestTryConvert(unittest.TestCase):
       self.assertEqual(utils.TryConvert(fn, src), result)
 
 
+class TestVerifyDictOptions(unittest.TestCase):
+  def setUp(self):
+    self.defaults = {
+      "first_key": "foobar",
+      "foobar": {
+        "key1": "value2",
+        "key2": "value1",
+        },
+      "another_key": "another_value",
+      }
+
+  def test(self):
+    some_keys = {
+      "first_key": "blubb",
+      "foobar": {
+        "key2": "foo",
+        },
+      }
+    utils.VerifyDictOptions(some_keys, self.defaults)
+
+  def testInvalid(self):
+    some_keys = {
+      "invalid_key": "blubb",
+      "foobar": {
+        "key2": "foo",
+        },
+      }
+    self.assertRaises(errors.OpPrereqError, utils.VerifyDictOptions,
+                      some_keys, self.defaults)
+
+  def testNestedInvalid(self):
+    some_keys = {
+      "foobar": {
+        "key2": "foo",
+        "key3": "blibb"
+        },
+      }
+    self.assertRaises(errors.OpPrereqError, utils.VerifyDictOptions,
+                      some_keys, self.defaults)
+
+  def testMultiInvalid(self):
+    some_keys = {
+        "foobar": {
+          "key1": "value3",
+          "key6": "Right here",
+        },
+        "invalid_with_sub": {
+          "sub1": "value3",
+        },
+      }
+    self.assertRaises(errors.OpPrereqError, utils.VerifyDictOptions,
+                      some_keys, self.defaults)
+
+
 if __name__ == '__main__':
   testutils.GanetiTestProgram()