From 3135f90223570612df9de6c07595d85654ddfb64 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Sat, 25 May 2024 12:55:51 -0500 Subject: [PATCH] unifi: Deploy Unifi controller The Unifi controller consists of three containerized processes: * Unifi Network itself * unifi_exporter for monitoring and metrics via Prometheus * Caddy for HTTPS _unifi_exporter_ is really the only component with any configuration. Unfortunately, it mixes secret and non-secret data in a single YAML file, which makes it impossible to use `yaml.Marshal` to render the configuration directly from the CUE source. --- app/unifi/templates.cue | 61 +++++++++++++++++++++++ env/prod/unifi.cue | 29 +++++++++++ host/unifi2.pyrocufflink.blue.cue | 16 ++++++ host/unifi2.pyrocufflink.blue.post.sh | 3 ++ host/unifi2.pyrocufflink.blue.pre.sh | 5 ++ instructions/unifi2.pyrocufflink.blue.cue | 17 +++++++ templates/unifi/Caddyfile | 13 +++++ templates/unifi/unifi.container | 36 +++++++++++++ templates/unifi/unifi.pod | 3 ++ templates/unifi/unifi.sysusers | 2 + templates/unifi/unifi_exporter.container | 32 ++++++++++++ templates/unifi/unifi_exporter.yml | 11 ++++ 12 files changed, 228 insertions(+) create mode 100644 app/unifi/templates.cue create mode 100644 env/prod/unifi.cue create mode 100644 host/unifi2.pyrocufflink.blue.cue create mode 100644 host/unifi2.pyrocufflink.blue.post.sh create mode 100644 host/unifi2.pyrocufflink.blue.pre.sh create mode 100644 instructions/unifi2.pyrocufflink.blue.cue create mode 100644 templates/unifi/Caddyfile create mode 100644 templates/unifi/unifi.container create mode 100644 templates/unifi/unifi.pod create mode 100644 templates/unifi/unifi.sysusers create mode 100644 templates/unifi/unifi_exporter.container create mode 100644 templates/unifi/unifi_exporter.yml diff --git a/app/unifi/templates.cue b/app/unifi/templates.cue new file mode 100644 index 0000000..84c163b --- /dev/null +++ b/app/unifi/templates.cue @@ -0,0 +1,61 @@ +package unifi + +import "du5t1n.me/cfg/base/schema/instructions" + +import "du5t1n.me/cfg/app/caddy" + +templates: [...instructions.#RenderInstruction] & [ + { + template: "unifi/unifi.sysusers" + dest: "/etc/sysusers.d/unifi.conf" + hooks: changed: [ + { + run: "systemd-sysusers /etc/sysusers.d/unifi.conf" + immediate: true + }, + ] + }, + { + template: "unifi/unifi_exporter.yml" + dest: "/etc/unifi_exporter.yml" + hooks: { + changed: [{run: "systemctl restart unifi_exporter"}] + } + }, + { + template: "unifi/unifi.pod" + dest: "/etc/containers/systemd/unifi.pod" + hooks: { + changed: [ + {run: "systemctl daemon-reload", immediate: true}, + ] + } + }, + { + template: "unifi/unifi.container" + dest: "/etc/containers/systemd/unifi.container" + hooks: { + changed: [ + {run: "systemctl daemon-reload", immediate: true}, + {run: "systemctl restart unifi"}, + ] + } + }, + { + template: "unifi/unifi_exporter.container" + dest: "/etc/containers/systemd/unifi_exporter.container" + hooks: { + changed: [ + {run: "systemctl daemon-reload", immediate: true}, + {run: "systemctl restart unifi_exporter"}, + ] + } + }, + { + template: "unifi/Caddyfile" + dest: "/etc/caddy/Caddyfile" + hooks: { + changed: [{run: "systemctl restart caddy"}] + } + }, +]+caddy.templates diff --git a/env/prod/unifi.cue b/env/prod/unifi.cue new file mode 100644 index 0000000..323911c --- /dev/null +++ b/env/prod/unifi.cue @@ -0,0 +1,29 @@ +package prod + +unifi: caddy: { + server_name: "unifi.pyrocufflink.blue" + acme: email: "unifi@pyrocufflink.blue" +} + +unifi: exporter: { + listen: { + address: ":9130" + metricspath: "/metrics" + } + unifi: { + address: "https://localhost:8443/" + insecure: true + password: """ + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvRVBncFB6YnJsYmlQSnJN + YXVqclJVTGV4eTRkd3JWbFhZOXN4WWJYc1NVCnlXdElESWJNdVcxRnZodnVUTlF5 + d2ovRjNNeE9jV25IOW01MERIM1ZKZnMKLS0tIEFneVBWdHVobzZBTlBvZjZaMHJp + T3A4WTRYaDd1RFduVVBnQ3hXSkE0WmcKEFBdNfdUTZSo7ebqcIcl9qckp/zc0Mf6 + LV9pZz8v3n9NO9fnF/vzXJrGyaJlzv3H + -----END AGE ENCRYPTED FILE----- + """ + site: "Pyrocufflink" + timeout: "5s" + username: "prometheus" + } +} diff --git a/host/unifi2.pyrocufflink.blue.cue b/host/unifi2.pyrocufflink.blue.cue new file mode 100644 index 0000000..380e896 --- /dev/null +++ b/host/unifi2.pyrocufflink.blue.cue @@ -0,0 +1,16 @@ +package unifi2 + +import ( + "du5t1n.me/cfg/env/prod" +) + +ssh: prod.ssh +sudo: prod.sudo + +promtail: prod.#promtail + +collectd: prod.collectd + +unifi: prod.unifi + +caddy: prod.caddy diff --git a/host/unifi2.pyrocufflink.blue.post.sh b/host/unifi2.pyrocufflink.blue.post.sh new file mode 100644 index 0000000..8f77fd5 --- /dev/null +++ b/host/unifi2.pyrocufflink.blue.post.sh @@ -0,0 +1,3 @@ +. scripts/no-coreos-default-sudo.sh + +systemctl start unifi diff --git a/host/unifi2.pyrocufflink.blue.pre.sh b/host/unifi2.pyrocufflink.blue.pre.sh new file mode 100644 index 0000000..92a083e --- /dev/null +++ b/host/unifi2.pyrocufflink.blue.pre.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +. scripts/pam-ssh-agent-auth.sh + +install_packages diff --git a/instructions/unifi2.pyrocufflink.blue.cue b/instructions/unifi2.pyrocufflink.blue.cue new file mode 100644 index 0000000..94b50fb --- /dev/null +++ b/instructions/unifi2.pyrocufflink.blue.cue @@ -0,0 +1,17 @@ +package unifi2 + +import ( + "list" + + "du5t1n.me/cfg/app/collectd" + "du5t1n.me/cfg/app/promtail" + "du5t1n.me/cfg/app/unifi" + "du5t1n.me/cfg/env/prod" +) + +render: list.Concat([ + prod.templates, + collectd.templates, + promtail.templates, + unifi.templates, +]) diff --git a/templates/unifi/Caddyfile b/templates/unifi/Caddyfile new file mode 100644 index 0000000..16e95da --- /dev/null +++ b/templates/unifi/Caddyfile @@ -0,0 +1,13 @@ +{# vim: set ft=jinja : -#} +{{ unifi.caddy.server_name }} { + reverse_proxy https://localhost:8443 { + transport http { + tls_insecure_skip_verify + } + } + + tls {{ unifi.caddy.acme.email }} { + ca {{ caddy.acme.url }} + ca_root /etc/caddy/acme-ca.crt + } +} diff --git a/templates/unifi/unifi.container b/templates/unifi/unifi.container new file mode 100644 index 0000000..84fbcc5 --- /dev/null +++ b/templates/unifi/unifi.container @@ -0,0 +1,36 @@ +[Unit] +Description=Unifi Network +Wants=network.target +After=network.target + +[Container] +Image=lscr.io/linuxserver/unifi-controller +Volume=/var/lib/unifi:/config:rw,Z +NoNewPrivileges=yes +UserNS=auto:gidmapping=911:911:1,uidmapping=911:911:1 +VolatileTmp=yes +Notify=yes +Pod=unifi.pod +PublishPort=6789:6789 +PublishPort=8080:8080 +PublishPort=8443:8443 +PublishPort=8843:8843 +PublishPort=8880:8880 + +[Service] +TimeoutStartSec=5min +Restart=always +PrivateTmp=yes +ProtectClock=yes +ProtectHome=yes +ProtectKernelModules=yes +ProtectProc=invisible +ProtectSystem=strict +ReadWritePaths=/run +ReadWritePaths=/var/lib/containers/storage +ReadWritePaths=/var/lib/unifi +RestrictRealtime=yes +UMask=0077 + +[Install] +WantedBy=multi-user.target diff --git a/templates/unifi/unifi.pod b/templates/unifi/unifi.pod new file mode 100644 index 0000000..82897db --- /dev/null +++ b/templates/unifi/unifi.pod @@ -0,0 +1,3 @@ +{# vim: set ft=systemd.jinja : -#} +[Pod] +PodName=unifi diff --git a/templates/unifi/unifi.sysusers b/templates/unifi/unifi.sysusers new file mode 100644 index 0000000..ded3312 --- /dev/null +++ b/templates/unifi/unifi.sysusers @@ -0,0 +1,2 @@ +g unifi 911 +u unifi 911:911 "Unifi" /var/lib/unifi /sbin/nologin diff --git a/templates/unifi/unifi_exporter.container b/templates/unifi/unifi_exporter.container new file mode 100644 index 0000000..35068d2 --- /dev/null +++ b/templates/unifi/unifi_exporter.container @@ -0,0 +1,32 @@ +[Unit] +Description=Prometheus metrics exporter for Unifi Controller +Wants=unifi.service +After=unifi.service + +[Container] +Image=docker.io/jessestuart/unifi_exporter:v0.4.0 +Volume=/etc/unifi_exporter.yml:/etc/unifi_exporter.yml:ro +NoNewPrivileges=yes +Exec=-config.file /etc/unifi_exporter.yml +User=200 +Group=200 +VolatileTmp=yes +Pod=unifi.pod +PublishPort=9130:9130 + +[Service] +Restart=always +RestartSec=2 +PrivateTmp=yes +ProtectClock=yes +ProtectHome=yes +ProtectKernelModules=yes +ProtectProc=invisible +ProtectSystem=strict +ReadWritePaths=/run +ReadWritePaths=/var/lib/containers/storage +RestrictRealtime=yes +UMask=0077 + +[Install] +WantedBy=multi-user.target diff --git a/templates/unifi/unifi_exporter.yml b/templates/unifi/unifi_exporter.yml new file mode 100644 index 0000000..98b069a --- /dev/null +++ b/templates/unifi/unifi_exporter.yml @@ -0,0 +1,11 @@ +{#- vim: set ft=yaml.jinja : -#} +listen: + address: {{ unifi.exporter.listen.address }} + metricspath: {{ unifi.exporter.listen.metricspath }} +unifi: + address: {{ unifi.exporter.unifi.address }} + insecure: {{ unifi.exporter.unifi.insecure }} + password: {{ unifi.exporter.unifi.password | decrypt }} + site: {{ unifi.exporter.unifi.site }} + timeout: {{ unifi.exporter.unifi.timeout }} + username: {{ unifi.exporter.unifi.username }}