IPScanner

Integraties

Forward auth voor nginx, Apache en HAProxy

Eén kleine container die nginx, Nginx Proxy Manager, Apache, HAProxy, Traefik of Caddy bij elk verzoek raadpleegt.

Installatie

  1. 1Voeg een forward-auth-site toe in het dashboard en kopieer de Site-ID.
  2. 2Draai de gate op het Docker-netwerk van je proxy met je API-sleutel en de Site-ID. Publiceer zijn poort niet.
  3. 3Voeg de snippet voor je proxy toe.

ghcr.io/ipscanner/forward-auth is een statische binary voor linux/amd64 en linux/arm64 die zonder root en zonder shell draait. Binaries voor Linux en macOS staan op de releasepagina.

Een nieuwe site start in monitor-modus: hij voegt headers toe en blokkeert niets tot je overschakelt naar enforce.

Overzicht op de pagina voor nginx, Apache en HAProxy, broncode op GitHub.

docker-compose.yml
services:
  ipscanner:
    image: ghcr.io/ipscanner/forward-auth:0.1
    restart: unless-stopped
    environment:
      IPSCANNER_API_KEY: ${IPSCANNER_API_KEY}
      SITE_ID: site_...

Snippets per proxy

  • nginxauth_request

    auth_request vraagt /check naar elk verzoek. Een geblokkeerde bezoeker krijgt de 403-pagina van de gate, en een onbereikbare gate laat verkeer door. nginx zoekt de gate op bij het starten, dus start de gate eerst.

  • Nginx Proxy Managerauth_request

    Hetzelfde, geplakt in het tabblad Advanced van de proxy host, met de gate op het Docker-netwerk van NPM.

  • TraefikForwardAuth

    Een ForwardAuth-middleware in de labels van je app. De Traefik-plugin doet hetzelfde zonder container.

  • Caddyforward_auth

    forward_auth naar /check, met de X-IPScanner-*-headers overgenomen. De Caddy-module doet hetzelfde zonder container.

  • HAProxyUPSTREAM_URL

    Proxy-modus met UPSTREAM_URL=http://app:80. De app is de backupserver, dus verkeer loopt door als de gate down is.

  • ApacheUPSTREAM_URL

    Proxy-modus zoals bij HAProxy, met de app als hot standby.

location / {
    auth_request /_ipscanner;
    auth_request_set $ipscanner_status     $upstream_http_x_ipscanner_status;
    auth_request_set $ipscanner_class      $upstream_http_x_ipscanner_class;
    auth_request_set $ipscanner_action     $upstream_http_x_ipscanner_action;
    auth_request_set $ipscanner_network    $upstream_http_x_ipscanner_network_class;
    auth_request_set $ipscanner_anonymized $upstream_http_x_ipscanner_anonymized;
    auth_request_set $ipscanner_risk       $upstream_http_x_ipscanner_risk;
    auth_request_set $ipscanner_country    $upstream_http_x_ipscanner_country;
    auth_request_set $ipscanner_site       $upstream_http_x_ipscanner_site;
    auth_request_set $ipscanner_request_id $upstream_http_x_ipscanner_request_id;
    error_page 403 = @ipscanner_blocked;

    proxy_set_header X-IPScanner-Status        $ipscanner_status;
    proxy_set_header X-IPScanner-Class         $ipscanner_class;
    proxy_set_header X-IPScanner-Action        $ipscanner_action;
    proxy_set_header X-IPScanner-Network-Class $ipscanner_network;
    proxy_set_header X-IPScanner-Anonymized    $ipscanner_anonymized;
    proxy_set_header X-IPScanner-Risk          $ipscanner_risk;
    proxy_set_header X-IPScanner-Country       $ipscanner_country;
    proxy_set_header X-IPScanner-Site          $ipscanner_site;
    proxy_set_header Host                      $host;
    proxy_set_header X-Forwarded-For           $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto         $scheme;
    proxy_pass http://app:80;
}

location = /_ipscanner {
    internal;
    proxy_pass http://ipscanner:8080/check;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Original-URI $request_uri;
    proxy_set_header X-Original-Method $request_method;
    proxy_connect_timeout 1s;
    proxy_read_timeout 5s;
    error_page 500 502 503 504 = @ipscanner_down;
}

location @ipscanner_down {
    return 204;
}

location @ipscanner_blocked {
    internal;
    proxy_method GET;
    proxy_pass_request_body off;
    proxy_set_header Content-Length "";
    proxy_set_header X-IPScanner-Request-Id $ipscanner_request_id;
    rewrite ^ /blocked break;
    proxy_pass http://ipscanner:8080;
}

Endpoints

  • /checkforward auth

    200 met de X-IPScanner-*-headers, of 403 met de blokkadepagina en X-IPScanner-Request-Id.

  • /blockedforward auth

    De 403-pagina voor het request-ID in X-IPScanner-Request-Id, voor error_page in nginx.

  • /healthzbeide modi

    200 als JSON: versie, modus, site, backoff, laatste fout en het gecachete beleid.

/check leest het oorspronkelijke verzoek uit de headers van de proxy: X-Forwarded-For (of IP_HEADERS), User-Agent, X-Forwarded-Uri of X-Original-URI, en X-Forwarded-Method of X-Original-Method.

Configuratie

  • IPSCANNER_API_KEY

    Je API-sleutel. Zonder sleutel gaat elk verzoek ongecheckt door.

  • IPSCANNER_API_KEY_FILE

    Bestand met de sleutel, voor Docker-secrets. Gaat vóór IPSCANNER_API_KEY.

  • SITE_ID

    Site-ID uit het dashboard. Modus en beleid komen dan uit het dashboard.

  • MODEstandaard monitor

    monitor of enforce. Met een site heeft alleen monitor effect: de site blijft dan in monitor-modus.

  • BLOCK_CLASSESstandaard malicious_automation

    Zonder site: klassen die enforce blokkeert, gescheiden door komma's, uit malicious_automation, ai_agent, tor, vpn, proxy, hosting, relay of none.

  • TRUSTED_PROXIESstandaard private

    Adressen en CIDR-bereiken waarvan IP- en URI-headers vertrouwd worden. private, cloudflare, of none voor alleen het peer-adres.

  • IP_HEADERSstandaard X-Forwarded-For

    Headers die op volgorde gelezen worden van een vertrouwde proxy. Achter Cloudflare: CF-Connecting-IP.

  • TIMEOUT_MSstandaard 1500

    Tijdbudget voor één check, in milliseconden. Bij een timeout gaat het verzoek door.

  • CACHE_TTLstandaard 600

    Seconden dat een oordeel per site, IP en user agent hergebruikt wordt. Duren zoals 10m werken ook.

  • CACHE_SIZEstandaard 10000

    Oordelen in het geheugen.

  • POLICY_TTLstandaard 30

    Seconden dat het beleid van de site hergebruikt wordt. Duren werken ook.

  • SKIP_PATHSstandaard statische bestanden

    Regex op het pad, hoofdletterongevoelig. Passende verzoeken worden niet gecheckt; leeg checkt elk pad.

  • UPSTREAM_URL

    Zet proxy-modus aan: toegestane verzoeken gaan naar deze URL.

  • LISTENstandaard :8080

    Luisteradres.

  • HEALTH_PATHstandaard /healthz

    Health-endpoint.

  • BLOCK_MESSAGEstandaard Blocked by IPScanner edge guard.

    Tekst van de 403-pagina.

  • IPSCANNER_API_URLstandaard https://ipscanner.io

    Basis-URL van de API.

  • DEBUGstandaard false

    Logt elke beslissing op één regel. In proxy-modus komen ook de status-, class- en action-headers op responses.

Ongeldige waarden stoppen de gate bij het starten met een logregel. De API-sleutel wordt nooit gelogd.

Client-IP

  • TRUSTED_PROXIES

    X-Forwarded-For wordt alleen gelezen als de peer in deze lijst staat, de keten terug tot het eerste adres dat geen vertrouwde proxy is. Bij iedereen anders telt het peer-adres.

  • private

    De standaard. Past bij een proxy die de gate via een Docker- of privénetwerk bereikt. Kunnen anderen op dat netwerk de gate bereiken, zet dan het adres van je proxy erin.

  • :8080

    Publiceer de poort van de gate niet: alleen je proxy hoort hem te bereiken.

Headers die erbij komen

Bij een 200 van /check, zodat je proxy ze aan de app doorgeeft, en in proxy-modus op het verzoek naar je app. Proxy-modus verwijdert inkomende X-IPScanner-*-headers; de snippets doen dat in de proxy.

  • X-IPScanner-Statusok, error, timeout, backoff, skipped

    Of de check gedraaid heeft, en zo niet, waarom.

  • X-IPScanner-Classhuman, verified_bot, ai_agent, …

    Verkeersklasse van de bezoeker.

  • X-IPScanner-Actionallow, flag, block, would_flag, would_block

    Wat er met het verzoek gebeurde. Monitor-modus geeft would_flag en would_block.

  • X-IPScanner-Network-Classresidential_clean, hosting, vpn, tor, …

    Netwerkklasse van het adres.

  • X-IPScanner-Anonymizedtrue, false

    Het netwerk verbergt waar de bezoeker is.

  • X-IPScanner-Risk0-100

    Risicoscore van het adres.

  • X-IPScanner-CountryDE

    Land van het adres.

  • X-IPScanner-Sitesite_...

    De Site-ID, als die gezet is.

Mislukt een check of wordt hij overgeslagen, dan is alleen X-IPScanner-Status gezet.

Verzoek naar je app
X-IPScanner-Status: ok
X-IPScanner-Class: ai_agent
X-IPScanner-Action: would_block
X-IPScanner-Network-Class: hosting
X-IPScanner-Anonymized: true
X-IPScanner-Risk: 60
X-IPScanner-Country: US
X-IPScanner-Site: site_4fQ8nZ2kLm7xR1vT9cBw

Cache en fail open

  • Beleid van de siteGET /v1/sites/{id}/policy

    Modus en beleid per klasse, 30 s gecachet. Mislukt een verversing, dan blijft het laatste goede beleid 24 uur gelden. Wijzigingen werken zonder herstart.

  • Oordeel-cache

    Eén check per bezoeker (site, IP, user agent) per 10 minuten, in het geheugen, per gate-instantie.

  • Fail open

    1,5 s voor oordeel en beleid samen. Bij een timeout of API-fout gaat het verzoek door en pauzeren checks 30 s, of 5 minuten na een 401, 402, 403 of 429.

  • Gate down

    nginx en NPM laten door na de connect-timeout van 1 s, HAProxy stuurt verkeer meteen naar de app, Apache laat één verzoek mislukken en gebruikt daarna de app. Traefik geeft 500 en Caddy 502, dus draai de gate met restart: unless-stopped.

  • Altijd door

    Geverifieerde crawlers, OPTIONS-verzoeken, private en loopback-adressen, en paden op de uitzonderingslijst.

  • Geblokkeerd

    Een 403-pagina met het request-ID. Monitor-modus blokkeert nooit.

  • Free-abonnement

    Sites op het Free-abonnement blijven in monitor-modus.

  • Kosten

    2 request-eenheden per bezoeker die niet in de cache zit. Herhaalde verzoeken binnen het cachevenster zijn gratis.

Wat er verstuurd wordt

  • POST /v1/edge/checkTelt als 2 verzoeken

    Eén call per bezoeker die niet in de cache zit.

  • Het beleid van de site, als een Site-ID gezet is.

  • X-IPScanner-Source: forward_auth

    Markeert de calls in je verkeer en verbruik als die van deze integratie.

  • User-Agent: ipscanner-forward-auth/<version>

    De versie, zichtbaar op de pagina van de site in het dashboard.

Request-body

  • sitestring

    De Site-ID, als die gezet is.

  • ipstring

    Het adres van de bezoeker.

  • user_agentstring

    De User-Agent van de bezoeker.

  • headersobject

    Accept, Accept-Language, Accept-Encoding, Sec-CH-UA* en Sec-Fetch-*, elk ingekort tot 512 bytes.

  • request_idstring

    De X-Request-Id van het verzoek of een nieuw ID, dat ook op de blokkadepagina staat.

De edge-check die hij doet
curl https://ipscanner.io/v1/edge/check \
  -H "Authorization: Bearer $IPSCANNER_API_KEY" \
  -H "X-IPScanner-Source: forward_auth" \
  -H "User-Agent: ipscanner-forward-auth/0.1.0" \
  -H "Content-Type: application/json" \
  -d '{
    "site": "site_4fQ8nZ2kLm7xR1vT9cBw",
    "ip": "203.0.113.7",
    "user_agent": "Mozilla/5.0",
    "headers": {
      "accept-language": "en-US"
    },
    "request_id": "9f2c41b7d03e77f2"
  }'