Start with observations
Before enabling response, inspect normal traffic and verify your client-IP topology. Establish a tested console or other recovery route. The examples use reserved documentation addresses; replace them with the real management and test addresses for your environment.
sudo -u bhim bhim-protection health --strict
sudo -u bhim bhim-protection incidents --limit 50
sudo -u bhim bhim-protection export --format json --limit 200
sudo journalctl -u bhim-agent.service -n 100 --no-pagerSSH detection and explicit response
SSH uses either journald or configured files, with a threshold and sliding time window. The checked-in policy uses journal, 5 failures, and 120 seconds. Configure actual administrator IPs before enabling blocking. allow_ips accepts individual IP addresses, not CIDR networks.
[protection]
auto_block = false
auto_restore = false
[blocking]
# Merge into the existing section; retain split executor settings.
enabled = true
block_ssh = true
block_http = false
duration_seconds = 600
allow_ips = ["127.0.0.1", "::1", "192.0.2.25"]
ssh_ports = [22]
http_ports = [80, 443]Block, inspect, and unblock
Run these as the bhim service account in the split profile so the helper authenticates the configured peer UID/GID. The command uses the configured duration; there is no --duration flag. A new block cannot overwrite an active or pending policy in the same scope.
sudo -u bhim bhim-protection block 192.0.2.10 --scope ssh --reason operator-test
sudo -u bhim bhim-protection blocks
sudo -u bhim bhim-protection unblock 192.0.2.10 --scope sshCountry-based access blocking
All countries are allowed by default. Explicitly select countries to deny by their two-letter codes. BHIM downloads and validates IPv4 and IPv6 ranges from IPdeny over HTTPS, caches them locally, and applies an atomic dedicated nftables table. No online lookup is needed per request.
Rules cover direct host INPUT TCP and UDP ports 80 and 443, leaving SSH and other ports unchanged. Behind a CDN, external proxy, load balancer, or container FORWARD path, enforce country policy at the edge. Geolocation is approximate; VPNs and proxies can change the apparent country.
# Required only when using country blocking
sudo apt install -y nftables
sudo bhimkvh country status
# Example: replace the denied list; use your actual management IP if needed
sudo bhimkvh country set --block CN,RU --allow-ip 203.0.113.10
sudo bhimkvh country refresh
sudo bhimkvh country disableDirect clients, proxies, and shared IPs
Direct-client HTTP host blocking requires http_rate.enabled=true, direct_peer_verified=true, blocking.block_http=true, and forwarded_clients=false. Only mark a peer verified after checking the actual traffic path. Forwarded clients require explicit trusted proxy CIDRs and cannot be host-blocked by this policy. Shared-IP networks use their own detection threshold and are excluded from automatic host bans.
Native Nginx rate limiting
Inline limiting is configured in Nginx separately from post-request BHIM log observation. The following example follows integrations/nginx/http-context.conf and requires ngx_http_realip_module for $realip_remote_addr. Put these directives inside the existing http context.
# BHIM offline HTTP rate enforcement via Nginx native limit_req module.
# Place inside the nginx `http {}` block (not in a server/location block).
# Uses $binary_remote_addr: configure REAL-IP trust to known ALB/proxy CIDRs
# separately, otherwise this may rate-limit the proxy, not each end user.
limit_req_zone $binary_remote_addr zone=bhim_per_ip:20m rate=100r/s;
limit_req_status 429;
limit_req_log_level warn;
# Recommended observation format: socket peer remains distinct from real-IP rewrites.
# Requires ngx_http_realip_module for $realip_remote_addr (verify with nginx -V).
# Point http_rate.log_paths at this file. msec gives millisecond sliding windows.
log_format bhim_observed escape=json '{"peer_ip":"$realip_remote_addr","msec":"$msec","xff":"$http_x_forwarded_for"}';
access_log /var/log/nginx/bhim-access.jsonl bhim_observed;Apply the zone to an existing location
Add the limit to the location that already serves the application. Do not create a duplicate location / block. This example permits 100 requests/second per key with burst 100; these native settings are independent of http_rate.threshold.
location / {
limit_req zone=bhim_per_ip burst=100 nodelay;
# Keep your existing proxy_pass, try_files, or application directives.
}
# Run in the shell after editing, before applying:
# sudo nginx -t
# sudo systemctl reload nginxTrusted proxy configuration
Configure Nginx real-IP trust only for your actual ingress networks. This example uses documentation CIDRs and must be edited. Keep the socket peer distinct from the rewritten client address in BHIM observation logs.
# http context. Replace documentation CIDRs with your actual ingress networks.
# Never trust 0.0.0.0/0 or arbitrary client-supplied forwarding headers.
set_real_ip_from 192.0.2.0/24;
set_real_ip_from 2001:db8:1234::/48;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# The BHIM JSON format keeps $realip_remote_addr as the socket peer even after
# $remote_addr has been rewritten for native Nginx rate enforcement.
# Corresponding BHIM TOML, after replacing the documentation networks:
# [http_rate]
# enabled = true
# forwarded_clients = true
# trusted_proxies = ["192.0.2.0/24", "2001:db8:1234::/48"]
# log_paths = ["/var/log/nginx/bhim-access.jsonl"]
# [blocking]
# block_http = falseDoS protection and AWS WAF boundaries
Local rate detection, native Nginx limits, and host INPUT blocking mitigate different traffic paths. They are not volumetric upstream DDoS protection or a complete payload-inspection WAF. The separate integrations/aws/waf_sync.py adapter can update a dedicated AWS WAF IP set from a reviewed plan. It needs AWS CLI credentials only for an explicit apply; the offline agent does not call it.
python3 integrations/aws/waf_sync.py reviewed-plan.json
# Read plan_sha256 from review output; no AWS request is made above.
python3 integrations/aws/waf_sync.py reviewed-plan.json --apply-sha256 REVIEWED_PLAN_SHA256Integrity baselines and investigation
Baseline trusted critical files, then inspect changes. Do not use baseline --replace to silence an unexplained alert: it accepts current content as the new baseline. Event confidence describes observations, not proof of compromise.
sudo bhim-protection baseline
sudo -u bhim bhim-protection verify
sudo -u bhim bhim-protection incidents --limit 20
sudo -u bhim bhim-protection timeline INCIDENT_ID
sudo -u bhim bhim-protection evidence-verifySnapshots, restore, and quarantine
These are explicit operator operations. Stop competing configuration writers before restore, review the file and current hash, and retain the returned snapshot ID. The snapshot manifest is JSON. Restore requires the current content hash you reviewed, or absent when the target must not exist.
sudo bhim-protection snapshot /etc/ssh/sshd_config
sudo bhim-protection snapshot-show SNAPSHOT_UUID
sudo sha256sum /etc/ssh/sshd_config
sudo bhim-protection restore SNAPSHOT_UUID --expected-current-sha256 REVIEWED_CURRENT_HASH
# Quarantine a reviewed non-critical file, on the same filesystem:
sudo sha256sum /var/www/html/suspect.php
sudo bhim-protection quarantine /var/www/html/suspect.php --expected-sha256 REVIEWED_FILE_HASH
sudo bhim-protection restore QUARANTINE_UUID --expected-current-sha256 absentOptional kernel and scanners
Kernel telemetry requires the separate BCC collector, matching kernel headers, tracepoints, and suitable privileges. Validate on the target kernel before enabling. Malware scanning can use pinned offline hash signatures; vulnerability scanning requires a pinned Trivy binary and database.
sudo /usr/bin/python3 scripts/ebpf_acceptance.py --binary target/release/bhim-protection
# Only after target validation and setting kernel.enabled=true:
sudo systemctl enable --now bhim-kernel.service
sudo systemctl restart bhim-agent.serviceMonitor coverage and evidence loss
Inspect health reasons, metrics, spool depth, and unavailable/drop/gap events. Bounded storage and sampling protect the host but can reduce coverage. A locally verified evidence chain has no independent trust anchor; a sufficiently privileged attacker can rewrite local evidence.
sudo -u bhim bhim-protection health --strict
sudo -u bhim bhim-protection metrics
sudo -u bhim bhim-protection export --format json --limit 500
sudo tail -n 50 /var/log/bhim-protection/security.log