split local and discord destinations and add network security

This commit is contained in:
Daniel afx 2021-01-30 04:24:55 +02:00
parent 5b1b201b48
commit 16e1724f31
13 changed files with 199 additions and 24 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
*.pyc

View file

@ -3,6 +3,8 @@ FROM alpine:3
ENV S6_OVERLAY_VERSION 2.2.0.1
ENV S6_OVERLAY_MD5HASH a114568c94d06dc69fdb9d91ed3f7535
RUN apk add --no-cache curl
RUN apk add --no-cache wget ca-certificates && \
apk --no-cache --update upgrade && \
cd /tmp && \
@ -22,8 +24,13 @@ RUN apk add --no-cache \
COPY /etc/ /etc/
COPY discord.sh /bin/discord.sh
RUN chmod +x /bin/discord.sh
EXPOSE 514/udp
EXPOSE 601/tcp
EXPOSE 6514/tcp
VOLUME /var/log
ENTRYPOINT ["/init"]

View file

@ -7,16 +7,23 @@ A small Alpine container running syslog-ng configured to log to `/var/log/messag
Basic usage with the default local destination:
```
docker build -t logmonitor .
docker run --env WEBHOOK=https://discordapp.com/api/webhooks/... -p 514:514/udp -d --name logmonitor --rm logmonitor:latest ; docker logs logmonitor --follow
docker stop logmonitor ; docker rm logmonitor
```
```
docker run -d --name syslog-ng -p 514:514/udp -p 601:601/tcp -p 6514:6514/tcp logmonitor
```
Destinations can be enabled or disabled with environment variables specified with `-e`.
### Environment variables
* `ENABLE_LOCAL` - set `True` to log to `/var/log/messages` in container (default: `False`)
* `ENABLE_LOCAL` - set `True` to log to `/var/log/system.log` in container (default: `False`)
* `ENABLE_DISCORD` - set `True` to log to `Discord` in container (default: `False`)
* `ALLOWED_SUBNET` - Define allowed network. (default: `10.0.0.0/24`)
* `SQL_HOST` - the IP or domain of the destination SQL server
* `SQL_PORT` - the port the destination SQL server runs on (defaults to `3306` if not specified)
* `SQL_USER` - the user name used to access the destination SQL server

30
discord.sh Normal file
View file

@ -0,0 +1,30 @@
#!/bin/sh
source /.envvars
SERVICE_URL="https://localhost:8443/"
# color codes examples: https://gist.github.com/deflax/e4fe4cced12103819c2663e2369911a5
while read LINE ; do
PRIO=`echo ${LINE} | cut -d ' ' -f 1`
if [ "${PRIO}" = "27" ] ; then
#test client notice - dark green
COLOR=2067276
elif [ "${PRIO}" = "134" ] ; then
#hpilo notice - grey
COLOR=9807270
else
#fallback to dark orange
COLOR=11027200
fi
SUBJECT=`echo ${LINE} | cut -d ' ' -f 2`
MESSAGE=`echo ${LINE} | cut -d ' ' -f 3-`
PAYLOAD=`printf "{ \"embeds\": [{\"title\": \"%s\", \"url\": \"%s\", \"description\": \"%s\", \"type\": \"link\", \"color\": %s }] }" "${SUBJECT}" "${SERVICE_URL}" "${MESSAGE}" "${COLOR}"`
echo ${PAYLOAD} > /var/log/discord.payload
HTTP_RESPONSE=`curl --write-out %{http_code} --silent --output /dev/null -X POST -H "Content-Type: application/json" -d @/var/log/discord.payload ${DISCORD_WEBHOOK}`
if [[ "${HTTP_RESPONSE}" != "204" ]] ; then
echo "Received HTTP-Code: ${HTTP_RESPONSE}" >> /var/log/discord.log
fi
done

22
docker-compose.yml Normal file
View file

@ -0,0 +1,22 @@
version: "3"
services:
logmonitor:
image: logmonitor:latest
ports:
- "514:514/udp"
volumes:
- "./data/logmonitor/log:/var/log"
environment:
ENABLE_LOCAL: true
ENABLE_DISCORD: true
DISCORD_WEBHOOK: https://discordapp.com/api/webhooks/CHANGEME
ALLOWED_SUBNET: 10.0.0.0/24
restart: always
networks:
- internal
labels:
- meta.role=logmonitor
networks:
internal: {}

View file

@ -3,7 +3,7 @@
CONFD=/etc/syslog-ng/conf.d
TEMPLATES=/etc/syslog-ng/templates
# enable and configure the SQL destination if SQL_* environment variables are set
# Setup the SQL destination if SQL_* environment variables are set
if $(env | grep -q SQL); then
if [ -z ${SQL_PORT+set} ]; then
@ -23,8 +23,8 @@ elif [ -f ${CONFD}/d_sql.conf ]; then
rm -f ${CONFD}/d_sql.conf
fi
DO_ENABLE_LOCAL=true
# Setup local template
DO_ENABLE_LOCAL=false
if [ ! -z ${ENABLE_LOCAL+set} ]; then
case $ENABLE_LOCAL in
true|True|TRUE|yes|Yes|YES|1|on|On|ON)
@ -32,12 +32,34 @@ if [ ! -z ${ENABLE_LOCAL+set} ]; then
;;
esac
fi
# enable the local destination if the appropriate environment variable is set
if ${DO_ENABLE_LOCAL}; then
echo "Logging to /var/log/messages ENABLED."
echo "Logging to Local ENABLED."
cp --remove-destination ${TEMPLATES}/d_local.template ${CONFD}/d_local.conf
else # otherwise make sure it's disabled
echo "Logging to /var/log/messages DISABLED."
echo "Logging to Local DISABLED."
rm -f ${CONFD}/d_local.conf
fi
# Setup discord template
DO_ENABLE_DISCORD=false
if [ ! -z ${ENABLE_DISCORD+set} ]; then
case $ENABLE_DISCORD in
true|True|TRUE|yes|Yes|YES|1|on|On|ON)
DO_ENABLE_DISCORD=true
;;
esac
fi
if ${DO_ENABLE_DISCORD}; then
echo "Logging to Discord ENABLED."
cp --remove-destination ${TEMPLATES}/d_discord.template ${CONFD}/d_discord.conf
if [ -z ${ALLOWED_SUBNET+set} ]; then
ALLOWED_SUBNET="10.0.0.0/24"
fi
echo "Allowed network subnet is ${ALLOWED_SUBNET}"
sed -i "s:ALLOWED_SUBNET:${ALLOWED_SUBNET}:" ${CONFD}/d_discord.conf
else # otherwise make sure it's disabled
echo "Logging to Discord DISABLED."
rm -f ${CONFD}/d_discord.conf
fi

View file

@ -1,8 +1,8 @@
#!/bin/sh
#!/usr/bin/with-contenv sh
while true
do
echo "] ping from logmonitor..."
sleep 10
echo "DISCORD_WEBHOOK=${DISCORD_WEBHOOK}" > /.envvars
sleep 3600
done

View file

@ -4,6 +4,6 @@ options {
keep_hostname(yes);
create_dirs(yes);
ts_format(iso);
time_reopen (10);
chain_hostnames (no);
time_reopen(10);
chain_hostnames(no);
};

View file

@ -18,7 +18,11 @@ source s_local {
};
source s_network {
default-network-drivers(
syslog(transport("udp"));
};
#source s_network {
# default-network-drivers(
# NOTE: TLS support
#
# the default-network-drivers() source driver opens the TLS
@ -30,8 +34,8 @@ source s_network {
# key-file("/etc/syslog-ng/certs/serverkey.pem")
# cert-file("/etc/syslog-ng/certs/servercert.pem")
# )
);
};
# );
#};
###
# Include all config files in /etc/syslog-ng/conf.d/

View file

@ -0,0 +1,13 @@
destination d_discord {
program("/bin/discord.sh" mark-mode(none) template("$PRI $HOST $MSGHDR $MSG\n"));
};
filter allowed_hosts {
netmask(ALLOWED_SUBNET);
};
log {
source(s_network);
filter(allowed_hosts);
destination(d_discord);
};

View file

@ -1,11 +1,9 @@
destination d_local {
file("/var/log/messages");
file("/var/log/messages-kv.log" template("$ISODATE $HOST $(format-welf --scope all-nv-pairs)\n") frac-digits(3));
file("/var/log/system.log" template("$ISODATE $PRI $HOST $MSGHDR $MSG\n"));
#file("/var/log/messages-kv.log" template("$ISODATE $HOST $(format-welf --scope all-nv-pairs)\n") frac-digits(3));
};
log {
source(s_local);
source(s_network);
destination(d_local);
};
};

10
tools/README.md Normal file
View file

@ -0,0 +1,10 @@
```
import syslog_client
log = syslog_client.Syslog("127.0.0.1")
log.notice("info msg")
log.warn("warning msg")
log.error("error msg")
```
```
log.send("howdy", syslog_client.WARNING)
```

61
tools/syslog_client.py Normal file
View file

@ -0,0 +1,61 @@
"""
Remote syslog client.
Works by sending UDP messages to a remote syslog server. The remote server
must be configured to accept logs from the network.
License: PUBLIC DOMAIN
Author: Christian Stigen Larsen
For more information, see RFC 3164.
"""
import socket
class Facility:
"Syslog facilities"
KERN, USER, MAIL, DAEMON, AUTH, SYSLOG, \
LPR, NEWS, UUCP, CRON, AUTHPRIV, FTP = range(12)
LOCAL0, LOCAL1, LOCAL2, LOCAL3, \
LOCAL4, LOCAL5, LOCAL6, LOCAL7 = range(16, 24)
class Level:
"Syslog levels"
EMERG, ALERT, CRIT, ERR, \
WARNING, NOTICE, INFO, DEBUG = range(8)
class Syslog:
"""A syslog client that logs to a remote server.
Example:
>>> log = Syslog(host="foobar.example")
>>> log.send("hello", Level.WARNING)
"""
def __init__(self,
host="localhost",
port=514,
facility=Facility.DAEMON):
self.host = host
self.port = port
self.facility = facility
self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def send(self, message, level):
"Send a syslog message to remote host using UDP."
data = "<%d>%s" % (level + self.facility*8, message)
self.socket.sendto(data, (self.host, self.port))
def warn(self, message):
"Send a syslog warning message."
self.send(message, Level.WARNING)
def notice(self, message):
"Send a syslog notice message."
self.send(message, Level.NOTICE)
def error(self, message):
"Send a syslog error message."
self.send(message, Level.ERR)
# ... add your own stuff here