diff --git a/lotus-land-story/logs.yml b/lotus-land-story/logs.yml
index 0b93bca..6a5a62d 100644
--- a/lotus-land-story/logs.yml
+++ b/lotus-land-story/logs.yml
@@ -24,12 +24,27 @@
command: -c /etc/vector/*.yml
volumes:
- /mnt/lotus-land-story/vector:/etc/vector:ro
- # - /var/log:/var/log
+ - /var/log:/var/log
- /var/run/docker.sock:/var/run/docker.sock
restart_policy: unless-stopped
networks:
- name: lotus_land_story
+ - name: Set up logrotate for gitea.log
+ ansible.builtin.copy:
+ content: |
+ /var/log/gitea.log
+ {
+ rotate 4
+ weekly
+ missingok
+ notifempty
+ compress
+ delaycompress
+ }
+ dest: /etc/logrotate.d/gitea-ssh
+ mode: "0600"
+
- name: VictoriaLogs
hosts: lotus-land-story
vars_files:
@@ -60,7 +75,10 @@
restart_policy: unless-stopped
ports:
- "514:514" # syslog
- - "9428:9428" # journald
+ # Exposed for journald via systemd-journal-upload - at some point, it
+ # might be nice to have journald go through vector, but would need to
+ # figure out how to make that work through docker.
+ - "9428:9428"
volumes:
- /mnt/lotus-land-story/victoria-logs:/data
networks:
diff --git a/lotus-land-story/security.yml b/lotus-land-story/security.yml
index 39db116..e27c2cc 100644
--- a/lotus-land-story/security.yml
+++ b/lotus-land-story/security.yml
@@ -42,6 +42,8 @@
- name: Import restarts
ansible.builtin.import_tasks: restarts.yml
+
+# Can use `fail2ban-client status sshd` to check on this
- name: Set up Fail2Ban
tags: fail2ban
hosts: lotus-land-story
@@ -52,14 +54,44 @@
name: fail2ban
state: present
- - name: Configure Fail2Ban
+ # TODO Reload fail2ban if this changes
+
+ - name: Configure Fail2Ban for sshd
ansible.builtin.copy:
- dest: /etc/jail.local
+ dest: /etc/fail2ban/jail.d/sshd.local
content: |
[sshd]
enabled = true
+ mode = aggressive
+ bantime = 24h
+ findtime = 12h
mode: "0600"
+ - name: Configure Fail2Ban for gitea
+ block:
+ - name: Create gitea filter
+ ansible.builtin.copy:
+ dest: /etc/fail2ban/filter.d/gitea.local
+ content: |
+ [Definition]
+ failregex = .*(Disconnected from invalid user).* <HOST> port
+ ignoreregex =
+ mode: "0600"
+
+ - name: Create gitea jail
+ ansible.builtin.copy:
+ dest: /etc/fail2ban/jail.d/gitea.local
+ content: |
+ [gitea]
+ enabled = true
+ filter = gitea
+ logpath = /var/log/gitea.log
+ maxretry = 3
+ bantime = 24h
+ findtime = 12h
+ action = iptables-allports[chain="FORWARD"]
+ mode: "0600"
+
- name: Start Fail2Ban
ansible.builtin.service:
name: fail2ban
diff --git a/lotus-land-story/templates/vector.yml b/lotus-land-story/templates/vector.yml
index af23dab..0e9e79a 100644
--- a/lotus-land-story/templates/vector.yml
+++ b/lotus-land-story/templates/vector.yml
@@ -1,6 +1,10 @@
sources:
docker:
type: docker_logs
+ varlogs:
+ type: file
+ include:
+ - /var/log/fail2ban.log
transforms:
docker_parsed:
@@ -54,18 +58,50 @@ transforms:
._stream_id = .container_name
._stream = { "container_name": .container_name }
+ varlogs_parsed:
+ type: remap
+ inputs:
+ - varlogs
+ source: |
+ ._time = del(.timestamp)
+ ._msg = del(.message)
+ ._stream_id = .file
+ ._stream = { "file": .file }
+
+ # A subset of gitea logs from docker that contain SSH information
+ gitea_ssh:
+ type: remap
+ inputs:
+ - docker
+ source: |
+ if .container_name == "gitea" && contains(string!(.message), "[preauth]") {
+ . = join!(
+ [
+ format_timestamp!(now(), "%b %d %H:%M:%S"),
+ .message,
+ ],
+ separator: " ",
+ )
+ } else {
+ . = []
+ }
+
sinks:
# console:
# inputs:
- # - remap_caddy
- # target: stdout
+ # - gitea_ssh
# type: console
# encoding:
- # codec: json
+ # codec: csv
+ # csv:
+ # fields:
+ # - message
+ # quote_style: never
victoria_logs:
inputs:
- docker_parsed
+ - varlogs_parsed
type: http
uri: http://victoria-logs:9428/insert/jsonline
compression: gzip
@@ -75,3 +111,19 @@ sinks:
method: newline_delimited
healthcheck:
enabled: false
+
+ # Since ssh logs from gitea only show up in docker logs and not gitea logs,
+ # ship them to /var/log for use with fail2ban
+ gitea_log:
+ inputs:
+ - gitea_ssh
+ type: file
+ path: /var/log/gitea.log
+ encoding:
+ # Surely there must be a better way to do unstructured logging than using
+ # CSV rows with a single field?
+ codec: csv
+ csv:
+ fields:
+ - message
+ quote_style: never