gitea 🤝 fail2ban
change
commit 6c6921cd10a672f5d39114c000d2855af3dfab4a
author Alpha Chen <alpha@kejadlen.dev>
date
parent 3e3b47eb
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