Commit Graph

1160 Commits (fb935985869768691c0a07ce809d334a5487b688)

Author SHA1 Message Date
Dustin 24bf145a34 all: Do not auto-update on weekends
I don't want machines updating themselves, rebooting, and potentially
breaking stuff over the weekend.
2024-06-21 22:08:03 -05:00
Dustin 7579429a0d r/samba-cert: Save firewall configuration
Without making the firewall changes permanent, when a server tries to
renew its certificate after rebooting, it will fail as the ACME server
cannot connect to the HTTP port.
2024-06-20 19:42:13 -05:00
Dustin 88c45e22b6 vm-hosts: Update VM autostart for new DCs 2024-06-20 18:49:04 -05:00
Dustin 4bdd00d339 gw1: Do not reboot after dnf automatic updates
We don't want the firewall rebooting itself after kernel updates.
Instead, I will reboot it manually at the next appropriate time.
2024-06-13 08:10:55 -05:00
Dustin 8400024249 cloud0: Exclude Nextcloud trash from backups
Files in the Nextcloud trash bin do not need to be backed up.  They are
often large (i.e. my Signal backups), and presumably, they are not
needed anyway; why would they be in the trash otherwise?
2024-06-12 19:04:46 -05:00
Dustin 7b24babfab r/collectd-version: Auto-restart service
Sometimes, the `collectd-version` script crashes or fails to start at
boot.  Configuring systemd to automatically restart it will ensure that
it's always running, so machines' versions are consistently inventoried.
2024-06-12 19:03:11 -05:00
Dustin afcd2f2f05 hosts: Replace domain controllers
New AD DC servers run Fedora 40.  Their LDAP server certificates are
issued by *step-ca* via ACME, signed by *dch-ca r2*.

I've changed the naming convention for domain controllers again.  I
found the random sequenc of characters to be too difficult to remember
and identify.  Using a short random word (chosen from the EFF word list
used by Diceware) should be a lot nicer.  These names are chosen by the
`create-dc.sh` script.
2024-06-12 19:01:37 -05:00
Dustin eb9db2d729 create-dc: Add script to provision DC VMs
Since I don't like to update Samba Active Directory Domain Controller
servers in-place (it's never worked as well as you would think it
should), I want the process for replacing them to be as automated as
possible.  To that end, I've written `create-dc.sh`, which handles the
whole process of creating and configuring a new ADDC VM.  The only
things it doesn't do are transfer the FSMO roles and demote existing DC
servers.
2024-06-12 19:00:43 -05:00
Dustin 292ab4585c all: promtail: Update trusted CA certificate
Loki uses a certificate signed by *dch-ca r2* now (actually has for
quite some time...)
2024-06-12 18:57:01 -05:00
Dustin 092dcee508 fixup-dch-root-ca-r2 2024-06-12 18:56:41 -05:00
Dustin 1babedaf55 gw1: squid: Cache RPMs and installer images
Installing Fedora on a bunch of machines, simultaneously or in rapid
succession, can be painfully slow, as several large files need to be
downloaded.  To speed this up, we download those files via the proxy and
cache them on the proxy server.

As a side-effect, the proxy needs to allow access to the Kickstart
"server" (i.e. my workstation, at least for now), since Anaconda will
use the configured proxy for everything it downloads.
2024-06-12 18:54:29 -05:00
Dustin 9365fd2dd5 gw1: squid: Allow access to FCOS update servers
*unifi2.pyrocufflink.blue*, which is connected to the management
network, can only access the Internet via the proxy.  In order for
Zincati/`rpm-ostree` to automatically update the machine, the proxy
needs to allow access to the FCOS update servers.
2024-06-12 18:52:54 -05:00
Dustin 74e4a4d898 r/squid: Let squid initialize cache dirs
The `squid.service` systemd unit now correctly initializes the
configured cache directories, so we do not need to do it explicitly
before starting the server.
2024-06-12 18:43:23 -05:00
Dustin f54858ee5e r/dch-selinux: Install from dch-yum repository
The *dch-selinux* package is now published to the same Yum repository as
other packages (e.g. *sshca-cli*, etc.), rather than its own repository.
2024-06-12 18:42:22 -05:00
Dustin 9fdd2243a6 pyrocufflink: Trust DCH Root CA R2
Now that the domain controller servers use certificates issued by
*step-ca*, client applications need to trust that root CA certificate.
2024-06-12 18:40:17 -05:00
Dustin ffe972d79b r/samba-cert: Obtain LDAP/TLS cert via ACME
The *samba-cert* role configures `lego` and HAProxy to obtain an X.509
certificate via the ACME HTTP-01 challenge.  HAProxy is necessary
because LDAP server certificates need to have the apex domain in their
SAN field, and the ACME server may contact *any* domain controller
server with an A record for that name.  HAProxy will forward the
challenge request on to the first available host on port 5000, where
`lego` is listening to provide validation.

Issuing certificates this way has a couple of advantages:

1. No need for the wildcard certificate for the *pyrocufflink.blue*
   domain any more
2. Renewals are automatic and handled by the server itself rather than
   Ansible via scheduled Jenkins job

Item (2) is particularly interesting because it avoids the bi-monthly
issue where replacing the LDAP server certificate and restarting Samba
causes the Jenkins job to fail.

Naturally, for this to work correctly, all LDAP client applications
need to trust the certificates issued by the ACME server, in this case
*DCH Root CA R2*.
2024-06-12 18:33:24 -05:00
Dustin 7b6e0bd100 r/haproxy: Support configuring resolvers
HAProxy uses a special configuration block, `resolvers`, to specify
how it should look up names in DNS.  This configuration is used for
e.g. dynamically discovering backend servers via DNS A or SRV records.
Since resolvers are global, they need to be specified in the global
configuration file, rather than a per-application drop-in.

We will use this functionality for the ACME HTTP-01 challenge solver
for Samba AD domain controllers.
2024-06-12 18:29:56 -05:00
Dustin 29ef364fab r/haproxy: Clean up for modern haproxy versions
The current version of *haproxy* packaged in Fedora already enables
configuration via fragments in a drop-in directory, though it uses
a different path by default.  I still like separating the global
configuration from the defaults, though, and keeping the main
`haproxy.cfg` file empty.
2024-06-12 18:28:16 -05:00
Dustin 58972cf188 auto-updates: Install and configure dnf-automatic
*dnf-automatic* is an add-on for `dnf` that performs scheduled,
automatic updates.  It works pretty much how I would want it to:
triggered by a systemd timer, sends email reports upon completion, and
only reboots for kernel et al. updates.

In its default configuration, `dnf-automatic.timer` fires every day.  I
want machines to update weekly, but I want them to update on different
days (so as to avoid issues if all the machines reboot at once).  Thus,
the _dnf-automatic_ role uses a systemd unit extension to change the
schedule.  The day-of-the-week is chosen pseudo-randomly based on the
host name of the managed system.
2024-06-12 06:25:17 -05:00
Dustin af295cec1b r/bitwarden_rs: Fix EROFS when starting container
Even with `Network=host`, Podman tries to write to
`/etc/containers/network` for some reason.  Fortunately, it doesn't
actually need to, so we can trick it into working by mounting an empty
*tmpfs* filesystem there.
2024-05-28 08:25:08 -05:00
Dustin 4c0d5bb473 r/jellyfin: Fix EROFS when starting container
Even with `Network=host`, Podman tries to write to
`/etc/containers/network` for some reason.  Fortunately, it doesn't
actually need to, so we can trick it into working by mounting an empty
*tmpfs* filesystem there.
2024-05-26 12:03:14 -05:00
Dustin 1f86fa27b6 vm-hosts: Auto-start unifi2 2024-05-26 10:51:16 -05:00
Dustin 5a9b8b178a hosts: Decommission unifi1
*unifi1.pyrocufflink.blue* is being replaced with
*unifi2.pyrocufflink.blue*.  The new server runs Fedora CoreOS.
2024-05-26 10:50:32 -05:00
Dustin 541dd625b5 r/web/hlc: Proxy for Enrollment 2024 form
The summer 2024 enrollment form is more complicated than the other
forms on the HLC site, as it integrates directly with Invoice Ninja.  As
such, it's handled by a different backend, which runs in Kubernetes.
2024-04-02 09:25:47 -05:00
Dustin 06b399994e public-web: Add Tabitha's new SSH key
We got Nicepage to work on Tabitha's Fedora Thinkpad, so now she'll do
most of her website work on that machine.
2024-03-15 10:29:03 -05:00
Dustin c51589adff gw1: Scrape BIND DNS server logs
The BIND server on the firewall is configured to write query logs and
RPZ rewrite logs to files under `/var/log/named`.  We can scrape these
logs with Promtail and use the messages for analytics on the DNS-based
firewall, etc.
2024-02-28 19:06:23 -06:00
Dustin 0578736596 unifi: Scrape logs from UniFi and device syslog
The UniFi controller can act as a syslog server, receiving log messages
from managed devices and writing them to files in the `logs/remote`
directory under the application data directory.  We can scrape these
logs, in addition to the logs created by the UniFi server itself, with
Promtail to get more information about what's happening on the network.
2024-02-28 19:04:30 -06:00
Dustin d9f46d6d62 r/promtail: Optionally run with DAC_READ_SEARCH
The *promtail* service runs as an unprivileged user by default, which is
fine in most cases (i.e. when scraping only the Journal), but may not
always be sufficient to read logs from other files.  Rather than run
Promtail as root in these cases, we can assign it the
CAP_DAC_READ_SEARCH capability, which will allow it to read any file,
but does not grant it any of root's other privileges.

To enable this functionality, the `promtail_dac_read_search` Ansible
variable can be set to `true` for a host or group.  This will create a
systemd unit configuration extension that configures the service to have
the CAP_DAC_READ_SEARCH capability in its ambient set.
2024-02-28 19:00:26 -06:00
Dustin 6645ec36c1 r/dch-yum: Explicitly disable proxy for repo
*unifi1.pyrocufflink.blue* requires a proxy to access Yum repositories
on the Internet, so it has the `proxy` setting configured globally.  The
proxy does NOT allow access to internal resources, however.  The
internal repository is directly accessible by that machine, so it needs
to be configured thus.
2024-02-27 17:42:10 -06:00
Dustin 8c88e58655 r/squid: Send cache log to syslog
The Squid "cache log" is where it writes general debug and error
messages.  It is distinct from the "access log," which is where it
writes the status of every proxy request.  We already had the latter
configured to go to syslog by default (so it would be captured in the
journal), but missed the former.
2024-02-26 08:37:49 -06:00
Dustin b96164ce11 gw1: Allow rpm.grafana.com via proxy
In order to install Promtail on machines (e.g. *unifi1*) that do not
have direct access to the Internet.
2024-02-22 20:40:51 -06:00
Dustin 19009bde1a promtail: Role/Playbook to deploy Promtail
Promtail is the log sending client for Grafana Loki.  For traditional
Linux systems, an RPM package is available from upstream, making
installation fairly simple.  Configuration is stored in a YAML file, so
again, it's straightforward to configure via Ansible variables.  Really,
the only interesting step is adding the _promtail_ user, which is
created by the RPM package, to the _systemd-journal_ group, so that
Promtail can read the systemd journal files.
2024-02-22 19:23:31 -06:00
Dustin 226a9e05fa nut: Drop group
NUT is managed by _cfg.git_ now.
2024-02-22 10:24:16 -06:00
Dustin 39400f3b2f hosts: Remove vars for zbx0.p.b
This machine is long dead.
2024-02-22 10:23:19 -06:00
Dustin 493663e77f frigate: Drop group
Frigate is no longer managed by Ansible.  Dropping the group so the file
encrypted with Ansible Vault can go away.
2024-02-22 10:23:19 -06:00
Dustin fdc59fe73b pyrocufflink-dns: Drop group
The internal DNS server for the *pyrocufflink.blue* et al. domains runs
on the firewall now, and is thus no longer managed by Ansible.  Dropping
the group variables so the file encrypted with Ansible Vault can go
away.
2024-02-22 10:23:19 -06:00
Dustin 19d833cc76 websites/d&t.com: drop obsolete formsubmit config
The *dustinandtabitha.com* website no longer uses *formsubmit* (the time
for RSVP has **long** passed).  Removing the configuration so the
file encrypted with Ansible Vault can go away.
2024-02-22 10:23:19 -06:00
Dustin f9f8d5aa29 Remove grafana, metricspi groups
With the Metrics Pi decommissioned and Victoria Metrics and Grafana
running in Kubernetes now, these groups are no longer needed.
2024-02-22 10:23:19 -06:00
Dustin 4dd2db92a3 r/squid: Add missing private-tmp.conf file 2024-02-22 10:19:25 -06:00
Dustin 18aba01422 r/ssh-user-ca: Add missing handlers file 2024-02-22 10:16:48 -06:00
Dustin 7451026d75 r/collectd: Ignore efivarfs mounts
There's not much point in alerting based on the utilization of this
virtual filesystem.
2024-02-16 20:24:46 -06:00
Dustin 13e6433fff hosts: Remove logs0.p.b
Decommissioning Graylog
2024-02-13 16:12:20 -06:00
Dustin 323ffa3426 r/ssh-user-ca: Remove old AuthorizedKeysCommand
A few hosts have `AuthorizedKeysCommand` set in their *sshd(8)*
configuration.  This was my first attempt at centrally managing SSH
keys, using a script which fetched a list of keys for each user from an
HTTP server.  This worked most of the time, but I didn't take good care
of the HTTP server, so the script would fail frequently.  Now that all
hosts trust the SSH user CA, there is no longer any need for this
"feature."
2024-02-01 19:27:52 -06:00
Dustin f83cea50e9 r/ssu-user-ca: Configure sshd TrustedUserCAKeys
The `TrustedUserCAKeys` setting for *sshd(8)* tells the server to accept
any certificates signed by keys listed in the specified file.
The authenticating username has to match one of the principals listed in
the certificate, of course.

This role is applied to all machines, via the `base.yml` playbook.
Certificates issued by the user CA managed by SSHCA will therefore be
trusted everywhere.  This brings us one step closer to eliminating the
dependency on Active Directory/Samba.
2024-02-01 18:46:40 -06:00
Dustin 0d30e54fd5 r/fileserver: Restrict non-administrators to SFTP
Normal users do not need shell access to the file server, and certainly
should not be allowed to e.g. forward ports through it.  Using a `Match`
block, we can apply restrictions to users who do not need administrative
functionality.  In this case, we restrict everyone who is not a member
of the *Server Admins* group in the PYROCUFFLINK AD domain.
2024-02-01 10:29:32 -06:00
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