Add security log summary command
This commit is contained in:
parent
88e7ccd214
commit
8f41a42a68
|
|
@ -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
10
jeannie
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 "$@"
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue