feat: add comprehensive access logging to Graylog with GeoIP
- Add fluent-bit inputs for Caddy access logs (JSON) and SSH logs - Create GeoIP task to download MaxMind GeoLite2-City database - Mount GeoIP database in Graylog container - Enable Gitea access logging via environment variables - Add parsers.conf for Caddy JSON log parsing - Remove unused nosql/redis container and configuration Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,6 +59,10 @@
|
|||||||
GITEA__security__INSTALL_LOCK: "true"
|
GITEA__security__INSTALL_LOCK: "true"
|
||||||
GITEA__service__DISABLE_REGISTRATION: "true"
|
GITEA__service__DISABLE_REGISTRATION: "true"
|
||||||
GITEA__service__REQUIRE_SIGNIN_VIEW: "false"
|
GITEA__service__REQUIRE_SIGNIN_VIEW: "false"
|
||||||
|
# Logging configuration - output to journald for fluent-bit capture
|
||||||
|
GITEA__log__MODE: console
|
||||||
|
GITEA__log__LEVEL: Info
|
||||||
|
GITEA__log__ENABLE_ACCESS_LOG: "true"
|
||||||
volumes:
|
volumes:
|
||||||
- "{{ git_home }}/volumes/gitea/data:/data"
|
- "{{ git_home }}/volumes/gitea/data:/data"
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ fulfillr_path: "{{ podman_volumes }}/fulfillr"
|
|||||||
gregtime_path: "{{ podman_volumes }}/gregtime"
|
gregtime_path: "{{ podman_volumes }}/gregtime"
|
||||||
hass_path: "{{ podman_volumes }}/hass"
|
hass_path: "{{ podman_volumes }}/hass"
|
||||||
# nginx_path: removed - nginx no longer used
|
# nginx_path: removed - nginx no longer used
|
||||||
nosql_path: "{{ podman_volumes }}/nosql"
|
# nosql_path: removed - nosql/redis no longer used
|
||||||
partkeepr_path: "{{ podman_volumes }}/partkeepr"
|
partkeepr_path: "{{ podman_volumes }}/partkeepr"
|
||||||
partsy_path: "{{ podman_volumes }}/partsy"
|
partsy_path: "{{ podman_volumes }}/partsy"
|
||||||
photos_path: "{{ podman_volumes }}/photos"
|
photos_path: "{{ podman_volumes }}/photos"
|
||||||
@@ -112,3 +112,25 @@ logs_server_name: logs.debyl.io
|
|||||||
|
|
||||||
# Fluent Bit is deployed as a systemd service (not container)
|
# Fluent Bit is deployed as a systemd service (not container)
|
||||||
# for direct journal access - see containers/base/fluent-bit.yml
|
# for direct journal access - see containers/base/fluent-bit.yml
|
||||||
|
|
||||||
|
# Fluent-bit Caddy log forwarding
|
||||||
|
caddy_log_path: "{{ caddy_path }}/logs"
|
||||||
|
caddy_log_names:
|
||||||
|
- caddy
|
||||||
|
- photos
|
||||||
|
- wiki
|
||||||
|
- assistant
|
||||||
|
- parts
|
||||||
|
- uptime-kuma
|
||||||
|
- graylog
|
||||||
|
- cloud
|
||||||
|
- cloud-skudak
|
||||||
|
- gitea-debyl
|
||||||
|
- fulfillr
|
||||||
|
|
||||||
|
# GeoIP configuration for Graylog
|
||||||
|
# Requires free MaxMind account: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
|
||||||
|
geoip_path: "{{ graylog_path }}/geoip"
|
||||||
|
geoip_database_edition: GeoLite2-City
|
||||||
|
# geoip_maxmind_account_id: defined in vault
|
||||||
|
# geoip_maxmind_license_key: defined in vault
|
||||||
|
|||||||
@@ -27,6 +27,25 @@
|
|||||||
name: fluent-bit
|
name: fluent-bit
|
||||||
state: present
|
state: present
|
||||||
|
|
||||||
|
- name: create fluent-bit state directory for tail db files
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: /var/lib/fluent-bit
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0755'
|
||||||
|
|
||||||
|
- name: deploy fluent-bit parsers configuration
|
||||||
|
become: true
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: fluent-bit/parsers.conf.j2
|
||||||
|
dest: /etc/fluent-bit/parsers.conf
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: '0644'
|
||||||
|
notify: restart fluent-bit
|
||||||
|
|
||||||
- name: deploy fluent-bit configuration
|
- name: deploy fluent-bit configuration
|
||||||
become: true
|
become: true
|
||||||
ansible.builtin.template:
|
ansible.builtin.template:
|
||||||
|
|||||||
59
ansible/roles/podman/tasks/containers/debyltech/geoip.yml
Normal file
59
ansible/roles/podman/tasks/containers/debyltech/geoip.yml
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
---
|
||||||
|
# Download MaxMind GeoLite2 database for Graylog GeoIP enrichment
|
||||||
|
# Requires free MaxMind account: https://dev.maxmind.com/geoip/geolite2-free-geolocation-data
|
||||||
|
|
||||||
|
- name: create geoip directory
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ geoip_path }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ podman_subuid.stdout }}"
|
||||||
|
group: "{{ podman_subuid.stdout }}"
|
||||||
|
mode: '0755'
|
||||||
|
notify: restorecon podman
|
||||||
|
tags: graylog, geoip
|
||||||
|
|
||||||
|
- name: download GeoLite2 database
|
||||||
|
become: true
|
||||||
|
ansible.builtin.get_url:
|
||||||
|
url: "https://download.maxmind.com/geoip/databases/{{ geoip_database_edition }}/download?suffix=tar.gz"
|
||||||
|
dest: "{{ geoip_path }}/{{ geoip_database_edition }}.tar.gz"
|
||||||
|
url_username: "{{ geoip_maxmind_account_id }}"
|
||||||
|
url_password: "{{ geoip_maxmind_license_key }}"
|
||||||
|
force: false
|
||||||
|
mode: '0644'
|
||||||
|
register: geoip_download
|
||||||
|
tags: graylog, geoip
|
||||||
|
|
||||||
|
- name: extract GeoLite2 database
|
||||||
|
become: true
|
||||||
|
ansible.builtin.unarchive:
|
||||||
|
src: "{{ geoip_path }}/{{ geoip_database_edition }}.tar.gz"
|
||||||
|
dest: "{{ geoip_path }}"
|
||||||
|
remote_src: true
|
||||||
|
extra_opts:
|
||||||
|
- --strip-components=1
|
||||||
|
- --wildcards
|
||||||
|
- "*/{{ geoip_database_edition }}.mmdb"
|
||||||
|
when: geoip_download.changed
|
||||||
|
tags: graylog, geoip
|
||||||
|
|
||||||
|
# Fix ownership of downloaded files to podman user's subuid range
|
||||||
|
- name: fix geoip files ownership for podman user
|
||||||
|
become: true
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ geoip_path }}"
|
||||||
|
state: directory
|
||||||
|
owner: "{{ podman_subuid.stdout }}"
|
||||||
|
group: "{{ podman_subuid.stdout }}"
|
||||||
|
recurse: true
|
||||||
|
tags: graylog, geoip
|
||||||
|
|
||||||
|
# Graylog runs as UID 1100 inside the container
|
||||||
|
- name: fix geoip database ownership for graylog container
|
||||||
|
become: true
|
||||||
|
become_user: "{{ podman_user }}"
|
||||||
|
changed_when: false
|
||||||
|
ansible.builtin.command: |
|
||||||
|
podman unshare chown -R 1100:1100 {{ geoip_path }}
|
||||||
|
tags: graylog, geoip
|
||||||
@@ -159,6 +159,7 @@
|
|||||||
GRAYLOG_MONGODB_URI: "mongodb://127.0.0.1:27017/graylog"
|
GRAYLOG_MONGODB_URI: "mongodb://127.0.0.1:27017/graylog"
|
||||||
volumes:
|
volumes:
|
||||||
- "{{ graylog_path }}/graylog/data:/usr/share/graylog/data:z"
|
- "{{ graylog_path }}/graylog/data:/usr/share/graylog/data:z"
|
||||||
|
- "{{ geoip_path }}/{{ geoip_database_edition }}.mmdb:/etc/graylog/server/GeoLite2-City.mmdb:ro"
|
||||||
requires:
|
requires:
|
||||||
- graylog-mongo
|
- graylog-mongo
|
||||||
- graylog-opensearch
|
- graylog-opensearch
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
---
|
|
||||||
- name: create nosql host directory volumes
|
|
||||||
become: true
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ item }}"
|
|
||||||
state: directory
|
|
||||||
owner: "{{ podman_user }}"
|
|
||||||
group: "{{ podman_user }}"
|
|
||||||
mode: 0755
|
|
||||||
notify: restorecon podman
|
|
||||||
loop:
|
|
||||||
- "{{ nosql_path }}/conf"
|
|
||||||
- "{{ nosql_path }}/data"
|
|
||||||
|
|
||||||
- name: flush handlers
|
|
||||||
ansible.builtin.meta: flush_handlers
|
|
||||||
|
|
||||||
- import_tasks: podman/podman-check.yml
|
|
||||||
vars:
|
|
||||||
container_name: nosql
|
|
||||||
container_image: "{{ image }}"
|
|
||||||
|
|
||||||
- name: create nosql container
|
|
||||||
become: true
|
|
||||||
become_user: "{{ podman_user }}"
|
|
||||||
containers.podman.podman_container:
|
|
||||||
name: nosql
|
|
||||||
image: "{{ image }}"
|
|
||||||
command: redis-server --requirepass {{ nosql_password }}
|
|
||||||
restart_policy: on-failure:3
|
|
||||||
log_driver: journald
|
|
||||||
volumes:
|
|
||||||
- "{{ nosql_path }}/conf:/usr/local/etc/redis/"
|
|
||||||
- "{{ nosql_path }}/data:/var/lib/redis"
|
|
||||||
env:
|
|
||||||
TZ: America/New_York
|
|
||||||
REDIS_REPLICATION_MODE: master
|
|
||||||
ports:
|
|
||||||
- 6379:6379/tcp
|
|
||||||
|
|
||||||
- name: create systemd startup job for nosql
|
|
||||||
include_tasks: podman/systemd-generate.yml
|
|
||||||
vars:
|
|
||||||
container_name: nosql
|
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
- import_tasks: containers/debyltech/fulfillr.yml
|
- import_tasks: containers/debyltech/fulfillr.yml
|
||||||
vars:
|
vars:
|
||||||
image: "git.debyl.io/debyltech/fulfillr:20260104.0001"
|
image: "git.debyl.io/debyltech/fulfillr:20260109.0522"
|
||||||
tags: debyltech, fulfillr
|
tags: debyltech, fulfillr
|
||||||
|
|
||||||
- import_tasks: containers/debyltech/uptime-kuma.yml
|
- import_tasks: containers/debyltech/uptime-kuma.yml
|
||||||
@@ -81,17 +81,15 @@
|
|||||||
image: docker.io/louislam/uptime-kuma:1
|
image: docker.io/louislam/uptime-kuma:1
|
||||||
tags: debyltech, uptime-kuma
|
tags: debyltech, uptime-kuma
|
||||||
|
|
||||||
|
- import_tasks: containers/debyltech/geoip.yml
|
||||||
|
tags: debyltech, graylog, geoip
|
||||||
|
|
||||||
- import_tasks: containers/debyltech/graylog.yml
|
- import_tasks: containers/debyltech/graylog.yml
|
||||||
tags: debyltech, graylog
|
tags: debyltech, graylog
|
||||||
|
|
||||||
- import_tasks: containers/base/fluent-bit.yml
|
- import_tasks: containers/base/fluent-bit.yml
|
||||||
tags: fluent-bit, graylog
|
tags: fluent-bit, graylog
|
||||||
|
|
||||||
- import_tasks: containers/home/nosql.yml
|
|
||||||
vars:
|
|
||||||
image: docker.io/redis:7.2.1-alpine
|
|
||||||
tags: nosql
|
|
||||||
|
|
||||||
- import_tasks: containers/home/gregtime.yml
|
- import_tasks: containers/home/gregtime.yml
|
||||||
vars:
|
vars:
|
||||||
image: localhost/greg-time-bot:1.5.2
|
image: localhost/greg-time-bot:1.5.2
|
||||||
|
|||||||
@@ -4,27 +4,72 @@
|
|||||||
Log_Level info
|
Log_Level info
|
||||||
Parsers_File parsers.conf
|
Parsers_File parsers.conf
|
||||||
|
|
||||||
# Read from systemd journal - filter for Podman container logs
|
# =============================================================================
|
||||||
|
# INPUT: Podman container logs
|
||||||
|
# =============================================================================
|
||||||
# Container logs come from conmon process with CONTAINER_NAME field
|
# Container logs come from conmon process with CONTAINER_NAME field
|
||||||
[INPUT]
|
[INPUT]
|
||||||
Name systemd
|
Name systemd
|
||||||
Tag journal.*
|
Tag podman.*
|
||||||
Systemd_Filter _COMM=conmon
|
Systemd_Filter _COMM=conmon
|
||||||
Read_From_Tail On
|
Read_From_Tail On
|
||||||
Strip_Underscores On
|
Strip_Underscores On
|
||||||
|
|
||||||
# Extract container name for better filtering in Graylog
|
# =============================================================================
|
||||||
|
# INPUT: SSH logs for security monitoring
|
||||||
|
# =============================================================================
|
||||||
|
[INPUT]
|
||||||
|
Name systemd
|
||||||
|
Tag ssh.*
|
||||||
|
Systemd_Filter _SYSTEMD_UNIT=sshd.service
|
||||||
|
Read_From_Tail On
|
||||||
|
Strip_Underscores On
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# INPUT: Caddy access logs (JSON format)
|
||||||
|
# =============================================================================
|
||||||
|
{% for log_name in caddy_log_names %}
|
||||||
|
[INPUT]
|
||||||
|
Name tail
|
||||||
|
Tag caddy.{{ log_name }}
|
||||||
|
Path {{ caddy_log_path }}/{{ log_name }}.log
|
||||||
|
Parser caddy_json
|
||||||
|
Read_From_Head False
|
||||||
|
Refresh_Interval 5
|
||||||
|
DB /var/lib/fluent-bit/caddy_{{ log_name }}.db
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
# =============================================================================
|
||||||
|
# FILTERS: Add metadata for Graylog categorization
|
||||||
|
# =============================================================================
|
||||||
[FILTER]
|
[FILTER]
|
||||||
Name record_modifier
|
Name record_modifier
|
||||||
Match journal.*
|
Match podman.*
|
||||||
Record host {{ ansible_hostname }}
|
Record host {{ ansible_hostname }}
|
||||||
Record source podman
|
Record source podman
|
||||||
|
Record log_type container
|
||||||
|
|
||||||
# Output to Graylog GELF UDP (local, port 12203)
|
[FILTER]
|
||||||
# Graylog needs a GELF UDP input configured on this port
|
Name record_modifier
|
||||||
|
Match ssh.*
|
||||||
|
Record host {{ ansible_hostname }}
|
||||||
|
Record source sshd
|
||||||
|
Record log_type security
|
||||||
|
|
||||||
|
[FILTER]
|
||||||
|
Name record_modifier
|
||||||
|
Match caddy.*
|
||||||
|
Record host {{ ansible_hostname }}
|
||||||
|
Record source caddy
|
||||||
|
Record log_type access
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# OUTPUT: All logs to Graylog GELF UDP
|
||||||
|
# =============================================================================
|
||||||
|
# Graylog needs a GELF UDP input configured on port 12203
|
||||||
[OUTPUT]
|
[OUTPUT]
|
||||||
Name gelf
|
Name gelf
|
||||||
Match journal.*
|
Match *
|
||||||
Host 127.0.0.1
|
Host 127.0.0.1
|
||||||
Port 12203
|
Port 12203
|
||||||
Mode udp
|
Mode udp
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[PARSER]
|
||||||
|
Name caddy_json
|
||||||
|
Format json
|
||||||
|
Time_Key ts
|
||||||
|
Time_Format %s.%L
|
||||||
Binary file not shown.
Reference in New Issue
Block a user