================
Configuring Zino
================
Minimal configuration
=====================
At minimum, Zino must be configured with a list of SNMP-enabled routers to
monitor, the :file:`polldevs.cf` file, and a list of users, the :file:`secrets`
file.
By default, it looks for :file:`polldevs.cf` in the current
working directory, but a different configuration file can be specified
using the ``--polldevs`` command line option.
See :download:`polldevs.cf.example <../polldevs.cf.example>` file for an
example of the configuration format, reproduced below:
.. literalinclude:: ../polldevs.cf.example
Zino will check :file:`polldevs.cf` for changes on a scheduled interval
while it’s running, so any changes made while Zino is running should be
picked up without requiring a restart of the process.
The :file:`secrets` file is of a much simpler format, see
:ref:`configuring-api-users`. If it is readable for other users than the one
Zino runs as, Zino will log a warning. This file is read on every log in.
Configuring other settings
==========================
Other settings can be also configured in a separate
`TOML `__ file, which defaults to ``zino.toml`` in
the current working directory, but a different file can be specified
using the ``--config-file`` command line option.
See the :download:`zino.toml.example <../zino.toml.example>` file for the
settings that can be configured and their default values, reproduced below:
.. literalinclude:: ../zino.toml.example
Zino does not currently check ``zino.toml`` for changes on a scheduled
interval while it's running, so Zino needs to be restarted for changes
to take effect.
.. _configuring-process:
Process configuration
---------------------
The ``[process]`` section controls process-level behavior.
.. code-block:: toml
[process]
user = "zino"
``user``
Username to switch to after binding to privileged ports. When Zino starts
as root, it will drop privileges to this user once protected ports (like
the SNMP trap port 162) are bound. This can be overridden by the ``--user``
command-line option. Default: not set (no privilege dropping).
.. _configuring-trap-reception:
Configuring trap reception
--------------------------
By default, Zino binds directly to a UDP port (default 162) to receive SNMP
traps. This requires Zino to start as root (or with the
``CAP_NET_BIND_SERVICE`` capability on Linux).
Alternatively, Zino can receive traps through an external SNMP trap
multiplexer. A trap multiplexer can run as root and bind to port 162, then
re-broadcasts incoming raw trap packets to connected clients. This allows Zino
(and an arbitrary number of other programs) to receive traps without having
elevated privileges.
Two multiplexer protocols are supported:
``straps``
The original trap multiplexer from the `Scotty
`_ project (version 2.1.x). It
creates a UNIX domain socket at ``/tmp/.straps-`` (e.g.
``/tmp/.straps-162``) and forwards framed trap packets to all connected
clients. The straps source can be found in the `scotty 2.1.11 tarball
`_ at
``tnm/snmp/straps.c`` — it is a self-contained C program with no external
dependencies.
``nmtrapd``
The newer variant from `FlightAware's scotty fork
`_. It uses a TCP socket on
localhost port 1702 instead of a UNIX domain socket. The source is at
``tnm/unix/nmtrapd.c`` in the repository.
To use a trap multiplexer, configure the ``[snmp.trap]`` section:
.. code-block:: toml
:caption: zino.toml
[snmp.trap]
source = "straps"
# straps_socket = "/tmp/.straps-162" # default
For nmtrapd:
.. code-block:: toml
:caption: zino.toml
[snmp.trap]
source = "nmtrapd"
# nmtrapd_host = "localhost" # default
# nmtrapd_port = 1702 # default
When using a multiplexer, the ``--trap-port`` command-line option is ignored.
Zino will automatically reconnect if the multiplexer connection is lost, and
includes a watchdog that detects silent connections (inspired by Zino 1's
``TrapWatchdog``).
.. _configuring-logging:
Configuring logging
-------------------
Zino uses the logging framework provided by the Python standard library. Most
aspects of how Zino handles logging can also be controlled through
:file:`zino.toml`. Specifically, Zino automatically feeds everything under the
`logging` section of :file:`zino.toml` to Python's
:py:func:`logging.config.dictConfig`. For a complete overview of which options
exist, please refer to `Python's documentation of the configuration dictionary
schema
`_.
The Zino example config includes comments that show Zino's default logging
setup.
Zino's log output is organized into a hierarchy of loggers that correspond to
the internal Python module hierarchy of Zino, which means that the log level of
different parts of Zino can be controlled individually. If, for example, you
specifically wanted the reachability task to log debug message, you could add
this to the configuration:
.. code-block:: toml
:caption: zino.toml
[logging.loggers."zino.tasks.reachabletask"]
level = "DEBUG"
A more complex example could be to specifically output all kinds of debug-level
information from `netsnmp-cffi` and the Net-SNMP C library to *a separate
file*. Due to the sheer volume of debug logs, it could even be desirable to
enable automatic log rotation every time the log file exceeds 1GB in size:
.. code-block:: toml
:caption: zino.toml
# Separate file handler for netsnmpy debug logs
[logging.handlers.netsnmp_file]
class = "logging.handlers.RotatingFileHandler"
formatter = "standard"
filename = "netsnmp-debug.log"
maxBytes = 1073741824 # 1GB
# Keep 3 backup files
backupCount = 3
# Send netsnmpy debug logs to a separate file to avoid console spam
[logging.loggers.netsnmpy]
level = "DEBUG"
handlers = ["netsnmp_file"]
# Avoid duplicate log message by disabling propagation to the root logger
propagate = false
.. tip::
Zino can also be manually made to log its list of currently executing
polling jobs (including their start times and runtime duration) by sending
it the ``USR1`` signal to a running Zino process, for example by using a
command like ``pkill -SIGUSR1 zino``.
.. _configuring-api-users:
Configuring API users
=====================
Zino 2 reimplements the text-based (vaguely SMTP-esque) API protocol
from Zino 1, warts and all. This means that the protocol runs over
**unencrypted** TCP sessions. Access to restricted API information
requires authentication through the ``USER`` command. Usernames and
passwords are configured in *cleartext* in a :file:`secrets` file, e.g.:
::
user1 password123
user2 my-pets-name
You should therefore ensure that the :file:`secrets` file is only readable
for the user that the ``zino`` command runs as.
Please note that passwords are *not transmitted in cleartext* over API
socket connections. The Zino server protocol utilizes a
challenge-response mechanism, in which the user logging in must prove
that they know the password by giving a correct response to the given
challenge.
When opening a connection to the API port, the Zino server will
immediately send a hello message with a session challenge included:
.. code:: console
$ telnet localhost 8001
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
200 6077fe9fa53e4921b35c11cf6ef8891bc0194875 Hello, there
To authenticate properly, the client must issue the ``USER`` command,
which has two arguments: A username and a challenge response string.
Given the challenge value from above
(``6077fe9fa53e4921b35c11cf6ef8891bc0194875``), the proper challenge
response for ``user1`` can be computed on the command line thus:
.. code:: shell
$ echo -n "6077fe9fa53e4921b35c11cf6ef8891bc0194875 password123" | sha1sum
4daf3c1448c2c4b3b92489024cc4676f70c26b1d -
$
The proper way to authenticate as ``user1`` would then be to issue this
command:
::
USER user1 4daf3c1448c2c4b3b92489024cc4676f70c26b1d