diff --git a/Dockerfile b/Dockerfile index 7936626..9f3c6fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,12 +5,15 @@ WORKDIR /app COPY update.py /app/update.py COPY entrypoint.sh /app/entrypoint.sh +COPY healthcheck.sh /app/healthcheck.sh RUN pip install --no-cache-dir requests==2.32.3 \ - && chmod +x /app/entrypoint.sh + && chmod +x /app/entrypoint.sh /app/healthcheck.sh ENV OUT_DIR=/data VOLUME ["/data"] ENTRYPOINT ["/app/entrypoint.sh"] +HEALTHCHECK --interval=5m --timeout=10s --start-period=30s --retries=3 \ + CMD /app/healthcheck.sh diff --git a/README.md b/README.md index 339f689..a38b00a 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,23 @@ Die dafür vorgesehenen Labels sind: Bitte füge diese zu dem Service hinzu, bei welchem man die gewünschten Header möchte. +## Run/Deploy (kurz) + +1. `example.env` kopieren und als `.env` befüllen (mindestens `MAXMIND_LICENSE_KEY`). +2. Den Updater-Container starten und `OUT_DIR` als Volume mounten (z. B. `/data`). +3. Den ASN-Detection-Service so starten, dass er **denselben** `OUT_DIR` liest. +4. Traefik ForwardAuth aktivieren und `authResponseHeaders` durchreichen. +5. Nach dem ersten Update sollten `GeoLite2-ASN.mmdb` und `nren_asns.txt` im `OUT_DIR` liegen. + +## example.env (kurz erklärt) + +- `MAXMIND_LICENSE_KEY`: notwendig für den GeoLite2 Download. +- `PDB_API_KEY`: optional, reduziert PeeringDB Rate-Limits. +- `OUT_DIR`: gemeinsamer Datenpfad zwischen Updater und Detection-Service. +- `PDB_BASE`, `PDB_INFO_TYPE`, `PDB_LIMIT`: PeeringDB Filter. +- `HTTP_TIMEOUT`: Timeout pro HTTP-Request. +- `INTERVAL_SECONDS`: Update-Intervall (Standard 30 Tage). + ## Update-Strategie - monatliche Aktualisierung der ASN-Daten diff --git a/example.env b/example.env new file mode 100644 index 0000000..866b001 --- /dev/null +++ b/example.env @@ -0,0 +1,19 @@ +# Required +MAXMIND_LICENSE_KEY= + +# Optional (helps with rate limits) +PDB_API_KEY= + +# Output data location shared with the detection service +OUT_DIR=/data + +# PeeringDB settings +PDB_BASE=https://www.peeringdb.com +PDB_INFO_TYPE=Educational/Research +PDB_LIMIT=250 + +# HTTP settings +HTTP_TIMEOUT=30 + +# Update interval (seconds, default 30 days) +INTERVAL_SECONDS=2592000 diff --git a/healthcheck.sh b/healthcheck.sh new file mode 100644 index 0000000..97a7601 --- /dev/null +++ b/healthcheck.sh @@ -0,0 +1,49 @@ +#!/bin/sh +set -eu + +OUT_DIR="${OUT_DIR:-/data}" +PDB_BASE="${PDB_BASE:-https://www.peeringdb.com}" +INFO_TYPE="${PDB_INFO_TYPE:-Educational/Research}" + +if [ -z "${MAXMIND_LICENSE_KEY:-}" ]; then + echo "[health] MAXMIND_LICENSE_KEY missing" >&2 + exit 1 +fi + +if [ ! -d "${OUT_DIR}" ]; then + echo "[health] OUT_DIR missing: ${OUT_DIR}" >&2 + exit 1 +fi + +if [ ! -s "${OUT_DIR}/GeoLite2-ASN.mmdb" ]; then + echo "[health] GeoLite2-ASN.mmdb missing in ${OUT_DIR}" >&2 + exit 1 +fi + +if [ ! -s "${OUT_DIR}/nren_asns.txt" ]; then + echo "[health] nren_asns.txt missing in ${OUT_DIR}" >&2 + exit 1 +fi + +mm_url="https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-ASN&license_key=${MAXMIND_LICENSE_KEY}&suffix=tar.gz" +mm_code="$(curl -fsS -o /dev/null -w "%{http_code}" "${mm_url}" || true)" +if [ "${mm_code}" != "200" ]; then + echo "[health] MaxMind download not accessible (status ${mm_code})" >&2 + exit 1 +fi + +pdb_code="000" +pdb_url="${PDB_BASE}/api/net" +pdb_args="--get --data-urlencode info_type=${INFO_TYPE} --data-urlencode limit=1 --data-urlencode skip=0 --data-urlencode fields=asn,status,info_type" +if [ -n "${PDB_API_KEY:-}" ]; then + pdb_code="$(curl -fsS -o /dev/null -w "%{http_code}" -H "Accept: application/json" -H "Authorization: Api-Key ${PDB_API_KEY}" ${pdb_args} "${pdb_url}" || true)" +else + pdb_code="$(curl -fsS -o /dev/null -w "%{http_code}" -H "Accept: application/json" ${pdb_args} "${pdb_url}" || true)" +fi + +if [ "${pdb_code}" != "200" ] && [ "${pdb_code}" != "429" ]; then + echo "[health] PeeringDB not accessible (status ${pdb_code})" >&2 + exit 1 +fi + +exit 0 diff --git a/update.py b/update.py index 6a7f8ad..c2fb954 100644 --- a/update.py +++ b/update.py @@ -5,7 +5,7 @@ OUT_DIR = os.getenv("OUT_DIR", "/data") LICENSE_KEY = os.getenv("MAXMIND_LICENSE_KEY", "").strip() PDB_API_KEY = os.getenv("PDB_API_KEY", "").strip() PDB_BASE = os.getenv("PDB_BASE", "https://www.peeringdb.com") -INFO_TYPE = os.getenv("PDB_INFO_TYPE", "Research and Education") +INFO_TYPE = os.getenv("PDB_INFO_TYPE", "Educational/Research") TIMEOUT = int(os.getenv("HTTP_TIMEOUT", "30")) LIMIT = int(os.getenv("PDB_LIMIT", "250")) @@ -49,7 +49,7 @@ def pdb_headers(): if not PDB_API_KEY: return {"Accept": "application/json"} # PeeringDB API Key (optional) - return {"Accept": "application/json", "Authorization": f"api-key {PDB_API_KEY}"} + return {"Accept": "application/json", "Authorization": f"Api-Key {PDB_API_KEY}"} def fetch_pdb_page(skip: int): url = f"{PDB_BASE}/api/net" @@ -105,4 +105,3 @@ def main(): if __name__ == "__main__": main() -