diff options
author | Csaba Henk <csaba@gluster.com> | 2011-09-20 16:20:18 +0200 |
---|---|---|
committer | Vijay Bellur <vijay@gluster.com> | 2011-09-22 05:24:41 -0700 |
commit | b27b9d36de798bb18eaa95524f3900f9e17ce3e5 (patch) | |
tree | 7357344c289afee7a196fbc8d01b4f56ae2a5d86 /xlators/features | |
parent | d7c9d2bfbd20727f90b0118c982ff9612aacacf2 (diff) |
geo-rep: implement IP address based access control
- gsyncd gets allow-network tunable which is expected to
hold a comma-separated list of IP network addresses
- for IP addess matching, bring in ipaddr module from Google
(http://code.google.com/p/ipaddr-py/, rev. trunk@225)
This will let users control master's access to slave's volumes
until we implement unprivileged geo-rep (delayed due to some
technical issues). It's also needed for the completeness of
our hardening efforts, as plain file slaves won't be able
to work with an unprivileged gsyncd.
Change-Id: I58431cba6592f8672e93ea89a5eef478905b00b9
BUG: 2825
Reviewed-on: http://review.gluster.com/488
Tested-by: Gluster Build System <jenkins@build.gluster.com>
Reviewed-by: Vijay Bellur <vijay@gluster.com>
Diffstat (limited to 'xlators/features')
-rw-r--r-- | xlators/features/marker/utils/syncdaemon/Makefile.am | 3 | ||||
-rw-r--r-- | xlators/features/marker/utils/syncdaemon/__codecheck.py | 61 | ||||
-rw-r--r-- | xlators/features/marker/utils/syncdaemon/gsyncd.py | 23 |
3 files changed, 64 insertions, 23 deletions
diff --git a/xlators/features/marker/utils/syncdaemon/Makefile.am b/xlators/features/marker/utils/syncdaemon/Makefile.am index ef2dc9aea..cc7cee102 100644 --- a/xlators/features/marker/utils/syncdaemon/Makefile.am +++ b/xlators/features/marker/utils/syncdaemon/Makefile.am @@ -1,5 +1,6 @@ syncdaemondir = $(libexecdir)/glusterfs/python/syncdaemon -syncdaemon_PYTHON = gconf.py gsyncd.py __init__.py master.py README.md repce.py resource.py configinterface.py syncdutils.py monitor.py libcxattr.py +syncdaemon_PYTHON = gconf.py gsyncd.py __init__.py master.py README.md repce.py resource.py configinterface.py syncdutils.py monitor.py libcxattr.py \ + $(top_builddir)/contrib/ipaddr-py/ipaddr.py CLEANFILES = diff --git a/xlators/features/marker/utils/syncdaemon/__codecheck.py b/xlators/features/marker/utils/syncdaemon/__codecheck.py index 832e75c44..e3386afba 100644 --- a/xlators/features/marker/utils/syncdaemon/__codecheck.py +++ b/xlators/features/marker/utils/syncdaemon/__codecheck.py @@ -1,27 +1,46 @@ import os import os.path import sys +import tempfile +import shutil -fl = os.listdir(os.path.dirname(sys.argv[0]) or '.') -fl.sort() -for f in fl: - if f[-3:] != '.py' or f[0] == '_': - continue - m = f[:-3] - sys.stdout.write('importing %s ...' % m) - __import__(m) - print(' OK.') +ipd = tempfile.mkdtemp(prefix = 'codecheck-aux') -def sys_argv_set(a): - sys.argv = sys.argv[:1] + a +try: + # add a fake ipaddr module, we don't want to + # deal with the real one (just test our code) + f = open(os.path.join(ipd, 'ipaddr.py'), 'w') + f.write(""" +class IPAddress(object): + pass +class IPNetwork(list): + pass +""") + f.close() + sys.path.append(ipd) -gsyncd = sys.modules['gsyncd'] -for a in [['--help'], ['--version'], ['--canonicalize-escape-url', '/foo']]: - print('>>> invoking program with args: %s' % ' '.join(a)) - pid = os.fork() - if not pid: - sys_argv_set(a) - gsyncd.main() - _, r = os.waitpid(pid, 0) - if r: - raise RuntimeError('invocation failed') + fl = os.listdir(os.path.dirname(sys.argv[0]) or '.') + fl.sort() + for f in fl: + if f[-3:] != '.py' or f[0] == '_': + continue + m = f[:-3] + sys.stdout.write('importing %s ...' % m) + __import__(m) + print(' OK.') + + def sys_argv_set(a): + sys.argv = sys.argv[:1] + a + + gsyncd = sys.modules['gsyncd'] + for a in [['--help'], ['--version'], ['--canonicalize-escape-url', '/foo']]: + print('>>> invoking program with args: %s' % ' '.join(a)) + pid = os.fork() + if not pid: + sys_argv_set(a) + gsyncd.main() + _, r = os.waitpid(pid, 0) + if r: + raise RuntimeError('invocation failed') +finally: + shutil.rmtree(ipd) diff --git a/xlators/features/marker/utils/syncdaemon/gsyncd.py b/xlators/features/marker/utils/syncdaemon/gsyncd.py index 9771822dc..f3b5988ad 100644 --- a/xlators/features/marker/utils/syncdaemon/gsyncd.py +++ b/xlators/features/marker/utils/syncdaemon/gsyncd.py @@ -13,6 +13,8 @@ from optparse import OptionParser, SUPPRESS_HELP from logging import Logger from errno import EEXIST, ENOENT +from ipaddr import IPAddress, IPNetwork + from gconf import gconf from syncdutils import FreeObject, norm, grabpidfile, finalize, log_raise_exception from syncdutils import GsyncdError @@ -159,6 +161,7 @@ def main_i(): op.add_option('--timeout', metavar='SEC', type=int, default=120) op.add_option('--sync-jobs', metavar='N', type=int, default=3) op.add_option('--turns', metavar='N', type=int, default=0, help=SUPPRESS_HELP) + op.add_option('--allow-network', metavar='IPS', default='') op.add_option('-c', '--config-file', metavar='CONF', type=str, action='callback', callback=store_local) # duh. need to specify dest or value will be mapped to None :S @@ -208,7 +211,9 @@ def main_i(): sys.stderr.write(op.get_usage() + "\n") sys.exit(1) - if os.getenv('_GSYNCD_RESTRICTED_'): + restricted = os.getenv('_GSYNCD_RESTRICTED_') + + if restricted: allopts = {} allopts.update(opts.__dict__) allopts.update(rconf) @@ -288,6 +293,22 @@ def main_i(): gconf.__dict__.update(opts.__dict__) gconf.configinterface = gcnf + if restricted and gconf.allow_network: + ssh_conn = os.getenv('SSH_CONNECTION') + if not ssh_conn: + #legacy env var + ssh_conn = os.getenv('SSH_CLIENT') + if ssh_conn: + allowed_networks = [ IPNetwork(a) for a in gconf.allow_network.split(',') ] + client_ip = IPAddress(ssh_conn.split()[0]) + allowed = False + for nw in allowed_networks: + if client_ip in nw: + allowed = True + break + if not allowed: + raise GsyncdError("client IP address is not allowed") + ffd = rconf.get('feedback_fd') if ffd: fcntl.fcntl(ffd, fcntl.F_SETFD, fcntl.FD_CLOEXEC) |