mirror of
https://github.com/linuxserver/docker-mods.git
synced 2026-03-23 00:05:28 +08:00
Merge pull request #32 from Roxedus/letsencrypt-F2BDiscord
Add letsencrypt:F2BDiscord
This commit is contained in:
commit
ca1083bc3e
BIN
.assets/Example.png
Normal file
BIN
.assets/Example.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 176 KiB |
@ -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:
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
FROM scratch
|
||||
LABEL maintainer="Roxedus"
|
||||
|
||||
|
||||
# copy local files
|
||||
COPY root/ /
|
||||
|
||||
@ -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/ /
|
||||
45
README.md
45
README.md
@ -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
|
||||
|
||||

|
||||
|
||||
98
root/AwesomeFolder/Fail2Ban.py
Normal file
98
root/AwesomeFolder/Fail2Ban.py
Normal 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)
|
||||
23
root/AwesomeFolder/discordEmbed.conf
Normal file
23
root/AwesomeFolder/discordEmbed.conf
Normal 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
|
||||
20
root/etc/cont-init.d/49-F2BDiscord
Normal file
20
root/etc/cont-init.d/49-F2BDiscord
Normal 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
|
||||
@ -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
|
||||
@ -1,3 +0,0 @@
|
||||
#!/usr/bin/with-contenv bash
|
||||
|
||||
sshuttle --dns --remote root@${HOST}:${PORT} 0/0 -x 172.17.0.0/16
|
||||
Loading…
x
Reference in New Issue
Block a user