抬头仰望星空,是否能发现自己的渺小。

伪斜杠青年
人们总是混淆了欲望和理想

关于 Docker Gitea 非 rootless 版配置 SSH Fail2ban 指南

也许,需要找时间更新至 rootless

标题很复杂,内容更是复杂。至于 rootless 版本理论上是内建 SSH 不存在这个问题,但标准版,也就是 gitea/gitea:latest 一定存在。因为 Gitea 标准版部署在 Docker 下的 SSH 无法获取日志,尝试过构建镜像,补全 rsyslog ,配置 openssh ,总之得到一个结论:无法在其容器中获取到 SSH 相关爆破日志。

官网的描述很简单的,只需要改下 app.ini 中的 MODE,一改一个不吱声,gitea.log 不会包含 SSH 相关,请放心做无用功。在 app.ini 中,存在一个 ENABLE_SSH_LOG 仅对 Gitea 内建 SSH 有效,抱歉的是,标准版中的 openssh 不可与内建 SSH 调和。

当配置为 Gitea 自建,也就是 DISABLE_SSHfalseSTART_SSH_SERVERtrue 时,SSH 会在 Gitea 后台显示被禁用,同时开启则端口冲突(也许自己做镜像关闭 openssh 或者更换端口后,可以达到内建 ssh 的效果,只是无法简单在 app.ini 中实现),其他情况则直接 502。于是简单说,不支持

在其 github 存在一个 issue ,回复是“既然日志不是由 Gitea 内建 SSH 提供,为何要求 ENABLE_SSH_LOG 会将日志写入 gitea.log ”。于是,只能剑走偏锋,在看到 potainer 中容器的 log 时,发现其正好可以查阅爆破日志,这也是一开始尝试自建镜像的原因。

问过 GPT,最终选择使用 docker logs -f,同时因为这样产生的日志缺少时间戳,而Fail2ban 需要时间戳,只能追加了--timestamps 补全时间戳并格式化,完整代码如下 gitea_log_monitor.sh

#!/bin/bash

LOG_DIR="/path/to/save/log"
LOG_FILE="$LOG_DIR/gitea.log"
CONTAINER_NAME="gitea"

# 确保日志目录存在
mkdir -p "$LOG_DIR"

while true; do
# 检查 gitea 容器是否在运行
if docker ps --format "{{.Names}}" | grep -q "^$CONTAINER_NAME$"; then
echo "[$(date +"%Y-%m-%d %H:%M:%S")] 监控 $CONTAINER_NAME 容器日志..."
docker logs -f --timestamps "$CONTAINER_NAME" | \
awk '{ cmd="date -d "$1" +\"%Y-%m-%d %H:%M:%S\""; cmd | getline ts; close(cmd); print ts, substr($0, index($0,$2)) }' >> "$LOG_FILE"
else
echo "[$(date +"%Y-%m-%d %H:%M:%S")] $CONTAINER_NAME 容器未运行,等待启动..."
fi

sleep 5 # 每 5 秒检查一次
done

增加一个系统服务:gitea-log-monitor.service ,内容如下:

[Unit]
Description=Gitea Log Monitor
After=docker.service
Requires=docker.service

[Service]
ExecStart=/path/to/gitea_log_monitor.sh
Restart=always
User=root

[Install]
WantedBy=multi-user.target

写一个执行脚本:install ,内容如下:

#!/bin/bash

chmod +x /path/to/gitea_log_monitor.sh
cp /path/to/gitea-log-monitor.service /etc/systemd/system/gitea-log-monitor.service

systemctl daemon-reload
systemctl enable gitea-log-monitor
systemctl start gitea-log-monitor

以上解决方案描述:系统启动时开启一个脚本轮询 gitea 容器日志并输出至文件,包含了容器未运行的容错处理。

总之,日志文件解决了,Fail2ban 就不是太想赘述了,当然,如果还是使用官网的那些规则,相信一条鱼都抓不到。简单贡献一下匹配规则:gitea.conf

[Definition]
failregex = ^.*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST> .*
^.* Invalid user .* from <HOST> .*
^.* <HOST> not allowed because not listed in AllowUsers.*
^Disconnected from invalid user .* <HOST> port.*
^Connection closed by invalid user .* <HOST> port.*
^Timeout before authentication for connection from <HOST> .*
ignoreregex =

由于 SSH 的特殊性,链选 FORWARD 才有效,请勿使用 DOCKER-USER :

[gitea]
enabled = true
chain = FORWARD
filter = gitea
logpath = /path/to/gitea.log
banaction = iptables-allports[blocktype=DROP]

结果自然是简单,试错是相当的麻烦。这里肯定不是 gitea 的最优解,却是获取容器日志的通解。以上。

后续

这里简单进行了对于端口冲突的尝试,切入容器:docker exec -it gitea /bin/bash 执行:

apk del openssh
rm -rf /etc/s6/openssh
s6-svscanctl -a /etc/s6

重启容器,开启 START_SSH_SERVER 并打开 ENABLE_SSH_LOG 也可以实现 rootless 想实现的结果,当然最好是做成 Dockfile,但何必不直接迁移 rootless

于是最后花时间迁移到了 rootless 版本,迁移没有想象中复杂,改改 app.ini 中的路径,除了 db 与 repository 路径需求修正,其他都可以不 care 甚至直接删除字段使用默认即可。

值得一提的是,标准版也就是 OpenSSH 版无法支持 nginx protocol。在切到 rootless 版使用内建 SSH 后,配置 SSH_SERVER_USE_PROXY_PROTOCOL = true 便支持了Nginx Stream IP 传递,如此便可全部交由 nginx 转发,而且多了更多的观测日志。

只是鱼塘里的鱼已经被抓完了,等新的鱼才能看看日志里是否有 ssh 相关信息(经测试包括 ssh 信息,与官方吻合)。

扩展:

OpenSSH logs are not included in the file mode logs


本站由以下主机服务商提供服务支持:

0条评论

发表评论