diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..89a377c67a2bd481600cb128879ad950be684a9b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea +*.iml +config/*.conf diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..e14962c1ed7a47c9cd433178717fc81b9468fbf4 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,50 @@ +image: docker:latest + +services: + - docker:dind + +before_script: + - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + +# +# TESTS +# + +lint:dockerfile: + stage: test + image: hadolint/hadolint:latest-debian + before_script: + - mkdir ~/.config + - cp ./.hadolint.yaml ~/.config/hadolint.yaml + script: + - hadolint ./context/Dockerfile + +lint:shell-script: + stage: test + image: koalaman/shellcheck-alpine:latest + before_script: + - shellcheck -V + script: +# - shellcheck ./context/s3-purge.sh + - exit 0 + +# +# IMAGE BUILDS/PUSHES +# + +build:master: + stage: deploy + script: + - docker build --pull -t "$CI_REGISTRY_IMAGE:latest" ./context/ +# - docker push "$CI_REGISTRY_IMAGE:latest" + only: + - master + when: manual + +build:dev: + stage: deploy + script: + - docker build --pull -t "$CI_REGISTRY_IMAGE:dev" ./context/ +# - docker push "$CI_REGISTRY_IMAGE:dev" + except: + - master diff --git a/.hadolint.yaml b/.hadolint.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6ee0f3754f078193f8068ea9d1a015d7bbde3776 --- /dev/null +++ b/.hadolint.yaml @@ -0,0 +1 @@ +ignored: diff --git a/README.md b/README.md index 801bae73fd97ba8a894f2492d64a10e2920361dc..8aced80e9ad99fa51c445cdf7d4830216b37751c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,12 @@ # nut-upsd +Fully-customizable `nut` instance in a container. Many images exist, but they are +feature-limited due to how `nut`'s configuration is handled. This image aims to +provide all `nut` options without making too many compromises. + +## Usage + +1. Copy any of the `./config/*.conf.sample` files to `./config/[FILENAME].conf` +and modify as needed. +1. `docker-compose up -d` +1. `nut` will be available on the container's port `3493`. diff --git a/config/hosts.conf.sample b/config/hosts.conf.sample new file mode 100644 index 0000000000000000000000000000000000000000..24beb829560e2c82d076284ae9d925fa9e74aef1 --- /dev/null +++ b/config/hosts.conf.sample @@ -0,0 +1,29 @@ +# Network UPS Tools: example hosts.conf +# +# This file is used to control the CGI programs. If you have not +# installed them, you may safely ignore or delete this file. +# +# ----------------------------------------------------------------------- +# +# upsstats will use the list of MONITOR entries when displaying the +# default template (upsstats.html). The "FOREACHUPS" directive in the +# template will use this file to find systems running upsd. +# +# upsstats and upsimage also use this file to determine if a host may be +# monitored. This keeps evil people from using your system to annoy +# others with unintended queries. +# +# upsset presents a list of systems that may be viewed and controlled +# using this file. +# +# ----------------------------------------------------------------------- +# +# Usage: list systems running upsd that you want to monitor +# +# MONITOR <system> "<host description>" +# +# Examples: +# +# MONITOR myups@localhost "Local UPS" +# MONITOR su2200@10.64.1.1 "Finance department" +# MONITOR matrix@shs-server.example.edu "Sierra High School data room #1" diff --git a/config/nut.conf.sample b/config/nut.conf.sample new file mode 100644 index 0000000000000000000000000000000000000000..b0c2685c7d7d1498bf905226292647e7348298b1 --- /dev/null +++ b/config/nut.conf.sample @@ -0,0 +1,32 @@ +# Network UPS Tools: example nut.conf +# +############################################################################## +# General section +############################################################################## +# The MODE determines which part of the NUT is to be started, and which +# configuration files must be modified. +# +# This file try to standardize the various files being found in the field, like +# /etc/default/nut on Debian based systems, /etc/sysconfig/ups on RedHat based +# systems, ... Distribution's init script should source this file to see which +# component(s) has to be started. +# +# The values of MODE can be: +# - none: NUT is not configured, or use the Integrated Power Management, or use +# some external system to startup NUT components. So nothing is to be started. +# - standalone: This mode address a local only configuration, with 1 UPS +# protecting the local system. This implies to start the 3 NUT layers (driver, +# upsd and upsmon) and the matching configuration files. This mode can also +# address UPS redundancy. +# - netserver: same as for the standalone configuration, but also need +# some more network access controls (firewall, tcp-wrappers) and possibly a +# specific LISTEN directive in upsd.conf. +# Since this MODE is opened to the network, a special care should be applied +# to security concerns. +# - netclient: this mode only requires upsmon. +# +# IMPORTANT NOTE: +# This file is intended to be sourced by shell scripts. +# You MUST NOT use spaces around the equal sign! + +MODE=none diff --git a/config/ups.conf.sample b/config/ups.conf.sample new file mode 100644 index 0000000000000000000000000000000000000000..f7de6db5e3158505aaf53c02db68c8b94564cd02 --- /dev/null +++ b/config/ups.conf.sample @@ -0,0 +1,141 @@ +# Network UPS Tools: example ups.conf +# +# --- SECURITY NOTE --- +# +# If you use snmp-ups and set a community string in here, you +# will have to secure this file to keep other users from obtaining +# that string. It needs to be readable by upsdrvctl and any drivers, +# and by upsd. +# +# --- +# +# This is where you configure all the UPSes that this system will be +# monitoring directly. These are usually attached to serial ports, but +# USB devices and SNMP devices are also supported. +# +# This file is used by upsdrvctl to start and stop your driver(s), and +# is also used by upsd to determine which drivers to monitor. The +# drivers themselves also read this file for configuration directives. +# +# The general form is: +# +# [upsname] +# driver = <drivername> +# port = <portname> +# < any other directives here > +# +# The section header ([upsname]) can be just about anything as long as +# it is a single word inside brackets. upsd uses this to uniquely +# identify a UPS on this system. +# +# If you have a UPS called snoopy, your section header would be "[snoopy]". +# On a system called "doghouse", the line in your upsmon.conf to monitor +# it would look something like this: +# +# MONITOR snoopy@doghouse 1 upsmonuser mypassword master +# +# It might look like this if monitoring in slave mode: +# +# MONITOR snoopy@doghouse 1 upsmonuser mypassword slave +# +# Configuration directives +# ------------------------ +# +# These directives are used by upsdrvctl only and should be specified outside +# of a driver definition: +# +# maxretry: Optional. Specify the number of attempts to start the driver(s), +# in case of failure, before giving up. A delay of 'retrydelay' is +# inserted between each attempt. Caution should be taken when using +# this option, since it can impact the time taken by your system to +# start. +# +# The built-in default is 1 attempt. +# +# retrydelay: Optional. Specify the delay between each restart attempt of the +# driver(s), as specified by 'maxretry'. Caution should be taken +# when using this option, since it can impact the time taken by your +# system to start. +# +# The default is 5 seconds. +# + +# Set maxretry to 3 by default, this should mitigate race with slow devices: +maxretry = 3 + +# These directives are common to all drivers that support ups.conf: +# +# driver: REQUIRED. Specify the program to run to talk to this UPS. +# apcsmart, bestups, and sec are some examples. +# +# port: REQUIRED. The serial port where your UPS is connected. +# /dev/ttyS0 is usually the first port on Linux boxes, for example. +# +# sdorder: optional. When you have multiple UPSes on your system, you +# usually need to turn them off in a certain order. upsdrvctl +# shuts down all the 0s, then the 1s, 2s, and so on. To exclude +# a UPS from the shutdown sequence, set this to -1. +# +# The default value for this parameter is 0. +# +# nolock: optional, and not recommended for use in this file. +# +# If you put nolock in here, the driver will not lock the +# serial port every time it starts. This may allow other +# processes to seize the port if you start more than one by +# mistake. +# +# This is only intended to be used on systems where locking +# absolutely must be disabled for the software to work. +# +# maxstartdelay: optional. This can be set as a global variable +# above your first UPS definition and it can also be +# set in a UPS section. This value controls how long +# upsdrvctl will wait for the driver to finish starting. +# This keeps your system from getting stuck due to a +# broken driver or UPS. +# +# The default is 45 seconds. +# +# synchronous: optional. The driver work by default in asynchronous +# mode (i.e *synchronous=no*). This means that all data +# are pushed by the driver on the communication socket to +# upsd (Unix socket on Unix, Named pipe on Windows) without +# waiting for these data to be actually consumed. With +# some HW, such as ePDUs, that can produce a lot of data, +# asynchronous mode may cause some congestion, resulting in +# the socket to be full, and the driver to appear as not +# connected. By enabling the 'synchronous' flag +# (value = 'yes'), the driver will wait for data to be +# consumed by upsd, prior to publishing more. This can be +# enabled either globally or per driver. +# +# The default is 'no' (i.e. asynchronous mode) for backward +# compatibility of the driver behavior. +# +# Anything else is passed through to the hardware-specific part of +# the driver. +# +# Examples +# -------- +# +# A simple example for a UPS called "powerpal" that uses the blazer_ser +# driver on /dev/ttyS0 is: +# +# [powerpal] +# driver = blazer_ser +# port = /dev/ttyS0 +# desc = "Web server" +# +# If your UPS driver requires additional settings, you can specify them +# here. For example, if it supports a setting of "1234" for the +# variable "cable", it would look like this: +# +# [myups] +# driver = mydriver +# port = /dev/ttyS1 +# cable = 1234 +# desc = "Something descriptive" +# +# To find out if your driver supports any extra settings, start it with +# the -h option and/or read the driver's documentation. diff --git a/config/upsd.conf.sample b/config/upsd.conf.sample new file mode 100644 index 0000000000000000000000000000000000000000..5cb94062ce5f090f5dd368f5de8e6f84e93b07ed --- /dev/null +++ b/config/upsd.conf.sample @@ -0,0 +1,121 @@ +# Network UPS Tools: example upsd configuration file +# +# This file contains access control data, you should keep it secure. +# +# It should only be readable by the user that upsd becomes. See the FAQ. +# +# Each entry below provides usage and default value. +# +# For more information, refer to upsd.conf manual page. + +# ======================================================================= +# MAXAGE <seconds> +# MAXAGE 15 +# +# This defaults to 15 seconds. After a UPS driver has stopped updating +# the data for this many seconds, upsd marks it stale and stops making +# that information available to clients. After all, the only thing worse +# than no data is bad data. +# +# You should only use this if your driver has difficulties keeping +# the data fresh within the normal 15 second interval. Watch the syslog +# for notifications from upsd about staleness. + +# ======================================================================= +# TRACKINGDELAY <seconds> +# TRACKINGDELAY 3600 +# +# This defaults to 1 hour. When instant commands and variables setting status +# tracking is enabled, status execution information are kept during this +# amount of time, and then cleaned up. + +# ======================================================================= +# STATEPATH <path> +# STATEPATH /var/run/nut +# +# Tell upsd to look for the driver state sockets in 'path' rather +# than the default that was compiled into the program. + +# ======================================================================= +# LISTEN <IP address or name> [<port>] +# LISTEN 127.0.0.1 3493 +# LISTEN ::1 3493 +# LISTEN myhostname 83493 +# LISTEN myhostname.mydomain +# +# This defaults to the localhost listening addresses and port 3493. +# In case of IP v4 or v6 disabled kernel, only the available one will be used. +# +# You may specify each interface IP address or name that you want upsd to +# listen on for connections, optionally with a port number. +# +# You may need this if you have multiple interfaces on your machine and +# you don't want upsd to listen to all interfaces (for instance on a +# firewall, you may not want to listen to the external interface). +# +# This will only be read at startup of upsd. If you make changes here, +# you'll need to restart upsd, reload will have no effect. + +# ======================================================================= +# MAXCONN <connections> +# MAXCONN 1024 +# +# This defaults to maximum number allowed on your system. Each UPS, each +# LISTEN address and each client count as one connection. If the server +# runs out of connections, it will no longer accept new incoming client +# connections. Only set this if you know exactly what you're doing. + +# ======================================================================= +# CERTFILE <certificate file> +# CERTFILE /usr/local/ups/etc/upsd.pem +# +# When compiled with SSL support with OpenSSL backend, +# you can enter the certificate file here. +# The certificates must be in PEM format and must be sorted starting with +# the subject's certificate (server certificate), followed by intermediate +# CA certificates (if applicable_ and the highest level (root) CA. It should +# end with the server key. See 'docs/security.txt' or the Security chapter of +# NUT user manual for more information on the SSL support in NUT. +# +# See 'docs/security.txt' or the Security chapter of NUT user manual +# for more information on the SSL support in NUT. + +# ======================================================================= +# CERTPATH <certificate file or directory> +# CERTPATH /usr/local/ups/etc/cert/upsd +# +# When compiled with SSL support with NSS backend, +# you can enter the certificate path here. +# Certificates are stored in a dedicated database (split into 3 files). +# Specify the path of the database directory. +# +# See 'docs/security.txt' or the Security chapter of NUT user manual +# for more information on the SSL support in NUT. + +# ======================================================================= +# CERTIDENT <certificate name> <database password> +# CERTIDENT "my nut server" "MyPasSw0rD" +# +# When compiled with SSL support with NSS backend, +# you can specify the certificate name to retrieve from database to +# authenticate itself and the password +# required to access certificate related private key. +# +# See 'docs/security.txt' or the Security chapter of NUT user manual +# for more information on the SSL support in NUT. + +# ======================================================================= +# CERTREQUEST <certificate request level> +# CERTREQUEST REQUIRE +# +# When compiled with SSL support with NSS backend and client certificate +# validation (disabled by default, see 'docs/security.txt'), +# you can specify if upsd requests or requires client's' certificates. +# Possible values are : +# - 0 to not request to clients to provide any certificate +# - 1 to require to all clients a certificate +# - 2 to require to all clients a valid certificate +# +# See 'docs/security.txt' or the Security chapter of NUT user manual +# for more information on the SSL support in NUT. + diff --git a/config/upsd.users.sample b/config/upsd.users.sample new file mode 100644 index 0000000000000000000000000000000000000000..15a0206a32a8fe8a0801a401ac31f2d4919c6deb --- /dev/null +++ b/config/upsd.users.sample @@ -0,0 +1,75 @@ +# Network UPS Tools: Example upsd.users +# +# This file sets the permissions for upsd - the UPS network daemon. +# Users are defined here, are given passwords, and their privileges are +# controlled here too. Since this file will contain passwords, keep it +# secure, with only enough permissions for upsd to read it. + +# -------------------------------------------------------------------------- + +# Each user gets a section. To start a section, put the username in +# brackets on a line by itself. To set something for that user, specify +# it under that section heading. The username is case-sensitive, so +# admin and AdMiN are two different users. +# +# Possible settings: +# +# password: The user's password. This is case-sensitive. +# +# -------------------------------------------------------------------------- +# +# actions: Let the user do certain things with upsd. +# +# Valid actions are: +# +# SET - change the value of certain variables in the UPS +# FSD - set the "forced shutdown" flag in the UPS +# +# -------------------------------------------------------------------------- +# +# instcmds: Let the user initiate specific instant commands. Use "ALL" +# to grant all commands automatically. There are many possible +# commands, so use 'upscmd -l' to see what your hardware supports. Here +# are a few examples: +# +# test.panel.start - Start a front panel test +# test.battery.start - Start battery test +# test.battery.stop - Stop battery test +# calibrate.start - Start calibration +# calibrate.stop - Stop calibration +# +# -------------------------------------------------------------------------- +# +# Example: +# +# [admin] +# password = mypass +# actions = SET +# instcmds = ALL +# + +# +# --- Configuring for a user who can execute tests only +# +# [testuser] +# password = pass +# instcmds = test.battery.start +# instcmds = test.battery.stop + +# +# --- Configuring for upsmon +# +# To add a user for your upsmon, use this example: +# +# [upsmon] +# password = pass +# upsmon master +# or +# upsmon slave +# +# The matching MONITOR line in your upsmon.conf would look like this: +# +# MONITOR myups@localhost 1 upsmon pass master (or slave) +# +# See comments in the upsmon.conf(.sample) file for details about this +# keyword and the difference of NUT slave and master systems. diff --git a/config/upsset.conf.sample b/config/upsset.conf.sample new file mode 100644 index 0000000000000000000000000000000000000000..921a20aa528d463fa54fc49468bf194b12fa8a5c --- /dev/null +++ b/config/upsset.conf.sample @@ -0,0 +1,36 @@ +# Network UPS Tools - upsset.conf sample file +# +# This file is provided to ensure that you do not expose your upsd server +# to the world upon installing the CGI programs. Specifically, it keeps +# the upsset.cgi program from running until you have assured it that you +# have secured your web server's CGI directory. +# +# By default, your web server will probably let anyone access upsset.cgi +# once it is installed. This means that anyone could attempt to crack +# upsd logins since they would appear to be coming from your web server, +# rather than the outside world, slipping through any ACL/ACCESS definitions. +# +# For this reason, you *MUST* first secure your CGI programs before +# enabling upsset in this configuration file. If you can't do this in +# your web server, then you should *not* run this program. +# +# For Apache, the .htaccess file can be used in the directory with the +# programs. You'll need something like this: +# +# <Files upsset.cgi> +# deny from all +# allow from your.network.addresses +# </Files> +# +# You will probably have to set "AllowOverride Limit" for this directory in +# your server-level configuration file as well. +# +# If this doesn't make sense, then stop reading and leave this program alone. +# +# Assuming you have all this done (and it works), then you may uncomment +# the line below and start using upsset.cgi through your web browser. +# + +### +### I_HAVE_SECURED_MY_CGI_DIRECTORY +### diff --git a/context/Dockerfile b/context/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..9091a3e93bba80869d8e53cc39a56272bc7bc199 --- /dev/null +++ b/context/Dockerfile @@ -0,0 +1,17 @@ +FROM debian:buster-slim + +LABEL maintainer="ethitter" +LABEL version="1.0" + +RUN echo "deb http://security.debian.org/ buster/updates main" >> /etc/apt/sources.list + +RUN apt-get update \ + && apt-get -y --no-install-recommends install \ + nut \ + && apt-get autoremove -y \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# TODO: entrypoint? + +EXPOSE 3493 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..a32bbfb48efcd59033d5401a1483740eb090de2f --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +version: "3.7" +services: + nut: + #image: containers.ethitter.com:443/docker/s3-object-expirer:latest + build: + context: ./context + restart: unless-stopped + # TODO: mount a dir +# secrets: +# - source: s3_config +# target: /s3_config +# - source: s3_bucket +# target: /s3_bucket +# - source: s3_expire_days +# target: /s3_expire_days +#secrets: +# s3_config: +# file: ./config/.s3cfg +# s3_bucket: +# file: ./config/bucket +# s3_expire_days: +# file: ./config/expire_age_days