From 7b61a7da7e95734c95d8fff9e63b9057cdf732b7 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 17:44:10 -0500 Subject: [PATCH 01/15] r/useproxy: Configure system-wide proxy The *useproxy* role configures the `http_proxy` et al. environmet variables for systemd services and interactive shells. Additionally, it configures Yum repositories to use a single mirror via the `baseurl` setting, rather than a list of mirrors via `metalink`, since the proxy a) the proxy only allows access to _dl.fedoraproject.org_ and b) the proxy caches RPM files, but this is only effective if all clients use the same mirror all the time. The `useproxy.yml` playbook applies this role to servers in the *needproxy* group. --- group_vars/Fedora.yml | 10 ++++ group_vars/needproxy.yml | 4 ++ hosts | 2 + roles/useproxy/defaults/main.yml | 1 + roles/useproxy/handlers/main.yml | 6 +++ roles/useproxy/tasks/main.yml | 73 +++++++++++++++++++++++++++ roles/useproxy/templates/proxy.env.j2 | 16 ++++++ useproxy.yml | 5 ++ 8 files changed, 117 insertions(+) create mode 100644 group_vars/Fedora.yml create mode 100644 group_vars/needproxy.yml create mode 100644 roles/useproxy/defaults/main.yml create mode 100644 roles/useproxy/handlers/main.yml create mode 100644 roles/useproxy/tasks/main.yml create mode 100644 roles/useproxy/templates/proxy.env.j2 create mode 100644 useproxy.yml diff --git a/group_vars/Fedora.yml b/group_vars/Fedora.yml new file mode 100644 index 0000000..2be3a47 --- /dev/null +++ b/group_vars/Fedora.yml @@ -0,0 +1,10 @@ +useproxy_yum_repos: + - file: fedora + name: fedora + baseurl: http://dl.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/ + - file: fedora-cisco-openh264 + name: fedora-cisco-openh264 + baseurl: https://codecs.fedoraproject.org/openh264/$releasever/$basearch/os/ + - file: fedora-updates + name: updates + baseurl: http://dl.fedoraproject.org/pub/fedora/linux/updates/$releasever/Everything/$basearch/ diff --git a/group_vars/needproxy.yml b/group_vars/needproxy.yml new file mode 100644 index 0000000..f7888b3 --- /dev/null +++ b/group_vars/needproxy.yml @@ -0,0 +1,4 @@ +http_proxy: http://proxy.pyrocufflink.blue:3128 +https_proxy: '{{ http_proxy }}' +all_proxy: '{{ http_proxy }}' +no_proxy: localhost,pyrocufflink.blue,*.pyrocufflink.blue,127.0.0.1,172.30.0.*,172.30.0.0/24 diff --git a/hosts b/hosts index 0c83d2a..b70015b 100644 --- a/hosts +++ b/hosts @@ -81,6 +81,8 @@ burp-server [nfs-client:children] k8s-node +[needproxy] + [nextcloud] cloud0.pyrocufflink.blue diff --git a/roles/useproxy/defaults/main.yml b/roles/useproxy/defaults/main.yml new file mode 100644 index 0000000..56d5579 --- /dev/null +++ b/roles/useproxy/defaults/main.yml @@ -0,0 +1 @@ +useproxy_yum_repos: [] diff --git a/roles/useproxy/handlers/main.yml b/roles/useproxy/handlers/main.yml new file mode 100644 index 0000000..41a6641 --- /dev/null +++ b/roles/useproxy/handlers/main.yml @@ -0,0 +1,6 @@ +- name: reload systemd + systemd: + daemon_reload: true + +- name: reset connection + meta: reset_connection diff --git a/roles/useproxy/tasks/main.yml b/roles/useproxy/tasks/main.yml new file mode 100644 index 0000000..049a7af --- /dev/null +++ b/roles/useproxy/tasks/main.yml @@ -0,0 +1,73 @@ +- name: ensure environment.d directory exists + file: + path: /etc/environment.d + owner: root + group: root + mode: u=rwx,go=rx + state: directory + tags: + - config +- name: ensure proxy environment variables are set + template: + src: proxy.env.j2 + dest: /etc/environment.d/40-proxy.env + owner: root + group: root + mode: u=rw,go=r + tags: + - config + +- name: ensure /etc/environment is assembled + assemble: + src: /etc/environment.d + dest: /etc/environment + owner: root + group: root + mode: u=rw,go=r + notify: + - reset connection + tags: + - config + +- name: ensure systemd default service drop-in directory exists + file: + path: /etc/systemd/system/service.d + owner: root + group: root + mode: u=rwx,go=rx + state: directory + tags: + - systemd +- name: ensure proxy is configured for systemd services + copy: + dest: /etc/systemd/system/service.d/40-proxy.conf + content: | + [Service] + EnvironmentFile=-/etc/environment.d/40-proxy.env + notify: + - reload systemd + tags: + - systemd + +- name: ensure yum repos are configured to use baseurl + ini_file: + path: /etc/yum.repos.d/{{ item.file }}.repo + section: '{{ item.name }}' + option: baseurl + value: '{{ item.baseurl }}' + state: present + loop: '{{ useproxy_yum_repos }}' + tags: + - yum +- name: ensure yum repos are configured to not use metalink + ini_file: + path: /etc/yum.repos.d/{{ item.file }}.repo + section: '{{ item.name }}' + option: metalink + state: absent + loop: '{{ useproxy_yum_repos }}' + tags: + - yum + +- name: flush handlers + meta: flush_handlers diff --git a/roles/useproxy/templates/proxy.env.j2 b/roles/useproxy/templates/proxy.env.j2 new file mode 100644 index 0000000..8ae17a8 --- /dev/null +++ b/roles/useproxy/templates/proxy.env.j2 @@ -0,0 +1,16 @@ +{% if http_proxy|d %} +http_proxy={{ http_proxy }} +HTTP_PROXY={{ http_proxy }} +{% endif %} +{% if https_proxy|d %} +https_proxy={{ https_proxy }} +HTTPS_PROXY={{ https_proxy }} +{% endif %} +{% if all_proxy|d %} +all_proxy={{ all_proxy }} +ALL_PROXY={{ all_proxy }} +{% endif %} +{% if no_proxy %} +no_proxy={{ no_proxy }} +NO_PROXY={{ no_proxy }} +{% endif %} diff --git a/useproxy.yml b/useproxy.yml new file mode 100644 index 0000000..471496e --- /dev/null +++ b/useproxy.yml @@ -0,0 +1,5 @@ +- import_playbook: dyngroups.yml + +- hosts: needproxy + roles: + - useproxy From 8dfb2e3e4fdcc9e1d1d5d1d78f8713ebf9e0bdef Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Fri, 9 Aug 2024 21:17:58 -0500 Subject: [PATCH 02/15] r/frigate: Clean up Frigate role * Switch to Quadlet-style `.container` for systemd unit * Update to new image tag naming scheme (not arch-specific) * Use environment variables for secrets * Allow the entire `frigate_config` variable to be overridden --- roles/frigate/defaults/main.yml | 11 ++++- roles/frigate/tasks/main.yml | 34 +++++++-------- roles/frigate/templates/frigate.container.j2 | 45 ++++++++++++++++++++ roles/frigate/templates/frigate.environ.j2 | 3 ++ roles/frigate/vars/aarch64.yml | 1 - roles/frigate/vars/main.yml | 4 -- roles/frigate/vars/x86_64.yml | 1 - 7 files changed, 74 insertions(+), 25 deletions(-) create mode 100644 roles/frigate/templates/frigate.container.j2 create mode 100644 roles/frigate/templates/frigate.environ.j2 diff --git a/roles/frigate/defaults/main.yml b/roles/frigate/defaults/main.yml index c448bae..30b2b9b 100644 --- a/roles/frigate/defaults/main.yml +++ b/roles/frigate/defaults/main.yml @@ -1,7 +1,16 @@ -frigate_image_tag: '{{ frigate_default_image_tag }}' +frigate_image_tag: 0.12.1 +frigate_image: ghcr.io/blakeblackshear/frigate:{{ frigate_image_tag }} frigate_mqtt: host: localhost frigate_detectors: cpu: type: cpu frigate_cameras: {} +frigate_enable_gpu: false +frigate_enable_tpu: false +frigate_shm_size: 256 +frigate_config: + mqtt: '{{ frigate_mqtt }}' + detectors: '{{ frigate_detectors }}' + cameras: '{{ frigate_cameras }}' +frigate_env: {} diff --git a/roles/frigate/tasks/main.yml b/roles/frigate/tasks/main.yml index 0248946..71c48ef 100644 --- a/roles/frigate/tasks/main.yml +++ b/roles/frigate/tasks/main.yml @@ -44,7 +44,7 @@ - name: ensure frigate container image is available podman_image: - name: docker.io/blakeblackshear/frigate:{{ frigate_image_tag }} + name: '{{ frigate_image }}' tag: stable state: present force: '{{ frigate_update|d|bool }}' @@ -54,22 +54,16 @@ - container-image - container -- name: ensure frigate systemd unit is installed +- name: ensure frigate container unit is installed template: - src: frigate.service.j2 - dest: /etc/systemd/system/frigate.service - mode: '0644' + src: frigate.container.j2 + dest: /etc/containers/systemd/frigate.container + mode: u=rw,go=r notify: - reload systemd - restart frigate tags: - systemd -- name: ensure frigate starts at boot - service: - name: frigate - enabled: true - tags: - - service - name: ensure frigate configuration directory exists file: @@ -82,7 +76,7 @@ - config - name: ensure frigate is configured copy: - dest: /etc/frigate/frigate.yml + dest: /etc/frigate/config.yml content: >- {{ frigate_config|to_nice_yaml(indent=2) }} mode: '0640' @@ -92,13 +86,17 @@ - restart frigate tags: - config - -- name: ensure frigate starts at boot - service: - name: frigate - enabled: true +- name: ensure frigate environment is set + template: + src: frigate.environ.j2 + dest: /etc/frigate/environ + mode: u=r,go= + owner: root + group: root + notify: + - restart frigate tags: - - service + - config - name: flush handlers meta: flush_handlers diff --git a/roles/frigate/templates/frigate.container.j2 b/roles/frigate/templates/frigate.container.j2 new file mode 100644 index 0000000..08373c5 --- /dev/null +++ b/roles/frigate/templates/frigate.container.j2 @@ -0,0 +1,45 @@ +# vim: set ft=systemd.jinja : +[Unit] +Description=Frigate NVR +Wants=network-online.target +After=network-online.target +{% if frigate_enable_tpu %} +Requires=dev-apex_0.device +After=dev-apex_0.device +{% endif %} +RequiresMountsFor=/var/lib/frigate + +[Container] +Image={{ frigate_image }} +Pull=never +PodmanArgs=--uidmap 0:{{ frigate_user.uid }}:1 +PodmanArgs=--gidmap 0:{{ frigate_user.group }}:1 +PodmanArgs=--uidmap 1:6000001:65536 +PodmanArgs=--gidmap 1:6000001:65536 +{% if frigate_shm_size|d %} +PodmanArgs=--shm-size {{ frigate_shm_size }}m +{% endif %} +EnvironmentFile=/etc/frigate/environ +Volume=/var/lib/frigate/media:/media/frigate:rw,z,U +Volume=/var/lib/frigate/tmp:/tmp:rw,z,U +Volume=/etc/frigate/config.yml:/config/config.yml:ro +{% if frigate_enable_tpu %} +AddDevice=/dev/apex_0 +{% endif %} +{% if frigate_enable_gpu %} +AddDevice=/dev/dri/renderD128 +{% endif %} +AddCapability=CAP_PERFMON +Network=host +Annotation=org.systemd.property.KillMode='none' + +[Service] +UMask=0077 +Restart=always +RestartSec=1 +TimeoutStopSec=infinity +StateDirectory=%N/tmp +StateDirectory=%N/media + +[Install] +WantedBy=multi-user.target diff --git a/roles/frigate/templates/frigate.environ.j2 b/roles/frigate/templates/frigate.environ.j2 new file mode 100644 index 0000000..c02aadc --- /dev/null +++ b/roles/frigate/templates/frigate.environ.j2 @@ -0,0 +1,3 @@ +{% for key, value in frigate_env.items() %} +{{ key }}={{ value }} +{% endfor %} diff --git a/roles/frigate/vars/aarch64.yml b/roles/frigate/vars/aarch64.yml index 5ac6d2f..e69de29 100644 --- a/roles/frigate/vars/aarch64.yml +++ b/roles/frigate/vars/aarch64.yml @@ -1 +0,0 @@ -frigate_default_image_tag: stable-aarch64 diff --git a/roles/frigate/vars/main.yml b/roles/frigate/vars/main.yml index 294fd1f..83b6884 100644 --- a/roles/frigate/vars/main.yml +++ b/roles/frigate/vars/main.yml @@ -1,6 +1,2 @@ frigate_podman_packages: - podman -frigate_config: - mqtt: '{{ frigate_mqtt }}' - detectors: '{{ frigate_detectors }}' - cameras: '{{ frigate_cameras }}' diff --git a/roles/frigate/vars/x86_64.yml b/roles/frigate/vars/x86_64.yml index 7b9881c..e69de29 100644 --- a/roles/frigate/vars/x86_64.yml +++ b/roles/frigate/vars/x86_64.yml @@ -1 +0,0 @@ -frigate_default_image_tag: stable-amd64 From 8239b606341a0f8a7bf419467632b34b9cadc71e Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 18:04:11 -0500 Subject: [PATCH 03/15] newvm: Add --network argument Although the `newvm.sh` script had a variable to configure the value specified for the `--network` argument to `virt-install`, it didn't expose a way to set it. We need this ability so we can e.g. create VMs on non-default networks like `camera` or `mgmt`. --- newvm.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/newvm.sh b/newvm.sh index 2541a10..b2ca0d0 100755 --- a/newvm.sh +++ b/newvm.sh @@ -58,6 +58,13 @@ while [ $# -gt 0 ]; do shift fedora="${1#*=}" ;; + --network) + shift + network="$1" + ;; + --network=*) + network="${1#*=}" + ;; --no-console|--noconsole) console=false ;; From 3250628cd1bc68f77978a21fbdc8501d42373ebc Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 18:07:31 -0500 Subject: [PATCH 04/15] gw1/squid: Allow NVR servers access to repos The Frigate NVR servers, prod & test, need to be able to access Fedora COPR (for the *gasket-dkms* package) and Github Container Registry (for Frigate itself). --- host_vars/gw1.pyrocufflink.blue/squid.yml | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/host_vars/gw1.pyrocufflink.blue/squid.yml b/host_vars/gw1.pyrocufflink.blue/squid.yml index 05ab766..90d36f6 100644 --- a/host_vars/gw1.pyrocufflink.blue/squid.yml +++ b/host_vars/gw1.pyrocufflink.blue/squid.yml @@ -7,6 +7,8 @@ squid_acl: - 'src fe80::/10 # RFC 4291 link-local (directly plugged) machines' trusted: - src 172.30.0.0/26 + - src 172.30.0.211/32 + - src 172.30.0.214/32 kubernetes: - src 172.30.0.160/28 unifi_controller: @@ -29,6 +31,9 @@ squid_acl: - dstdomain dl.fedoraproject.org - dstdomain fedoraproject-updates-archive.fedoraproject.org - dstdomain mirrors.fedoraproject.org + fedora_copr: + - dstdomain copr.fedorainfracloud.org + - dstdomain download.copr.fedorainfracloud.org dch_repo: - url_regex files.pyrocufflink.blue/yum/.+ google_fonts: @@ -43,10 +48,11 @@ squid_acl: - dstdomain docker.io - dstdomain auth.docker.io - dstdomain production.cloudflare.docker.com - linuxserverio: - - dstdomain lscr.io + ghcr: - dstdomain ghcr.io - dstdomain pkg-containers.githubusercontent.com + linuxserverio: + - dstdomain lscr.io squid_http_access: - 'deny !Safe_ports' @@ -56,12 +62,15 @@ squid_http_access: - deny to_localhost - allow localnet fcos_updates - allow localnet fedora_repo +- allow localnet fedora_copr - allow localnet grafana_rpm - allow google_fonts - allow trusted kickstart - allow trusted dch_repo +- allow trusted ghcr - allow kubernetes stripe_api - allow unifi_controller dockerhub +- allow unifi_controller ghcr - allow unifi_controller linuxserverio - deny all From 59be10a51c96246be699ad2d190ee87d38ad97f2 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 18:12:30 -0500 Subject: [PATCH 05/15] r/gasket-dkms: Build/sign Coral TPU driver The *gasket-dkms* package provides the `gasket` and `apex` kernel modules, which are needed fro the Google Coral Edge TPU. Since these are out-of-tree modules, they are not allowed in Fedora proper, so they are provided in a COPR, and have to be rebuilt for every kernel version. The DKMS framework handles automatically building the modules whenever the kernel updates. For systems usign UEFI with SecureBoot enabled, kernel modules must be signed by a key trusted by the platform. For locally-built modules, we can use the Machine Owner Key (MOK). Unfortunately, enrolling a new MOK requires rebooting and manual intervention during the boot process. Therefore, the *gasket-dkms* role has a `pause` step to ensure someone is paying attention and able handle the key enrollment interactively. Eventually, I'd like to have an RPM package with these modules pre-built, so production servers do not need the kernel development tools (`perl`, `gcc`, headers, etc.). It will be tricky, though, to make sure the modules get rebuilt for every kernel version as Fedora releases them. --- frigate.yml | 2 + roles/gasket-dkms/defaults/main.yml | 1 + roles/gasket-dkms/files/sign.dkms.conf | 4 ++ roles/gasket-dkms/handlers/main.yml | 25 ++++++++++ roles/gasket-dkms/tasks/main.yml | 64 ++++++++++++++++++++++++++ roles/gasket-dkms/vars/main.yml | 2 + 6 files changed, 98 insertions(+) create mode 100644 roles/gasket-dkms/defaults/main.yml create mode 100644 roles/gasket-dkms/files/sign.dkms.conf create mode 100644 roles/gasket-dkms/handlers/main.yml create mode 100644 roles/gasket-dkms/tasks/main.yml create mode 100644 roles/gasket-dkms/vars/main.yml diff --git a/frigate.yml b/frigate.yml index 0112a7b..800848e 100644 --- a/frigate.yml +++ b/frigate.yml @@ -1,4 +1,6 @@ - hosts: frigate roles: + - role: gasket-dkms + tags: gasket-dkms - role: frigate tags: frigate diff --git a/roles/gasket-dkms/defaults/main.yml b/roles/gasket-dkms/defaults/main.yml new file mode 100644 index 0000000..c6498ea --- /dev/null +++ b/roles/gasket-dkms/defaults/main.yml @@ -0,0 +1 @@ +gasket_dkms_copr: kylegospo/google-coral-dkms diff --git a/roles/gasket-dkms/files/sign.dkms.conf b/roles/gasket-dkms/files/sign.dkms.conf new file mode 100644 index 0000000..90c7508 --- /dev/null +++ b/roles/gasket-dkms/files/sign.dkms.conf @@ -0,0 +1,4 @@ +# vim set ft=sh : +sign_tool='/etc/dkms/sign_helper.sh' +mok_signing_key='/etc/pki/tls/private/dkms.key' +mok_certificate='/etc/pki/tls/certs/dkms.der' diff --git a/roles/gasket-dkms/handlers/main.yml b/roles/gasket-dkms/handlers/main.yml new file mode 100644 index 0000000..9255fc8 --- /dev/null +++ b/roles/gasket-dkms/handlers/main.yml @@ -0,0 +1,25 @@ +# vim: set ft=yaml.jinja : + +- name: enroll uefi mok + shell: | + mokutil --import /etc/pki/tls/certs/dkms.der <- + The machine will now reboot and you must manually enroll the MOK. + Pres ENTER to continue + +- name: reboot the system + reboot: + reboot_timeout: 300 + tags: + - reboot diff --git a/roles/gasket-dkms/tasks/main.yml b/roles/gasket-dkms/tasks/main.yml new file mode 100644 index 0000000..e5956d6 --- /dev/null +++ b/roles/gasket-dkms/tasks/main.yml @@ -0,0 +1,64 @@ +# vim: set ft=yaml.jinja : +- name: load secrets + include_vars: vault/dkms + +- name: ensure prerequisite packages are installed + package: + name: + - dkms + - dnf-command(copr) + - mokutil + - openssl + state: present + tags: + - install + +- name: ensure dkms module signing key is present + command: + openssl req + -new + -x509 + -newkey rsa:4096 + -keyout /etc/pki/tls/private/dkms.key + -nodes + -subj '/CN=DKMS Modules' + -days 3650 + -outform DER + -out /etc/pki/tls/certs/dkms.der + args: + creates: /etc/pki/tls/certs/dkms.der + notify: + - enroll uefi mok + tags: + - cert + - dkms + +- name: ensure dkms is configured to sign modules with the mok + copy: + src: sign.dkms.conf + dest: /etc/dkms/framework.conf.d/10-sign.conf + owner: root + group: root + mode: u=rw,go=r + tags: + - config + - dkms + +- name: flush handlers + meta: flush_handlers + +- name: ensure gasket dkms copr is enabled + command: + dnf copr enable -y {{ gasket_dkms_copr }} + args: + creates: /etc/yum.repos.d/{{ gasket_dkms_copr_repo_filename }} + tags: + - copr + - repo + +- name: ensure gasket-dkms is installed + package: + name: gasket-dkms + state: present + tags: + - install diff --git a/roles/gasket-dkms/vars/main.yml b/roles/gasket-dkms/vars/main.yml new file mode 100644 index 0000000..80db820 --- /dev/null +++ b/roles/gasket-dkms/vars/main.yml @@ -0,0 +1,2 @@ +gasket_dkms_copr_repo_filename: >- + _copr:copr.fedorainfracloud.org:{{ gasket_dkms_copr | replace("/", ":")}}.repo From 6c71d96f8134edb481d6b6bd920e9e6ee655de30 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 18:27:41 -0500 Subject: [PATCH 06/15] r/frigate-caddy: Deploy Caddy in front of Frigate Deploying Caddy as a reverse proxy for Frigate enables HTTPS with a certificate issued by the internal CA (via ACME) and authentication via Authelia. Separating the installation and base configuratieon of Caddy into its own role will allow us to reuse that part for other sapplications that use Caddy for similar reasons. --- frigate.yml | 2 + group_vars/frigate.yml | 9 +++++ roles/caddy/files/Caddyfile | 1 + roles/caddy/handlers/main.yml | 4 ++ roles/caddy/tasks/main.yml | 47 ++++++++++++++++++++++ roles/frigate-caddy/defaults/main.yml | 1 + roles/frigate-caddy/meta/main.yml | 3 ++ roles/frigate-caddy/tasks/main.yml | 11 +++++ roles/frigate-caddy/templates/Caddyfile.j2 | 23 +++++++++++ 9 files changed, 101 insertions(+) create mode 100644 group_vars/frigate.yml create mode 100644 roles/caddy/files/Caddyfile create mode 100644 roles/caddy/handlers/main.yml create mode 100644 roles/caddy/tasks/main.yml create mode 100644 roles/frigate-caddy/defaults/main.yml create mode 100644 roles/frigate-caddy/meta/main.yml create mode 100644 roles/frigate-caddy/tasks/main.yml create mode 100644 roles/frigate-caddy/templates/Caddyfile.j2 diff --git a/frigate.yml b/frigate.yml index 800848e..176425d 100644 --- a/frigate.yml +++ b/frigate.yml @@ -4,3 +4,5 @@ tags: gasket-dkms - role: frigate tags: frigate + - role: frigate-caddy + tags: frigate-caddy diff --git a/group_vars/frigate.yml b/group_vars/frigate.yml new file mode 100644 index 0000000..05c9126 --- /dev/null +++ b/group_vars/frigate.yml @@ -0,0 +1,9 @@ +# vim: set ft=yaml.jinja : + +frigate_caddy_forward_auth: + url: https://auth.pyrocufflink.blue + path: /api/verify + location: '?rd=https://{{ frigate_caddy_server_name }}' +frigate_caddy_acme: + email: frigate@pyrocufflink.blue + url: https://ca.pyrocufflink.blue/acme/acme/directory diff --git a/roles/caddy/files/Caddyfile b/roles/caddy/files/Caddyfile new file mode 100644 index 0000000..644d82b --- /dev/null +++ b/roles/caddy/files/Caddyfile @@ -0,0 +1 @@ +import Caddyfile.d/*.caddyfile diff --git a/roles/caddy/handlers/main.yml b/roles/caddy/handlers/main.yml new file mode 100644 index 0000000..e4c3a6f --- /dev/null +++ b/roles/caddy/handlers/main.yml @@ -0,0 +1,4 @@ +- name: reload caddy + service: + name: caddy + state: reloaded diff --git a/roles/caddy/tasks/main.yml b/roles/caddy/tasks/main.yml new file mode 100644 index 0000000..ab37b0e --- /dev/null +++ b/roles/caddy/tasks/main.yml @@ -0,0 +1,47 @@ +- name: ensure caddy is installed + package: + name: caddy + state: present + tags: + - install + +- name: ensure base caddy configuration is set + copy: + src: Caddyfile + dest: /etc/caddy/Caddyfile + owner: root + group: root + mode: u=rw,go=r + notify: + - reload caddy + tags: + - config + +- name: ensure firewall is configured for caddy + firewalld: + service: '{{ item }}' + permanent: true + immediate: true + state: enabled + when: host_uses_firewalld|d(true) + loop: + - http + - https + tags: + - firewalld + +- name: flush handlers + meta: flush_handlers + +- name: ensure caddy starts at boot + service: + name: caddy + enabled: true + tags: + - service +- name: ensure caddy is running + service: + name: caddy + state: started + tags: + - service diff --git a/roles/frigate-caddy/defaults/main.yml b/roles/frigate-caddy/defaults/main.yml new file mode 100644 index 0000000..4182b9d --- /dev/null +++ b/roles/frigate-caddy/defaults/main.yml @@ -0,0 +1 @@ +frigate_caddy_server_name: frigate.{{ ansible_domain }} diff --git a/roles/frigate-caddy/meta/main.yml b/roles/frigate-caddy/meta/main.yml new file mode 100644 index 0000000..e278138 --- /dev/null +++ b/roles/frigate-caddy/meta/main.yml @@ -0,0 +1,3 @@ +dependencies: +- role: caddy + tags: caddy diff --git a/roles/frigate-caddy/tasks/main.yml b/roles/frigate-caddy/tasks/main.yml new file mode 100644 index 0000000..5791b65 --- /dev/null +++ b/roles/frigate-caddy/tasks/main.yml @@ -0,0 +1,11 @@ +- name: ensure caddy is configured to proxy for frigate + template: + src: Caddyfile.j2 + dest: /etc/caddy/Caddyfile.d/frigate.caddyfile + owner: root + group: root + mode: u=rw,go=r + notify: + - reload caddy + tags: + - config diff --git a/roles/frigate-caddy/templates/Caddyfile.j2 b/roles/frigate-caddy/templates/Caddyfile.j2 new file mode 100644 index 0000000..b9c46f7 --- /dev/null +++ b/roles/frigate-caddy/templates/Caddyfile.j2 @@ -0,0 +1,23 @@ +{# vim: set sw=4 ts=4 sts=4 et : #} +{{ frigate_caddy_server_name }} { +{% if frigate_caddy_forward_auth|d %} + forward_auth {{ frigate_caddy_forward_auth.url }} { + uri {{ frigate_caddy_forward_auth.path }} + header_up Host {upstream_hostport} + + @unauthorized status 401 + handle_response @unauthorized { + respond "" 301 + header Location {{ frigate_caddy_forward_auth.url}}{{ frigate_caddy_forward_auth.location }} + } + } + +{% endif %} + reverse_proxy localhost:5000 +{% if frigate_caddy_acme|d %} + + tls {{ frigate_caddy_acme.email }} { + ca {{ frigate_caddy_acme.url }} + } +{% endif %} +} From d2b3b1f7b3caeaac092c111e44ba1877aa629021 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 18:43:18 -0500 Subject: [PATCH 07/15] hosts: Deploy production Frigate on nvr2.p.b *nvr2.pyrocufflink.blue* originally ran Fedora CoreOS. Since I'm tired of the tedium and difficulty involved in making configuration changes to FCOS machines, I am migrating it to Fedora Linux, managed by Ansible. --- deploy/nvr2.sh | 25 ++++ group_vars/frigate-prod.yml | 193 +++++++++++++++++++++++++++ host_vars/nvr2.pyrocufflink.blue.yml | 5 + hosts | 11 ++ 4 files changed, 234 insertions(+) create mode 100644 deploy/nvr2.sh create mode 100644 group_vars/frigate-prod.yml create mode 100644 host_vars/nvr2.pyrocufflink.blue.yml diff --git a/deploy/nvr2.sh b/deploy/nvr2.sh new file mode 100644 index 0000000..3e4f35e --- /dev/null +++ b/deploy/nvr2.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# vim: set sw=4 ts=4 sts=4 noet : + +ansible-playbook \ + -l nvr2.pyrocufflink.blue \ + wait-for-host.yml \ + || exit + +printf 'Waiting for SSH host certificate to be signed ... ' +until ssh-keyscan -c nvr2.pyrocufflink.blue 2>/dev/null | grep -q cert; do + sleep 1 +done +echo done +ansible-playbook \ + -l nvr2.pyrocufflink.blue \ + useproxy.yml \ + datavol.yml \ + bootstrap.yml \ + pyrocufflink.yml \ + frigate.yml \ + collectd.yml \ + promtail.yml \ + -u root \ + -e @join.creds \ + || exit diff --git a/group_vars/frigate-prod.yml b/group_vars/frigate-prod.yml new file mode 100644 index 0000000..e54c0bc --- /dev/null +++ b/group_vars/frigate-prod.yml @@ -0,0 +1,193 @@ +frigate_enable_gpu: true +frigate_enable_tpu: true +frigate_config: + ffmpeg: + hwaccel_args: preset-vaapi + cameras: + front_porch: + detect: + height: 1080 + width: 1920 + ffmpeg: + inputs: + - path: rtsp://127.0.0.1:8554/front_porch + input_args: preset-rtsp-restream + roles: + - detect + - path: rtsp://frigate:{FRIGATE_AMCREST_RTSP_PASSWORD}@172.30.0.213/cam/realmonitor?channel=1&subtype=0 + roles: + - record + objects: + track: + - person + - cat + - dog + - bird + filters: + dog: + threshold: 0.8 + bird: + threshold: 0.8 + record: + enabled: true + events: + retain: + default: 365 + retain: + days: 30 + rtmp: + enabled: false + snapshots: + enabled: true + retain: + default: 365 + zones: + front_door: + coordinates: 1920,1080,1920,0,1770,0,1366,657,1533,1080 + front_porch_window: + coordinates: 1168,337,1026,75,1040,0,1300,0,1257,231 + front_steps: + coordinates: 0,1080,1533,1080,1366,595,925,672,531,529,216,587 + motion: + mask: + - 189,0,0,0,0,175 + driveway: + detect: + height: 1080 + width: 1920 + ffmpeg: + inputs: + - path: rtsp://127.0.0.1:8554/driveway + input_args: preset-rtsp-restream + roles: + - detect + - path: rtsp://frigate:{FRIGATE_AMCREST_RTSP_PASSWORD}@172.30.0.212/cam/realmonitor?channel=1&subtype=0 + roles: + - record + objects: + track: + - person + - cat + - dog + - car + filters: + person: + threshold: 0.8 + dog: + threshold: 0.8 + bird: + threshold: 0.8 + record: + enabled: true + events: + retain: + default: 365 + required_zones: + - driveway_entry_zone + - garage_pad_zone + retain: + days: 30 + rtmp: + enabled: false + snapshots: + enabled: true + retain: + default: 365 + required_zones: + - driveway_entry_zone + - garage_pad_zone + zones: + neighbor_zone: + coordinates: 1920,0,1920,317,1644,179,1382,89,1030,0 + objects: [] + driveway_entry_zone: + coordinates: 624,0,148,0,0,107,0,251,111,328 + garage_pad_zone: + coordinates: 0,507,0,431,616,23,834,51,1180,119,1545,243,1475,583,1285,1080,404,1080,239,843 + motion: + mask: + - 157,0,0,0,0,119 + - 1419,89,1058,0,1920,0,1920,324,1823,267 + back_yard: + detect: + height: 1080 + width: 1920 + ffmpeg: + inputs: + - path: rtsp://127.0.0.1:8554/back_yard + input_args: preset-rtsp-restream + roles: + - detect + - path: rtsp://frigate:{FRIGATE_AMCREST_RTSP_PASSWORD}@172.30.0.215/cam/realmonitor?channel=1&subtype=0 + roles: + - record + objects: + track: + - person + - cat + - dog + record: + enabled: true + events: + retain: + default: 365 + retain: + days: 30 + rtmp: + enabled: false + snapshots: + enabled: true + retain: + default: 365 + zones: + pool_zone: + coordinates: 532,78,1063,21,1117,31,979,208,931,301,515,307,406,375,231,373,204,291 + go2rtc: + streams: + front_porch: + - rtsp://frigate:{FRIGATE_AMCREST_RTSP_PASSWORD}@172.30.0.213/cam/realmonitor?channel=1&subtype=0 + driveway: + - rtsp://frigate:{FRIGATE_AMCREST_RTSP_PASSWORD}@172.30.0.212/cam/realmonitor?channel=1&subtype=0 + back_yard: + - rtsp://frigate:{FRIGATE_AMCREST_RTSP_PASSWORD}@172.30.0.215/cam/realmonitor?channel=1&subtype=0 + detectors: + coral: + device: pci:0 + type: edgetpu + birdseye: + restream: true + mqtt: + host: mqtt.pyrocufflink.blue + password: '{FRIGATE_MQTT_PASSWORD}' + port: 8883 + tls_ca_certs: /etc/ssl/certs/ca-certificates.crt + user: frigate + +frigate_env: + FRIGATE_AMCREST_RTSP_PASSWORD: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 64353062663837623164386433333966303233313064343665313434643434663131346664666333 + 3862333434616235306432336534653036633837613931310a343630373832343465656231646665 + 63303964306334316330653966373836623966363836303331613631346235643061613463376232 + 3538303063633930370a303861663161366335346465633262336537336164373431326330383733 + 30656437343837623432356532636461663666636163663634373837353734313163 + FRIGATE_MQTT_PASSWORD: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 30613633316564303239363734633761666164643062636137383232313961363665666539373162 + 3235623565386663323234326365303133643732663462320a666136623939316634616265326532 + 39373933353261633264633532393838333632346464303837623836303630636438366532663765 + 6563616533333338320a333933643734666631343932613561303930366238653632346530653438 + 39646635313162646463613263643665363936356361353933653334336533346136323932363936 + 64363061653233363962623333303337303863623736323232366535633263656332363964373163 + 333339396137363862663037313861643066 + LIBVA_DRIVER_NAME: radeonsi + PLUS_API_KEY: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 32373139306134646230393961623365643938393430626362353130616661326161613630353533 + 6463326333373638636463353366343531396237326637350a323465373561656236633935393639 + 38343239643333363235386139393936373337333138336161663736366131336336396237356630 + 3532373537303237350a633530373461393630383262366562343638353062653764356135306461 + 31336137353464376332613738386439613161663065333533653465346661663964626332336232 + 64326434346638366262326463336639393037316361323039623265626163663539343063636164 + 31333862333831353461376435303565633163663364383732626639383032313234363030353965 + 65303430356237383965 diff --git a/host_vars/nvr2.pyrocufflink.blue.yml b/host_vars/nvr2.pyrocufflink.blue.yml new file mode 100644 index 0000000..49dc958 --- /dev/null +++ b/host_vars/nvr2.pyrocufflink.blue.yml @@ -0,0 +1,5 @@ +data_volumes: +- dev: /dev/md/frigate + fstype: btrfs + mountpoint: /var/lib/frigate + mountopts: x-systemd.mount-timeout=3m diff --git a/hosts b/hosts index b70015b..3b3eb71 100644 --- a/hosts +++ b/hosts @@ -47,6 +47,15 @@ bitwarden_rs [file-servers] file0.pyrocufflink.blue +[frigate:children] +frigate-prod +frigate-test + +[frigate-prod] +nvr2.pyrocufflink.blue + +[frigate-test] + [gitea] git0.pyrocufflink.blue @@ -82,6 +91,7 @@ burp-server k8s-node [needproxy] +nvr2.pyrocufflink.blue [nextcloud] cloud0.pyrocufflink.blue @@ -111,6 +121,7 @@ file0.pyrocufflink.blue git0.pyrocufflink.blue k8s-ctrl0.pyrocufflink.blue matrix0.pyrocufflink.blue +nvr2.pyrocufflink.blue pxe0.pyrocufflink.blue smtp1.pyrocufflink.blue web0.pyrocufflink.blue From 217b13faff361579d4d14a3dfe8debeec07bc647 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 18:49:29 -0500 Subject: [PATCH 08/15] dch-root-ca: Add PB to trust DCH Root CA For machines that are not members of the AD domain --- dch-root-ca.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 dch-root-ca.yml diff --git a/dch-root-ca.yml b/dch-root-ca.yml new file mode 100644 index 0000000..708dbe0 --- /dev/null +++ b/dch-root-ca.yml @@ -0,0 +1,7 @@ +- hosts: all + roles: + - role: trustca + ca: dch-root-ca + - role: trustca + ca: dch-root-ca-r2 + tags: dch-root-ca-r2 From 34fcaa52efa72a333ef73b60e34b34625d9730c0 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 22:10:10 -0500 Subject: [PATCH 09/15] r/frigate: Increase service startup timeout Starting the Frigate container can take quite some time, since `podman` needs to check permissions/SELinux labels for the entire media volume. --- roles/frigate/templates/frigate.container.j2 | 1 + 1 file changed, 1 insertion(+) diff --git a/roles/frigate/templates/frigate.container.j2 b/roles/frigate/templates/frigate.container.j2 index 08373c5..7f3f274 100644 --- a/roles/frigate/templates/frigate.container.j2 +++ b/roles/frigate/templates/frigate.container.j2 @@ -37,6 +37,7 @@ Annotation=org.systemd.property.KillMode='none' UMask=0077 Restart=always RestartSec=1 +TimeoutStartSec=10m TimeoutStopSec=infinity StateDirectory=%N/tmp StateDirectory=%N/media From 9ae88a5f3632ec064a4c1df735585724b6358d0b Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Mon, 12 Aug 2024 22:11:27 -0500 Subject: [PATCH 10/15] datavol: Only set SELinux label of root directory Restoring the SELinux label of a mount point is really only necessary for a band new filesystem, which will have no label at all. In other cases, changing the context is probably neither necessary nor desirable, as the existing data is potentially labelled correctly already. Changing the label on on only the root directory should be sufficient to ensure applications run correctly with newly-provisioned filesystems, since they only have one directory anyway, without impacting too much for existing filesystems. --- datavol.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datavol.yml b/datavol.yml index e16225a..6c0bf09 100644 --- a/datavol.yml +++ b/datavol.yml @@ -48,5 +48,5 @@ - name: fix data volume selinux context command: - restorecon -RF {{ item.mountpoint }} + restorecon -F {{ item.mountpoint }} loop: '{{ data_volumes }}' From 0ec9401c6eb9e8a43eb6d5d16212de77e2936154 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Wed, 14 Aug 2024 20:12:41 -0500 Subject: [PATCH 11/15] r/squid: Support configuring auth_param The `auth_param` directive is used to configure proxy authentication helpers. --- roles/squid/templates/squid.conf.j2 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/roles/squid/templates/squid.conf.j2 b/roles/squid/templates/squid.conf.j2 index f347c51..91b547a 100644 --- a/roles/squid/templates/squid.conf.j2 +++ b/roles/squid/templates/squid.conf.j2 @@ -1,4 +1,12 @@ cache_log {{ squid_cache_log }} +{% if squid_auth_param|d %} + +{% for scheme in squid_auth_param %} +{% for key, value in squid_auth_param[scheme].items() %} +auth_param {{ scheme }} {{ key }} {{ value }} +{% endfor %} +{% endfor %} +{% endif %} {% if squid_acl is not defined %} # # Recommended minimum configuration: From 14a7d39e11508dea7abc13bf81e6fef6976c2df1 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Wed, 14 Aug 2024 19:45:37 -0500 Subject: [PATCH 12/15] gw1/squid: Allow Frigate access to Github API Frigate uses the Github API to check for new releases. It then populates the `update.frigate_server` entity in Home Assistant via MQTT with the information it retrieved. If it is unable to access the Github API, the Home Assistant entity will be marked as "unavailable," which triggers an alert notification from Home Assistant. Thus, we need to allow Frigate to access Github if we want to use that entity as an indicator of whether or not Frigate is connected to the MQTT broker. I don't want to allow access to the Github API to everything on the Frigate server, just Frigate itself. To do that, I've assigned a unique username and password for Frigate. Only requests with the proper `Proxy-Authorization` header will be allowed access. By providing the credentials only the Frigate container, we can ensure no other process has access. I think I did this mostly as an exercise; there's no particular reason to disallow access to the Github API, since it's mostly read-only and can't really be used to exfiltrate any data (probably?). --- host_vars/gw1.pyrocufflink.blue/squid.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/host_vars/gw1.pyrocufflink.blue/squid.yml b/host_vars/gw1.pyrocufflink.blue/squid.yml index 90d36f6..f754cc3 100644 --- a/host_vars/gw1.pyrocufflink.blue/squid.yml +++ b/host_vars/gw1.pyrocufflink.blue/squid.yml @@ -1,3 +1,8 @@ +squid_auth_param: + basic: + program: /usr/lib64/squid/basic_ncsa_auth /etc/squid/squid.htpasswd + children: 1 + squid_acl: localnet: - 'src 10.0.0.0/8 # RFC 1918 local private network (LAN)' @@ -20,6 +25,10 @@ squid_acl: - 'port 443 # https' CONNECT: - method CONNECT + frigate: + - proxy_auth frigate + github_api: + - dstdomain api.github.com kickstart: - url_regex rosalina.pyrocufflink.blue/~dustin/kickstart/.*\.ks$ fcos_updates: @@ -72,6 +81,7 @@ squid_http_access: - allow unifi_controller dockerhub - allow unifi_controller ghcr - allow unifi_controller linuxserverio +- allow trusted frigate github_api - deny all squid_cache_dir: From 6d65e0594fabcd95097001873506a9081fdcf661 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Wed, 14 Aug 2024 20:04:02 -0500 Subject: [PATCH 13/15] frigate: Configure HTTPS proxy with creds Only the _frigate_ user is allowed to access the Github API via the proxy. --- group_vars/frigate-prod.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/group_vars/frigate-prod.yml b/group_vars/frigate-prod.yml index e54c0bc..4c74083 100644 --- a/group_vars/frigate-prod.yml +++ b/group_vars/frigate-prod.yml @@ -163,7 +163,17 @@ frigate_config: tls_ca_certs: /etc/ssl/certs/ca-certificates.crt user: frigate +frigate_https_proxy_password: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 62363833343565316638356665316534393035356664396638313330616663613639366334353663 + 3934356433303066343431343935633138656264363064650a393636363062383437656464383262 + 30653965353264336665653264303036323430363030313165626536353736333132386365623230 + 3534326634343838650a643063666637666636333863326634356630663135326464666433356565 + 30353339356433376436363863663730323165643232356633376266323536373431643564666562 + 3935646435306537653530616230343239623966656434313334 + frigate_env: + https_proxy: http://frigate:{{ frigate_https_proxy_password }}@proxy.pyrocufflink.blue:3128 FRIGATE_AMCREST_RTSP_PASSWORD: !vault | $ANSIBLE_VAULT;1.1;AES256 64353062663837623164386433333966303233313064343665313434643434663131346664666333 From a2cf78f3f54dfbc7e8c377c6750c010c89b2f4cf Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Wed, 14 Aug 2024 20:07:49 -0500 Subject: [PATCH 14/15] vm-hosts: Update vm-autostart *logs0.pyrocufflink.blue* has been replaced by *loki0.pyrocufflink.blue* since ages, so I'm not sure how I hadn't updated the autostart list with it yet. *unifi3.pyrocufflink.blue* replaced *unifi2.p.b* recently, when I was testing *Luci*/etcd. --- group_vars/vm-hosts.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/group_vars/vm-hosts.yml b/group_vars/vm-hosts.yml index a9c0aaf..7bbb167 100644 --- a/group_vars/vm-hosts.yml +++ b/group_vars/vm-hosts.yml @@ -243,7 +243,7 @@ vm_autostart: - dc-grumbly - dc-headphone - delay 30s -- logs0 +- loki0 - delay 10s - db0 - k8s-ctrl0 @@ -262,4 +262,4 @@ vm_autostart: - matrix0 - delay 10s - pxe0 -- unifi2 +- unifi3 From 6e5e12f8b66a37a05cef2b49f16a12d4dbb1051a Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Wed, 14 Aug 2024 20:13:59 -0500 Subject: [PATCH 15/15] hosts: Add nvr2.p.b to collectd-sensors group To enable collecting temperature et al. sensor data. --- hosts | 1 + 1 file changed, 1 insertion(+) diff --git a/hosts b/hosts index 3b3eb71..9d95b94 100644 --- a/hosts +++ b/hosts @@ -28,6 +28,7 @@ pyrocufflink collectd [collectd-sensors] +nvr2.pyrocufflink.blue [dch-proxy]