Skip to content
Configuration

Configuration

Every Kartis component is configured through a YAML file plus a small number of Docker Compose / .env variables. All three long-running commands take -c/--config <path>:

ComponentDefault config path
kartis-scan (serve, daemon, scan)/etc/kartis/kartis-scan.yaml
kartis-discovery/etc/kartis/kartis-discovery.yaml
kartis-recon/etc/kartis/kartis-recon.yaml
kartis-scheduler/etc/kartis/kartis-scheduler.yaml

kartis-scan.yaml

name: kartis-scan
listen: ":8080"
database: "postgres://<postgres-user>:<postgres-password>@<host>:5432/kartis?sslmode=require"

redis:
  host: localhost
  port: 6379
  password: "<redis-password>"

scan_profile: polite   # polite | normal | aggressive — which entry in `profiles` is active

profiles:
  polite:
    nmap_timing: T2
    nmap_scan_type: "-sT"
    max_rate_pps: 50
    inter_probe_delay_ms: 200
    concurrent_services_per_ip: 1
    concurrent_runs: 5
  normal:
    nmap_timing: T3
    nmap_scan_type: "-sT"
    max_rate_pps: 200
    inter_probe_delay_ms: 50
    concurrent_services_per_ip: 2
    concurrent_runs: 10
  aggressive:
    nmap_timing: T4
    nmap_scan_type: "-sS"
    max_rate_pps: 1000
    inter_probe_delay_ms: 0
    concurrent_services_per_ip: 4
    concurrent_runs: 20
  • listen defaults to :8080 and scan_profile to polite if omitted.
  • profiles tunes nmap pacing (timing template, scan type, max packets/sec, inter-probe delay) and concurrency (services scanned per IP at once, concurrent_runs = the daemon’s worker-pool size) — this is the same profile value that can be overridden per-run via --profile or the API’s profile field, orthogonal to scan depth (max_level).
  • -sT (polite/normal) is a plain TCP connect scan; -sS (aggressive) is a raw-socket SYN scan and needs the NET_RAW capability (in Docker Compose: cap_add: ["NET_RAW"]).

Portal

The customer-facing portal is served by kartis-scan serve and is disabled by default, so an existing deployment that only serves Eon Center keeps the surface it has. See Portal for what it exposes.

portal:
  enabled: true
  trusted_proxies: "127.0.0.1"   # who may set X-Forwarded-For / X-Forwarded-Proto
  insecure: false                # drop the __Host- cookie prefix and Secure flag
  smtp_host: localhost           # delivers the login codes
  smtp_port: 25
  mail_from: kartis@example.com
KeyMeaning
enabledMount /portal/... at all. Default false
trusted_proxiesAddresses or CIDRs whose X-Forwarded-For and X-Forwarded-Proto are believed. Empty means believe nobody — right when nothing fronts the process, wrong the moment nginx does
insecureDrops the __Host- cookie prefix and the Secure flag, for a test over plain HTTP. The portal is otherwise served behind TLS and the browser would reject the cookie
smtp_host / smtp_port / mail_fromDelivery of the one-time login codes

kartis-scheduler.yaml

The scheduler needs the database and nothing else: it does not scan and serves no HTTP.

database: "postgres://<postgres-user>:<postgres-password>@<host>:5432/kartis?sslmode=require"
interval: "1m"   # how often to look for due sessions
batch: 50        # most runs placed per tick

interval only decides how long after a slot a run is placed, since cadences are monthly or biweekly. batch caps a backlog so it is worked through over several ticks rather than arriving at the customer all at once.

kartis-discovery.yaml

name: kartis-discovery

redis:
  host: localhost
  port: 6379
  password: "<redis-password>"

db:
  host: localhost
  port: 5432
  database: kartis
  username: <postgres-user>
  password: <postgres-password>

rate_limit:
  whois_per_minute: <n>
  ctlogs_per_minute: <n>
  reverse_ip_per_minute: <n>
  asn_per_minute: <n>
  dns_recon_per_minute: <n>
  tech_fp_per_minute: <n>
  ai_calls_per_minute: <n>

sources:
  enable_whois: true
  enable_ctlogs: true
  enable_reverse_ip: true
  enable_asn: true
  enable_dns_recon: true
  enable_tech_fingerprint: true
  enable_ai_correlation: true

  enable_reverse_whois: false        # opt-in, needs whoisxml_api_key (paid)
  whoisxml_api_key: ${WHOISXML_API_KEY}

  enable_brand_permutation: false    # opt-in — permute brand label across common TLDs
  enable_ai_org_expansion: false     # opt-in — AI-assisted organization expansion, needs ai.api_key

ai:
  provider: anthropic               # anthropic | openai | ollama (local)
  api_key: ${ANTHROPIC_API_KEY}
  model: <model>
  # base_url: http://localhost:11434   # ollama only

Each enable_* flag under sources turns a discovery source on or off independently; the run <domain> recursive-expansion parameters (--depth, --min-confidence, --max-related-per-job, --max-jobs) are CLI flags, not config keys (see Scanning).

kartis-recon.yaml

name: kartis-recon

redis:
  host: localhost
  port: 6379
  password: "<redis-password>"

db:
  host: localhost
  port: 5432
  database: kartis
  username: <postgres-user>
  password: <postgres-password>

ai:
  provider: anthropic
  api_key: ${ANTHROPIC_API_KEY}
  model: <model>

Environment variables (.env / Docker Compose)

.env (copy from .env.example, or generate it with ./setup.sh) feeds variable substitution into the Docker Compose file, and is what the ${VAR} references inside the YAML files above expand from at container startup.

VariablePurpose
POSTGRES_PASSWORD / POSTGRES_USER / POSTGRES_DBPostgres credentials — no default in prod compose
REDIS_PASSWORDRedis auth — required
KARTIS_TAGimage tag the Compose file pulls (default latest)
KARTIS_PORThost-side port mapped to the API’s internal 8080
KARTIS_SCAN_LISTENlisten address baked into kartis-scan.yaml by setup.sh
KARTIS_SCAN_PROFILEdefault scan profile: polite | normal | aggressive
KARTIS_SCAN_CONTACTcontact URL/mailto: appended to the scanner’s User-Agent and SSH ident comment
KARTIS_SCAN_EHLOhostname announced in SMTP EHLO/HELO (default scanner.eon-kartis)
ANTHROPIC_API_KEYenables the AI-assisted subdomain source and the run --judge review pass
SHODAN_API_KEYenables the Shodan host/port enrichment source
SECURITYTRAILS_API_KEYoptional discovery enrichment source
WHOISXML_API_KEYenables reverse-WHOIS (enable_reverse_whois)

An empty API key simply disables the corresponding optional source — none are required for the core discovery/scan pipeline to run.

Bearer tokens

kartis-scan serve authenticates every /v1/... route except /healthz and /readyz with a bearer token (only a hash is stored):

kartis-scan token create --name operator   # prints the plaintext token once
kartis-scan token list                     # prefixes + metadata, no plaintext
kartis-scan token revoke <prefix-or-uuid>

Store the printed token as a secret in whatever consumes the API (Eon Center, Eon Aethis, Eon Insights, an operator’s ~/.kartis-token, CI); it cannot be retrieved again after creation.

Deployment lifecycle

On the target, ./setup.sh interactively writes .env and the runtime YAMLs, ./install.sh brings the stack up via Docker Compose, and ./upgrade.sh applies an upgrade package on top of an existing install (backing up compose, .env, and YAML under .upgrade-backup-<timestamp>/).