summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/server/acl.txt41
-rw-r--r--doc/server/plugins/misc/acl.txt33
-rw-r--r--src/lib/Bcfg2/Client/__init__.py1
-rw-r--r--src/lib/Bcfg2/Server/Core.py28
4 files changed, 96 insertions, 7 deletions
diff --git a/doc/server/acl.txt b/doc/server/acl.txt
new file mode 100644
index 000000000..6ea276a53
--- /dev/null
+++ b/doc/server/acl.txt
@@ -0,0 +1,41 @@
+.. -*- mode: rst -*-
+
+.. _server-access-control:
+
+================
+ Access Control
+================
+
+.. versionadded:: 1.4.0
+
+Bcfg2 exposes various functions via XML-RPC calls. Some of these are
+relatively benign (e.g., the calls necessary to generate a client
+configuration) while others can be used to inspect potentially private
+data on the server or very easily mount a denial of service attack.
+As a result, access control lists to limit exposure of these calls is
+built in. There are two possible ACL methods: built-in, and the
+:ref:`server-plugins-misc-acls` plugin.
+
+The built-in approach simply applies a restrictive default ACL that
+lets ``localhost`` perform all XML-RPC calls, and restricts all other
+machines to only the calls necessary to run the Bcfg2 client.
+Specifically:
+
+* If the remote client is ``127.0.0.1``, the call is allowed. Note
+ that, depending on where your Bcfg2 server listens and how it
+ communicates with itself, it likely will not identify to itself as
+ ``localhost``.
+* If the remote client is not ``127.0.0.1`` and the call is any of the
+ ``set_debug`` or ``toggle_debug`` methods (including
+ ``[toggle|set]_core_debug``), it is rejected.
+* If the remote client is not ``127.0.0.1`` and the call is
+ ``get_statistics`` (used by ``bcfg2-admin perf``), it is rejected.
+* If the remote client is not ``127.0.0.1`` and the call includes a
+ ``.`` -- i.e., it is dispatched to any plugin, such as
+ ``Packages.Refresh`` -- then it is rejected.
+* Otherwise, the call is allowed.
+
+The built-in ACL is *only* intended to ensure that Bcfg2 is secure by
+default; it will not be sufficient in many (or even most) cases. In
+these cases, it's recommended that you use the
+:ref:`server-plugins-misc-acls` plugin.
diff --git a/doc/server/plugins/misc/acl.txt b/doc/server/plugins/misc/acl.txt
index 45780bef8..226b56a44 100644
--- a/doc/server/plugins/misc/acl.txt
+++ b/doc/server/plugins/misc/acl.txt
@@ -200,3 +200,36 @@ could also do something like ``*.toggle_debug`` to allow a host to
enable or disable debugging for all plugins.
No other bash globbing is supported.
+
+Examples
+========
+
+The :ref:`default ACL list <server-access-control>` can be described
+in ``ip.xml`` fairly simply:
+
+.. code-block:: xml
+
+ <ACL>
+ <Allow address="127.0.0.1" method="*.*"/>
+ <Allow address="127.0.0.1" method="*"/>
+ <Deny method="*.*"/>
+ <Deny method="*_debug"/>
+ <Deny method="get_statistics"/>
+ <Allow method="*"/>
+ </ACL>
+
+A basic configuration that is still very secure but perhaps more
+functional could be given in ``metadata.xml``:
+
+.. code-block:: xml
+
+ <ACL>
+ <Group name="bcfg2-server">
+ <Allow method="*.*"/>
+ <Allow method="*"/>
+ </Group>
+ <Deny method="*.*"/>
+ <Deny method="*_debug"/>
+ <Deny method="get_statistics"/>
+ <Allow method="*"/>
+ </ACL>
diff --git a/src/lib/Bcfg2/Client/__init__.py b/src/lib/Bcfg2/Client/__init__.py
index 005163607..19db94015 100644
--- a/src/lib/Bcfg2/Client/__init__.py
+++ b/src/lib/Bcfg2/Client/__init__.py
@@ -88,7 +88,6 @@ class Client(object):
options = Proxy.ComponentProxy.options + [
Bcfg2.Options.Common.syslog,
- Bcfg2.Options.Common.location,
Bcfg2.Options.Common.interactive,
Bcfg2.Options.BooleanOption(
"-q", "--quick", help="Disable some checksum verification"),
diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py
index b0b80e956..20ba62e0a 100644
--- a/src/lib/Bcfg2/Server/Core.py
+++ b/src/lib/Bcfg2/Server/Core.py
@@ -78,9 +78,23 @@ class NoExposedMethod (Exception):
method exposed with the given name. """
-# pylint: disable=W0702
+class DefaultACL(Plugin, ClientACLs):
+ """ Default ACL 'plugin' that provides security by default. This
+ is only loaded if no other ClientACLs plugin is enabled. """
+ def __init__(self, core, datastore):
+ Bcfg2.Server.Plugin.Plugin.__init__(self, core, datastore)
+ Bcfg2.Server.Plugin.ClientACLs.__init__(self)
+
+ def check_acl_ip(self, address, rmi):
+ return (("." not in rmi and
+ not rmi.endswith("_debug") and
+ rmi != 'get_statistics') or
+ address[0] == "127.0.0.1")
+
+
# in core we frequently want to catch all exceptions, regardless of
# type, so disable the pylint rule that catches that.
+# pylint: disable=W0702
class Core(object):
""" The server core is the container for all Bcfg2 server logic
@@ -282,7 +296,7 @@ class Core(object):
continue
self.logger.info("File monitor thread terminated")
- @Bcfg2.Server.Statistics.track_statistics()
+ @track_statistics()
def _update_vcs_revision(self):
""" Update the revision of the current configuration on-disk
from the VCS plugin """
@@ -344,14 +358,16 @@ class Core(object):
"failed to instantiate Core")
raise CoreInitError("No Metadata Plugin")
+ # ensure that an ACL plugin is loaded
+ if not self.plugins_by_type(Bcfg2.Server.Plugin.ClientACLs):
+ self.init_plugin(DefaultACL)
+
def init_plugin(self, plugin):
""" Import and instantiate a single plugin. The plugin is
stored to :attr:`plugins`.
- :param plugin: The name of the plugin. This is just the name
- of the plugin, in the appropriate case. I.e.,
- ``Cfg``, not ``Bcfg2.Server.Plugins.Cfg``.
- :type plugin: string
+ :param plugin: The plugin class to load.
+ :type plugin: type
:returns: None
"""
self.logger.debug("Loading plugin %s" % plugin.name)