HackerTrans
TopNewTrendsCommentsPastAskShowJobs

_mig5

82 karmajoined 6 ay önce
A freelance sysadmin consultant. I work on OnionShare and a few other open source tools.

[email protected] https://mig5.net

Submissions

[untitled]

1 points·by _mig5·5 gün önce·0 comments

[untitled]

1 points·by _mig5·5 gün önce·0 comments

[untitled]

1 points·by _mig5·6 gün önce·0 comments

[untitled]

1 points·by _mig5·6 ay önce·0 comments

[untitled]

1 points·by _mig5·6 ay önce·0 comments

Show HN: cspresso - CLI tool to scan a website & generate/evaluate a CSP header

cspresso.cafe
3 points·by _mig5·6 ay önce·0 comments

Show HN: Bouquin, an encrypted planner app written in PySide6 and SQLCipher

git.mig5.net
2 points·by _mig5·6 ay önce·0 comments

[untitled]

1 points·by _mig5·6 ay önce·0 comments

Show HN: Enroll, a tool to reverse-engineer servers into Ansible config mgmt

enroll.sh
265 points·by _mig5·6 ay önce·56 comments

comments

_mig5
·6 gün önce·discuss
No ads. No tracking. Inspired by Bored Zebra's 100 Jumps (and shared with their blessing. Thanks!).

Couple of screenshots: https://goto.mig5.net/@mig5/statuses/01KWRJMJDFSF1TA28XTN5FA...

Have fun.
_mig5
·6 ay önce·discuss
Hi everyone! I'm pleased to report I'm releasing Enroll 0.4.0 today. It has some cool new features:

--ignore-package-versions for 'enroll diff' ,so you don't get alerted to just standard software updates of existing packages

--exclude-path for 'enroll diff', in case you need to ignore noisy drift but can't ignore the path from the harvest itself

'enroll manifest' will now add 'tags' in the playbook so you can use --tags with ansible to selectively apply specific roles from the playbook instead of everything.

And get ready for the big one....

--enforce for 'enroll diff'! Here's a video of it https://asciinema.org/a/766934

If a diff exists and `ansible-playbook` is available, Enroll will: 1) generate a manifest from the *old* harvest into a temporary directory

2) run `ansible-playbook -i localhost, -c local <tmp>/playbook.yml` (often with `--tags role_<...>` to limit how much has to run in the play)

3) record in the diff report that the old harvest was enforced

Enforcement is intentionally “safe”:

- reinstalls packages that were removed (`state: present`), but does *not* attempt downgrades/pinning

- restores users, files (contents + permissions/ownership), and service enable/start state

If `ansible-playbook` is not on `PATH`, Enroll returns an error and does not enforce.

Basically, 'enroll diff [...] --enforce' is akin to Puppet agents checking in with Puppetmaster and re-applying the declared state.

The new release also has some other smaller features also in place, such as 'enroll validate' which will check that a harvest is not corrupted or containing any orphaned artifacts.

Enjoy! And thanks for all the fish^Wlove.
_mig5
·6 ay önce·discuss
I captured most of the above in the docs now:

https://enroll.sh/docs.html#harvest

I've also published a JSONSchema of the state.json file here to help people understand its structure: https://enroll.sh/schema.html
_mig5
·6 ay önce·discuss
Cool tool, didn't know it existed! :) Thanks for passing on the word. 'Capture app and system stuff and deploy anywhere' is totally the goal :)
_mig5
·6 ay önce·discuss
Thanks for all the love HN!

I had a lot of good feedback directly from the comments here, and have made a new release that contains some bug fixes, as well as an improvement to support remote harvesting when the user requires a password for sudo. Thanks to 'slhck' here for the help, advice and patch for that.

There have also been some questions about 'what does enroll harvest actually capture in its state'. I've updated the docs here to clarify the process:

https://enroll.sh/docs.html#harvest

And for the data/API nerds, I've also published a JSON Schema of the state.json file here:

https://enroll.sh/schema.html

Thanks again!
_mig5
·6 ay önce·discuss
Dang! Seems strange.. I guess you are not using password-less sudo? (I'm interested to understand how Ansible itself works for you then too in such a setup, you have it prompting for a password when it invokes sudo?)

Yeah, I haven't been confident enough with Forgejo's federation capabilities yet to open up PRs/login etc. Maybe soon. Trying to avoid using Github and the other big providers if I can help it :) but I recognise it's a hindrance..

I'll happily take a patch and credit you, if you can be bothered, but I understand if not. Feel free to email [email protected]

*EDIT* reading up on it, sounds like I need to use sudo -S and accept stdin..
_mig5
·6 ay önce·discuss
Thanks for the comment and questions! Very wise.

Let me break it down as to what harvest does:

1) Detects the OS and its package backend (e.g dpkg vs rpm etc)

2) Detects what packages are installed

3) For each package, it tries to detect files in /etc/ that have been modified from the default that get shipped with the package . It does't walk the whole filesystem, it looks straight in /etc for stuff here.

4) It detects running/enabled services and timers via systemd. For each of these, it looks for the unit files, any 'drop-in' files, environment variable files, etc, as well as what executable it executes, and tries to map those systemd services to the packages it's already learned about earlier (that way, those 'packages' or future Ansible roles, can also be associated with 'handlers' in Ansible, to handle restart of the services if/when the configs change)

5) Aside from known packages already learned, it optimistically tries to capture extra system configuration in /etc that is common for config management. This is stuff like crons, logrotate configs, networking settings (as you noted!), hosts files, etc.

6) It also looks for other snowflake stuff in /etc not associated with packages/services or other typical system config, and will put these into an etc_custom role

7) Likewise, it looks in /usr/local for stuff, on the assumption that this is an area that custom apps/configs might've been placed in. These go into a usr_local_custom role.

8) It captures non-system user accounts, their group memberships and their .ssh/authorized_keys

9) takes into account anything the user set with --exclude-path or --include-path . For anything extra that is included, it will put these into an 'extra_paths' role. The location could be anywhere e.g something in /opt, /srv/ whatever you want.

10) writes the state.json and captures the artifacts

So yes, you're right - it does capture stuff that many people might want to exclude if they are going to use the manifests to build other machines from that harvest (as opposed to just rebuild the same machine itself).

But you can use --exclude-path /etc/network and so on to skip the bits you don't want. You also can always comment out from the playbook.yml or delete certain roles it generates once you've run the 'enroll manifest'.

It doesn't have any knowledge of Ansible Galaxy roles/modules etc. It generates all the roles itself. I admit, many of the existing roles out there are a lot more pleasant/easier to read (especially Jeff Geerling's). I still use those myself day to day. A lot of configs out there are also good candidates for being Jinja templates with abstracted vars for separate hosts. Enroll does use my companion tool JinjaTurtle if it's installed, but JinjaTurtle only recognises certain types of files (.ini style, .json, .xml, .yaml, .toml, but not special ones like Nginx or Apache conf files which have their own special syntax).

I consider Enroll to be a good 'quick, grab it all, so I can sleep at night' method, perhaps best for DR purposes.

In terms of safety measures: it doesn't traverse symlinks, and it has an 'IgnorePolicy' that makes it ignore most binary files (except GPG binary keys used with apt) - though if you specify certain paths with --include-path and use --dangerous, it will skip its own policy. See https://git.mig5.net/mig5/enroll/src/branch/main/enroll/igno... .

It will skip files that are too large, and it also currently has a hardcoded cap of the number of files that it will harvest (4000 for /etc/ and /usr/local/etc and /usr/local/bin, and 500 per 'role'), to avoid 'bomb' situations.

I think your caution is very warranted and wise, and I highly recommend to always use --check with Ansible when/if you get to applying the playbook!

Thanks again.
_mig5
·6 ay önce·discuss
Ah, this is not a problem for me on my remote hosts. I'm guessing this comes down to a sudoers policy on certain distros (redhat-like ones perhaps).

I'm about to make a new release and I'll set `get_pty=True` for the paramiko calls that use sudo. I'm not 100% sure if it will fix it for all use cases, but hopefully it will.
_mig5
·6 ay önce·discuss
Thanks usrme! Good questions.

I run QubesOS as my workstation, so it's been really beneficial here, because Qubes is all VMs and templates. I've been 'harvesting' one Qube VM and then building another and running the manifest on the second machine. It's been working very well to align it with the first machine. Most of my testing has been visually watching the Ansible play install/configure things that I expect to see occur.

Where it falls down:

1) Systems that are so old, the packages that it detected as being installed, are no longer 'installable' on a new system (e.g the apt repositories no longer have those packages, they just did at the time of the original install)

2) Packages that were installed not via an apt repo but, say, dpkg -i (of a .deb file). Slack Desktop is a good example. Obviously the deb is not in the harvest, so it fails there.

So, there'll always be corner cases, but assuming everything that you have installed on the old/obscure machine is still something that can be installed via the usual methods, it should be okay. (If you are running a system that is so old, its packages are no longer available upstream, it's probably time to let it go! :) )

You'll want to use --exclude-path to ignore some server-specific stuff, perhaps, such as static network configuration etc. And of course, you can also comment out whatever roles are superfluous, in the playbook, before running it.

Always use --check with Ansible first just in case.
_mig5
·6 ay önce·discuss
Hi mlrtime. You could run it on a base system, and use --exclude-path and --include-path all you want, to capture or ignore the things you don't care about.

Treat that as your 'golden' harvest state. You could then run a 'harvest' on the production system. You'd then be able to run 'enroll diff --old baseline --new production' to compare the difference.

You could also first run the manifest of the baseline harvest against your production, to ensure it has (at least) all the same things as the baseline.

A 'harvest' of production after that, would probably then show just stuff that existed on production already that wasn't in the baseline.

I hope that makes sense!
_mig5
·6 ay önce·discuss
Thank you, Jeff! What an honour! Let me say that nothing compares to your catalogue of Ansible roles that I have benefited from for many years, which are far better written than anything Enroll generates :) I intend for Enroll only to be a 'rapid grab-it-all', good for certain use cases.

Appreciate it!
_mig5
·6 ay önce·discuss
Yup - it can be pretty overwhelming, it depends on what it detected on your system! The state.json will usually explain why it 'harvested' something (perhaps it was because it found a running systemd service, perhaps it was due to detecting a package having been manually installed, etc)

There is the --exclude option which might help (also keep in mind you can define an enroll.ini file to manage the flags so it's less cumbersome). Otherwise, you can always prune the roles from the ansible dir/playbook.

I'm going to continue to work on easy options to skip stuff. In particular I do think many of the 'lib' packages could be omitted if they are just dependencies of other packages already detected as part of the harvest. (Need to basically build a dependency graph)

Thanks for trying it out!
_mig5
·6 ay önce·discuss
It does! There are several sort of 'catch-alls' in place:

1) stuff in /etc that doesn't belong to any obvious package, ends up in an 'etc_custom' role

2) stuff in /usr/local ends up in a 'usr_local_custom' role

3) Anything you include with --include will end up in a special 'extra_paths' role.

Here's a demo (which is good, helped me spot a small bug, the role is included twice in the playbook :) I'll get that fixed!) https://asciinema.org/a/765385

Thanks for your interest!
_mig5
·6 ay önce·discuss
Hi westurner!

> Could it also detect changed package files; if there are per-package-file checksums like with debsums and `rpm -V`?

Yes, that's exactly what it does. See https://git.mig5.net/mig5/enroll/src/branch/main/enroll/plat... and https://git.mig5.net/mig5/enroll/src/branch/main/enroll/rpm....

It also tries to ignore packages that came with the distro automatically, e.g focusing on stuff that was explicitly installed (based on 'apt-mark showmanual' for Debian, and 'dnf -q repoquery --userinstalled' (and related commands, like dnf -q history userinstalled) for RH-like)

> Does it check extended filesystem labels with e.g. getfacl for SELinux support?

Not yet, but that's interesting, I'll look into it.

> At least once I've scripted better then regex to convert a configuration file to a Jinja2 templated configuration file (from the current package's default commented config file with the latest options).

Yep, that was the inspiration for my companion tool https://git.mig5.net/mig5/jinjaturtle (which enroll will automatically try and use if it finds it on the $PATH - if it can't find it, it will just use 'copy' mode for Ansible tasks, and the original files).

Note that running the `enroll manifest` command against multiple separate 'harvests' (e.g harvested from separate machines) but storing it in the same common manifest location, will 'merge' the Ansible manifests. Thereby 'growing' the Ansible manifest as needed. But each host 'feature flips' on/off which files/templates should be deployed on it, based on what was 'harvested' from that host.

> Does it log a list of running processes and their contexts; with `ps -Z`?

It doesn't use ps, but it examines systemctl to get a list of running services and also timers. Have a look at https://git.mig5.net/mig5/enroll/src/branch/main/enroll/syst...

Thanks for the other ideas! I'll look into them.
_mig5
·6 ay önce·discuss
I agree! It's always a 'best effort' tool. There's going to be corner cases where something that might end up in the 'logrotate' role could arguably be better placed in a more specific app's role.

It does an okay job at this sort of thing, but definitely human eyes are needed :)
_mig5
·6 ay önce·discuss
Whoops, thanks, I'll adjust that example!

Indeed when using single-shot, unless you're using the --remote modes (in which case, the harvest is pulled down to a machine-generated path locally), indeed you need to supply the path to the harvest so that the 'manifest' part under the hood, knows what to use.

(By contrast, if you are using just the 'enroll harvest' command by itself, and omit the --out option, it will by default store the harvest in a random directory in ~/.cache/enroll/harvest/xxxxxxx)

Thanks for trying it out!
_mig5
·6 ay önce·discuss
Here's a video of JinjaTurtle, the companion tool that converts configs to Jinja2 templates and Ansible vars:

https://asciinema.org/a/765293

Enroll will automatically make use of jinjaturtle if it's on the $PATH, to generate templates.
_mig5
·6 ay önce·discuss
Definitely! It's all too easy to make a direct change and later forget to 'fold it in' to Ansible and run a playbook. My hope is that `enroll diff` serves as a good reminder if nothing else.

I'm pondering adding some sort of `--enforce` argument to make it re-apply a 'golden' harvest state if you really want to be strictly against drift. For now, it's notifications only though.
_mig5
·6 ay önce·discuss
Haha, same! I ran it on a server I've been shepherding along since 2008 and wow, it was insightful, there were even cron jobs it found that I had forgotten about :)

If you are using a Debian-like or Fedora-like workstation, it's also really useful to 'ansibilize' your desktop OS in case you need to reinstall :)
_mig5
·6 ay önce·discuss
Indeed! I'm showing my age, but I do remember using this with Puppet and it was one of my inspirations :D (no commits in nearly 13 years, ouch) https://github.com/devstructure/blueprint