summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.rst33
-rw-r--r--common/changes/create_db_cmd2
-rw-r--r--common/src/leap/soledad/common/command.py17
-rw-r--r--common/src/leap/soledad/common/couch.py19
-rw-r--r--common/src/leap/soledad/common/tests/test_command.py4
-rw-r--r--common/src/leap/soledad/common/tests/test_couch.py4
-rw-r--r--server/changes/create_db_cmd3
-rwxr-xr-xserver/pkg/create-user-db16
8 files changed, 79 insertions, 19 deletions
diff --git a/README.rst b/README.rst
index b98eec06..a2755f92 100644
--- a/README.rst
+++ b/README.rst
@@ -55,3 +55,36 @@ to run tests in development mode you must do the following::
Note that to run CouchDB tests, be sure you have ``CouchDB`` installed on your
system.
+
+
+Privileges
+-----
+In order to prevent privilege escalation, Soledad should not be run as a
+database administrator. This implies the following side effects:
+
+-----------------
+Database creation:
+-----------------
+Can be done via a script located in ``server/pkg/create-user-db``
+It reads a netrc file that should be placed on
+``/etc/couchdb/couchdb-admin.netrc``.
+That file holds the admin credentials in netrc format and should be accessible
+only by 'soledad-admin' user.
+
+The debian package will do the following in order to automate this:
+
+* create a user ``soledad-admin``
+* make this script available as ``create-user-db`` in ``/usr/bin``
+* grant restricted sudo access, that only enables user ``soledad`` to call this
+ exact command via ``soledad-admin`` user.
+
+The server side process, configured via ``/etc/leap/soledad-server.conf``, will
+then use a parameter called 'create_cmd' to know which command is used to
+allocate new databases. All steps of creation process is then handled
+automatically by the server, following the same logic as u1db server.
+
+------------------
+Database deletion:
+------------------
+No code at all handles this and privilege to do so needs to be removed as
+explained before. This can be automated via a simple cron job.
diff --git a/common/changes/create_db_cmd b/common/changes/create_db_cmd
new file mode 100644
index 00000000..00bbdf71
--- /dev/null
+++ b/common/changes/create_db_cmd
@@ -0,0 +1,2 @@
+ o Add a sanitized command executor for database creation and re-enable
+ user database creation on CouchServerState via command line.
diff --git a/common/src/leap/soledad/common/command.py b/common/src/leap/soledad/common/command.py
index 978cec91..811bf135 100644
--- a/common/src/leap/soledad/common/command.py
+++ b/common/src/leap/soledad/common/command.py
@@ -24,26 +24,27 @@ Utility to sanitize and run shell commands.
import subprocess
-def exec_validated_cmd(cmd, args, validator=None):
+def exec_validated_cmd(cmd, argument, validator=None):
"""
- Executes cmd, validating args with validator.
+ Executes cmd, validating argument with a validator function.
:param cmd: command.
:type dbname: str
- :param args: arguments.
- :type args: str
- :param validator: optional function to validate args
+ :param argument: argument.
+ :type argument: str
+ :param validator: optional function to validate argument
:type validator: function
:return: exit code and stdout or stderr (if code != 0)
:rtype: (int, str)
"""
- if validator and not validator(args):
+ if validator and not validator(argument):
return 1, "invalid argument"
command = cmd.split(' ')
- command.append(args)
+ command.append(argument)
try:
- process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ process = subprocess.Popen(command, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
except OSError, e:
return 1, e
(out, err) = process.communicate()
diff --git a/common/src/leap/soledad/common/couch.py b/common/src/leap/soledad/common/couch.py
index d9ed5026..4c5f6400 100644
--- a/common/src/leap/soledad/common/couch.py
+++ b/common/src/leap/soledad/common/couch.py
@@ -435,7 +435,7 @@ class CouchDatabase(CommonBackend):
self._set_replica_uid(replica_uid)
if ensure_ddocs:
self.ensure_ddocs_on_db()
- self.ensure_security()
+ self.ensure_security_ddoc()
self._cache = None
@property
@@ -468,10 +468,15 @@ class CouchDatabase(CommonBackend):
getattr(ddocs, ddoc_name)))
self._database.save(ddoc)
- def ensure_security(self):
+ def ensure_security_ddoc(self):
"""
Make sure that only soledad user is able to access this database as
- a member.
+ an unprivileged member, meaning that administration access will
+ be forbidden even inside an user database.
+ The goal is to make sure that only the lowest access level is given
+ to the unprivileged CouchDB user set on the server process.
+ This is achieved by creating a _security design document, see:
+ http://docs.couchdb.org/en/latest/api/database/security.html
"""
security = self._database.security
security['members'] = {'names': ['soledad'], 'roles': []}
@@ -1386,12 +1391,9 @@ class CouchSyncTarget(CommonSyncTarget):
source_replica_transaction_id)
-DB_NAME_MASK = "^user-[a-f0-9]+$"
-
-
def is_db_name_valid(name):
"""
- Validate a user database using DB_NAME_MASK.
+ Validate a user database using a regular expression.
:param name: database name.
:type name: str
@@ -1399,7 +1401,8 @@ def is_db_name_valid(name):
:return: boolean for name vailidity
:rtype: bool
"""
- return re.match(DB_NAME_MASK, name) is not None
+ db_name_regex = "^user-[a-f0-9]+$"
+ return re.match(db_name_regex, name) is not None
class CouchServerState(ServerState):
diff --git a/common/src/leap/soledad/common/tests/test_command.py b/common/src/leap/soledad/common/tests/test_command.py
index af4903eb..420f91ae 100644
--- a/common/src/leap/soledad/common/tests/test_command.py
+++ b/common/src/leap/soledad/common/tests/test_command.py
@@ -50,4 +50,6 @@ class ExecuteValidatedCommandTest(unittest.TestCase):
def test_return_status_code_number_on_failure(self):
status, out = exec_validated_cmd("ls", "user-bebacafe")
self.assertEquals(status, 2)
- self.assertIn('ls: cannot access user-bebacafe: No such file or directory\n', out)
+ self.assertIn(
+ 'ls: cannot access user-bebacafe: No such file or directory\n',
+ out)
diff --git a/common/src/leap/soledad/common/tests/test_couch.py b/common/src/leap/soledad/common/tests/test_couch.py
index 3622bb56..d1a07a3a 100644
--- a/common/src/leap/soledad/common/tests/test_couch.py
+++ b/common/src/leap/soledad/common/tests/test_couch.py
@@ -1504,11 +1504,11 @@ class CouchDatabaseExceptionsTests(CouchDBTestCase):
def test_ensure_security_doc(self):
"""
Ensure_security creates a _security ddoc to ensure that only soledad
- will have member access to a db.
+ will have the lowest privileged access to an user db.
"""
self.create_db(ensure=False)
self.assertFalse(self.db._database.security)
- self.db.ensure_security()
+ self.db.ensure_security_ddoc()
security_ddoc = self.db._database.security
self.assertIn('admins', security_ddoc)
self.assertFalse(security_ddoc['admins']['names'])
diff --git a/server/changes/create_db_cmd b/server/changes/create_db_cmd
new file mode 100644
index 00000000..cee0a935
--- /dev/null
+++ b/server/changes/create_db_cmd
@@ -0,0 +1,3 @@
+ o Adds a new config parameter 'create_cmd', which allows sysadmin to specify
+ which command will create a database. That command was added in
+ pkg/create-user-db and debian package automates steps needed for sudo access.
diff --git a/server/pkg/create-user-db b/server/pkg/create-user-db
index edcb8a82..dd68f792 100755
--- a/server/pkg/create-user-db
+++ b/server/pkg/create-user-db
@@ -1,4 +1,20 @@
#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# create-user-db
+# Copyright (C) 2015 LEAP
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
import sys
import netrc