Commit Graph

815 Commits (b5c54d7bb3d1a5188e550dff6b8e40dafb6a1d28)

Author SHA1 Message Date
Dustin b5c54d7bb3 ci: Remove extraneous copy of ssh_known_hosts
This doesn't actually work, because the shell expands `~` to the value
of the `HOME` environment variable, but `ssh` ignores that variable and
reads from the path from the user's `passwd` entry.  Since managed hosts
all have certificates now, and the CA key is included in the global host
key database, individual host keys are not needed anymore anyway.
2024-01-28 12:18:55 -06:00
Dustin 1bff9b2649 gw1: Enable pam_ssh_agent_auth for sudo
This machine is _not_ a member of the _pyrocufflink.blue_ AD domain, so
it does not inherit the settings from that group.  Also, Jenkins does
not manage it, so only my personal keys are authorized.
2024-01-28 12:16:35 -06:00
Dustin 6bad6dcb7a ci: Use SSH key for sudo auth
Now that servers are configured to use *pam_ssh_agent_auth* for `sudo`
authentication, the Jenkins CI pipelines no longer need to manage the
raw password for the *jenkins* user.  A special SSH public key for
Jenkins is listed in `/etc/security/sudo.authorized_keys`, so as long
as a) the corresponding private key is in the SSH agent and b) SSH
agent forwarding is enabled, Ansible will be able to perform privileged
operations without a password.
2024-01-28 12:16:35 -06:00
Dustin 4b8b5fa90b pyrocufflink: Enable pam_ssh_agent_auth for sudo
By default, `sudo` requires users to authenticate with their passwords
before granting them elevated privileges.  It can be configured to
allow (some) users access to (some) privileged commands without
prompting for a password (i.e. `NOPASSWD`), however this has a real
security implication.  Disabling the password requirement would
effectively grant *any* program root privileges.  Prompting for a
password prevents malicious software from running privileged commands
without the user knowing.

Unfortunately, handling `sudo` authentication for Ansible is quite
cumbersome.  For interactive use, the `--ask-become-pass`/`-K` argument
is useful, though entering the password for each invocation of
`ansible-playbook` while iterating on configuration policy development
is a bit tedious.  For non-interactive use, though, the password of
course needs to be stored somewhere.  Encrypting it with Ansible Vault
is one way to protect it, but it still ends up stored on disk somewhere
and needs to be handled carefully.

*pam_ssh_agent_auth* provides an acceptable solution to both issues.  It
is better than disabling `sudo` authentication entirely, but a lot more
convenient than dealing with passwords.  It uses the calling user's SSH
agent to assert that the user has access to a private key corresponding
to one of the authorized public keys.  Using SSH agent forwarding, that
private key can even exist on a remote machine.  If the user does not
have a corresponding private key, `sudo` will fall back to normal
password-based authentication.

The security of this solution is highly dependent on the client to store
keys appropriately.  FIDO2 keys are supported, though when used with
Ansible, it is quite annoying to have to touch the token for _every
task_ on _every machine_.  Thus, I have created new FIDO2 keys for both
my laptop and my desktop that have the `no-touch-required` option
enabled.  This means that in order to use `sudo` remotely, I still need
to have my token plugged in to my computer, but I do not have to tap it
every time it's used.

For Jenkins, a hardware token is obviously impossible, but using a
dedicated key stored as a Jenkins credential is probably sufficient.
2024-01-28 12:16:35 -06:00
Dustin 091d9e1f78 r/sudo: Optionally enable pam_ssh_agent_auth
The [pam_ssh_agent_auth][0] PAM module authenticates users using keys in
their SSH agent.  Using SSH agent forwarding, it can even authenticate
users with keys on a remote system.  By adding it to the PAM stack for
`sudo`, we can configure the latter to authenticate users without
requiring a password.  For servers especially, this is significantly
more secure than configuring `sudo` not to require a password, while
still being almost as convenient.

For this to work, users need to enable SSH agent forwarding on their
clients, and their public keys have to be listed in the
`/etc/security/sudo.authorized_keys` file.  Additionally, although the
documentation suggests otherwise, the `SSH_AUTH_SOCK` environment
variable has to be added to the `env_keep` list in *sudoers(5)*.

[0]: https://github.com/jbeverly/pam_ssh_agent_auth
2024-01-28 12:16:35 -06:00
Dustin 7569c9da0d r/squid: Fix SELinux AVC denial after cache init
Running `squid -z` as *root* leaves behind temporary files in
`/dev/shm`.  When *squid.service* starts squid, in the proper SELinux
domain, it is unable to access these files and crashes.  To avoid this,
we mount a private *tmpfs* so no existing files are accessible in the
service's namespace.
2024-01-27 20:28:06 -06:00
Dustin be63424fd8 hosts: Deploy Squid on gw1
Running Squid on the firewall makes sense; it's a sort of layer-7
firewall, after all.  There's not much storage on that machine, though
so we don't really want to cache anything.  In fact, it's only purpose
is to allow very limited web access for certain applications.  All
outbound traffic is blocked, with two exceptions:

* Fedora package repositories (for the UniFi controller server)
* Google Fonts (for Invoice Ninja)
2024-01-27 20:09:34 -06:00
Dustin 541a6385e2 r/squid: Update default config for latest version
At some point, the default `squid.conf` file changed a bit.  Updating
the template to match.
2024-01-27 20:08:16 -06:00
Dustin 1d94dc9528 r/squid: Support custom cache rules
Instead of hard-coding a single cache directory and a set of refresh
patterns, the *squid* role can now have custom cache rules defined with
the `squid_cache_dir` variable (which now takes a list of `cache_dir`
settings) and the `squid_refresh_pattern` variable (which takes a list
of refresh patterns).  If neither of these are defined, the default
configuration is used.

This is a breaking change, since `squid_cache_dir` used to refer to a
directory, and the previous default was to configure one cache path.
There are no extant users of this role, though, so it doesn't really
matter.
2024-01-27 20:05:35 -06:00
Dustin af18a575d1 r/squid: Support custom ACLs and rules
The default set of access control lists and access rules for Squid are
fine for allowing hosts on the local network access to the web in
general.  For other uses, such as web filtering, etc. more complex rules
may be needed.  To that end, the *squid* role now supports some
additional variables.  Notably, `squid_acl` contains a map of ACL names
to list entries and `squid_http_access` contains a list of access rules.
If these are set, their corresponding defaults are not included in the
rendered configuration file.
2024-01-27 19:56:02 -06:00
Dustin 7b54bc4400 nut-monitor: Require both UPS to be online
Unfortunately, the automatic transfer switch does not seem to work
correctly.  When the standby source is a UPS running on battery, it does
*not* switch sources if the primary fails.  In other words, when the
power is out and both UPS are running on battery, when the first one
dies, it will NOT switch to the second one.  It has no trouble switching
when the second source is mains power, though, which is very strange.

I have tried messing with all the settings including nominal input
voltage, sensitivity, and frequency tolerence, but none seem to have any
effect.

Since it is more important for the machines to shut down safely than it
is to have an extra 10-15 minutes of runtime during an outage, the best
solution for now is to configure the hosts to shut down as soon as the
first UPS battery gets low.  This is largely a waste of the second UPS,
but at least it will help prevent data loss.
2024-01-25 21:22:04 -06:00
Dustin 2e77502a2f hosts: Decommission serial0.p.b
*serial0.pyrocufflink.blue* has been replaced by
*serial1.pyrocufflink.blue*.  The latter runs Fedora CoreOS and is
managed by the CUE-based configuration policy in *cfg.git*.
2024-01-25 20:22:00 -06:00
Dustin 236e6dced6 r/web/hlc: Add formsubmit config for summer signup
And of course, Tabitha lost her SSH key so she had to get another one.
2024-01-23 22:04:29 -06:00
Dustin 5287ff601b r/jellyfin: Enable service auto restart 2024-01-22 20:37:21 -06:00
Dustin 54727e148f r/nut{,-monitor}: Enable nut.target
Recent versions of NUT have a *nut.target* unit that collects all of the
NUT-related services.  Enabling any of the services individually does
effectively nothing, as it only adds the service as a `Wants` dependency
for *nut.target*, and that unit already has dependencies for all of
them. Thus, in order for the service to start at boot, *nut.target* has
to be enabled instead.

In situations where only *nut-monitor* should be enabled, enabling
*nut.target* is inappropriate, since that enables *nut-driver* and
*nut-server* as well. It's not clear why upstream made this change (it
was part of a [HUGE pull request][0]), but restoring the desired
behavior is easy enough by clearing the dependencies from *nut.target*.
Services that we want to start automatically can still be enabled
individually, and will start as long as *nut.target* is enabled.

[0]: https://github.com/networkupstools/nut/pull/330
2024-01-22 09:03:15 -06:00
Dustin 764177daf3 vmhost0: Shut down when first UPS goes low battery
The automatic transfer switch does not seem to work reliably when both
UPS sources are running on battery.  This means all systems lose power
after the first UPS battery dies, even though the second UPS is still
online.  To minimize the risk of data loss, at least until I figure out
what's wrong, I want both VM hosts to shut down as soon as the first UPS
signals that its battery is low.
2024-01-22 08:46:32 -06:00
Dustin 07f84e7fdc vm-hosts: Increase VM start delay after K8s
Increasing the delay after starting the Kubernetes cluster to hopefully
allow things to "settle down" enough that starting services on follow up
VMs doesn't time out.
2024-01-22 08:35:40 -06:00
Dustin 681384872c r/synapse: Increase service startup timeout
The Synapse server can sometimes take a very long time to start.
Increasing the start timeout should keep it from failing to come up when
the machine is under load.
2024-01-21 19:05:00 -06:00
Dustin 6f4fb70baa vm-hosts: Clean up vm-autostart list
Start Kubernetes earlier.  Start Synapse later (it takes a long time to
start up and often times out when the VM hosts are under heavy load).
Start SMTP relay later as it's not really needed.
2024-01-21 18:42:28 -06:00
Dustin 55e26a7c81 r/unifi: Increase startup timeout
The UniFi controller service can sometimes take a really long time to
start up.  This most frequently happens after a full outage, when the VM
hosts are very busy bringing everything up.
2024-01-21 16:12:29 -06:00
Dustin bba55b5182 r/unifi: Enable service auto restart
Automatically restart the UniFi service in case it crashes (which it
tends to do quite frequently).
2024-01-21 16:12:29 -06:00
Dustin 1bbcbcd929 ci: Add Jenkins pipeline for UniFi controller 2024-01-21 16:12:29 -06:00
Dustin b4fcbb8095 unifi: Deploy unifi_exporter
`unifi_exporter` provides Prometheus metrics for UniFi controller.
2024-01-21 16:12:29 -06:00
Dustin 6f5b400f4a vm-hosts: Fix test network device name
The network device for the test/*pyrocufflink.red* network is named
`br1`.  This needs to match in the systemd-networkd configuration or
libvirt will not be able to attach virtual machines to the bridge.
2024-01-21 15:55:37 -06:00
Dustin fb445224a0 vm-hosts: Add k8s-amd64-n3 to autostart list 2024-01-21 15:55:23 -06:00
Dustin d5de7131a0 r/vmhost: Remove system call filters from unit
The `vm-autostart` script fails with `bad system call` errors when
trying to start libvirt domains.  Removing the system call filters works
around this.  Ideally, we should figure out exactly which system call is
being rejected and allow it, but that's rather difficult to do and
probably not really worth the effort in this case.
2024-01-21 15:53:44 -06:00
Dustin 823d899e9e r/minio: Start more reliably on boot
The MinIO service often fails to start from a cold boot.  Delaying
starting the service until the network is online, plus increasing the
startup timeout, should help with this.  If not, enabling auto restart
will let systemd try to start the service again if it still fails to
come up on time.
2024-01-21 15:53:33 -06:00
Dustin 423951bac1 {burp1, gw1}: Configure upsmon 2024-01-19 21:55:36 -06:00
Dustin d0b0f2ff38 hosts: gw1: Deploy BURP, collectd
Although *gw1* is not really managed by Ansible, it is much easier to
deploy collectd and BURP with the existing playbooks.
2024-01-19 20:52:48 -06:00
Dustin 525f2b2a04 nut-monitor: Configure upsmon
`upsmon` is the component of [NUT] that monitors (local or remote) UPS
devices and reacts to changes in their state.  Notably, it is
responsible for powering down the system when there is insufficient
power to the system.
2024-01-19 20:50:03 -06:00
Dustin f31018f514 hosts: Remove serial0 from nut group
*nut0.pyrocufflink.blue* is the new NUT server.  It's not managed by
this configuration policy.
2024-01-16 17:41:50 -06:00
Dustin 60fa380e5d dyngroups: Always run all tasks
Adding the `always` tag to the tasks in `dyngroups.yml` ensures that
hosts will get added to the appropriate groups dynamically, even when
running a subset of tasks by targeting specific tags.  Ansible will
always run tasks with this tag when a tag selection is passed to
`ansible-playbook`.
2024-01-09 18:18:34 -06:00
Dustin 1226f1f005 hosts: Decommission mtrcs0.p.b
The Metrics Pi has bit the dust.  The NVMe disk has never been
particularly reliable, but now it's gotten to the point where it's a
real issue.  The Pi needs rebooted at least once a day.

I've moved the Victoria Metrics/Grafana ecosystem to Kubernetes.
2023-12-31 19:15:55 -06:00
Dustin ab30fa13ca file-servers: Set Apache ServerName
Since *file0.pyrocufflink.blue* now hosts a couple of VirtualHosts,
accessing its HTTP server by the *files.pyrocufflink.blue* alias no
longer works, as Apache routes unknown hostnames to the first
VirtualHost, rather than the global configuration.  To resolve this, we
must set `ServerName` to the alias.
2023-12-29 10:46:13 -06:00
Dustin fe258c51ac r/web/dcow: Proxy to Kubernetes
I've moved the Dark Chest of Wonders website to run in a container on
Kubernetes.  This will keep it from breaking every time the OS is
updated on the web server, when the version of Python in Fedora changes.
2023-12-17 20:16:51 -06:00
Dustin 3da74b8e53 ci: Add pipeline for file server 2023-12-04 13:59:48 -06:00
Dustin 00be022c04 ci: Add pipeline for Jellyfin 2023-12-04 12:20:39 -06:00
Dustin 5c297df6b9 r/gitea: use sshd_config.d
Recent(-ish) versions of Fedora have a drop-in configuration directory
for `sshd`.  This allows applications, etc. to define certain settings
for the SSH server, without having to manage the entire server
configuration.  For Gitea specifically, we only need to set a few
settings for the *gitea* user, leaving the remaining settings alone.

This commit does not include any migration to undo the settings that
were originally set,  but that should be as simple as `mv
/etc/ssh/sshd_config.rpmnew /etc/ssh/sshd_config && systemctl reload
sshd`.
2023-11-13 17:45:21 -06:00
Dustin dfd828af08 r/ssh-host-certs: Manage SSH host certificates
The *ssh-host-certs* role, which is now applied as part of the
`base.yml` playbook and therefore applies to all managed nodes, is
responsible for installing the *sshca-cli* package and using it to
request signed SSH host certificates.  The *sshca-cli-systemd*
sub-package includes systemd units that automate the process of
requesting and renewing host certificates.  These units need to be
enabled and provided the URL of the SSHCA service.  Additionally, the
SSH daemon needs to be configured to load the host certificates.
2023-11-07 21:27:02 -06:00
Dustin c3f58aff83 r/dch-yum: Configure dch Yum repository
The *dch* repository, hosted on *file0.pyrocufflink.blue* and managed by
the *repohost* Ansible role, is where I plan to host RPM packages for
internal use (e.g. *sshca-cli*, *dch-selinux*, etc.).  The *dch-yum*
role configures Yum/dnf to use this repository.  Roles that need to
install a package from here will list this role as a dependency.
2023-11-07 21:24:40 -06:00
Dustin c6f0ea9720 r/repohost: Configure Yum package repo host
So it turns out Gitea's RPM package repository feature is less than
stellar.  Since each organization/user can only have a single
repository, separating packages by OS would be extremely cumbersome.
Presumably, the feature was designed for projects that only build a
single PRM for each version, but most of my packages need multiple
builds, as they tend to link to system libraries.  Further, only the
repository owner can publish to user-scoped repositories, so e.g.
Jenkins cannot publish anything to a repository under my *dustin*
account.  This means I would ultimately have to create an Organization
for every OS/version I need to support, and make Jenkins a member of it.
That sounds tedious and annoying, so I decided against using that
feature for internal packages.

Instead, I decided to return to the old ways, publishing packages with
`rsync` and serving them with Apache.  It's fairly straightforward to
set this up: just need a directory with the appropriate permissions for
users to upload packages, and configure Apache to serve from it.

One advantage Gitea's feature had over a plain directory is its
automatic management of repository metadata.  Publishers only have to
upload the RPMs they want to serve, and Gitea handles generating the
index, database, etc. files necessary to make the packages available to
Yum/dnf.  With a plain file host, the publisher would need to use
`createrepo` to generate the repository metadata and upload that as
well.  For repositories with multiple packages, the publisher would need
a copy of every RPM file locally in order for them to be included in the
repository metadata.  This, too, seems like it would be too much trouble
to be tenable, so I created a simple automatic metadata manager for the
file-based repo host.  Using `inotifywatch`, the `repohost-createrepo`
script watches for file modifications in the repository base directory.
Whenever a file is added or changed, the directory containing it is
added to a queue.  Every thirty seconds, the queue is processed; for
each unique directory in the queue, repository metadata are generated.

This implementation combines the flexibility of a plain file host,
supporting an effectively unlimited number of repositories with
fully-configurable permissions, and the ease of publishing of a simple
file upload.
2023-11-07 20:51:10 -06:00
Dustin 6955c4e7ad hosts: Decommission dc-4k6s8e.p.b
Replaced by *dc-nrtxms.pyrocufflink.blue*
2023-10-28 16:07:56 -05:00
Dustin 420764d795 hosts: Add dc-nrtxms.p.b
New Fedora 38 Active Directory Domain Controller
2023-10-28 16:07:39 -05:00
Dustin a8c184d68c hosts: Decommission dc-ag62kz.p.b
Replaced by *dc-qi85ia.pyrocufflink.blue*
2023-10-28 16:07:08 -05:00
Dustin f334363aab r/samba-dc: sysvolsync: Remove winbind cache file
The `net cache flush` command does not seem to always work to clear the
identity mapping cache used by winbind.  Explicitly moving the file
does, though.
2023-10-28 09:56:44 -05:00
Dustin 3e70600691 r/samba-dc: sysvolsync: Fix running on fresh DC
On a new DC, the `idmap.ldb` file does not yet exist the first time
`sysvolsync` runs.  This causes a syntax error in the condition that
checks the modification timestamp of the file.
2023-10-28 09:52:24 -05:00
Dustin c814007c6d hosts: Add dc-qi85ia.p.b
New Fedora 38 domain controller.
2023-10-28 09:50:07 -05:00
Dustin 73499e3593 samba-dc: Do not apply sudo role
The *sudo* role should not be applied by the `samba-dc.yml` playbook.
It's not relevant to deploying Samba, and will just get applied by the
`domain-controller.yml` playbook later, anway.  Further, it fails when
a new domain controller is first provisioned, because at this step,
the system is not yet configured to resolve user IDs via winbind;
rather than add users to groups, it tries to create them.
2023-10-27 17:57:20 -05:00
Dustin 5bffdc68a2 r/samba-dc: sysvolsync: Use system DNS server
Forcing the PDC lookup to use localhost as the DNS server does not work
when first adding a new domain controller, as the `sysvolsync` script
runs before Samba starts.  There isn't much advantage to using the local
DNS server over the system-defined server anyway.
2023-10-27 17:55:44 -05:00
Dustin b45e647382 r/gitea: Update to v1.20.5 2023-10-27 17:41:43 -05:00