Drive the allowlist from your own tooling
Overview: Root Lock by HeartSuite is designed to be driven by your existing central tooling. The Dashboard is the surface for a single host. At fleet scale, your control planes curate policy, apply it to each host, and collect what each host reports back.
Cloud Path and Local Path remain how each host is installed. This page covers the fleet work around that install: harvesting an allowlist baseline from one host, installing that seeded package on many hosts, and applying extras without a Dashboard session on every machine.
Each host enforces its own allowlist, and Lockdown seals that allowlist on the host. HeartSuite has no central server that pushes policy to many hosts — your automation applies it per host, and each host exports status, alerts, and an approval log for central visibility and attribution.
Keep policy curation, change approval, and fleet-wide visibility inside the tools you already run (Ansible, Terraform, GitOps repositories, ServiceNow, Splunk, Elastic, custom orchestration).
Policy curation in your central systems
A repository you already run — usually Git, applied by Ansible, Terraform, or similar — holds the list of approved programs, file-access paths, and network destinations. Your CMDB keeps describing hosts and apps, and your ITSM tickets keep approving changes; the repository is where the grants themselves live.
- Keep policy as text lists (one absolute program path per line) or structured data your automation can parse.
- Put changes through your normal processes: code review in Git, change tickets in ServiceNow, or a policy-as-code pipeline.
Two ways to seed the allowlist
Root Lock accepts seed policy at two points. An install-time baseline gives a new host the full allowlist of a host that already ran the same workload, so initial setup finishes quickly instead of running a multi-hour observation period on every node. A post-install program list adds programs to a host that is already running Root Lock.
| Install-time baseline pre-seed | Post-install program list | |
|---|---|---|
| Purpose | Start initial setup from a known baseline harvested from a reference host | Add program approvals after Root Lock is up |
| When | Before or during install — the package or image carries the baseline | After Root Lock is installed and initial setup is complete |
| Shape | Installer baseline material, enabled with installer options such as --apo-seed | Plain text: one absolute program path per line (# comments allowed) |
| Apply with | The seeded installer or image; Ansible runs that installer | hs_seeds / hs_programs (Ansible role), batch_record_add.py, /.hs/sys/hs-app-perm-orders-manager |
A program list carries program paths; the installer baseline also carries each program’s grants and is what shortens initial setup. Re-applying a harvested baseline as a text list after initial setup therefore gains nothing. Program lists earn their place for role-scoped bootstrap lists (for example SSH and application entry points), for stack extras you approve after reviewing the queues, and for hosts that never ran those paths during setup.
Seed a fleet from one reference host
- Reference host. Run initial setup on one host of this class under its real, full workload, then review what remains in the queues. If this host was installed without a baseline, this is the one time the fleet pays the multi-hour observation period.
- Harvest the installer baseline from that host with the harvest and packaging tooling. Ansible can orchestrate the collection over SSH. The result is installer baseline material — programs and their grants — for step 4, not an
hs_seedslist. - Review the baseline and promote it into your package pipeline.
- Build or obtain a Root Lock install package with baseline pre-seed enabled (for example installer option
--apo-seed). Packages can ship with pre-seed off; enable it here. - Start each fleet node from a clean OS.
- Install Root Lock with Ansible, pointing the playbook’s install bundle at the pre-seeded installer. Initial setup starts from the baseline and finishes quickly.
- Deploy application and hardening automation, then review only the differences in the Dashboard.
- Optional: harvest extras with
get_allowlist_programs()from thelimited_toolsPython API, which prints one program path per line, and review the paths. Apply them withhs_seeds, which approves each program path, or withbatch_record_add.py, which approves those paths and also grants read on/usr/liband/etc. - Activate Lockdown once the subscription, alert, and queue checks pass.
The first reference host of a class has no baseline to start from: install it on a clean OS without pre-seed, let initial setup run under the real workload, review the queues, and harvest from step 2. Every later host follows the order above.
Seed only what the reference host’s real workload ran, and leave out paths from test runs or one-off commands. An item in the pending queue becomes a grant only when you approve it.
Applying policy from automation
Use the CLI tools shipped with every installation (documented in the Appendices and Batch Allowlisting Tools) to apply post-install policy from your control plane:
/.hs/sys/hs-app-perm-orders-manager— inspect current state, add or remove specific entries for programs, file paths, and network destinations./.hs/sysis not onPATH, so call it by its full path.batch_record_add.py— bulk-seed programs from a plain-text list of paths (adds each with standard library and configuration directories).
Run these tools over SSH, via config-management agents, or as part of provisioning scripts after Root Lock is installed and initial setup is complete. Your central system prepares the seed data or change set; the automation layer delivers and applies it to each target host.
Subscription activation (hs-activate-subscription) is still required on each host before Lockdown can be engaged — this is the entitlement step and remains local.
Examples for the primary integration patterns follow.
1. Ansible — playbooks for seeding and applying policy
HeartSuite provides an official declarative Ansible role (heartsecurity.root_lock) for fleet policy application and Lockdown transitions. It is modelled on linux-system-roles.selinux and ships with coordinated release materials; email support@heartsecsuite.com if you need the role package.
On every installed host, the limited_tools Python API under /opt/heartsuite is the runtime integration surface the role uses. A shell-and-CLI alternative using batch_record_add.py and hs-app-perm-orders-manager follows below for ad-hoc or legacy playbooks.
Official Ansible role: heartsecurity.root_lock
Overview: The role provides variable-driven management of allowlist programs and mode transitions. Re-running a play does not create duplicate entries. It is modelled on linux-system-roles.selinux (and rhel-system-roles.selinux) so administrators familiar with RHEL declarative SELinux policy can apply the same playbook patterns.
The role assumes Root Lock is already installed. It focuses on allowlist management plus mode transitions (Setup Mode / Lockdown). Full server provisioning — base OS preparation, hardening (for example the dev-sec collection), SFTP receiver setup, bundle-based installation, and post-install configuration — belongs in thin orchestrator playbooks that compose heartsecurity.root_lock with upstream collections and host-specific tasks.
A reference provisioning example for a Debian 12 server is in the code repository under ansible/examples/hs-debian12-provision/. The pattern: install Root Lock and let initial setup run, start with a minimal role-scoped bootstrap allowlist from a seed file, and run the real workload. After you review the queues, keep the extra programs Setup Mode logged in a seed file and re-apply it with the role on the hosts that need those paths.
Requirements:
- Root Lock already installed on managed hosts.
- Initial setup finished before you apply workload
hs_seedsor stack playbooks that expect a reviewed baseline. become: true— all operations are privileged.- Ansible >= 2.9.
- The role invokes the production Python API in
/opt/heartsuite(limited_toolsvia/opt/heartsuite/venv/bin/python3and/opt/heartsuite/src).
Key variables (all prefixed hs_ to avoid collision with SELinux role variables):
| Variable | Purpose |
|---|---|
hs_state | Mode transition: secure or lockdown (synonyms). setup is informational only (no-op). Unset leaves mode unchanged. Calls switch_to_secure() with the same precondition gates as the Dashboard. Leave it unset until the subscription, alert, and queue checks pass. |
hs_programs | List of absolute program paths to approve (uses apply_allowlist_seed() internally). |
hs_seeds | List of seed file paths, or literal inline paths when the entry is not an existing file. Seed files are plain text, one program path per line; # comments and blank lines are ignored. Combine freely with hs_programs. |
Additional variables include hs_gather_status (default true, exposes hs_status fact), hs_purge / hs_purge_allowlist (emit a warning only — the scriptable surface adds entries by design), and hs_python / hs_src_path overrides for non-standard install layouts.
Re-run behaviour: All allowlist operations return CommandResult with kind == "noop" when an entry is already present. The role uses this for correct changed_when reporting, so repeated plays do not show spurious changes.
Minimal example playbook:
# heartsuite-root-lock.yml
- name: Configure HeartSuite allowlist and engage Lockdown
hosts: heartsuite_fleet
become: true
vars:
hs_state: secure
hs_programs:
- /usr/sbin/sshd
- /usr/bin/python3
hs_seeds:
- /var/lib/ansible/heartsuite/seed.txt
roles:
- heartsecurity.root_lock
After switching to secure or lockdown, a reboot is typically required for full seal; the role does not reboot automatically. Register facts (hs_status, hs_apply_result, hs_switch_result) are available for assertions or subsequent tasks.
Python API alternative: For custom Ansible modules or non-Ansible automation, the same functions are exposed via limited_tools: approve_program_path, apply_allowlist_seed, get_status, get_allowlist_programs, and switch_to_secure. These reuse the same gates and CommandResult semantics.
The heartsecurity.root_lock role is the preferred declarative path for post-install allowlist and mode work. Use the Python API (or thin custom tasks) when composing larger provisioning playbooks that also handle OS setup, hardening, or host-specific services.
See the reference provisioning starter in the code repository (ansible/examples/hs-debian12-provision/) for composition: it delegates SSH/SFTP hardening to the dev-sec collection, performs bundle-based installation, registers backup directories and alert configuration, starts with a minimal allowlist bootstrap, and shows how to harvest from real workload observation into a seed file before using the role for allowlist and mode.
Use these playbooks to carry out the change records your central system approves.
Shell + register alternative
Use Ansible to distribute seed files and invoke the batch or management tools with become: true:
# heartsuite-policy-apply.yml
- hosts: heartsuite_fleet
become: true
tasks:
- name: Copy central program seed list
copy:
src: "policy/seeds/programs-{{ inventory_hostname }}.txt"
dest: "/tmp/heartsuite-programs.txt"
owner: root
mode: '0600'
- name: Apply baseline programs via batch tool
shell: "/.hs/sys/batch_record_add.py /tmp/heartsuite-programs.txt"
args:
creates: "/.hs/sys/allowlist_applied_{{ inventory_hostname }}.stamp"
- name: Apply targeted network and file deltas from central policy
shell: |
/.hs/sys/hs-app-perm-orders-manager add -x /usr/bin/curl -n 93.184.216.34
/.hs/sys/hs-app-perm-orders-manager add -x /usr/bin/curl -d /etc/ssl/certs
# Idempotency and error handling left to your playbook
- name: Harvest the applied program list on the host
shell: >
/opt/heartsuite/venv/bin/python3 -c "import sys; sys.path.insert(0, '/opt/heartsuite/src');
from core.limited_tools import get_allowlist_programs;
print('\\n'.join(sorted(get_allowlist_programs() or [])))"
register: hs_allowlist
changed_when: false
- name: Record application in central audit
copy:
content: "{{ hs_allowlist.stdout }}\n"
dest: "policy/harvest/allowlist-{{ inventory_hostname }}.txt"
delegate_to: localhost
become: false
# Then commit the harvest back to your policy repo
Without the role there is no CommandResult.kind == "noop" to drive changed_when, so add your own re-run checks (for example creates, or register + conditional tasks).
2. Splunk / Elastic (and similar SIEMs) — ingesting for central dashboards and policy triggers
The primary use of Splunk and Elastic is consumption of the structured data streams (see SIEM and Fleet Integration). Once events are in the SIEM:
- Build dashboards showing per-node mode, pending counts (from status.json), block rates, and approval activity (from the JSONL approval log forwarded via syslog or other shipper).
- Build views of the current allowlist and associated risks from the structured policy snapshots and posture data, including tables of programs with grant counts,
risk_level, and broad-write and network flags. Compare the allowlist you keep in Git for drift. Policy identity is not onstatus.json, syslog, webhook, or Kibana. - Use SOAR playbooks or alert actions in the SIEM to trigger Ansible Tower / AWX jobs or Terraform runs that apply approved policy updates back to affected hosts.
- Correlate HeartSuite enforcement events with change tickets to close the audit loop.
Syslog is the recommended high-volume path for both the per-decision enforcement stream and higher-level alerts. For richer views of the allowlist and posture (tables, metrics, and correlation) see SIEM and Fleet Integration.
3. Terraform + GitOps — policy in repository, applied at provision and drift remediation
Store allowlist seeds and change manifests in the same Git repository as your infrastructure code.
- Use Terraform
local_fileortemplatefileto render per-host or per-role seed files from a central policy definition. - During
terraform apply, aremote-execprovisioner,local-execthat calls Ansible, or a custom provider runs the seed application andhs-app-perm-orders-managerinvocations on the new or updated instance. - Drift detection: scheduled jobs (or Terraform Cloud/Enterprise runs) harvest the program list with
get_allowlist_programs()from thelimited_toolsPython API, compare it with the allowlist you keep in Git, and open PRs or apply corrections.status.jsonis the health snapshot, not the policy identity. - Git history becomes the authoritative change record for policy; the on-host JSONL approval log provides the per-host attribution of when and by which uid/tty the change was executed.
This pattern works especially well for immutable or frequently reprovisioned fleets.
4. ServiceNow or ITSM platforms — change-driven policy
- Model allowlist additions, removals, or baseline updates as standard or emergency change requests.
- Approved changes update the Git (or equivalent) policy repository, then automation applies them per host.
- The automation (Ansible, scripts, or ServiceNow Flow Designer + MID server) applies the delta to the target hosts using the CLI tools above.
- On completion, the automation closes the change ticket and posts the resulting JSONL approval log excerpts (or a pointer to the SIEM record) as evidence.
This keeps policy changes inside the same approval workflow used for all other infrastructure changes.
5. Custom scripts and other configuration management (Puppet, Chef, Salt, etc.)
Any tool that can copy files and run commands as root on the target can drive policy:
- Puppet: a custom resource or exec that writes a seed list managed by Hiera or PuppetDB and then invokes
batch_record_add.pyorhs-app-perm-orders-manager. - Chef: a recipe that templates policy from a data bag and executes the CLI tools.
- Pure scripts (Python, Bash, or your language of choice) run from a central runner or cron on a bastion: query the authoritative policy store, compute the diff for each host (or use a node-specific tag), SSH in, and apply.
The dedicated JSONL approval log (with uid/tty attribution for each change) and the enforcement/alert syslog streams give you the same audit trail regardless of which tool performed the apply.
Consuming data for central visibility, auditing, and harvesting
Status JSON and the JSONL approval log are written whenever the alert daemon is running. Syslog is off until you enable it on Alert Settings → Fleet. Webhook requires an HTTPS URL on that same tab.
Status JSON (
~/.cache/heartsuite/status.json, updated every 60 seconds) — lightweight pull surface for health and pending counts. Use from Ansible facts, Nagios/Zabbix checks over SSH, or any scheduled collector. Key fields for fleet dashboards:mode,lockdown,is_hs_kernel,daemon_ok,pending_*counts,node_id. See the schema in the Appendices.Dedicated JSONL approval log (
/var/log/heartsuite/allowlist-audit.log) — persistent, append-only record of every allowlist approval (not skips or removals) with timestamp, uid, and tty. This is the primary artifact for change attribution. Forward that file with your existing log shipper. It is not copied into syslog.Structured syslog streams — when Fleet Syslog is on, denial lines (
HS-PROG-DENY,HS-FILE-DENY, and similar) and aggregated alerts (new_program_blocked, mode changes) share identheartsuite. Alert lines use the message prefixheartsuite-alert:. A single rsyslog rule forwards both. Full configuration examples and Filebeat patterns are in the SIEM and Fleet Integration page.Webhook — HTTPS POST of compact JSON alert payloads on every significant event. Configure the endpoint in Alert Settings; use for immediate routing into ServiceNow, PagerDuty, or your own policy-evaluation service.
Harvest current allowlist state — run
get_allowlist_programs()from thelimited_toolsPython API, or/.hs/sys/hs-app-perm-orders-manager view -afor each program’s grants, on a schedule or on demand and commit the output to your central policy repository. This closes the loop: central sees what is actually enforced on each host and can detect drift or feed the next baseline.
See Alert Settings for configuration of syslog and webhook (Fleet tab) and SIEM and Fleet Integration for production-scale ingestion patterns.
Relationship to the Dashboard and Lockdown
The Dashboard remains the right surface for one-off investigation, initial setup on a new host, and guided maintenance windows. At fleet scale, routine policy application and observation move to your central tooling.
While Lockdown is on, alerts for programs waiting in the pending queues go to every configured channel.
Central automation drives allowlist policy and first install. It does not lift Lockdown.
- Similar hosts, first install: harvest once, package with install-time pre-seed, Ansible installs that package — the order above.
- Already in Lockdown: the official role does not unseal.
hs_state: setupleaves mode unchanged. Package installs and Root Lock bundle updates wait for Setup Mode — Protecting During Maintenance and Updating Root Lock. - Many locked hosts: reprovision from an updated image rather than a console session per node — Enterprise Adoption Guide.
Next steps and related documentation
- Configure the base alert channels on a pilot host: Alert Settings
- Review the CLI tools available for automation: Batch Allowlisting Tools and Appendices.
- Set up log ingestion: SIEM and Fleet Integration.
- Understand maintenance windows, unseal, and fleet image reprovision: Maintenance.
- Compliance context for auditors: SOC 2 Control Mapping and Compliance Reference: NIST CSF & ISO 27001.
For support with large-scale or custom automation patterns, contact support@heartsecsuite.com.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.