From d8bbfbdf8b503538fff01bff80c5e6e12bfb44b3 Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Tue, 12 Nov 2013 23:48:25 +0100 Subject: Add probes.allowed_groups option to restrict group assignments. --- doc/server/plugins/probes/index.txt | 40 ++++++++++++++++++++++++++++++++++ doc/unsorted/dynamic_groups.txt | 27 ----------------------- src/lib/Bcfg2/Options.py | 17 ++++++++++++++- src/lib/Bcfg2/Server/Plugins/Probes.py | 10 ++++++++- 4 files changed, 65 insertions(+), 29 deletions(-) delete mode 100644 doc/unsorted/dynamic_groups.txt diff --git a/doc/server/plugins/probes/index.txt b/doc/server/plugins/probes/index.txt index 306a752b6..6f745e359 100644 --- a/doc/server/plugins/probes/index.txt +++ b/doc/server/plugins/probes/index.txt @@ -13,6 +13,9 @@ the system disk, you would want to know this information to correctly generate an `/etc/auto.master` autofs config file for each type. Here we will look at how to do this. +Probes also allow dynamic group assignment for clients, see +:ref:`_server-plugins-probes-dynamic-groups`. + First, create a ``Probes`` directory in our toplevel repository location:: @@ -119,6 +122,43 @@ is to add the ``/etc/auto.master`` to a Bundle: +.. _server-plugins-probes-dynamic-groups: + +Dynamic Group Assignment +======================== + +The output lines of the probe matching "group:" are used to +dynamically assign hosts to groups. These dynamic groups need not already +exist in ``Metadata/groups.xml``. If a dynamic group is defined in +``Metadata/groups.xml``, clients that include this group will also get +all included groups and bundles. + +Consider the following output of a probe:: + + group:debian-wheezy + group:amd64 + +This assigns the client to the groups debian-wheezy and amd64. + +To prevent clients from manipulating the probe output and choosing +unexpected groups (and receiving their potential sensitive files) you +can use the ``allowed_groups`` option in the ``[probes]`` section of +``bcfg2.conf`` on the server. This whitespace-separated list of anchored +regular expressions (must match the complete group name) controls +dynamic group assignments. Only matching groups are allowed. The +default allows all groups. + +.. versionadded:: TODO + +Example:: + + [probes] + allowed_groups = debian-(squeeze|wheezy|sid) i386 + +This allows the groups debian-squeeze, debian-wheezy, debian-sid and +i386. With the probe output from above, this setting would disallow +the group amd64. + Handling Probe Output ===================== diff --git a/doc/unsorted/dynamic_groups.txt b/doc/unsorted/dynamic_groups.txt deleted file mode 100644 index 11535dc8b..000000000 --- a/doc/unsorted/dynamic_groups.txt +++ /dev/null @@ -1,27 +0,0 @@ -.. -*- mode: rst -*- - -.. _unsorted-dynamic_groups: - -============== -Dynamic Groups -============== - -Bcfg2 supports the use of dynamic groups. These groups are not included -in a client's profile group, but instead are derived from the results -of probes executed on the client. These dynamic groups need not already -exist in ``Metadata/groups.xml``. If a dynamic group is defined in -``Metadata/groups.xml``, clients that include this group will also get -all included groups and bundles. - -Setting up dynamic groups -========================= - -In order to define a dynamic group, setup a probe that outputs the text -based on system properties:: - - group:groupname - -This output is processed by the Bcfg2 server, and results in dynamic -group membership in groupname for the client. See the :ref:`Probes -` page for a more thorough description -of probes. diff --git a/src/lib/Bcfg2/Options.py b/src/lib/Bcfg2/Options.py index 95abe64ae..f9b6a998b 100644 --- a/src/lib/Bcfg2/Options.py +++ b/src/lib/Bcfg2/Options.py @@ -311,6 +311,14 @@ def list_split(c_string): return re.split(r'\s*,\s*', c_string) return [] +def list_split_anchored_regex(c_string): + """ like list_split but split on whitespace and compile each element as + anchored regex """ + try: + return [re.compile('^' + x + '$') for x in re.split(r'\s+', c_string)] + except re.error: + raise ValueError("Not a list of regexes", c_string) + def colon_split(c_string): """ split an option string on colons, returning a list """ @@ -641,6 +649,12 @@ SERVER_CHILDREN = \ cf=('server', 'children'), cook=get_int, long_arg=True) +SERVER_PROBE_ALLOWED_GROUPS = \ + Option('Whitespace-separated list of group names (as regex) to which ' + 'probes can assign a client by writing "group:" to stdout.', + default=['.*'], + cf=('probes', 'allowed_groups'), + cook=list_split_anchored_regex) # database options DB_ENGINE = \ @@ -1225,7 +1239,8 @@ SERVER_COMMON_OPTIONS = dict(repo=SERVER_REPOSITORY, perflog=LOG_PERFORMANCE, perflog_interval=PERFLOG_INTERVAL, children=SERVER_CHILDREN, - client_timeout=CLIENT_TIMEOUT) + client_timeout=CLIENT_TIMEOUT, + probe_allowed_groups=SERVER_PROBE_ALLOWED_GROUPS) CRYPT_OPTIONS = dict(encrypt=ENCRYPT, decrypt=DECRYPT, diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py index 84e1638d6..59a73c4aa 100644 --- a/src/lib/Bcfg2/Server/Plugins/Probes.py +++ b/src/lib/Bcfg2/Server/Plugins/Probes.py @@ -204,6 +204,7 @@ class Probes(Bcfg2.Server.Plugin.Probing, err = sys.exc_info()[1] raise Bcfg2.Server.Plugin.PluginInitError(err) + self.allowed_cgroups = core.setup['probe_allowed_groups'] self.probedata = dict() self.cgroups = dict() self.load_data() @@ -391,11 +392,18 @@ class Probes(Bcfg2.Server.Plugin.Probing, if line.split(':')[0] == 'group': newgroup = line.split(':')[1].strip() if newgroup not in cgroups: - cgroups.append(newgroup) + if self._group_allowed(newgroup): + cgroups.append(newgroup) + else: + self.logger.info("Disallowed group assignment %s from %s" + % (newgroup, client.hostname)) dlines.remove(line) dobj = ProbeData("\n".join(dlines)) cprobedata[data.get('name')] = dobj + def _group_allowed(self, group): + return any(r.match(group) for r in self.allowed_cgroups) + def get_additional_groups(self, meta): return self.cgroups.get(meta.hostname, list()) get_additional_groups.__doc__ = \ -- cgit v1.2.3-1-g7c22