diff --git a/daemons/ganeti-rapi b/daemons/ganeti-rapi
index b6c0f80d94723f4f80acd87cdad0f5ea5f06a577..4607b0d15b614e53bfc32f778efd701f565fd3d8 100755
--- a/daemons/ganeti-rapi
+++ b/daemons/ganeti-rapi
@@ -26,6 +26,7 @@ import logging
 import optparse
 import sys
 import os
+import os.path
 import signal
 
 from ganeti import constants
@@ -36,6 +37,7 @@ from ganeti import ssconf
 from ganeti import utils
 from ganeti.rapi import connector
 
+import ganeti.http.auth
 import ganeti.http.server
 
 
@@ -46,16 +48,27 @@ class RemoteApiRequestContext(object):
   def __init__(self):
     self.handler = None
     self.handler_fn = None
+    self.handler_access = None
 
 
-class RemoteApiHttpServer(http.server.HttpServer):
+class RemoteApiHttpServer(http.auth.HttpServerRequestAuthentication,
+                          http.server.HttpServer):
   """REST Request Handler Class.
 
   """
+  AUTH_REALM = "Ganeti Remote API"
+
   def __init__(self, *args, **kwargs):
     http.server.HttpServer.__init__(self, *args, **kwargs)
+    http.auth.HttpServerRequestAuthentication.__init__(self)
     self._resmap = connector.Mapper()
 
+    # Load password file
+    if os.path.isfile(constants.RAPI_USERS_FILE):
+      self._users = http.auth.ReadPasswordFile(constants.RAPI_USERS_FILE)
+    else:
+      self._users = None
+
   def _GetRequestContext(self, req):
     """Returns the context for a request.
 
@@ -74,10 +87,41 @@ class RemoteApiHttpServer(http.server.HttpServer):
       except AttributeError, err:
         raise http.HttpBadRequest()
 
+      ctx.handler_access = getattr(ctx.handler, "%s_ACCESS" % method, None)
+
+      # Require permissions definition (usually in the base class)
+      if ctx.handler_access is None:
+        raise AssertionError("Permissions definition missing")
+
       req.private = ctx
 
     return req.private
 
+  def Authenticate(self, req, username, password):
+    """Checks whether a user can access a resource.
+
+    """
+    ctx = self._GetRequestContext(req)
+
+    # Check username and password
+    valid_user = False
+    if self._users:
+      user = self._users.get(username, None)
+      if user and user.password == password:
+        valid_user = True
+
+    if not valid_user:
+      # Unknown user or password wrong
+      return False
+
+    if (not ctx.handler_access or
+        set(user.options).intersection(ctx.handler_access)):
+      # Allow access
+      return True
+
+    # Access forbidden
+    raise http.HttpForbidden()
+
   def HandleRequest(self, req):
     """Handles a request.
 
diff --git a/lib/constants.py b/lib/constants.py
index 7dfa2ac41f271d8ab3a1047a7b17737bbd1e9343..9ae904414a46e2dc757f164b96fa16ddfce2c378 100644
--- a/lib/constants.py
+++ b/lib/constants.py
@@ -96,6 +96,7 @@ CLUSTER_CONF_FILE = DATA_DIR + "/config.data"
 SSL_CERT_FILE = DATA_DIR + "/server.pem"
 WATCHER_STATEFILE = DATA_DIR + "/watcher.data"
 SSH_KNOWN_HOSTS_FILE = DATA_DIR + "/known_hosts"
+RAPI_USERS_FILE = DATA_DIR + "/rapi_users"
 QUEUE_DIR = DATA_DIR + "/queue"
 ETC_HOSTS = "/etc/hosts"
 DEFAULT_FILE_STORAGE_DIR = _autoconf.FILE_STORAGE_DIR
diff --git a/lib/rapi/__init__.py b/lib/rapi/__init__.py
index 15360b5831a14231849b63d31accd45d89e95e1d..fde366c8097358ea81b252e42442c75814036491 100644
--- a/lib/rapi/__init__.py
+++ b/lib/rapi/__init__.py
@@ -19,4 +19,4 @@
 # 02110-1301, USA.
 
 
-# empty file for package definition
+RAPI_ACCESS_WRITE = "write"
diff --git a/lib/rapi/baserlib.py b/lib/rapi/baserlib.py
index 58d68a165d94df5a78d3531260d7bcc2ffccec8d..1409476120f48389623beaf975e3b4bdba8e5c10 100644
--- a/lib/rapi/baserlib.py
+++ b/lib/rapi/baserlib.py
@@ -27,6 +27,7 @@ import ganeti.cli
 import ganeti.opcodes
 
 from ganeti import luxi
+from ganeti import rapi
 
 
 def BuildUriList(ids, uri_format, uri_fields=("name", "uri")):
@@ -149,6 +150,12 @@ class R_Generic(object):
   """Generic class for resources.
 
   """
+  # Default permission requirements
+  GET_ACCESS = []
+  PUT_ACCESS = [rapi.RAPI_ACCESS_WRITE]
+  POST_ACCESS = [rapi.RAPI_ACCESS_WRITE]
+  DELETE_ACCESS = [rapi.RAPI_ACCESS_WRITE]
+
   def __init__(self, items, queryargs, req):
     """Generic resource constructor.