.env.example 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. # =============================================================================
  2. # IRDB — IP Reputation Database — environment configuration
  3. # =============================================================================
  4. # Copy this file to `.env` and fill in the blanks.
  5. # Generate 32-byte hex secrets with: openssl rand -hex 32
  6. # =============================================================================
  7. # -----------------------------------------------------------------------------
  8. # Docker host ports (consumed by docker-compose.yml only)
  9. # -----------------------------------------------------------------------------
  10. # Host-side ports for the published service mappings. Container-internal
  11. # ports are fixed at 8081 (api) and 8080 (ui) — only the host side here is
  12. # remappable, so port collisions on the host can be resolved without
  13. # rebuilding the images. If you change UI_PORT, also update PUBLIC_URL
  14. # below so the browser-facing URL matches.
  15. API_PORT=8081
  16. UI_PORT=8080
  17. # -----------------------------------------------------------------------------
  18. # Shared (consumed by both api and ui containers)
  19. # -----------------------------------------------------------------------------
  20. # IRDB-format service token. The api uses this to authenticate the ui's
  21. # calls; the ui presents it on every API request together with
  22. # X-Acting-User-Id. Format: irdb_svc_<32 base32 chars>. Generate one with
  23. # (note `--entrypoint php` — the api image's default entrypoint is a
  24. # dispatcher with `api` / `migrate` modes, so ad-hoc PHP bypasses it):
  25. # docker compose run --rm -T --entrypoint php api -r 'require "/app/vendor/autoload.php";
  26. # echo (new App\Domain\Auth\TokenIssuer())->issue(App\Domain\Auth\TokenKind::Service), PHP_EOL;'
  27. UI_SERVICE_TOKEN=
  28. # -----------------------------------------------------------------------------
  29. # api container
  30. # -----------------------------------------------------------------------------
  31. APP_ENV=production # development | production
  32. LOG_LEVEL=info
  33. # Database
  34. DB_DRIVER=sqlite # sqlite | mysql
  35. DB_SQLITE_PATH=/data/irdb.sqlite
  36. DB_MYSQL_HOST=
  37. DB_MYSQL_PORT=3306
  38. DB_MYSQL_DATABASE=
  39. DB_MYSQL_USERNAME=
  40. DB_MYSQL_PASSWORD=
  41. # OIDC role mapping (defaults applied if no group mapping matches)
  42. OIDC_DEFAULT_ROLE=viewer # viewer | none
  43. # Reputation engine
  44. SCORE_RECOMPUTE_INTERVAL_SECONDS=300
  45. SCORE_REPORT_HARD_CUTOFF_DAYS=365
  46. # Internal jobs
  47. INTERNAL_JOB_TOKEN= # 32-byte hex (api refuses to boot if shorter than 32 hex chars)
  48. # Comma- or whitespace-separated CIDR list of sources allowed to reach
  49. # /internal/*. Empty (the default) means loopback-only (127.0.0.1/32 +
  50. # ::1/128). The bundled `compose.scheduler.yml` shares the api's network
  51. # namespace, so its calls hit loopback and need no extra entries.
  52. # Production topologies that genuinely need extra sources (host cron on
  53. # a private bridge, etc.) list them here AND mirror them into the api
  54. # Caddyfile's @internal matcher.
  55. INTERNAL_CIDR_ALLOWLIST=
  56. # Comma- or whitespace-separated CIDR list of trusted reverse-proxy IPs
  57. # whose `X-Forwarded-For` header Caddy should honour for REMOTE_ADDR
  58. # rewriting. Default (loopback-only) means no XFF rewriting from any
  59. # real client. Set to your reverse proxy's CIDR (e.g. "10.0.0.5/32") if
  60. # the api sits behind one — required for accurate audit-log source IPs.
  61. # SEC_REVIEW F25: never include broad RFC1918 ranges in deployments
  62. # where untrusted neighbours can reach the api on the same docker bridge.
  63. TRUSTED_PROXIES=
  64. # HSTS header value — applied prod-only by both Caddyfiles. Default is
  65. # 1 year + subdomains, NO preload (preload-listing is a one-way
  66. # commitment; browser preload removals take months). Operators who
  67. # want to apply for the HSTS preload list at https://hstspreload.org/
  68. # set:
  69. # HSTS_HEADER="max-age=31536000; includeSubDomains; preload"
  70. # SEC_REVIEW F60.
  71. HSTS_HEADER=
  72. JOB_RECOMPUTE_MAX_RUNTIME_SECONDS=240
  73. JOB_RECOMPUTE_MAX_ROWS_PER_TICK=5000
  74. JOB_AUDIT_RETENTION_DAYS=180
  75. JOB_GEOIP_REFRESH_INTERVAL_DAYS=7
  76. # Manual blocks / allowlist evaluator
  77. # In-process cache TTL for the CidrEvaluator. Mutations invalidate explicitly,
  78. # so this only matters for cross-replica visibility (per replica is fine).
  79. CIDR_EVALUATOR_TTL_SECONDS=60
  80. # Distribution endpoint
  81. # Per-policy blocklist cache TTL. Mutations to policies / manual_blocks /
  82. # allowlist invalidate explicitly; this is the cross-replica window.
  83. BLOCKLIST_CACHE_TTL_SECONDS=30
  84. # GeoIP / ASN enrichment
  85. # Three pluggable MMDB providers — pick one. The on-disk paths below are
  86. # provider-agnostic; the refresh-geoip job atomic-replaces them with the
  87. # selected provider's files.
  88. # - dbip (default, no auth required, CC BY 4.0 — UI shows attribution)
  89. # - maxmind (opt-in, requires MAXMIND_LICENSE_KEY)
  90. # - ipinfo (opt-in, requires IPINFO_TOKEN — UI shows attribution)
  91. GEOIP_ENABLED=true
  92. GEOIP_PROVIDER=dbip
  93. GEOIP_COUNTRY_DB=/data/geoip/country.mmdb
  94. GEOIP_ASN_DB=/data/geoip/asn.mmdb
  95. MAXMIND_LICENSE_KEY=
  96. IPINFO_TOKEN=
  97. # CORS — origin of the ui container (or future SPA frontend)
  98. UI_ORIGIN=http://localhost:8080
  99. # Rate limiting (public API)
  100. API_RATE_LIMIT_PER_SECOND=60
  101. # Public API docs viewer.
  102. # `false` (default): /api/docs and /api/v1/openapi.yaml are not
  103. # registered — Slim returns 404 — so the OpenAPI spec doesn't leak
  104. # the full admin/internal route surface to unauthenticated callers.
  105. # Set `true` for open APIs / dev environments where the menu is
  106. # meant to be public. SEC_REVIEW F68.
  107. API_DOCS_PUBLIC=false
  108. # -----------------------------------------------------------------------------
  109. # ui container
  110. # -----------------------------------------------------------------------------
  111. # (APP_ENV / LOG_LEVEL above are reused; the ui reads its own copies of those.)
  112. PUBLIC_URL=http://localhost:8080
  113. # Where the ui finds the api (internal docker network DNS)
  114. API_BASE_URL=http://api:8081
  115. # OIDC (Entra ID) — lives in ui only
  116. OIDC_ENABLED=true
  117. OIDC_ISSUER=https://login.microsoftonline.com/<tenant>/v2.0
  118. OIDC_CLIENT_ID=
  119. OIDC_CLIENT_SECRET=
  120. OIDC_REDIRECT_URI=https://reputation.example.com/oidc/callback
  121. # Local admin — lives in ui only
  122. LOCAL_ADMIN_ENABLED=true
  123. LOCAL_ADMIN_USERNAME=admin
  124. # Generate with: php -r "echo password_hash('s3cret', PASSWORD_ARGON2ID);"
  125. LOCAL_ADMIN_PASSWORD_HASH=
  126. # Optional BCP 47 locale fallback for date/time formatting (e.g. "de-CH",
  127. # "en-GB"). The browser's locale wins; this is appended as a fallback so
  128. # JavaScript's Intl.DateTimeFormat picks something sensible if the
  129. # browser's preference isn't supported. Empty = browser-only.
  130. UI_LOCALE=
  131. # How often (seconds) the UI re-validates the cached user role/identity
  132. # against `GET /api/v1/admin/me`. Lower = faster propagation of Entra
  133. # group changes and explicit user-disable actions; higher = fewer api
  134. # calls per active user. Default 300 (5 min).
  135. UI_SESSION_REVALIDATE_SECONDS=300