diff options
-rw-r--r-- | doc/server/acl.txt | 41 | ||||
-rw-r--r-- | doc/server/plugins/misc/acl.txt | 33 | ||||
-rw-r--r-- | src/lib/Bcfg2/Client/__init__.py | 1 | ||||
-rw-r--r-- | src/lib/Bcfg2/Server/Core.py | 28 |
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) |