If you're repeating flags (include/exclude patterns, SOPS settings, etc.), store defaults in enroll.ini and keep your muscle memory intact.
If you're repeating flags (include/exclude patterns, SOPS settings, etc.), store defaults in ~/config/enroll/enroll.ini and keep your muscle memory intact.
-c/--config, set ENROLL_CONFIG, or let Enroll auto-discover ./enroll.ini, ./.enroll.ini, or ~/.config/enroll/enroll.ini.-c/--config, set ENROLL_CONFIG, let Enroll auto-discover either your XDG config default directory, or finally ~/.config/enroll/enroll.ini..bashrc and similar files are now only harvested from user directories when --dangerous is used, since this is a common place for sensitive environment variables to be set. As always, remember that --dangerous gives better harvest coverage, but you should use --sops or some other means of your own to encrypt the harvested data at rest safely!no_log to avoid potentially sensitive output, particularly of systemd unit state.iptables and ipset rules!.enroll.ini or enroll.ini in the current working directory. Instead, it's recommended to put your config file in ~/.config/enroll/enroll.ini, or pass an explicit path with --config or through use of the ENROLL_CONFIG environment variable.enroll validate makes sure the harvest doesn't contain unsafe things such as symlinks traversing out of the artifacts tree.enroll manifest takes an internal pass via validate to make sure the harvest validates ok before trying to render config management code. If you find that your harvest is not passing validation, and don't believe it's been tampered with, it may be that it was created on an older version of Enroll and so doesn't pass the current schema. Consider re-harvesting the host.--fqdn is safe$PATH contains the cwd or a world-writable location (to resist attacks via malicious versions of binaries Enroll calls such as dpkg, rpm, systemctl etc)With these changes comes a lot of new 'variance' and argument input to the app. Pytest coverage is now at about 86%, and there is a big suite unit tests for Ansible, Puppet and Salt too, in CI. I'm continuing to try and automate testing all the ways you can use this tool.
+With these changes comes a lot of new 'variance' and argument input to the app. Pytest coverage is now at about 86%, and there is a big suite unit tests for Ansible, Puppet and Salt too, in CI, running across both Debian and AlmaLinux environments. I'm continuing to try and automate testing all the ways you can use this tool.
Thanks to everyone who has reached out with suggestions, constructive criticism, and bug reports!
diff --git a/src/content/security.html b/src/content/security.html index 2218f29..a56743a 100644 --- a/src/content/security.html +++ b/src/content/security.html @@ -48,6 +48,43 @@ description: "Security posture and safe workflows for Enroll outputs."--sops mode, you'll need to decrypt and extract the bundle before running ansible-playbook, puppet apply, or salt-call.Enroll is often run as root because it needs to inspect system state. Version 0.5.5 added stricter filesystem checks so root does not accidentally write harvests or generated output through an unsafe path.
+ +Harvest and manifest outputs are created with restrictive permissions, and Enroll refuses to reuse an existing harvest directory unless that mode is explicitly expected for an internal workflow.
+When running as root, Enroll checks path components and parent directories so output is not created below a parent controlled by another user. This reduces the risk of symlink and time-of-check/time-of-use path races.
+Captured files and generated artifacts are validated as regular files, with traversal, symlink, hardlink, and special-file cases rejected when bundles are validated or extracted.
+PATH hygieneFor root runs, Enroll warns about unsafe PATH entries so helper commands are not resolved from relative, writable, or non-root-owned directories.
/var/tmp/enroll, /root, or a fresh directory directly under the normal sticky /tmp.Enroll is a command-line systems administration tool. It is designed to be run intentionally by an administrator, often as root, to inspect a host, harvest selected system state, and optionally generate or apply configuration-management output.
+That makes Enroll different from a web application, daemon, network service, or setuid helper. It is not intended to be a sandbox for hostile local users. Instead, it assumes an operator-controlled execution environment, while still adding defense-in-depth checks for common filesystem, path traversal, secret-handling, and command-resolution mistakes.
+ +enroll.ini file is loaded, its location and contents are assumed to be owned, selected, and understood by the operator.--dangerous, --assume-safe-path, --sops, --enforce, --remote-host, and --remote-ssh-config.manifest, diff, or diff --enforce are assumed to come from a trusted source unless the operator is deliberately inspecting them without applying them.Enroll invokes ordinary administrative tools such as SSH, sudo, SOPS, package managers, Docker, Podman, Flatpak, Snap, Ansible, Puppet, Salt, and system utilities. These are assumed to be the trusted tools the operator intended to execute.
If an attacker can replace or redirect those tools, the host already has a local trust-boundary problem outside Enroll's ability to fully solve.
+Enroll still performs substantial hardening because privileged CLI tools can otherwise be easy to misuse. These controls are intended to protect careful administrators from common dangerous mistakes.
PATH entries during root runsThe following are normally considered local compromise, operator-controlled behavior, or trust-boundary failures rather than Enroll vulnerabilities by themselves:
+PATH, or invoked binariesenroll.ini file whose contents intentionally request dangerous behavior--dangerous and observing that Enroll may collect sensitive data--assume-safe-path and observing that Enroll does not prompt about PATH safetydiff --enforceHarvest bundles should be treated as sensitive administrative artifacts. A harvest may contain hostnames, usernames, package lists, service state, filesystem metadata, configuration files, firewall snapshots, container image references, Flatpak/Snap state, and other operational details. In --dangerous mode it may contain substantially more sensitive material.
Enroll validates harvest structure and artifact safety, but validation does not prove that the desired state represented by a harvest is safe to apply. Only run manifest, diff, or especially diff --enforce against bundles that came from hosts and people you trust.
--dangerous--dangerous and collect dangerous data--assume-safe-path and bypass the root PATH warningmig5.55)When Enroll is run as root, it deliberately refuses to create a harvest below a parent directory that is controlled by a non-root user. This is a safety check: a user-owned parent directory can be renamed or replaced while a root process is writing files, which can become a symlink or path-race problem.
+ +error: harvest output parent is not owned by root; refusing root-run output: /home/alice
+error: harvest output parent is not owned by root; refusing root-run output: /tmp/tmp.abcd1234
+ Harvest output can contain detailed system state and, when --dangerous is used, may contain sensitive configuration material. If Enroll is running as root, it needs the output path to stay exactly where it was checked. Refusing user-owned parent directories helps avoid accidental writes through symlinks or paths that can be swapped underneath the process.
Create a dedicated root-owned directory and place harvests underneath it:
+$ sudo install -d -m 700 -o root -g root /var/tmp/enroll
+$ sudo enroll harvest --out /var/tmp/enroll/host1/tmp itself is okayA fresh output directory directly under the normal root-owned sticky /tmp directory is accepted. The output path must not already exist.
$ sudo enroll harvest --out /tmp/host1-harvestsudo enroll harvest --out ~/harvest may expand to a path below a user-owned home directory. Use /var/tmp/enroll, /root, or a fresh directory directly under /tmp instead.In normal remote mode, Enroll uses sudo on the remote host so it can collect system-level state. Recent Enroll versions create a separate root-owned temporary directory for the remote bundle. If an older version reports this error for a path like /tmp/tmp.xxxxx during remote harvest, upgrade Enroll. Use --no-sudo only when you intentionally want a limited, non-root harvest.
If a manifest task points at a missing source file, validate the original harvest first. Validation checks state.json, referenced artifacts, generated firewall/sysctl files, and unreferenced artifact warnings.
For non-Ansible targets, make sure puppet or salt-call is installed and on PATH before running enforcement.
You see an error like error: harvest state does not match this Enroll version's schema; please re-harvest the host with this version of Enroll.
The harvest has either been tampered with, become corrupt, or was made with an earlier version of Enroll, which means its layout is a different structure than what Enroll now expects.
+The best thing to do is run the harvest again. Enroll will validate the harvest against the latest schema when you go to manifest it.
+If you still experience the error, please report it as a bug!
+