Merge pull request #32 from Roxedus/letsencrypt-F2BDiscord

Add letsencrypt:F2BDiscord
This commit is contained in:
aptalca 2020-04-09 17:05:09 -04:00 committed by GitHub
commit ca1083bc3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 179 additions and 66 deletions

BIN
.assets/Example.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

View File

@ -4,7 +4,7 @@ language: shell
branches:
only:
- <baseimagename>-<modname> #replace variables, omit brackets
- letsencrypt-f2bdiscord #replace variables, omit brackets
services:
- docker
@ -12,8 +12,8 @@ services:
env:
global:
- DOCKERHUB="linuxserver/mods" #don't modify
- BASEIMAGE="baseimagename" #replace
- MODNAME="modname" #replace
- BASEIMAGE="letsencrypt" #replace
- MODNAME="f2bdiscord" #replace
jobs:
include:

View File

@ -1,4 +1,6 @@
FROM scratch
LABEL maintainer="Roxedus"
# copy local files
COPY root/ /

View File

@ -1,21 +0,0 @@
## Buildstage ##
FROM lsiobase/alpine:3.9 as buildstage
RUN \
echo "**** install packages ****" && \
apk add --no-cache \
curl && \
echo "**** grab rclone ****" && \
mkdir -p /root-layer && \
curl -o \
/root-layer/rclone.deb -L \
"https://downloads.rclone.org/v1.47.0/rclone-v1.47.0-linux-amd64.deb"
# copy local files
COPY root/ /root-layer/
## Single layer deployed image ##
FROM scratch
# Add files from buildstage
COPY --from=buildstage /root-layer/ /

View File

@ -1,17 +1,38 @@
# Rsync - Docker mod for openssh-server
# F2B Discord Notification - Docker mod which allows Fail2Ban Discord embeds
This mod adds rsync to openssh-server, to be installed/updated during container start.
This mod enhances the Letsencrypt container adding better Fail2Ban notifications for discord.
In openssh-server docker arguments, set an environment variable `DOCKER_MODS=linuxserver/mods:openssh-server-rsync`
## Configuration
If adding multiple mods, enter them in an array separated by `|`, such as `DOCKER_MODS=linuxserver/mods:openssh-server-rsync|linuxserver/mods:openssh-server-mod2`
### Enable
# Mod creation instructions
In letsencrypt docker arguments, set an environment variable `DOCKER_MODS=linuxserver/mods:letsencrypt-f2bdiscord` to enable.
* Ask the team to create a new branch named `<baseimagename>-<modname>`. Baseimage should be the name of the image the mod will be applied to. The new branch will be based on the `template` branch.
* Fork the repo, checkout the newly created branch.
* Edit the `Dockerfile` for the mod. `Dockerfile.complex` is only an example and included for reference; it should be deleted when done.
* Inspect the `root` folder contents. Edit, add and remove as necessary.
* Edit this readme with pertinent info, delete these instructions.
* Finally edit the `travis.yml`. Customize the build branch, and the vars for `BASEIMAGE` and `MODNAME`.
* Submit PR against the branch created by the team.
### Mod configuration
**Environment variables used by this mod:**
[Discord webhook](https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks), it just need the last parts. `-e DISC_HOOK=40832456738934/7DcEpWr5V24OIEIELjg-KkHky86SrOgTqA`
[Your discord ID](https://support.discordapp.com/hc/en-us/articles/206346498-Where-can-I-find-my-User-Server-Message-ID-). `-e DISC_ME=120970603556503552`
[Map API Key](https://developer.mapquest.com/), get a key from mapquest. `-e DISC_API=YourKey`
#### Jail configuration example
```ini
[bitwarden]
filter = bitwarden
enabled = true
logpath = /fail2ban/bw/bitwarden.log
action = discordEmbed[bantime=24]
iptables-allports[name=Bitwarden]
```
Action arguments:
`bantime`(hour) is optional, but defaults to 24 when not set. Just reflects in the message, does not change the ban time
## Example
![Example picture](.assets/Example.png)

View File

@ -0,0 +1,98 @@
#!/usr/bin/env python3
import argparse
import collections
import datetime
import geoip2.database
import os
import requests
class Discord:
def __init__(self, data, action):
self.action = action
self.base = "https://discordapp.com/api/webhooks/"
self.data = data
self.token = os.getenv('DISC_HOOK', "") # If not setting enviroment variables, edit this
self.you = os.getenv('DISC_ME', "120970603556503552") # If not setting enviroment variables, edit this
def create_payload(self):
webhook = {
"username":"Fail2Ban",
"content": f"<@{self.you}>",
"embeds": [{}]
}
webhook["embeds"][0]["author"] = {"name": "Fail2Ban"}
webhook["embeds"][0]["timestamp"] = f"{datetime.datetime.utcnow()}"
if "ban" in self.action.action:
webhook["embeds"][0]["url"] = f"https://db-ip.com/{self.data['ip']}"
webhook["embeds"][0]["image"] = {"url": f"{self.data['map-img']}"}
webhook["embeds"][0]["fields"] = [{}]
webhook["embeds"][0]["fields"][0]["name"] = f":flag_{self.data['iso'].lower()}:"
webhook["embeds"][0]["fields"][0]["value"] = self.data["city"] or self.data["name"]
if self.action.action == "ban":
webhook["embeds"][0]["fields"].append({"name": f"Map", "value": f"[Link]({self.data['map-url']})"})
webhook["embeds"][0]["fields"].append({"name": f"Unban cmd", "value": f"fail2ban-client unban {self.data['ip']}"})
webhook["embeds"][0]["title"] = f"New ban on `{self.action.jail}`"
webhook["embeds"][0]["description"] = f"**{self.data['ip']}** got banned for `{self.action.time}` hours after `{self.action.fail}` tries"
webhook["embeds"][0]["color"] = 16194076
elif self.action.action == "unban":
webhook["embeds"][0]["title"] = f"Revoked ban on `{self.action.jail}`"
webhook["embeds"][0]["description"] = f"**{self.data['ip']}** is now unbanned"
webhook["embeds"][0]["color"] = 845872
elif self.action.action == "start":
webhook["content"] = ""
webhook["embeds"][0]["description"] = f"Started `{self.action.jail}`"
webhook["embeds"][0]["color"] = 845872
elif self.action.action == "stopped":
webhook["content"] = ""
webhook["embeds"][0]["description"] = f"Stopped `{self.action.jail}`"
webhook["embeds"][0]["color"] = 16194076
elif self.action.action == "test":
webhook["content"] = ""
webhook["embeds"][0]["description"] = f"I am working"
webhook["embeds"][0]["color"] = 845872
else:
return None
return webhook
def send(self, payload):
r = requests.post(url=f"{self.base}{self.token}", json=payload)
class Helpers:
def __init__(self, ip):
self.data = {"ip": ip}
self.map_api = os.getenv('DISC_API', "") # If not setting enviroment variables, edit this
self.reader = geoip2.database.Reader('/config/geoip2db/GeoLite2-City.mmdb')
self.f2b()
self.map()
def f2b(self):
r = self.reader.city(self.data['ip'])
self.data["iso"] = r.country.iso_code
self.data["name"] = r.country.name
self.data["city"] = r.city.name
self.data["lat"] = r.location.latitude
self.data["lon"] = r.location.longitude
def map(self):
img_params={"center":f"{self.data['lat']},{self.data['lon']}", "size":"500,300", "key": self.map_api}
img_r = requests.get('https://www.mapquestapi.com/staticmap/v5/map', params=img_params)
self.data["map-img"] = img_r.url
url_params={"center":f"{self.data['lat']},{self.data['lon']}", "size":"500,300"}
url_r = requests.get('https://mapquest.com/', params=url_params)
self.data["map-url"] = url_r.url
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Discord notifier for F2B')
parser.add_argument('-a', '--action', help="Which F2B action triggered the script", required=True)
parser.add_argument('-i', '--ip', help="ip which triggered the action", default="1.1.1.1")
parser.add_argument('-j', '--jail', help="jail which triggered the action")
parser.add_argument('-t', '--time', help="The time the action is valid")
parser.add_argument('-f', '--fail', help="Amount of attempts done")
args = parser.parse_args()
data = Helpers(args.ip).data
disc = Discord(data, args)
if (payload := disc.create_payload()):
disc.send(payload)

View File

@ -0,0 +1,23 @@
# Author: Roxedus
# Adapted Source: Gilbn from https://technicalramblings.com
[Definition]
# Notify on Startup
actionstart = python3 /config/fail2ban/Fail2Ban.py -a start -j <name>
# Notify on Shutdown
actionstop = python3 /config/fail2ban/Fail2Ban.py -a stopped -j <name>
#
actioncheck =
# Notify on Banned
actionban = python3 /config/fail2ban/Fail2Ban.py -a ban -j <name> -i <ip> -t <bantime> -f <failures>
# Notify on Unbanned
actionunban = python3 /config/fail2ban/Fail2Ban.py -a unban -j <name> -i <ip> -t <bantime> -f <failures>
[Init]
# Name of the jail in your jail.local file. default = [your-jail-name]
name = default

View File

@ -0,0 +1,20 @@
#!/usr/bin/with-contenv bash
if [ ! -d /usr/lib/python3.8/site-packages/geoip2 ]; then
echo '------------------------------------------------------------------------'
echo '| Running installation of required modules for letsencrypt-f2bdiscord'
echo '------------------------------------------------------------------------'
pip3 install --no-cache-dir -U \
requests \
argparse \
geoip2
fi
if [ ! -f /config/fail2ban/Fail2Ban.py ]; then
cp /AwesomeFolder/Fail2Ban.py /config/fail2ban/
chmod +x /config/fail2ban/Fail2Ban.py
fi
if [ ! -f /config/fail2ban/action.d/discordEmbed.conf ]; then
cp /AwesomeFolder/discordEmbed.conf /config/fail2ban/action.d
fi

View File

@ -1,27 +0,0 @@
#!/usr/bin/with-contenv bash
# Determine if setup is needed
if [ ! -f /usr/local/lib/python***/dist-packages/sshuttle ] && \
[ -f /usr/bin/apt ]; then
## Ubuntu
apt-get update
apt-get install --no-install-recommends -y \
iptables \
openssh-client \
python3 \
python3-pip
pip3 install sshuttle
fi
if [ ! -f /usr/lib/python***/site-packages/sshuttle ] && \
[ -f /sbin/apk ]; then
# Alpine
apk add --no-cache \
iptables \
openssh \
py3-pip \
python3
pip3 install sshuttle
fi
chown -R root:root /root
chmod -R 600 /root/.ssh

View File

@ -1,3 +0,0 @@
#!/usr/bin/with-contenv bash
sshuttle --dns --remote root@${HOST}:${PORT} 0/0 -x 172.17.0.0/16