Skip to content
English
  • There are no suggestions because the search field is empty.

Hardening Guide

Harden your Kilter instance to ensure your enterprise security posture.

The appliance ships with root as the primary account, and services, scripts and DB connections depend on root to function properly. This guide lists those dependencies, what you can harden, and what hardening actions are prohibited.

  • Kilter by BackBox is hardened by default with STIG and NIST 800-53 guidelines while attempting to maintain backwards compatibility with legacy devices.
  • Operating system updates are managed by updates to Kilter from BackBox. Operating system updates should not be installed outside of the appliance update process.
  • Installing third-party applications on Kilter by BackBox is not supported.
  • The firewall is firewalld (nftables), zone backbox, target REJECT. iptables must not be installed.
  • SELinux is permissive (no supported enforcing mode on this release). FIPS and fapolicyd are opt-in.
Hardening RecommendationsSSH Root Login Hardening

NOTE: The CLI (root to the Server IP from guacd) and Debug Mode (root to 127.0.0.1) use the root password. The cluster/agent sync uses root keys. Blocking any of these breaks the respective feature. Remote device access is unaffected.

Do not use PermitRootLogin no/prohibit-password globally. Append after the existing Match group blocks:

PermitRootLogin no

# Debug Mode (127.0.0.1) and CLI (guacd on the Docker bridge)
Match Address 127.0.0.1,::1,255.255.255.0/24
PermitRootLogin yes

# Cluster peers and agents: key-based only
Match Address <peer-mgmt-ip>,<agent-ip-1>,<agent-ip-2>
PermitRootLogin prohibit-password

  • Bridge subnet is from daemon.json (bip 255.255.255.3/24, copied to /etc/docker/ each upgrade). You can confirm this with docker network inspect bridge. The docker zone accepts docker0, so Access Rules do not apply.
  • sshd_updates.sh never touches PermitRootLogin, Match, Allow*, MaxAuthTries or Banner and keeps customer values, but appends missing crypto keys to end of file (inside your last Match block). Keep Ciphers, KexAlgorithms, MACs, HostKeyAlgorithms, GSSAPIAuthentication in the global section.
  • Plain PermitRootLogin no loses CLI, Debug Mode and cluster/agent sync. Ensure a sudo user and console access exist first.

Also set MaxAuthTries 4, LoginGraceTime 60, Banner /etc/issue.net (5.8); keep MaxSessions/MaxStartups 800. Avoid AllowUsers. If you allowlist, use groups and include everything Kilter requires:

AllowGroups root wheel ssh_users os_users backbox-ops backbox-audit

NOTE: Omitting root, ssh_users or os_users breaks the CLI, cluster sync, device backups and SFTP/SCP users.

Root Password and Lockout

Kilter does not ship PAM quality, aging, or lockout settings at this time. Change root's password via the webUI (3.1). For local accounts: /etc/security/pwquality.conf (minlen=14, dcredit/ucredit/ocredit/lcredit=-1, maxrepeat=3), chage -M 90 -m 7 -W 14 <user>, and lockout:

authselect enable-feature with-faillock
# /etc/security/faillock.conf
deny = 5
unlock_time = 900
fail_interval = 900

NOTE: An expired root password breaks CLI/Debug Mode; create a second admin first and rotate via the webUI. Faillock skips root unless even_deny_root is set: do not set it, or SSH brute-forcing locks root and every CLI session. In a cluster /etc/shadow is copied to the secondary, so changes propagate. The webUI has its own lockout (4.2).

Audit Logging

Only backbox-selinux.rules and a -e 1 seed ship (audit=1 is set). Add the following:

# /etc/audit/rules.d/root-activity.rules
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k root_commands

NOTE: /var/log/audit is 2 GB with about 100 MB retention (num_logs=5). Raise this value or forward it off-box before broad rules.

Prohibited Configurations

Prohibited Configuration

Reasoning

Lock root (passwd -l, usermod -L) or give it a nologin** shell**

Breaks CLI, Debug Mode, console, manual hotfix.sh. nologinalso breaks cluster/agent sync and sudo -i. The service still starts (systemd execs directly); webUI-based upgrades via at remain functional.

Delete root / change its UID

Blocked by the webUI and a DB trigger.

passwd root** without updating** UNIX_USERS

CLI/Debug Mode fail, with no divergence warning on this release. Use Authentication → OS users.

PermitRootLogin no/prohibit-passwordglobally, or Match Address 127.0.0.1,::1 alone

Blocks CLI/Debug (and cluster sync for no); loopback alone fixes Debug Mode only.

AllowUsers/AllowGroups without root, ssh_users, os_users

Blocks cluster sync, jailed sessions, SFTP/SCP users.

Drop root@localhost from MariaDB

Appliance operation, device provisioning, upgrades and credential discovery depend on it; upgrades will fail.

Stop/mask atd; remove root's systemctl

webUI upgrades use at; backbox, sshd, docker, firewalld, nats, guacamole, mariadb require it.

Install iptables-services/iptables-nft

Unsupported: masked on every upgrade, flagged by validate-firewalld.sh (STIG RHEL-09-231190).

Remove Python 3 / python

dnf, firewalld, hotfix_rl9.sh, ITSM wrappers and OS-user password changes require it.

SELinux disabled or manual enforcing

Upgrade raises disabled to permissive. If enforcing was manually set, it is preserved, though unsupported. .

Root umask 0077; noexec on /data or /backbox

Breaks jail/SFTP provisioning and scripts run from /data/tmp, /backbox/scripts, /data/jail/scripts. (/tmp is already noexec.)

Edit/delete RAND* users or ssh_users/os_usersgroups

Managed by JailCreator, jail.sh, add_os_user.sh; used by sshd chroot blocks.

Create accounts with RAND anywhere in the passwd line

Upgrades run an unanchored sed -i '/RAND/d' on /etc/passwd, subuid, subgid (hotfix_rl9.sh 2878-2882) and delete them.

Password Update Methodology

3.1 Linux Root Password

NOTE: Change root's password only in the webUI in Authentication → OS users, edit the root row. Kilter runs the Python usermod and, only on success, stores the encrypted value (ENC: + AES-256) in UNIX_USERS. passwd rootmakes them diverge and the CLI/Debug Mode fail silently.

Avoid \, $, and backticks in the password (interpolated into a shell/Python one-liner). If the change has no effect, usermod or python failed; check general.log.

3.2 Rotation Schedule

Account

Frequency

Method

Linux root

90 days

webUI (Authentication → OS users)

BackBox SSH key (/root/.ssh/id_rsa)

Annually, staged

Authentication → Local authentication → SSH tab → Generate Key. It is also the device public key and cluster/agent key; regenerating breaks both until redeployed. RSA 3072 via webUI (4096 from hotfix_rl9.sh).

Named admins

Per policy

passwd / chage

4. General Security Best Practices

  1. Stay current: upgrades deliver OS packages (incl. kernel) from the bundle, installed offline.
  2. fapolicyd is opt-in: configure-fapolicyd.sh --enable (in /backbox/scripts/fapolicyd/). Trust your own scripts: fapolicyd-cli --file add <path> --trust-file backbox && fapolicyd-cli --update.
  3. Use Access Rules (Administration → Access Rules), not firewall-cmd. FirewallReconciliationService recreates rules from ACCESS_RULES list every 15 minutes and removes manually added ones. Defaults allow TCP 22, 80, 443 from anywhere: restrict 22 and 80. Docker-published ports (NATS 7422, Headscale 8080) bypass the zone; check ss -tlnp and filter upstream.
  4. Monitor: /var/log/secure, /var/log/backbox/, /backbox/app-server/logs/general.log, drops via journalctl -k (prefix [BackBox][<COMMENT>]).
  5. SSH algorithms: sshd_updates.sh sets strong Kex/MACs/host keys and Ciphers aes128-gcm,aes256-gcm,aes256-ctr (no CBC). It runs once per version bump, keeps customer values, and is skipped if /backbox/conf/ignoreSSHUpdates.flag exists. The outbound /etc/ssh/ssh_config stays legacy-permissive for old devices (3DES, CBC, MD5, DH group1) and is overwritten on every upgrade, flag or not.
  6. Back up /backbox/conf/ (DB properties, keystore, flags, application.yml) and /backbox/custom_db_properties/.

4.1 Firewall Facts

  • firewalld, nftables, default zone backbox (REJECT, loopback accepted, rate-limited ICMP echo, LogDenied=all); /etc/firewalld/zones/{backbox,docker}.xml (docker0 ACCEPT). No /etc/sysconfig/iptables, no ipsets. Device rules are individual rich rules (not reconciled).
    NOTE: Kilter will update this to DROP in 9.1.0 and newer.
  • FirewalldManager/FirewalldProcessFallback manage rules. Jailed users get nft chains in inet bb_jail. hotfix_rl9.sh migrates old iptables appliances and masks iptables, ip6tables, iptables-nft.
  • Checks: firewall-cmd --zone=backbox --list-all, nft list ruleset. Recovery: emergency_firewall_access.sh, firewalld_recovery.sh, resetFirewall.sh.

4.2 Built-in Application Controls

  • Web: TLS 1.2/1.3 AEAD only, HSTS, X-Frame-Options: deny, secure cookies (/backbox/conf/application.yml); 30 minute idle timeout, 1 session per user.
  • Lockout/password length: Authentication → User settings → Login Settings; backbox.security.properties (10 attempts, 15 min; installed once, not refreshed on upgrade).
  • Identity: Google Authenticator 2FA, SSO via SAML/OIDC, LDAP, RADIUS, TACACS+, API tokens, Web Banner (all under Authentication).
  • Audit: Administration → Alerts → Syslog; Administration → CLI Audit (/data/cli_histories/).
  • CLI RBAC: the webUI hides the CLI button by role name, but the server authorizes the tunnel with access.terminal.run (same as device terminals). Grant Access → Terminal → Run to administrators only(Authentication → User settings → Roles).
  • FIPS: enable-fips.sh (5.13).

5. OS Hardening & Non-Root User Management

5.1 Non-Root Administration

The app must run as root, but day-to-day admin should use named, unprivileged accounts. BackBox ships none of those below. It deletes RAND* and UNIX_USERS users, and upgrades delete any passwd line containing RAND (see 2): avoid that string. bbadmin is also the GRUB superuser name (a boot-loader identity only).

User

Groups

Purpose

Sudo

bbadmin

wheel

Full admin

Full (default %wheel)

bboperator

backbox-ops, systemd-journal

Monitor, logs, restart services

Fixed commands only

bbauditor

backbox-audit, systemd-journal

Read-only review

None

# Pattern per user (bboperator shown); key auth
groupadd -f backbox-ops
useradd -m -G backbox-ops,systemd-journal -c "BackBox Operator" bboperator
passwd bboperator
install -d -m 700 -o bboperator -g bboperator /home/bboperator/.ssh
echo "ssh-ed25519 AAAA... operator@company.com" > /home/bboperator/.ssh/authorized_keys
chmod 600 /home/bboperator/.ssh/authorized_keys && chown bboperator:bboperator /home/bboperator/.ssh/authorized_keys

Reading status and logs does not require sudo: systemctl status --no-pager <unit> works for anyone, systemd-journal members read the journal (containers log there), and log files via ACLs (use g:backbox-audit for auditors):

setfacl -R -m g:backbox-ops:rX /var/log/backbox/ /backbox/app-server/logs/
setfacl -R -d -m g:backbox-ops:rX /var/log/backbox/ /backbox/app-server/logs/

Operator sudo, fixed arguments only:

cat > /etc/sudoers.d/backbox-ops << 'EOF'
Cmnd_Alias BB_SERVICES = /usr/bin/systemctl restart backbox, \
/usr/bin/systemctl stop backbox, \
/usr/bin/systemctl start backbox, \
/usr/bin/systemctl restart mariadb, \
/usr/bin/systemctl restart guacamole
Cmnd_Alias BB_FIREWALL_RO = /usr/bin/firewall-cmd --zone=backbox --list-all
%backbox-ops ALL=(root) NOPASSWD: BB_SERVICES, BB_FIREWALL_RO
EOF
chmod 440 /etc/sudoers.d/backbox-ops && visudo -cf /etc/sudoers.d/backbox-ops

NOTES:

  • Do not allow less/cat/tail/journalctl/docker logs in sudoers: sudoers * matches /, spaces and .. (cat /var/log/backbox/x /etc/shadow), and pagers give a root shell (!sh). Never add operators to the dockergroup.
  • Migration checklist: create users; apply 1.1; test CLI, Debug Mode, cluster/agent sync, a device backup, an SFTP/SCP user and a webUI upgrade (test sshd changes from a second terminal; recovery is the VM console).
  • Root-only: manual hotfix.sh, sshd_config, fapolicyd trust, Docker beyond logs, NFS mounts, GRUB/kernel. Root password goes through the webUI; firewall through Access Rules.
  • Compliance (IDs carried from v8; re-check per benchmark): named accounts, restricted su (5.10), SSH root login disabled with documented CLI/Debug/cluster exceptions, SOC 2 CC6.1/6.2, PCI DSS 8.6.1 (change or lock bbsupport).

5.2 Paths Non-Root Users Must NOT Modify

Read-only at most: /backbox/ (conf/, custom_db_properties/, app-server/), /data/ (jail/, External_Backup/os_users/), /root/.ssh/, /etc/ssh/sshd_config, /etc/fapolicyd/, /etc/firewalld/(managed; reconciliation overwrites changes).

5.3 OS Package Management

Packages come only from BackBox upgrades, installed offline (--disablerepo='*' --cacheonly). Do not run dnf update/install from external repos: java-21-openjdk, docker-ce, python3, nftables, firewalld etc. are protected. Never install iptables-services. Extra packages (e.g. aide) come from the bundle only (appliances may be air-gapped).

5.4 Sysctl

Kilter writes /etc/sysctl.d/70-backbox.conf each upgrade (already sets all.send_redirects=0, default.accept_redirects=0, secure_redirects, kernel.sysrq=0, buffers). Put yours in /etc/sysctl.d/99-customer.conf (documented override). Not set by default: net.ipv4.conf.{all,default}.rp_filter=2; accept_redirects=0 (IPv4 all, IPv6 all/default); send_redirects=0 (default); tcp_syncookies=1; log_martians=1; accept_source_route=0 (IPv4/IPv6, all/default); kernel.kptr_restrict=2; kernel.dmesg_restrict=1; net.core.bpf_jit_harden=2; fs.suid_dumpable=0. Apply with sysctl --system.

NOTE: Never set net.ipv4.ip_forward=0 (Docker, Guacamole/CLI, NATS need it). Use loose rp_filter=2: strict (1) breaks multi-NIC/asymmetric routing (v8 had this inverted). [verify] with Tailscale/Headscale agents.

5.5 File Integrity Monitoring

aide is in the bundle but never initialized or scheduled. Check rpm -q aide (if missing, install from the bundle only), then aide --init && mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz and a daily script:

# /etc/cron.daily/aide-check (chmod 700)
#!/bin/bash
/usr/sbin/aide --check > /var/log/aide-check.log 2>&1 || logger -p authpriv.warning -t aide "AIDE changes on $(hostname)"

Exclude in /etc/aide.conf: !/data, !/var/lib/docker, !/var/lib/mysql, !/var/log, !/backbox/app-server/logs. Trust the script if fapolicyd is on. Re-baseline after every upgrade (aide --update).

5.6 Services

Kickstart already removes bluez and Wi-Fi; no cups/avahi daemons exist. Review rpcbind (:111; disable if NFSv3 unused). snmpd, vsftpd, tftp-server are re-enabled by every upgrade (hotfix_rl9.sh:2904); if unused, restrict them with Access Rules.

NOTE: Do not disable: docker, mariadb, backbox, guacamole, nats, sshd, chronyd, firewalld, auditd, rsyslog, crond, atd, logrotate.timer, tailscaled/headscale if used, fapolicyd if enabled. iptables/ip6tables are intentionally masked.

5.7 Cron and At

All Kilter cron jobs run as root. No cron.allow/at.allow is configured. Use echo root > /etc/cron.allow (add your admin) and echo root > /etc/at.allow.

NOTE: Keep root in at.allow and atd running: webUI upgrades use at.

5.8 Banner

issue.sh writes /etc/issue and preserves customer edits. /etc/issue.net is unmanaged and sshd has Banner none. Create /etc/issue.net, change the existing line to Banner /etc/issue.net (do not add a second), and prepend to /etc/issue to keep the version display. The web banner is separate (Authentication → Web Banner).

5.9 TMOUT

# /etc/profile.d/backbox-timeout.sh
readonly TMOUT=900
export TMOUT

NOTE: It skips services, at and cron, but the CLI and Debug Mode are interactive root SSH sessions and will close when idle. Choose a suitable value or apply to named admins only.

5.10 Restrict su

Add auth required pam_wheel.so use_uid to /etc/pam.d/su. Not set by Kilter, no Kilter code uses su, so it is safe. It doesn't affect Debug Mode's SSH root shell.

5.11 Core Dumps

Not restricted by default. Add * hard core 0 and root hard core 0 in /etc/security/limits.d/99-backbox-nocore.conf, and Storage=none, ProcessSizeMax=0 under [Coredump] in /etc/systemd/coredump.conf. JVM heap dumps (/data/tmp/java/, 3-day age-out) are unaffected.

5.12 Mounts

Fresh installs of 9.0.1 and newer apply STIG options via the kickstart: / nodev; /boot nodev; /var nodev,noatime; /var/log, /var/log/audit, /var/tmp nodev,nosuid,noexec; /tmp (10 GB LV) nodev,nosuid,noexec,noatime; /home nodev,nosuid; /data nosuid,noatime. Upgrades (harden_fstab_mount_options) only add options to existing /, /boot, /var, /tmp, /data mounts; missing partitions only WARN. Verify with findmnt. Remaining: tmpfs /dev/shm tmpfs defaults,noexec,nosuid,nodev 0 0.

NOTE: Do not replace /tmp with tmpfs. Do not noexec /data or /backbox. Upgrades run from /data/tmp and still clear /tmp.

5.13 Crypto Policy

Default DEFAULT:SHA1 (legacy devices; also in the jail). Do not set FUTUR or change the policy by hand. FIPS is opt-invia /backbox/scripts/enable-fips.sh (restricts TLS ciphers, migrates keystore JKS to PKCS12, fips-mode-setup --enable, reboot required; disable-fips.sh reverses). The JVM then sets -Dorg.apache.sshd.security.fipsEnabled=true. No STIG subpolicy on this release. Inbound sshd_config and outbound ssh_config are separate; sshd_updates.sh removes CBC/curve25519 inbound only.

5.14 SELinux

Permissive by default (kickstart; configure-selinux.sh --enable at install). Upgrades raise disabled to permissive (relabel on next boot) and run setenforce 0 during the upgrade; an appliance already in enforcing stays enforcing. No enforcing support on this release (no enable-selinux.sh, policy module or verify service). Do not set SELINUX=disabled (reverted); do not enable enforcing without full testing. BackBox doesn't strip selinux=0 kernel arguments [verify].

5.15 GRUB Password

The kickstart and every upgrade (hotfix_rl9.sh 2918-2919, configure_grub_superuser 1058) set a GRUB password (superuser bbadmin, RHEL-09-212050) using a hash shared by all appliances, to help with support troubleshooting. Verify: cat /boot/grub2/user.cfg.

NOTE: A grub2-setpassword change is overwritten by the next upgrade. Re-apply after upgrades and rely on console control (section 6, Console).

5.16 Extended auditd Rules

Beyond 1.4, add -w ... -p wa watches (in /etc/audit/rules.d/backbox-hardening.rules, then augenrules --load) on /etc/pam.d/, /etc/security/, /etc/ssh/sshd_config, /backbox/conf/, /etc/fapolicyd/, /etc/shadow, /etc/sudoers, /etc/sudoers.d/, and -a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k kernel_modules.

NOTE: JailCreator runs useradd/userdel per jailed session, so /etc/passwd, /etc/group, /etc/shadow watches are very noisy. If STIG requires them, raise num_logs or forward off-box. Do not add -e 2: configure-selinux.shand configure-fapolicyd.sh call augenrules/auditctl and would fail until reboot.

6. VM-Specific Hardening

Kilter ships as an ISO, OVA, VHD, and AWS/Azure/GCP images (BIOS only). Physical deployments are not supported.

  • Guest tools: open-vm-tools and qemu-guest-agent are in the bundle and auto-enabled
  • Snapshots: short-term only; snapshot before upgrades, delete after. They hold passwords, os user credentials, SSH keys and keystore: after a revert re-sync via the webUI; revert cluster nodes consistently.
  • Virtual Hardware: remove floppy, CD/DVD, serial, parallel, USB; on VMware set isolation.tools.copy.disable, .dnd.disable, .diskShrink.disable. Kilter blocklists no kernel modules; optionally install <mod> /bin/false in /etc/modprobe.d/ for usb-storage, cramfs, firewire-core, bluetooth, atm, can, tipc.
  • Console: bypasses SSH but requires the root password. Limit hypervisor console access and enable console logging; the shared GRUB password (5.15) makes this more important.
  • Encryption/Secure Boot: VM encryption and vTPM are compatible (TPM unused). UEFI nor Secure Boot are supported at this time . LUKS is not recommended (boot passphrase blocks automated restarts). Datastore encryption is recommended.
  • Network: dedicated management VLAN; hypervisor firewall in addition to firewalld; no promiscuous mode; disable MAC changes/forged transmits; filter 7422 and 8080 upstream.
  • Resources (guidance; no installer checks): 4+ vCPU, 8+ GB RAM, thick-provisioned /data.
    • Reserve all memory when possible: JVM heap is 50% of RAM (reset each boot by rc.local with a 2 GB floor; app-server.sh's 4 GB is only a default), InnoDB buffer pool 25% (min 1 GB), plus up to 1 GB metaspace and 512 MB code cache. The kickstart uses about 62 GB for OS volumes before /data (/ 20G, /var 20G, /var/log 4G, audit 2G, /var/tmp 1G, /home 1G, /tmp 10G, swap 4G).