Configuration format and editing
BHIM KVH reads TOML, not YAML. The installed path is /etc/bhim-protection/config.toml. Do not duplicate a section when merging an example: edit its existing keys and preserve split executor settings.
sudo cp -p /etc/bhim-protection/config.toml /etc/bhim-protection/config.toml.backup
sudoedit /etc/bhim-protection/config.toml
sudo -u bhim bhim-protection config-show
sudo systemctl restart bhim-response.service
sudo systemctl restart bhim-agent.service
sudo -u bhim bhim-protection health --strictLicense files are separate from policy
Licensing data is not a TOML switch. The client verifies a pinned public key embedded in the binary. No enabled=false config setting bypasses licensing. Device credentials and signed leases live under /etc/bhim-protection/license; the root-owned clock floor lives under /var/lib/bhim-license.
Source profile versus safe starting profile
The licensed 0.4.1 source and monitoring example start with response disabled. The downloadable example is not a replacement for an existing split policy: preserve actual executor UID/GID and socket settings.
[agent]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| agent.state_dir | "/var/lib/bhim-protection" | Absolute state directory, no parent traversal; distinct from log_dir. Contains events.sqlite3 and recovery state. |
| agent.log_dir | "/var/log/bhim-protection" | Absolute category log directory, no parent traversal; distinct from state_dir. |
| agent.poll_seconds | 1 | Poll interval in seconds; 1–3600. |
| agent.retention_days | 7 | SQLite event retention in days; 1–36500. Separate exports have independent retention. |
| agent.max_log_bytes | 52428800 | Rotation threshold per JSONL log; at least 1024 bytes. Up to five archives per category. |
[ssh]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| ssh.source | "journal" | files or journal. Journal uses saved cursor/state. |
| ssh.log_paths | [] | Absolute file paths. Empty in files mode falls back to auth.log and secure. Journal mode reads journald. |
| ssh.threshold | 5 | Failure threshold; 1–10000. |
| ssh.window_seconds | 120 | SSH observation window in seconds; 1–86400. |
[integrity]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| integrity.paths | ["/etc/ssh/sshd_config", "/etc/passwd", "/etc/group", "/etc/sudoers"] | Absolute critical-file paths. Baseline these only after review. |
[monitor]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| monitor.ssh | true | SSH authentication observation. |
| monitor.processes | true | Procfs process observation; polling can miss transient activity. |
| monitor.network | true | Socket/network observation; proc_net_path chooses procfs view. |
| monitor.files | true | Integrity observation for configured paths. |
| monitor.firewall | true | Read-only firewall sampling; may degrade under unprivileged service constraints. |
| monitor.malware | false | Enable the bounded malware scanner. |
| monitor.health | true | Host memory/disk health observations. |
| monitor.vulnerability | false | Enable Trivy only with pinned binary and database settings. |
| monitor.proc_net_path | "/proc/net" (parser default) | Absolute procfs network path. Node host-namespace deployment uses /proc/1/net. |
[health]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| health.memory_percent | 90.0 | Host memory usage alert threshold; 1–100 percent. |
| health.disk_percent | 90.0 | Disk usage alert threshold; 1–100 percent. |
[malware]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| malware.paths | ["/tmp"] | Absolute scan roots; choose narrow, reviewed directories. |
| malware.max_files | 100 | Per-scan file budget; 1–100000. |
| malware.max_file_bytes | 16777216 (parser default) | Maximum scanned file size; 1024–67108864 bytes. |
| malware.scan_milliseconds | 500 (parser default) | Scan time budget per poll; 10–5000 ms. |
| malware.signatures_file | "" (parser default) | Offline JSON mapping SHA-256 hashes to indicator names. If set, signatures_sha256 is required. |
| malware.signatures_sha256 | "" (parser default) | 64-character hex digest pinning the signature file. |
[vulnerability]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| vulnerability.target | "/" | Absolute scan target. |
| vulnerability.interval_hours | 24 | Scheduled scan interval; 1–720 hours. |
| vulnerability.binary | "/usr/bin/trivy" (parser default) | Absolute path to the Trivy executable. |
| vulnerability.binary_sha256 | "" (parser default) | 64-character pinned executable digest; required when enabled. |
| vulnerability.database_path | "" (parser default) | Absolute preloaded database file path; use CACHE/db/trivy.db with metadata. |
| vulnerability.database_sha256 | "" (parser default) | 64-character pinned database digest; required when enabled. |
[protection]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| protection.auto_block | false | Automatic response switch. Requires blocking.enabled. |
| protection.auto_restore | false | Must remain false; automatic destructive restore is rejected. |
[http_rate]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| http_rate.forwarded_clients | false | Enable trusted-chain client extraction; requires trusted_proxies. Incompatible with host HTTP blocking. |
| http_rate.trusted_proxies | [] | Explicit proxy IP/CIDR list, maximum 256 entries. Never trust all Internet addresses. |
| http_rate.shared_ips | [] | Reviewed shared/NAT IP/CIDR ranges, maximum 256 entries; excluded from automatic host bans. |
| http_rate.shared_ip_threshold | 1000 | Shared-IP threshold; 1–10000. |
| http_rate.enabled | true | Read configured access logs and observe rate windows. |
| http_rate.log_paths | ["/var/log/nginx/access.log", "/var/log/apache2/access.log", "/var/log/httpd/access_log", "/var/log/apache2/other_vhosts_access.log", "/usr/local/lsws/logs/access.log", "/var/log/lsws/access.log", "/var/log/caddy/access.log"] | Absolute access-log paths. Choose actual logs and verify read permissions. |
| http_rate.threshold | 100 | Base observed per-IP threshold; 1–10000. Exceeding this threshold triggers a finding. |
| http_rate.window_milliseconds | 1000 | Observed sliding-window size; 100–60000 ms. |
| http_rate.direct_peer_verified | false | Operator confirmation that observed direct-peer addresses are valid for host enforcement. |
| http_rate.max_tracked_ips | 1000000 | Tracked-IP capacity; positive values replace internal capacity. Resource usage depends on workload. |
| http_rate.max_samples | 10000000 | Sample capacity; positive values replace internal capacity. Finite buffers can drop samples. |
| http_rate.global_threshold | 5000 | Aggregate observed-request threshold used by adaptive rate logic; not an inline request limiter. |
| http_rate.adaptive_enabled | true | Tighten observed per-IP threshold when global volume exceeds the configured threshold. |
| http_rate.adaptive_min_threshold | 20 | Lower floor for the adaptive threshold; keep no greater than the base threshold. |
| http_rate.critical_paths | [] | Parsed configuration field but not consumed by the current rate detector; no path-specific enforcement is implemented. |
[blocking]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| blocking.enabled | false | Enable response capability. Requires nonempty allow_ips. |
| blocking.block_ssh | false | Enable SSH-scope actions for ssh_ports. |
| blocking.block_http | false | Requires enabled HTTP collection, direct_peer_verified, nonempty logs, and forwarded_clients=false. |
| blocking.duration_seconds | 600 | 0 permanent, or 60–86400 seconds. Applies to new requests, not a CLI duration argument. |
| blocking.allow_ips | ["127.0.0.1", "::1"] | Exact management IPv4/IPv6 addresses, maximum 256; CIDRs are not accepted. |
| blocking.ssh_ports | [22] | 1–32 TCP destination ports, each 1–65535; cannot be empty. |
| blocking.http_ports | [80, 443] | 1–32 TCP destination ports, each 1–65535; cannot be empty. |
| blocking.executor_socket | "unset" (parser default) | Absolute local helper socket path. Split installer inserts /run/bhim-protection/response.sock. |
| blocking.executor_uid | 0 (parser default) | Actual allowed bhim peer UID, inserted by split installer. Do not copy 0 into a split deployment. |
| blocking.executor_gid | 0 (parser default) | Actual allowed bhim peer GID, inserted by split installer. |
[reliability]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| reliability.spool_bytes | 134217728 | Durable spool budget; 1–256 MiB. |
| reliability.database_bytes | 1073741824 | SQLite page budget; 16 MiB–64 GiB. WAL cleanup targets are additional, not a total disk guarantee. |
| reliability.snapshot_bytes | 134217728 | Recovery snapshot budget; 8 MiB–1 GiB. |
| reliability.max_batch_events | 50000 | Maximum events per batch; 1–100000. |
[kernel]
| Setting | Source profile / fallback | Meaning and constraints |
|---|---|---|
| kernel.enabled | false | Consume separate BCC collector output. Does not load probes by itself. |
| kernel.log_path | "/var/log/bhim-kernel/events.jsonl" | Absolute collector JSONL path. Enable service only after target-kernel acceptance. |
config-set supported keys
config-set accepts only the following numeric or Boolean settings. It validates the complete result before an atomic write. Paths, arrays, trust settings, executor values, blocking.enabled, and protection.auto_block require manual protected-TOML edits.
- agent.poll_seconds
- agent.retention_days
- ssh.threshold
- ssh.window_seconds
- monitor.ssh
- monitor.processes
- monitor.network
- monitor.files
- monitor.firewall
- monitor.malware
- monitor.health
- monitor.vulnerability
- health.memory_percent
- health.disk_percent
- malware.max_files
- vulnerability.interval_hours
- http_rate.enabled
- http_rate.threshold
- http_rate.window_milliseconds
- blocking.duration_seconds
- blocking.block_ssh
- blocking.block_http
sudo bhim-protection config-set ssh.threshold 8
sudo bhim-protection config-set ssh.window_seconds 120
sudo bhim-protection config-set blocking.duration_seconds 600
sudo chown root:bhim /etc/bhim-protection/config.toml
sudo chmod 0640 /etc/bhim-protection/config.toml
sudo systemctl restart bhim-response.service
sudo systemctl restart bhim-agent.serviceSplit-profile policy permissions
sudo chown root:bhim /etc/bhim-protection /etc/bhim-protection/config.toml
sudo chmod 0750 /etc/bhim-protection
sudo chmod 0640 /etc/bhim-protection/config.toml
sudo -u bhim bhim-protection config-showPinned signature and scanner inputs
Obtain trusted offline signature and Trivy database files through your reviewed process. Compute and independently verify SHA-256 values before enabling scanners; replace every placeholder. Preload database metadata as required by Trivy.
sha256sum /absolute/path/signatures.json
sha256sum /usr/bin/trivy
sha256sum /absolute/cache/db/trivy.db
# Merge into the existing TOML sections:
# [malware]
# signatures_file = "/absolute/path/signatures.json"
# signatures_sha256 = "REVIEWED_64_CHARACTER_HEX_DIGEST"
# [vulnerability]
# binary = "/usr/bin/trivy"
# binary_sha256 = "REVIEWED_EXECUTABLE_DIGEST"
# database_path = "/absolute/cache/db/trivy.db"
# database_sha256 = "REVIEWED_DATABASE_DIGEST"Common validation failures
| Failure | Resolution |
|---|---|
| auto_block requires blocking.enabled | Enable response deliberately or leave auto_block false. |
| blocking requires explicit admin allow_ips | Set real exact management IP addresses before enforcement. |
| host blocking cannot enforce forwarded client IPs | Use ingress rate limits/WAF and keep blocking.block_http=false. |
| HTTP blocking requires enabled rate collection | Review enabled, direct_peer_verified, and logs together. |
| unsupported setting | Use an allowed config-set key or edit protected TOML. |
| automatic destructive rollback is unsupported | Leave protection.auto_restore=false. |
| Trivy requires absolute paths and pinned SHA-256 | Provide reviewed binary and database paths/hashes before enabling. |