141 lines
5.3 KiB
Bash
Executable File
141 lines
5.3 KiB
Bash
Executable File
#!/usr/bin/env sh
|
|
set -eu
|
|
cd "$(dirname "$0")"
|
|
|
|
command -v docker >/dev/null 2>&1 || { echo "Docker fehlt." >&2; exit 1; }
|
|
docker compose version >/dev/null 2>&1 || { echo "Docker Compose Plugin fehlt." >&2; exit 1; }
|
|
|
|
PRESET_ENROLLMENT_KEY="${ENROLLMENT_KEY:-}"
|
|
|
|
randhex() {
|
|
n="$1"
|
|
if command -v openssl >/dev/null 2>&1; then
|
|
openssl rand -hex "$n"
|
|
else
|
|
dd if=/dev/urandom bs="$n" count=1 2>/dev/null | od -An -tx1 | tr -d ' \n'
|
|
fi
|
|
}
|
|
|
|
get_env() {
|
|
key="$1"
|
|
awk -F= -v k="$key" '$1==k {sub(/^[^=]*=/, ""); print; exit}' .env 2>/dev/null || true
|
|
}
|
|
|
|
set_env() {
|
|
key="$1"; value="$2"; tmp=".env.tmp.$$"
|
|
awk -v k="$key" -v v="$value" '
|
|
BEGIN {done=0}
|
|
index($0,k"=")==1 {print k"="v; done=1; next}
|
|
{print}
|
|
END {if(!done) print k"="v}
|
|
' .env > "$tmp"
|
|
mv "$tmp" .env
|
|
}
|
|
|
|
# Start from a complete template, but preserve all values from an existing .env.
|
|
[ -f .env ] || : > .env
|
|
while IFS= read -r line || [ -n "$line" ]; do
|
|
case "$line" in
|
|
''|'#'*) continue ;;
|
|
esac
|
|
key=${line%%=*}
|
|
if ! grep -q "^${key}=" .env 2>/dev/null; then
|
|
printf '%s\n' "$line" >> .env
|
|
fi
|
|
done < .env.example
|
|
|
|
# Generate secrets only if absent/blank/placeholder. Existing installations keep their credentials.
|
|
for key in POSTGRES_PASSWORD CLICKHOUSE_PASSWORD UI_PASSWORD GARAGE_SECRET_KEY GARAGE_RPC_SECRET GARAGE_ADMIN_TOKEN GARAGE_METRICS_TOKEN; do
|
|
val="$(get_env "$key")"
|
|
if [ -z "$val" ] || [ "$val" = "CHANGE_ME" ]; then
|
|
case "$key" in
|
|
POSTGRES_PASSWORD|CLICKHOUSE_PASSWORD) val="$(randhex 24)" ;;
|
|
UI_PASSWORD) val="$(randhex 18)" ;;
|
|
*) val="$(randhex 32)" ;;
|
|
esac
|
|
set_env "$key" "$val"
|
|
fi
|
|
done
|
|
|
|
val="$(get_env GARAGE_ACCESS_KEY)"
|
|
if [ -z "$val" ] || [ "$val" = "CHANGE_ME" ]; then
|
|
set_env GARAGE_ACCESS_KEY "GK$(randhex 16)"
|
|
fi
|
|
|
|
val="$(get_env ENROLLMENT_KEY)"
|
|
if [ -n "$PRESET_ENROLLMENT_KEY" ]; then
|
|
set_env ENROLLMENT_KEY "$PRESET_ENROLLMENT_KEY"
|
|
elif [ -z "$val" ] || [ "$val" = "CHANGE_ME" ]; then
|
|
set_env ENROLLMENT_KEY "$(randhex 32)"
|
|
fi
|
|
|
|
chmod 600 .env 2>/dev/null || true
|
|
|
|
# Validate required settings without sourcing .env as shell code. Docker Compose parses
|
|
# .env itself; this also keeps values with shell-special characters safe.
|
|
for key in POSTGRES_PASSWORD CLICKHOUSE_PASSWORD UI_PASSWORD ENROLLMENT_KEY GARAGE_ACCESS_KEY GARAGE_SECRET_KEY GARAGE_RPC_SECRET GARAGE_ADMIN_TOKEN GARAGE_METRICS_TOKEN; do
|
|
val="$(get_env "$key")"
|
|
if [ -z "$val" ] || [ "$val" = "CHANGE_ME" ]; then
|
|
echo "Ungültige .env: $key fehlt oder ist noch CHANGE_ME." >&2
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
UI_PORT_VALUE="$(get_env UI_PORT)"; [ -n "$UI_PORT_VALUE" ] || UI_PORT_VALUE=8080
|
|
INGRESS_PORT_VALUE="$(get_env INGRESS_PORT)"; [ -n "$INGRESS_PORT_VALUE" ] || INGRESS_PORT_VALUE=8090
|
|
CLICKHOUSE_USER_VALUE="$(get_env CLICKHOUSE_USER)"; [ -n "$CLICKHOUSE_USER_VALUE" ] || CLICKHOUSE_USER_VALUE=siem
|
|
CLICKHOUSE_DB_VALUE="$(get_env CLICKHOUSE_DB)"; [ -n "$CLICKHOUSE_DB_VALUE" ] || CLICKHOUSE_DB_VALUE=siem
|
|
CLICKHOUSE_PASSWORD_VALUE="$(get_env CLICKHOUSE_PASSWORD)"
|
|
CLICKHOUSE_HTTP_PORT_VALUE="$(get_env CLICKHOUSE_HTTP_PORT)"; [ -n "$CLICKHOUSE_HTTP_PORT_VALUE" ] || CLICKHOUSE_HTTP_PORT_VALUE=8123
|
|
CLICKHOUSE_NATIVE_PORT_VALUE="$(get_env CLICKHOUSE_NATIVE_PORT)"; [ -n "$CLICKHOUSE_NATIVE_PORT_VALUE" ] || CLICKHOUSE_NATIVE_PORT_VALUE=9000
|
|
UI_USERNAME_VALUE="$(get_env UI_USERNAME)"; [ -n "$UI_USERNAME_VALUE" ] || UI_USERNAME_VALUE=admin
|
|
UI_PASSWORD_VALUE="$(get_env UI_PASSWORD)"
|
|
ENROLLMENT_KEY_VALUE="$(get_env ENROLLMENT_KEY)"
|
|
|
|
# Validate the final config before pulling/building anything.
|
|
echo "Prüfe Compose-Konfiguration ..."
|
|
docker compose config >/dev/null
|
|
|
|
echo "Baue und starte Greenfield SIEM ..."
|
|
docker compose build --pull
|
|
docker compose up -d --remove-orphans
|
|
|
|
http_ok() {
|
|
url="$1"
|
|
if command -v curl >/dev/null 2>&1; then curl -fsS "$url" >/dev/null 2>&1; return $?; fi
|
|
if command -v wget >/dev/null 2>&1; then wget -q -O /dev/null "$url" >/dev/null 2>&1; return $?; fi
|
|
return 2
|
|
}
|
|
|
|
echo "Prüfe Readiness ..."
|
|
i=0
|
|
while [ "$i" -lt 90 ]; do
|
|
api_ok=0; ingress_ok=0; ch_ok=0; garage_ok=0
|
|
http_ok "http://127.0.0.1:${UI_PORT_VALUE}/readyz" && api_ok=1 || true
|
|
http_ok "http://127.0.0.1:${INGRESS_PORT_VALUE}/readyz" && ingress_ok=1 || true
|
|
docker compose exec -T clickhouse clickhouse-client --user "${CLICKHOUSE_USER_VALUE}" --password "${CLICKHOUSE_PASSWORD_VALUE}" --query 'SELECT 1' >/dev/null 2>&1 && ch_ok=1 || true
|
|
docker compose exec -T garage /garage status >/dev/null 2>&1 && garage_ok=1 || true
|
|
if [ "$api_ok" -eq 1 ] && [ "$ingress_ok" -eq 1 ] && [ "$ch_ok" -eq 1 ] && [ "$garage_ok" -eq 1 ]; then
|
|
break
|
|
fi
|
|
i=$((i+1))
|
|
sleep 2
|
|
done
|
|
|
|
if [ "$i" -ge 90 ]; then
|
|
echo "Mindestens ein Dienst wurde nicht bereit. Diagnose:" >&2
|
|
docker compose ps >&2 || true
|
|
echo >&2
|
|
docker compose logs --tail=120 garage clickhouse clickhouse-schema postgres postgres-schema redpanda redpanda-init ingress processor api >&2 || true
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "Greenfield SIEM läuft."
|
|
echo "UI: http://127.0.0.1:${UI_PORT_VALUE}/ui"
|
|
echo "Ingress: http://127.0.0.1:${INGRESS_PORT_VALUE}/ingest"
|
|
echo "UI-Login: ${UI_USERNAME_VALUE} / ${UI_PASSWORD_VALUE}"
|
|
echo "ClickHouse: user=${CLICKHOUSE_USER_VALUE} db=${CLICKHOUSE_DB_VALUE} http=127.0.0.1:${CLICKHOUSE_HTTP_PORT_VALUE} native=127.0.0.1:${CLICKHOUSE_NATIVE_PORT_VALUE}"
|
|
echo "Enrollment-Key: ${ENROLLMENT_KEY_VALUE}"
|
|
echo "Alle Parameter stehen vollständig in .env."
|