Add security log summary command

This commit is contained in:
juvdiaz 2026-06-29 15:01:27 -06:00
parent 88e7ccd214
commit 8f41a42a68
4 changed files with 127 additions and 1 deletions

View File

@ -159,6 +159,10 @@ on first. This command is report-only.
: Run quick HTTPS, status, and defensive-header checks against owned web
targets.
`security-logs`
: Summarize recent Gitea and Traefik logs for common scanner paths, suspicious
user agents, auth failures, and HTTP errors.
### Maintenance
`state-backup`
@ -233,6 +237,9 @@ smoke test. Defaults to `cloudflare.com`.
`SECURITY_WEB_TARGET`
: Optional single URL override for `security-web`.
`SECURITY_LOG_SINCE`
: Log window for `security-logs`. Defaults to `24h`.
`lynis`
: `security-host` requires Lynis to be installed on the Debian host. Install it
explicitly with `sudo apt install lynis`.

10
jeannie
View File

@ -5805,6 +5805,11 @@ security_web() {
"${REPO_ROOT}/scripts/security-scan" web
}
security_logs() {
require_debian_server "security-logs"
"${REPO_ROOT}/scripts/security-logs"
}
case "${1:-}" in
up)
up
@ -5933,6 +5938,9 @@ case "${1:-}" in
security-web)
security_web
;;
security-logs)
security_logs
;;
openwrt)
openwrt
;;
@ -5944,7 +5952,7 @@ case "${1:-}" in
echo "Log: ${JEANNIE_LOG_FILE}"
;;
*)
echo "Usage: $0 {up|plan [all|provisioning|cluster|platform|apps|edge]|rebuild-cluster|stop-cluster|start-cluster|status|apps|website-translation-model|website-ollama-listen|ollama-setup|deploy-gitea|rpi-services|bootstrap-gitea-repo|backup-gitea|drill-gitea-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|doctor-edge|doctor-gitea|doctor-rpi|doctor-cluster|preflight|doctor-preapply|inventory-check|state-backup|fix-debian-docker-root|secrets-init|secrets-check|tailnet-policy-check|ai-index|ai-check|security-scan|security-prepare|security-zap|security-k8s|security-host|security-trivy|security-secrets|security-nuclei|security-web|openwrt|nuke}"
echo "Usage: $0 {up|plan [all|provisioning|cluster|platform|apps|edge]|rebuild-cluster|stop-cluster|start-cluster|status|apps|website-translation-model|website-ollama-listen|ollama-setup|deploy-gitea|rpi-services|bootstrap-gitea-repo|backup-gitea|drill-gitea-restore|install-gitea-runner|move-prometheus-stack-workers|doctor-versions|doctor-edge|doctor-gitea|doctor-rpi|doctor-cluster|preflight|doctor-preapply|inventory-check|state-backup|fix-debian-docker-root|secrets-init|secrets-check|tailnet-policy-check|ai-index|ai-check|security-scan|security-prepare|security-zap|security-k8s|security-host|security-trivy|security-secrets|security-nuclei|security-web|security-logs|openwrt|nuke}"
exit 1
;;
esac

103
scripts/security-logs Executable file
View File

@ -0,0 +1,103 @@
#!/usr/bin/env bash
set -euo pipefail
HOMELAB_STATE_DIR="${HOMELAB_STATE_DIR:-${XDG_DATA_HOME:-${HOME}/.local/share}/homelab}"
SECURITY_REPORT_DIR="${SECURITY_REPORT_DIR:-${HOMELAB_STATE_DIR}/security-reports}"
SECURITY_LOG_SINCE="${SECURITY_LOG_SINCE:-24h}"
GITEA_CONTAINER="${GITEA_CONTAINER:-${LAB_GITEA_CONTAINER_NAME:-homelab-gitea}}"
KUBECONFIG="${KUBECONFIG:-${HOME}/.kube/config}"
timestamp() {
date -u +%Y%m%dT%H%M%SZ
}
ensure_report_dir() {
mkdir -p "${SECURITY_REPORT_DIR}"
}
print_matches() {
local title="$1"
local log_file="$2"
local pattern="$3"
local limit="${4:-20}"
printf '\n== %s ==\n' "${title}"
if [[ ! -s "${log_file}" ]]; then
printf 'no log input\n'
return 0
fi
if grep -Eai "${pattern}" "${log_file}" >/dev/null; then
grep -Eai "${pattern}" "${log_file}" | tail -n "${limit}"
else
printf 'none\n'
fi
}
collect_gitea_logs() {
local output_file="$1"
if ! command -v docker >/dev/null 2>&1; then
return 0
fi
if ! docker ps --format '{{.Names}}' | grep -Fxq "${GITEA_CONTAINER}"; then
return 0
fi
docker logs --since "${SECURITY_LOG_SINCE}" "${GITEA_CONTAINER}" >"${output_file}" 2>&1 || true
}
collect_traefik_logs() {
local output_file="$1"
if ! command -v kubectl >/dev/null 2>&1; then
return 0
fi
if [[ ! -f "${KUBECONFIG}" ]]; then
return 0
fi
kubectl --kubeconfig "${KUBECONFIG}" -n traefik logs \
-l app.kubernetes.io/name=traefik \
--since="${SECURITY_LOG_SINCE}" \
--tail="${SECURITY_LOG_TAIL:-5000}" >"${output_file}" 2>&1 || true
}
main() {
local stamp
local gitea_log
local traefik_log
local report_file
local suspicious_paths
local suspicious_agents
stamp="$(timestamp)"
ensure_report_dir
gitea_log="${SECURITY_REPORT_DIR}/security-gitea-logs-${stamp}.txt"
traefik_log="${SECURITY_REPORT_DIR}/security-traefik-logs-${stamp}.txt"
report_file="${SECURITY_REPORT_DIR}/security-logs-${stamp}.txt"
suspicious_paths='/(wp-admin|wp-login|xmlrpc\.php|\.env|\.git|vendor/phpunit|cgi-bin|boaform|solr|actuator|server-status)|\.\./|%2e%2e|/etc/passwd|/proc/self/environ'
suspicious_agents='nikto|sqlmap|nuclei|masscan|zgrab|gobuster|dirbuster|dirsearch|wpscan|acunetix|nessus|openvas|curl/[0-9]|python-requests|Go-http-client'
collect_gitea_logs "${gitea_log}"
collect_traefik_logs "${traefik_log}"
{
echo "Homelab security log summary"
echo "Generated: ${stamp}"
echo "Window: ${SECURITY_LOG_SINCE}"
echo
print_matches "Gitea auth or permission failures" "${gitea_log}" 'authentication failed|invalid credentials|denied|forbidden|unauthorized|failed login|401|403'
print_matches "Gitea suspicious repo/path activity" "${gitea_log}" "${suspicious_paths}"
print_matches "Traefik suspicious paths" "${traefik_log}" "${suspicious_paths}"
print_matches "Traefik suspicious user agents" "${traefik_log}" "${suspicious_agents}"
print_matches "Traefik client/server errors" "${traefik_log}" ' 4[0-9][0-9] | 5[0-9][0-9] |level=error|level=warn'
echo
echo "Raw Gitea log sample: ${gitea_log}"
echo "Raw Traefik log sample: ${traefik_log}"
} | tee "${report_file}"
echo "Security log report: ${report_file}"
}
main "$@"

View File

@ -12,6 +12,7 @@ Use Jeannie from the Debian homelab host:
./jeannie security-k8s
./jeannie security-host
./jeannie security-web
./jeannie security-logs
```
The default `security-scan` runs:
@ -33,6 +34,8 @@ The focused commands are:
- `security-nuclei`: low-rate nuclei HTTP exposure scans only.
- `security-web`: quick HTTPS, status, and defensive-header checks for owned
web targets.
- `security-logs`: read-only summary of recent Gitea and Traefik security
signals.
Reports are written to:
@ -54,3 +57,8 @@ Ollama/RAG helper to select exactly one finding; otherwise it falls back to the
first Lynis warning, then the first suggestion. The full Lynis report is still
saved so you can review the complete output before adding any explicit hardening
command.
`security-logs` uses recent Docker logs from the Debian Gitea container and
Traefik pod logs when Kubernetes is reachable. It is intentionally heuristic:
use it to spot scanner noise, auth failures, suspicious paths, and obvious
client/server errors before opening the raw logs.