Commit Graph

1105 Commits (2d36d1fc8fc245fd8cafcd02f4f02fc40bb64306)

Author SHA1 Message Date
Dustin 2d36d1fc8f websites: Remove darkchestofwonders.us
This website has been moved to Kubernetes since some time ago.  We don't
need to configure the web server to host it anymore.
2025-07-22 13:10:30 -05:00
Dustin b2213416d0 scrape-collectd-configmap: Add PB
I didn't realize this playbook wasn't even in the Git repository when I
added it to `site.yml`.

This playbook manages the `scrape-collectd` ConfigMap, which is used by
Victoria Metrics to identify the hosts it should scrape to retrieve
metrics from _collectd_.
2025-07-20 21:27:54 -05:00
Dustin a5b47eb661 hosts: Add vm-hosts to collectd group
Now that the VM hosts are not members of the AD domain, they need to be
added to the _collectd_ group directly.
2025-07-18 12:47:55 -05:00
Dustin 506ddad2dc site: Apply scrape-collectd-configmap PB
Machines that are not part of the Kubernetes cluster, need to be
explicitly listed in this ConfigMap in order for Victoria Metrics to
scrape collectd metrics from them.
2025-07-18 12:46:22 -05:00
Dustin f7546791cc kubelet: Fix CA cert for Docker Hub proxy
The man page for _containers-certs.d(5)_ says that subdirectories of
`/etc/containers/certs.d` should be named `host:port`, however, this is
a bit misleading.  It seems instead, the directory name must match the
name of the registry server as specified, so in the case of a server
that supports HTTPS on port 443, where the port would be omitted from
the image name, it must also be omitted from the `certs.d` subdirectory
name.
2025-07-16 16:05:19 -05:00
Dustin ba3f61fb08 r/containers-image: Fix registries.conf path
`/etc/containers/registries.conf.d` is distinct from
`/etc/containers/registries.d`.  The latter contains YAML files relating
to image signatures, while the former contains TOML files relating to
registry locations.
2025-07-14 16:21:58 -05:00
Dustin 1bf6ae6d3c kubernetes: Disable become for delegated task
We do not need "become" for the Kubernetes resource manipulation task
that runs on the control machine.
2025-07-14 16:19:33 -05:00
Dustin e65bcc25ba r/k8s-worker: Fix typo in variable name
This typographical error was causing the "join" tasks to be executed
every time.
2025-07-14 16:18:35 -05:00
Dustin 61a4f64bbb r/nginx: Fix disabling access/error log files
It turns out _nginx_ has a built-in default value for `access_log` and
`error_log`, even if they are omitted from the configuration file.  To
actually disable writing logs to a file, we need to explicitly specify
`off`.
2025-07-14 16:11:35 -05:00
Dustin b4f5b419e1 newvm: Stop waiting for VM events if install fails
If `virt-install` fails before the VM starts for the first time; the
`virsh event` process running in the background will never terminate and
therefore the main process will `wait` forever.  We can avoid this by
killing the background process if `virt-install` fails.
2025-07-14 15:57:12 -05:00
Dustin 51e8cae618 newvm: Fix vCPU count/CPU model
Although the `newvm.sh` script had a `--vcpus` argument, its value was
never being used.

The `--cpu host` argument for `virt-install` is deprecated in favor of
`--cpu host`.
2025-07-14 15:57:12 -05:00
Dustin 04718fa6d0 newvm: Avoid adding graphics adapter by default
VMs don't really need graphical consoles; serial terminals are good
enough, or even better given that they are logged.  For the few cases
where a graphical console is actually necessary, the `newvm.sh` script
can add one with the `--graphics` argument.
2025-07-14 15:57:12 -05:00
Dustin 0824e6bea0 newvm: Update default kickstart location
Since the kickstart scripts are now generated from templates by Jenkins,
we need to fetch the final rendered artifacts from the PXE server,
rather than the source files from Gitea.
2025-07-14 15:57:12 -05:00
Dustin 7823a2ceaf ci: Add Jenkins pipeline for pxe.yml 2025-07-13 16:10:20 -05:00
Dustin b9a046c7f4 plugins: Add lookup cache plugin
One major weakness with Ansible's "lookup" plugins is that they are
evaluated _every single time they are used_, even indirectly.  This
means, for example, a shell command could be run many times, potentially
resulting in different values, or executing a complex calculation that
always provides the same result.  Ansible does not have a built-in way
to cache the result of a `lookup` or `query` call, so I created this
one.  It's inspired by [ansible-cached-lookup][0], which didn't actually
work and is apparently unmaintained.  Instead of using a hard-coded
file-based caching system, however, my plugin uses Ansible's
configuration and plugin infrastructure to store values with any
available cache plugin.

Although looking up the _pyrocufflink.net_ wildcard certificate with the
Kubernetes API isn't particularly expensive by itself right now, I can
envision several other uses that may be.  Having this plugin available
could speed up future playbooks.

[0]: https://pypi.org/project/ansible-cached-lookup
2025-07-13 16:02:57 -05:00
Dustin 906819dd1c r/apache: Use variables for HTTPS cert/key content
Using files for certificates and private keys is less than ideal.
The only way to "share" a certificate between multiple hosts is with
symbolic links, which means the configuration policy has to be prepared
for each managed system.  As we're moving toward a much more dynamic
environment, this becomes problematic; the host-provisioner will never
be able to copy a certificate to a new host that was just created.
Further, I have never really liked the idea of storing certificates and
private keys in Git anyway, even if it is in a submodule with limited
access.
2025-07-13 16:02:57 -05:00
Dustin f08f147931 r/pxe: Depend on apache role
Now that we're serving kickstart files from the PXE server, we need to
have a correctly-configured HTTPD server, with valid HTTPS certificates,
running there.
2025-07-13 16:02:57 -05:00
Dustin 6667066826 kubelet: Configure cri-o container registries
The _containers-image_ role configures _containers-registries.conf(5)_ and
_containers-cert.d(5)_, which are used by CRI-O (and `podman`).
Specifically, we'll use these to redirect requests for images on Docker
Hub (docker.io) to the internal caching proxy.
2025-07-12 16:45:47 -05:00
Dustin f8f3dd5f83 docker-proxy: Deploy a proxy/cache for Docker Hub
Docker Hub's rate limits are so low now that they've started to affect
my home lab.  Deploying a caching proxy and directing all pull requests
through it should prevent exceeding the limit.  It will also help
prevent containers from starting if access to the Internet is down, as
long as their images have been cached recently.
2025-07-12 16:45:47 -05:00
Dustin 6d1442faf0 r/lego-nginx: Configure LEGO for nginx
The *lego-nginx* role automates obtaining certificates for *nginx* via
ACME using `lego`.  It generates a shell script with the appropriate
arguments for `lego run`, runs it once to obtain a certificate
initially, then schedules it to run periodically via a systemd timer
unit. Using `lego`'s "hook" capability, the script signals the `nginx`
server process to reload.  This uses `doas` for now, but could be
adapted easily to use `sudo`, if the need ever arises.
2025-07-12 16:45:47 -05:00
Dustin 0393f074a4 host-setup: Import datavol Playbook
The `host-setup.yml` playbook now imports the `datavol.yml` playbook, so
that new machines (particularly those provisioned by the
host-provisioner) get their data volumes formatted and mounted
automatically.
2025-07-12 16:45:47 -05:00
Dustin 6359a140ac gw1/squid: Allow proxy access from kube network
Since we use the proxy when PXE booting to speed up Live OS image and
RPM package downloads, we need to allow machines using it to access the
kickstart files which are now hosted on the PXE server.  Virtual
machines on the Kubernetes network (_pyrocufflink.black_ also need
access to those kickstarts, so we need to mark that subnet as trusted.
2025-07-12 16:45:47 -05:00
Dustin fefa85c83b gw1: squid: Allow access to PXE/kickstarts
The PXE server now hosts the kickstart scripts.
2025-07-12 16:12:23 -05:00
Dustin a23bb1f043 r/pxe: Add directory for serving kickstarts
Now that kickstart scripts are generated from templates by a Jenkins
job, they need to be stored somewhere besides Gitea.  It makes sense to
serve them from the PXE server, since it's involved in the installation
process anyway (at least for physical machines).   Thus, we need a path
where the generated files can be uploaded by Jenkins and served by
Apache.
2025-07-12 16:12:23 -05:00
Dustin 6447ff5f4b v-l: Add data volume for logs storage 2025-07-12 16:08:40 -05:00
Dustin 4218137e1e r/minio-backups-cert: Fix nsupdate kinit for f42
The version of Samba in Fedora 42 has got some really weird bugs.  In
this case, it seems `net ads kerberos kinit -P` no longer works.  It
prints a vague `NT_STATUS_INTERNAL_ERROR` message, with no other
indication of what went wrong.  Fortunately, it's still possible to get
a ticket-granting ticket for the machine account using the host keytab.
2025-07-12 16:08:21 -05:00
Dustin 87d90a617d minio-backups: Disable nginx access logs entirely
The _nginx_ access log files are absolutely spammed with requets from
Restic and WAL-G, to the point where they fill the log volume on
_chromie_ every day.  They're not particularly useful anyway; I've never
looked at them, and any information they contain can be obtained in
another way, if necessary, for troubleshooting.
2025-07-03 11:15:40 -05:00
Dustin f3c432dbff r/minio: Do not pull images automatically
We don't want `podman` pulling a new container image and updating
without our concent.  The image will already be there on the first
start, since we pulled it in an Ansible task.
2025-07-02 09:23:18 -05:00
Dustin 5edfbf2408 r/minio: Do not mount storage volume with :Z
The `:Z` flag tells the container runtime to run `chcon` recursively on
the specified path, in order to ensure that the files are accessible
inside the container.  For a very large volume like the MinIO storage
directory, this can take an extremely long time.  It's really only
necessary on the first startup anyway, because the context won't change
after that.  To avoid spending a bunch of time, we can set the context
correctly when we create the directory, and then not worry about it
after that.
2025-07-02 09:21:57 -05:00
Dustin 84cd6022c0 r/k8s-worker: Use K8s API to create join token
Using the Kubernetes API to create bootstrap tokens makes it possible
for the host-provisioner to automatically add new machines to the
Kubernetes cluster.  The host provisioner cannot connect to existing
machines, and thus cannot run the `kubeadm token create` command on
a control plane node.  With the appropriate permissions assigned to the
service account associated with the pod it runs in, though, it can
directly create the secret via the API.

There are actually two pieces of information required for a node to
join a cluster, though: a bootstrap token and the CA certificate.  When
using the `kubeadm token create` command to issue a bootstrap token, it
also provides (a hash of) the CA certificate with the command it prints.
When creating the token manually, we need an alternative method for
obtaining and distributing the CA certificate, so we use the
`cluster-info` ConfigMap.  This contains a stub `kubeconfig` file, which
includes the CA certificate, which can be used by the `kubeadm join`
command with a join configuration file.  Generating both of these files
may be a bit more involved than computing the CA certificate hash and
passing that on the command line, but there are a couple of advantages.
First, it's more extensible, as the join configuration file can specify
additional configuration for the node (which we may want to use later).
It's also somewhat more secure, since the token is not passed as a
command-line argument.

Interestingly, the most difficult part of this implementation was
getting the expiration timestamp.  Ansible exposes very little date math
capability; notably lacking is the ability to construct a `timedelta`
object, so the only way to get a timestamp in the future is to convert
the `datetime` object returned by `now` to a Unix timestamp and add some
number of seconds to it.  Further, there is no direct way to get a
`datetime` object from the computed Unix timestamp value, but we can
rely on the fact that Python class methods can be called on instances,
too, so `now().fromtimestamp()` works the same as
`datetime.fromtimestamp()`.
2025-07-01 08:09:11 -05:00
Dustin a399591f16 hosts: Decommission node-refrain.k.p.b
I did something stupid to this machine trying to clear up its
`/var/lib/containers/storage` volume and now it won't start any new
pods.  Killing it and replacing.
2025-06-21 17:51:06 -05:00
Dustin 025f2ddd8c hosts: Remove VM hosts from AD domain
Having the VM hosts as members of the domain has been troublesome since
the very beginning.  In full shutdown events, it's often difficult or
impossible to log in to the VM hosts while the domain controller VMs are
down or still coming up, even with winbind caching.

Now that we have the `users.yml` playbook, the SSH certificate
authority, and `doas`+*pam_ssh_agent_auth*, we really don't need the AD
domain for centralized authentication.
2025-06-08 09:04:27 -05:00
Dustin 2d4eb76f24 users: Do not clear supplemental groups
To ensure the `users.yml` playbook is idempotent in cases where the
users it manages are also managed by other playbooks, we have to set
`append: true`.  This prevents the managed user(s) from being removed
from additional groups other playbooks may have added them to.
2025-06-08 09:00:16 -05:00
Dustin a5e2920223 r/victoria-logs: Update to v1.23.3 2025-06-03 18:59:25 -05:00
Dustin 3df5b06169 site: Import victoria-logs PB 2025-05-30 21:52:23 -05:00
Dustin d4d3f0ef81 r/victoria-logs: Deploy VictoriaLogs
I've become rather frusted witih Grafana Loki lately.  It has several
bugs that affect my usage, including issues with counting and
aggregation, completely broken retention and cleanup, spamming itself
with bogus error log messages, and more.  Now that VitoriaLogs has
first-class support in Grafana and support for alerts, it seems like a
good time to try it out.  It's under very active development, with bugs
getting fixed extremely quickly, and new features added constantly.
Indeed, as I was experimenting with it, I thought, "it would be nice if
the web UI could decode ANSI escapes for terminal colors," and just a
few days later, that feature was added!  Native support for syslog is
also a huge benefit, as it will allow me to collect logs directly from
network devices, without first collecting them into a file on the Unifi
controller.

This new role deploys VictoriaLogs in a manner very similar to how I
have Loki set up, as a systemd-managed Podman container.   As it has no
built-in authentication or authorization, we rely on Caddy to handle
that.  As with Loki, mTLS is used to prevent anonymous access to
querying the logs, however, authentication via Authelia is also an
option for human+browser usage.  I'm re-using the same certificate
authority as with Loki to simplify Grafana configuration.  Eventually, I
would like to have a more robust PKI, probably using OpenBao, at which
point I will (hopefully) have decided which log database I will be
using, and can use a proper CA for it.
2025-05-30 21:19:05 -05:00
Dustin 1768678213 frigate: Set logout URL
Although I'm sure it will never be used, we might as well set the logout
URL to the correct value.  When the link is clicked, the browser will
navigate to the Authelia logout page, which will invalidate all SSO
sessions.
2025-04-21 08:28:49 -05:00
Dustin 57c5afc0c8 r/frigate: Fix Authelia redirect
HTTP 301 is "moved permanently." Browsers will cache this response and
never send the request to the real server again.  We need to use a
temporary redirect, such as "see other" to avoid getting stuck in a
login loop.
2025-04-21 08:27:34 -05:00
Dustin 113ffa2b96 r/frigate: Update to v0.15
Frigate has evolved a lot over the past year or so since v0.13.
Notably, some of the configuration options have been renamed, and
_events_ have become _alerts_ and _detections_.  There's also now
support for authenication, though we don't need it because we're using
Authelia.
2025-04-20 16:23:04 -05:00
Dustin 1b94530b1f frigate: Add front yard camera
We're trying to sell the Hustler lawn mower, so we plan to set it out
at the end of the driveway for passers-by to see.  I've temporarily
installed one of the Annke cameras in the kitchen, pointed out the
front window, to monitor it.
2025-04-20 14:10:27 -05:00
Dustin 641ddf8613 site: Import restic playbook
This will automatically configure backups on new machines that should
have them.
2025-03-29 09:37:55 -05:00
Dustin 6df0cc39da unifi: Back up with Restic
The Unifi Network data will now be backed up by Restic.
2025-03-29 09:36:37 -05:00
Dustin 572022b557 restic: Trust dch-root-ca certificate
Since the MinIO server that Restic uses to store snapshots has a
certificate signed by the DCH CA, we need to trust the root certificate
in order to communicate with it.  Existing servers already had this CA
trusted by the `pyrocufflink.yml` playbook, but new servers are not
(usually) AD domain members anymore, so we need to be explicit now.
2025-03-29 09:34:17 -05:00
Dustin daa59bdba5 r/useproxy: Configure dnf to use proxy
Although running `dnf` from the command line works without explicitly
configuring the proxy, because it inherits the environment variables set
by PAM on login from the user's shell, the `dnf` Ansible module does
not, as it does not inherit those variables.  Thus, we need to
explicitly configure the `proxy` setting in `dnf.conf` in order to be
able to install packages via Ansible.

Since `dnf` does not have separate settings for different protocols
(e.g. HTTP, HTTPS, FTP), we need a way to specify which of the
configured proxies to use if there are multiple.  As such, the
*useproxy* role will attempt to use the value of the `dnf_proxy`
variable, if it is set, falling back to `yum_proxy` and finally
`http_proxy`.  This should cover most situations without any explicit
configuration, but allows flexibility for other cases.
2025-03-29 09:30:08 -05:00
Dustin cdd64b6309 unifi: Fix Promtail log scrape paths
The linuxserver.io Unifi container stored Unifi server and device logs
under `/var/lib/unifi/logs`, while the new container stores them under
`/var/log/unifi`.
2025-03-29 09:28:48 -05:00
Dustin 923c8a3ebc r/unifi: Open firewall port for syslog server
The Unifi Network controller runs a syslog server (listening on UDP port
5514) where Unifi devices can send their logs.  We need to open the port
in the firewall in order for it to receive log messages and write them
to disk.
2025-03-29 09:27:28 -05:00
Dustin 00acc54402 Merge branch 'unifi-redux' 2025-03-29 08:03:39 -05:00
Dustin 0c070c9807 gw1/squid: Allow Unifi controller to internal repos
I've move the Unifi controller back to running on a Fedora Linux
machine.  It therefore needs access to Fedora RPM repositories, as well
as the internal "dch" RPM repository, for system packages.

I also created a new custom container image for the Unifi Network
software (the linuxserver.io one sucks), so the server needs access to
the OCI repo on Gitea.
2025-03-29 08:01:50 -05:00
Dustin 0a956297c1 r/vmhost: Update for latest libvirt
Some time ago, _libvirt_ was refactored to use separate daemons and
sockets for each of its responsibilities, and the original "monolithic"
`libvirtd` was made obsolete.  The Fedora packages have more recently
been adjusted to favor this new approach, and now default to omitting
the monolithic daemon entirely (when `install_weak_deps` is disabled).

One interesting packaging snafu, though, is that without the weak
dependencies, there is _no_ way for clients to connect by default.
Clients run `which virt-ssh-helper` to see if it is installed, which it
is, but `which` is not.  They then fall back to running `nc`, which is
_also_ not installed.  So even though the tools they actually need are
present, their logic for detecting this is broken.  As such, we need to
explicitly install `which` to satisfy them.
2025-03-29 07:34:58 -05:00
Dustin 78d70af574 hosts: Add Unifi controllers to needproxy group
Since the network device management network does not have access to the
Internet, the Unifi controller machines must access it via the proxy.
2025-03-19 07:50:52 -05:00