Commit Graph

227 Commits (d0bf4f9893a364c0fc5848f0dfb1ca996d3dc6f2)

Author SHA1 Message Date
Dustin 2da26d9bf6 roles/bitwarden_rs: Ensure docker service runs
Since the *bitwarden_rs* relies on Docker for distribution and process
management (at least for now), it needs to ensure that the `docker`
service starts automatically.
2020-12-30 21:02:32 -06:00
Dustin f9e8c78e5a roles/websites: Set authorized_keys file perms
Because the various "webapp.*" users' home directories are under
`/srv/www`, the default SELinux context type is `httpd_sys_content_t`.
The SSH daemon is not allowed to read files with this label, so it
cannot load the contents of these users' `authorized_keys` files.  To
address this, we have to explicitly set the SELinux type to
`ssh_home_t`.
2020-12-30 20:59:27 -06:00
Dustin c92af29e84 roles/named: Send application logs to syslog
BIND sends its normal application logs (as opposed to query logs) to the
`default_debug` channel.  By sending these log messages to syslog, they
can be routed and rotated using the normal system policies.  Using a
separate dedicated log file just ends up consuming a lot of space, as it
is not managed by any policy.
2020-12-26 11:36:15 -06:00
Dustin 59e8244a08 roles/apache: Add tags to tasks
Adding tags to tasks makes them easier to run in isolation.
2020-12-26 11:35:45 -06:00
Dustin aa1ab75edd roles/apache: logrotate: Compress logs immediately
To conserve space on the log volume of web servers, "old" log files are
now compressed immediately, as opposed to waiting until the next
rotation.
2020-12-26 11:33:09 -06:00
Dustin b519f97f6a roles/apache: Disable ssl_request_log
I am not sure the point of having both `ssl_request_log` and
`ssl_access_log`.  The former includes the TLS ciphers used in the
connection, which is not particularly interesting information.  To save
space on the log volume of web servers using Apache, we should just stop
creating this log file.
2020-12-26 11:31:24 -06:00
Dustin d1cdc8bfc3 roles/cert: Add handler topic notification
Changing/renewing a certificate generally requires restarting or
reloading some service.  Since the *cert* role is intended to be generic
and reusable, it naturally does not know what action to take to effect
the change.  It works well for the initial deployment of a new
application, since the service is reloaded anyway in order for the new
configuration to be applied.  It fails, however, for continuous
enforcement, when a certificate is renewed automatically (i.e. by
`lego`) but no other changes are being made.  This has caused a number
of disruptions when some certificate expires and its replacement is
available but has not yet been loaded.

To address this issue, I have added a handler "topic" notification to
the *certs* role.  When either the certificate or private key file is
replaced, the relevant task will "notify" a generic handler "topic."
This allows some other role to define a specific handler, which
"listens" for these notifications, and takes the appropriate action for
its respective service.

For this mechanism to work, though, the *cert* role can only be used as
a dependency of another role.  That role must define the handler and
configure it to listen to the generic "certificate changed" topic.  As
such, each of the roles that are associated with a certificate deployed
by the *cert* role now declare it as a dependency, and the top-level
playbooks only include those roles.
2020-12-26 10:38:17 -06:00
Dustin 8a18c92730 roles/collectd-prometheus: Configure plugin
The *collectd-prometheus* role configures the *write_prometheus* plugin
for collectd.  This plugin exposes data collected or received by the
collectd process in the Prometheus Exposition Format over HTTP.  It
provides the same functionality as the "official" collectd Exporter
maintained by the Prometheus team, but integrates natively into the
collectd process, and is much more complete.

The main intent of this role is to provide a mechanism to combine the
collectd data from all Pyrocufflink hosts and insert it into Prometheus.
By configuring the collectd instance on the Prometheus server itself to
enable and use the *write_prometheus* plugin and to receive the
multicast data from other hosts, collectd itself provides the desired
functionality.
2020-12-26 09:44:04 -06:00
Dustin 8e180d00ab collectd: Ensure service is enabled 2020-12-23 21:25:49 -06:00
Dustin 8d442b2aaf roles/collectd: Support setting server interface
For hosts with multiple network interfaces, collectd may not send
multicast messages through the correct interface.  To ensure that it
does, the `Interface` configuration option can be specified with each
`Server` option.  To define this option, entries in the
`collectd_network_servers` list can now have an `interface` property.
2020-12-23 20:54:48 -06:00
Dustin cbbef24bbd collectd: Install and configure collectd
The *collectd* role, with its corresponding `collectd.yml` playbook,
installs *collectd* onto the managed node and manages basic
configuration for it.  By default, it will enable several plugins,
including the `network` plugin.  The `collectd_disable_plugins` variable
can be set to a list names of plugins that should NOT be enabled.

The default configuration for the `network` plugin instructs *collectd*
to send metrics to the default IPv6 multicast group.  Any host that has
joined this group and is listening on the specified UDP port (default
25826) can receive the data.  This allows for nearly zero configuration,
as the configuration does not need to be updated if the name or IP
address of the receiver changes.

This configuration is ready to be deployed without any variable changes
to all Pyrocufflink servers.  Once *collectd* is running on the servers,
we can set up a *collectd* instance to receive the data and store them
in a time series database (i.e. Prometheus).
2020-12-08 21:11:27 -06:00
Dustin 750cc8afd4 roles/logrotate: Install and enable logrotate
Since Apache HTTPD does not have any built-in log rotation capability,
we need `logrotate`.  Somewhere along the line, the *logrotate* package
stopped being installed by default.  Additionally, with Fedora 30, it
changed from including a drop-in file for (Ana)cron to providing a
systemd timer unit.

The *logrotate* role will ensure that the *logrotate* package is
installed, and that the *logrotate.timer* service is enabled and
running.  This in turn will ensure that `logrotate` runs daily.  Of
course, since the systemd units were added in Fedora 30, machines to
which this role is applied must be running at least that version.

By listing the *logrotate* role as a dependency of the *httpd* role, we
can ensure that `logrotate` manages the Apache error and access log
files on any server that runs Apache HTTPD.
2020-12-08 20:59:40 -06:00
Dustin 1e42959863 roles/bitwarden_rs: Update to new Docker image
The bitwarden_rs team now maintains its Docker images under the
*bitwardenrs* namespace on Docker Hub.
2020-11-13 06:52:56 -06:00
Dustin 132689a3b8 roles/protonvpn: Set infinite keying retries
By default, strongSwan will only attempt key negotiation once and then
give up.  If the VPN connection is closed because of a network issue, it
is unlikely that a single attempt to reconnect will work, so let's keep
trying until it succeeds.
2020-10-10 11:10:12 -05:00
Dustin 3a36d6b7ff hosts: Add motion0.p.b
*motion0.pyrocufflink.blue* hosts motionEye
2020-10-03 11:30:38 -05:00
Dustin ef4e769ed2 motioneye: Deploy motionEye camera software
The *motioneye* role installs motionEye on a Fedora machine using `pip`.
It configures Apache to proxy for motionEye for outside (HTTPS) access.

The official installation instructions and default configuration for
motionEye assume it will be running as root.  There is, however, no
specific reason for this, as it works just fine as an unprivileged user.
The only minor surprise is that the `conf_path` configuration setting
must be writable, as this is where motionEye places generated
configuration for `motion`.  This path does not, however, have to
include the `motioneye.conf` file itself, which can still be read-only.
2020-10-03 11:29:39 -05:00
Dustin 8ca093050b pyrocufflink-dns: Cloudflare over ProtonVPN
This commit adds a new playbook, `protonvpn.yml`, and its supporting
roles *strongswan-swanctl* and *protonvpn*.  This playbook configures
strongSwan to connect to ProtonVPN using IPsec/IKEv2.

With this playbook, we configure the name servers on the Pyrocufflink
network to route all DNS requests through the Cloudflare public DNS
recursive servers at 1.1.1.1/1.0.0.1 over ProtonVPN.  Using this setup,
we have the benefit of the speed of using a public DNS server (which is
*significantly* faster than running our own recursive server, usually by
1-2 seconds per request), and the benefit of anonymity from ProtonVPN.

Using the public DNS server alone is great for performance, but allows
the server operator (in this case Cloudflare) to track and analyze usage
patterns.  Using ProtonVPN gives us anonymity (assuming we trust
ProtonVPN not to do the very same tracking), but can have a negative
performance impact if its used for all Internet traffic.  By combining
these solutions, we can get the benefits of both!
2020-09-06 11:06:58 -05:00
Dustin f536c9633e roles/named: Support logging queries to syslog
This commit adds two new variables to the *named* role:
`named_queries_syslog` and `named_rpz_syslog`.  These variables control
whether BIND will send query and RPZ log messages to the local syslog
daemon, respectively.
2020-09-06 10:40:27 -05:00
Dustin 84313601ef roles/named: Implement response policy zones
BIND response policy zones (RPZ) support provides a mechanism for
overriding the responses to DNS queries based on a wide range of
criteria.  In the simplest form, a response policy zone can be used to
provide different responses to different clients, or "block" some DNS
names.

For the Pyrocufflink and related networks, I plan to use an RPZ to
implement ad/tracker blocking.  The goal will be to generate an RPZ
definition from a collection of host lists (e.g. those used by uBlock
Origin) periodically.

This commit introduces basic support for RPZ configuration in the
*named* role.  It can be activated by providing a list of "response
policy" definitions (e.g. `zone "name"`) in the `named_response_policy`
variable, and defining the corresponding zones in `named_zones`.
2020-09-06 10:40:01 -05:00
Dustin 44404950c1 Merge branch 'graylog' into master 2020-08-31 20:17:12 -05:00
Dustin b32b4a2c99 roles/ssh-hostkeys: Add missing host keys
Several new hosts did not have recorded SSH host keys:

* build1-aarch64
* build2-armv7hl
* hass1
* hassdb0
2020-08-28 21:17:02 -05:00
Dustin f1b4598601 roles/hassdb: Deploy Home Assistant database
Normally, Home Assistant uses a SQLite database for storing state
history.  On a Raspberry Pi with only an SD card for storage like
*hass1.pyrocufflink.blue*, this can become extremely slow, especially
for large data sets.  To speed up features like history and logbook,
Home Assistant supports using an external database engine such as
PostgreSQL or MariaDB.

The *hassdb* role and corresponding `hassdb.yml` playbook deploys a
PostgreSQL server for Home Assistant to use.  It needs only to create
the role and database, as Home Assistant manages its own schema.
2020-07-14 11:38:30 -05:00
Dustin a614f7b5c7 roles/postgresql-server: Remove postgresql-setup
The *postgresql-setup* service is no longer necessary, as upstream has
fixed the SELinux policy to allow root to invoke the `postgresql-setup`
command directly.
2020-07-14 10:56:01 -05:00
Dustin f4e5aacf52 roles/postgresql-server: Support SSL configuration
This commit adds a task to generate a PostgreSQL configuration file from
a template.  Previously, the default configuration file generated by
`initdb` was sufficient, but in order to enable SSL connections, some
changes to it are required.

Naturally, SSL connections require a server certificate, so the
*postgresql-server* role will now also copy certificate files to the
managed node, if any.
2020-07-14 10:52:25 -05:00
Dustin add233b9e8 roles/strongswan: Update service name
Fedora has renamed the *strongswan* service to *strongswan-starter*.
The *strongswan* service now controls strongSwan via Vici, which uses a
different configuration format and is not compatible with the files in
`/etc/strongswan/ipsec.d`.  As I am migrating everything to Wireguard
now, it does not make sense to rewrite all of the IPsec configuration in
this new format, so using the legacy format with the renamed service
makes more sense.
2020-07-04 14:32:22 -05:00
Dustin 7a4b46b455 Merge branch 'hass1' 2020-07-04 14:26:13 -05:00
Dustin b4db8eb74d roles/homeassistant: Add HTTPS redirect
Enforce HTTPS access to Home Assistant web UI using a redirect and HSTS.
2020-07-04 14:25:16 -05:00
Dustin b99c7aa27d roles/homeassistant: Install in a virtualenv
Because the Home Assistant user's home directory is on `/var`, Python
packages installed in the "user site" do not get the correct SELinux
labels and thus run in the wrong domain.  This causes a lot of AVC
denials and other issues that prevent Home Assistant from working
correctly.

To resolve this issue, Home Assistant is now installed in a virtual
environment at `/usr/local/homeassistant`.  This directory is still
owned by the Home Assistant user, allowing Home Assistant to manage
packages installed there.  Since it is rooted under `/usr`, files are
labelled correctly and processes launched from executables there will
run in the correct domain.
2020-07-04 14:25:16 -05:00
Dustin 0a48d1f325 roles/net-ifaces: Update VLAN for pyrocufflink.blue
The main network, *pyrocufflink.blue* (172.30.0.0/26) is now on VLAN 1
instead of VLAN 30.  This changed when I replaced the Cisco SG200-26
with the UniFI Switch 48, to simplify configuration of all of the
Ubiquiti devices.
2020-05-25 09:17:24 -05:00
Dustin e0624a62cf roles/nextcloud: Update to 18.0.2 2020-03-22 11:26:20 -05:00
Dustin 4c661478b2 hosts: bw0: Use Lego cert 2020-03-17 08:45:34 -05:00
Dustin bb73d28c05 websites/darkchestofwonders.us: Use Lego cert 2020-03-17 08:45:34 -05:00
Dustin e4ecd5d58a websites/proxy: Add reverse proxy configuration
For some time, I have been trying to design a new configuration for the
reverse proxy on port 443 to correctly handle all the types of traffic
on that port.  In the original implementation, all traffic on port 443
was forwarded by the gateway to HAProxy.  HAproxy then used TLS SNI to
route connections to the correct backend server based the requested host
name.  This allowed both HTTPS and OpenVPN-over-TLS to use the same
port, however it was not without issues.  A layer 4 (TCP) proxy like
this "hides" the real source address of clients connecting to the
backend, which makes IP-based security (e.g. rate limiting, blacklists,
etc.) impossible at the application level.  In particular, Nextcloud,
which implements rate limiting was constantly imposing login delays on
all users, because legitimate traffic was indistinguishable from
Internet background noise.

To alleviate these issues, I needed to change the proxy to operate in
layer 7 (HTTP) mode, so that headers like *X-Forwarded-For* and
*X-Forwarded-Host* could be added.  Unfortunately, this was not easy,
because of the simultaneous requirement to forward OpenVPN traffic.
HAProxy can only do SNI inspection in TCP mode.  So, I began looking for
an alternate way to proxy both HTTP and non-HTTP traffic on the same
port.

The HTTP protocol defines the `CONNECT` method, which is used by forward
proxies to tunnel HTTPS over plain HTTP.  OpenVPN clients support
tunneling OpenVPN over HTTP using this method as well.  HAProxy has
limited support for the CONNECT method (i.e. it doesn't do DNS
resolution, and I could find no way of restricting the destination) with
the `http_proxy` option, so I looked for alternate proxy servers that
had more complete support.  Unsurprisingly, Apache HTTPD has the most
complete implementation of the `CONNECT` method (Nginx doesn't support
it at all).  Using a name-based virtual host on port 443, Apache will
accept requests for *vpn.pyrocufflink.net* (using TLS SNI) and allow the
clients to use the `CONNECT` method to create a tunnel to the OpenVPN
server.  This requires OpenVPN clients to a) use *stunnel* to wrap plain
HTTP proxy connections in TLS and b) configure OpenVPN to use the
TLS-wrapped HTTP proxy.

With Apache accepting all incoming connections, it was trivial to also
configure it as a layer 7 forward proxy for Bitwarden, Gitea, Jenkins,
and Nextcloud.  Unfortunately, proxying for the other websites
(darkchestofwonders.us, chmod777.sh, dustin.hatch.name) was not quite as
straightforward.  These websites would need to have an internal name
that differed from their external name, and thus a certificate valid for
that name.  Rather than reconfigure all of these sites and set all of
that up, I decided to just move the responsibility for handling direct
connections from outside to the *web0* and eliminate the dedicated
reverse proxy.  This was not possible before, because Apache could not
forward the OpenVPN traffic directly, but now with the forward proxy
configuration, there is no reason to have a separate server for these
connections.

Overall, I am pleased with how this turned out.  It makes the OpenVPN
configuration simpler (*stunnel* no longer needs to run on the OpenVPN
server itself, since Apache is handling TLS termination), eliminates a
network hop for the websites, makes the reverse proxy configuration for
the other web applications much easier to understand, and resolves the
original issue of losing client connection information.
2020-03-16 14:19:08 -05:00
Dustin 1de8e9fa90 websites/pyrocufflink.net: Add HTTP virtual host
A name-based HTTP (not HTTPS)  virtual host for *pyrocufflink.net* is
necessary to ensure requests are handled properly, now that there is
another HTTP virtual host (chmod777.sh) defined on the same server.
2020-03-16 14:17:51 -05:00
Dustin 0694594445 websites/pyrocufflink.net: Use lego certificate
This commit updates the configuration for *pyrocufflink.net* to use the
wildcard certificate managed by *lego* instead of an unique certificate
managed by *certbot*.
2020-03-16 14:16:34 -05:00
Dustin db6d13013a websites: Add chmod777.sh
*chmod777.sh* is a simple static website, generated by Hugo.  It is
built and published from a Jenkins pipeline, which runs automatically
when new commits are pushed to Gitea.

The HTTPS certificate for this site is signed by Let's Encrypt and
managed by `lego` in the `certs` submodule.
2020-03-09 20:29:52 -05:00
Dustin 2b49c5a02e roles/dch-proxy: Configure proxy for Nextcloud
This commit adds front-end and back-end configuration for HAProxy to
proxy HTTP/HTTPS for
*nextcloud.pyrocufflink.net*/*nextcloud.pyrocufflink.blue* to
*cloud0.pyrocufflink.blue*.
2020-03-09 20:24:28 -05:00
Dustin b09bf84a3b nextcloud: Deploy Nextcloud w/ Apache+PHP-FPM
The *nextcloud* role installs Nextcloud from the specified release
archive, downloading it to the control machine first if necessary, and
configures Apache and PHP-FPM to serve it.

The `nextcloud.yml` playbook uses the *cert* role to install the X.509
certificate for the Nextcloud server, sets up Apache HTTPD with the
*apache* role, and installs Nextcloud using the *nextcloud* role.

The host *cloud0.pyrocufflink.blue* is the Nextcloud server for
Pyrocufflink.
2020-03-09 20:18:07 -05:00
Dustin 2aaf8c5239 roles/cert: Common role for installing certs
The *cert* role is intended to be a generic, reusable role to copy an
X.509 certificate and/or private key file to managed nodes.  It is
intended to be included in a playbook with at least the `cert_src` and
`cert_dest` variables defined, e.g.:

```
- hosts: whatever
  roles:
  - role: cert
    cert_src: whatever.cer
    cert_dest: /path/to/whatever.cer
```
2020-03-09 20:17:47 -05:00
Dustin dd0892e208 roles/haproxy: Fix undefined var on Fedora hosts
the `haproxy_ssl_default_bind_options` variable is not defined for
machines running Fedora, because this parameter is not used in the
default configuration file there.
2020-03-03 19:27:19 -06:00
Dustin cd1cf38774 hosts: git0: Switch to Lego wildcard cert 2020-02-22 16:43:46 -06:00
Dustin f8b7f28469 roles/gitea: Install from upstream binary
I seem to have forgotten how I got the RPM for Gitea.  I think I built
it, but I cannot find the spec file, nor the RPM package.  Since this is
clearly not reproducible, I decided to switch to using the binary
provided by upstream for now, until either I or Fedora get around to
making a better RPM.

Installing Gitea from the upstream binary is simple: just download it
and copy it to `/usr/local/bin`.  Of course, the OS user and systemd
unit have to be managed by configuration policy when it's installed this
way.
2020-02-22 16:43:46 -06:00
Dustin 7543815e9b hosts: Add burp1.p.b
*burp1.pyrocufflink.blue* will replace *burp0.pyrocufflink.blue* as the
BURP server for Pyrocufflink.  It is a physical machine (Fitlet), making
it simpler to manage the USB drives.  The old virtual machine will be
decommissioned soon.
2020-01-25 13:57:04 -06:00
Dustin d290eca833 roles/burp-server: switch to version_compare test
Ansible replaced the `version_compare` filter with a `version_compare`
test that does the same thing.  The former is completely gone now,
causing the template to fail to render, so its usage of that filter
needs to be updated.
2020-01-25 13:54:42 -06:00
Dustin 87843e5926 burp-client: Use burp.p.b name
Using the generic *burp.pyrocufflink.blue* name will allow easier
transition to a new BURP server.  However, since this is not the actual
name, it cannot be used for task delegation, so a separate variable is
required to store the real name of the BURP server.  This is only used
during client deployment, and not by BURP itself.
2020-01-18 12:10:53 -06:00
Dustin e25b9a2e8e hosts: Add logs0.p.b
*logs0.pyrocufflink.blue* hosts Graylog
2019-10-28 18:47:09 -05:00
Dustin 3aad9c1dda roles/graylog: Add Graylog server deployment
The *graylog* role installs Graylog from the *graylog2.org* Yum
repository and manages basic server configuration.  It augments the
default systemd unit to provide the `CAP_NET_BIND_SERVICE` capability to
the Graylog server process via ambient capabilities, thereby allowing
the server to bind to the privileged Syslog UDP port.
2019-10-28 18:47:09 -05:00
Dustin 07eb3633e3 roles/mongodb: Add MongoDB deployment
The *mongodb* role installs MongoDB from the *mongodb.org* Yum
repository and manages basic server configuration.
2019-10-28 18:34:45 -05:00
Dustin dd4ccb3a32 roles/elasticsearch: Add Elasticsearch deployment
The *elasticsearch* role installs Elasticsearch from the Elastic.co Yum
repository and manages basic node configuration.
2019-10-28 18:33:37 -05:00
Dustin c57de29054 roles/hass-dhcp: Enable DNS query logging 2019-09-19 19:50:35 -05:00