Compare commits

...

26 Commits

Author SHA1 Message Date
Berwn d8bbf08c7a Add mx1 to secret vars/shared/mail-dmarc-cred/passphrase 2026-06-21 03:28:02 +07:00
Berwn e6036d9d1b Add mx1 to secret vars/shared/mail-dmarc-cred/hash 2026-06-21 03:28:01 +07:00
Berwn f7b64617b9 Update vars via generator mail-dmarc-cred for machine control 2026-06-21 03:27:56 +07:00
Berwn 60db8c60b0 Add parsedmarc DMARC report analyzer on control
Deliver cnx.email DMARC aggregate/forensic reports to a dedicated dmarc@cnx.email
mailbox on mx1 and analyze them with parsedmarc on control, storing parsed
reports in a local loopback Elasticsearch and visualizing via the auto-provisioned
Grafana dashboard. parsedmarc fetches the mailbox over IMAPS across the mesh
(mx1.cnx.email pinned to its mesh address so TLS still validates), using a shared
mail-dmarc-cred clan var so mx1's mailserver and control see the same password.
2026-06-21 03:27:23 +07:00
Berwn b8bea27a9c Update runbook docs for web01 reverse proxy and per-host ACME keys
Reflect web01 in the machines table and monitoring scrape list, note Grafana is
now also published publicly via web01's reverse proxy, add the CNX Uptime
dashboard, and document the dedicated acme_mx1/acme_web01 DNS-01 keys.
2026-06-21 03:17:51 +07:00
Berwn 415a050f6a Scrape web01 node_exporter into VictoriaMetrics
Add web01 to the mesh map and the node scrape job so it appears on the
uptime/host dashboards alongside the other hosts.
2026-06-21 03:08:56 +07:00
Berwn 3f3f4118c1 Use Singapore time (UTC+8) for mx1 and web01
Both hosts are in the Singapore region, not UTC+3.
2026-06-21 03:07:57 +07:00
Berwn dfdeb84ab8 Set time.timeZone on mx1 and web01
Both had NTP (timesyncd) enabled but no timezone, unlike control/ns1/ns2.
Default to Etc/GMT-3 to match the majority of hosts.
2026-06-21 03:07:31 +07:00
Berwn 48bf7fb250 Add web01 public reverse proxy with DNS-01 wildcard TLS
web01 terminates TLS for grafana.cnx.network and proxies to Grafana on
control over the mesh. Caddy serves a *.cnx.network wildcard cert obtained
via ACME DNS-01, using a dedicated acme_web01 TSIG key scoped on ns1 to
_acme-challenge on the cnx.network zone only. Ports 80/443 are the only
public exposure (80 just redirects); admin and the backend ride ZeroTier.

Also reload Caddy on cert renewal for both web01 and mx1, since both
reference the cert via explicit tls file paths and would otherwise keep
serving a stale cert after a silent renewal.
2026-06-21 03:05:54 +07:00
Berwn 86a2928825 update(inventory.json): Installed web01 2026-06-21 02:28:43 +07:00
Berwn f6da01ba18 Add web01 to secret vars/shared/dns-acme-web01-secret/secret 2026-06-21 02:26:44 +07:00
Berwn eeed40bcb5 Update vars via generator dns-acme-web01-rfc2136 for machine web01 2026-06-21 02:26:44 +07:00
Berwn aac8f9d8e6 Update vars via generator dns-acme-web01-knot for machine ns1 2026-06-21 02:26:43 +07:00
Berwn f5874bc337 Update vars via generator zerotier for machine web01 2026-06-21 02:26:33 +07:00
Berwn 2481d4bf92 Update vars via generator tor_tor for machine web01 2026-06-21 02:26:32 +07:00
Berwn 2d8096ee57 Update vars via generator state-version for machine web01 2026-06-21 02:26:30 +07:00
Berwn 1a4a749d78 Update vars via generator root-password for machine web01 2026-06-21 02:26:30 +07:00
Berwn 1c779d8013 Update vars via generator openssh for machine web01 2026-06-21 02:26:30 +07:00
Berwn 9c4e036b09 Update vars via generator emergency-access for machine web01 2026-06-21 02:26:30 +07:00
Berwn 8139b91fbc Add machine web01 to secrets 2026-06-21 02:26:30 +07:00
Berwn c436389619 Update secret web01-age.key 2026-06-21 02:26:29 +07:00
Berwn 9fc97e65b2 Update vars via generator dns-acme-web01-secret for machine ns1 2026-06-21 02:26:29 +07:00
Berwn bd84bf7c85 Set disk schema of machine: web01 to single-disk 2026-06-21 02:25:24 +07:00
Berwn 848dc0dff7 machines/web01/facter.json: update hardware configuration 2026-06-21 02:23:00 +07:00
Berwn 95aff44f86 Add machine web01 2026-06-21 01:58:59 +07:00
Berwn f42569e992 Add provisioned Grafana uptime dashboard for all hosts 2026-06-21 01:57:08 +07:00
80 changed files with 3983 additions and 29 deletions
+1
View File
@@ -24,6 +24,7 @@ in
ns1 = { };
ns2 = { };
mx1 = { };
web01 = { };
};
inventory.instances = {
+18 -6
View File
@@ -61,13 +61,25 @@ requires re-submitting the DS.
## ACME DNS-01
A dedicated TSIG key (`acme_ddns`), scoped by `acl_acme` to `TXT` updates at or
under `_acme-challenge.<zone>` on `ns1` only. Knot signs the record and transfers
it to `ns2`, which never needs this key. Retrieve the client config with:
Certificates are issued by `_acme-challenge` TXT updates that `ns1` accepts over
TSIG, signs, and transfers to `ns2` (which never needs these keys). Each consumer
gets its **own** key, scoped by an ACL to exactly the owner names it needs and
attached only to the zone it lives in — so a leaked key can write nothing but its
own challenges.
```
clan vars get ns1 dns-acme-tsig/acme.conf
```
- **`acme_ddns`** (`acl_acme`) — the general key, scoped to `TXT` at or under
`_acme-challenge.<zone>` and attached to every zone. Client config:
```
clan vars get ns1 dns-acme-tsig/acme.conf
```
- **`acme_mx1`** (`acl_acme_mx1`) — held only by `mx1`, scoped to
`_acme-challenge.{mx1,mta-sts,mail}` and attached only to `cnx.email` (the mail
cert plus its MTA-STS and client-alias SANs). Secret shared via the
`dns-acme-mx1-secret` generator.
- **`acme_web01`** (`acl_acme_web01`) — held only by `web01`, scoped to
`_acme-challenge` and attached only to `cnx.network` (where the wildcard
`*.cnx.network` challenge lands, at the apex). Secret shared via the
`dns-acme-web01-secret` generator.
## Runbook: stale secondary
+34 -7
View File
@@ -1,6 +1,7 @@
# Monitoring
Metrics and dashboards live on `control`, reachable only over the ZeroTier mesh.
Metrics and logs live on `control` over the ZeroTier mesh; the Grafana dashboards
are also published publicly through `web01` (see [Dashboards](#dashboards)).
## Collection
@@ -18,8 +19,8 @@ Metrics and dashboards live on `control`, reachable only over the ZeroTier mesh.
## Storage & scraping
**VictoriaMetrics** on `control`, bound to `127.0.0.1:8428`, 180-day retention
(`modules/monitoring/server.nix`). It scrapes `control` over loopback and `ns1`/
`ns2` over the mesh.
(`modules/monitoring/server.nix`). It scrapes `control` over loopback and
`ns1`/`ns2`/`mx1`/`web01` over the mesh.
> The scraper dials IPv4-only by default, so mesh (IPv6) targets need
> `extraOptions = [ "-enableTCP6" ]`. Without it, ns1/ns2 are dropped with
@@ -31,8 +32,10 @@ Metrics and dashboards live on `control`, reachable only over the ZeroTier mesh.
## Dashboards
**Grafana** on `control` (`:3000`), mesh-only, anonymous access disabled. The
admin password is a clan var:
**Grafana** on `control` (`:3000`), anonymous access disabled. Reachable directly
over the mesh, and publicly at `https://grafana.cnx.network` via `web01`'s reverse
proxy (TLS termination — see [Overview](./overview.md)). The admin password is a
clan var:
```
clan vars get control grafana-admin/password
@@ -46,6 +49,30 @@ there is picked up):
outside-in DNS probes.
- **CNX Backups** (`backups.json`) — borgbackup job health, time since the last
run, and per-job state. See [Backups](./backups.md).
- **CNX Uptime** (`uptime.json`) — per-host up/down status, current uptime,
availability over the selected window, and up/down history. Label-driven, so
every scraped host appears automatically.
- **parsedmarc** — DMARC aggregate/forensic report viewer. Auto-provisioned by
the `parsedmarc` module (not from `dashboards/`); reads its own Elasticsearch
datasource, not VictoriaMetrics. See [DMARC reports](#dmarc-reports) below.
## DMARC reports
The `cnx.email` DMARC record (`rua`/`ruf`) points at the `dmarc@cnx.email`
mailbox on `mx1`. **parsedmarc** on `control` (`modules/monitoring/parsedmarc.nix`)
polls that mailbox over IMAPS, parses the XML reports, and stores them in a local
**Elasticsearch** (`127.0.0.1:9200`, loopback-only); Grafana renders them via the
auto-provisioned parsedmarc dashboard + Elasticsearch datasource.
The IMAP fetch rides the **mesh**, not the public net: `control` pins
`mx1.cnx.email` to mx1's mesh address in `/etc/hosts`, so TLS still validates
against the public cert while the bytes stay on the overlay. The mailbox
passphrase is the shared `mail-dmarc-cred` clan var (so both mx1's mailserver and
control's parsedmarc see the same value):
```
clan vars get mx1 mail-dmarc-cred/passphrase
```
## Logs
@@ -53,8 +80,8 @@ there is picked up):
(`modules/monitoring/server.nix`). All three hosts ship journald to it via
systemd's own `services.journald.upload` → the `/insert/journald` endpoint
(`modules/monitoring/exporters.nix`); no extra agent. `control` uploads over
loopback so its logs survive a mesh outage, `ns1`/`ns2` push over the mesh, and
9428 is firewall-scoped to the mesh like everything else.
loopback so its logs survive a mesh outage, the other hosts push over the mesh,
and 9428 is firewall-scoped to the mesh like everything else.
> Same IPv4-only default as the scraper: VictoriaLogs binds `0.0.0.0:9428` for a
> bare `:9428`, so mesh (IPv6) pushes from ns1/ns2 are refused until you pass
+7 -6
View File
@@ -6,12 +6,13 @@ this book is built from `docs/` and served on `control` over the ZeroTier mesh.
## Machines
| Machine | Role | Public IPv4 | Public IPv6 |
| --------- | ------------------------------------- | ---------------- | ----------------------- |
| `control` | ZeroTier controller, monitoring, docs | `77.42.68.181` | `2a01:4f9:c013:e6d0::1` |
| `ns1` | Knot DNS **primary** (master) | `46.224.170.206` | `2a01:4f8:c014:b5c5::1` |
| `ns2` | Knot DNS **secondary** (slave) | `157.180.70.82` | `2a01:4f9:c014:6d87::1` |
| `mx1` | Mail server (**MX** for cnx.email) | `5.223.65.38` | `2a01:4ff:2f0:1963::1` |
| Machine | Role | Public IPv4 | Public IPv6 |
| --------- | -------------------------------------- | ---------------- | ----------------------- |
| `control` | ZeroTier controller, monitoring, docs | `77.42.68.181` | `2a01:4f9:c013:e6d0::1` |
| `ns1` | Knot DNS **primary** (master) | `46.224.170.206` | `2a01:4f8:c014:b5c5::1` |
| `ns2` | Knot DNS **secondary** (slave) | `157.180.70.82` | `2a01:4f9:c014:6d87::1` |
| `mx1` | Mail server (**MX** for cnx.email) | `5.223.65.38` | `2a01:4ff:2f0:1963::1` |
| `web01` | Public reverse proxy (TLS termination) | `5.223.55.246` | `2a01:4ff:2f0:2d8f::1` |
## Access
+3
View File
@@ -11,6 +11,9 @@
},
"mx1": {
"installedAt": 1781757322
},
"web01": {
"installedAt": 1781983723
}
}
}
+1
View File
@@ -10,6 +10,7 @@ in
../../modules/monitoring/server.nix
../../modules/monitoring/blackbox.nix
../../modules/monitoring/alerts.nix
../../modules/monitoring/parsedmarc.nix
../../modules/docs.nix
];
+1
View File
@@ -18,5 +18,6 @@ in
address = hosts.${config.networking.hostName}.ipv6;
};
time.timeZone = "Etc/GMT-8"; # UTC+8 (Singapore, fixed offset, no DST)
services.timesyncd.enable = true;
}
+33 -1
View File
@@ -13,6 +13,7 @@ in
imports = [
../../modules/dns/authoritative.nix
../../modules/dns/acme-mx1-secret.nix
../../modules/dns/acme-web01-secret.nix
../../modules/static-ipv6.nix
../../modules/monitoring/exporters.nix
];
@@ -74,9 +75,28 @@ in
'';
};
# ACME DNS-01, dedicated web01 key. A *separate* TSIG key (acme_web01) that only
# web01 holds, rendered from the shared secret (generator dns-acme-web01-secret,
# imported above). acl_acme_web01 scopes it to TXT updates at _acme-challenge on
# the cnx.network zone — the owner the wildcard *.cnx.network challenge uses — so
# this credential can write nothing but web01's own cert challenges.
clan.core.vars.generators.dns-acme-web01-knot = {
files."acme.conf" = {
secret = true;
owner = "knot";
group = "knot";
};
dependencies = [ "dns-acme-web01-secret" ];
script = ''
printf 'key:\n - id: acme_web01\n algorithm: hmac-sha256\n secret: %s\n' \
"$(cat "$in"/dns-acme-web01-secret/secret)" > "$out"/acme.conf
'';
};
services.knot.keyFiles = [
config.clan.core.vars.generators.dns-acme-tsig.files."acme.conf".path
config.clan.core.vars.generators.dns-acme-mx1-knot.files."acme.conf".path
config.clan.core.vars.generators.dns-acme-web01-knot.files."acme.conf".path
];
services.knot.settings.acl = [
@@ -102,6 +122,17 @@ in
"_acme-challenge.mail"
];
}
{
id = "acl_acme_web01";
key = "acme_web01";
action = [ "update" ];
"update-type" = [ "TXT" ];
"update-owner" = "name";
"update-owner-match" = "sub-or-equal";
# Wildcard *.cnx.network places its challenge at _acme-challenge.cnx.network,
# i.e. _acme-challenge at the cnx.network apex (where this acl is attached).
"update-owner-name" = [ "_acme-challenge" ];
}
];
# Automatic DNSSEC signing policy (primary only). ECDSA P-256/SHA-256 with
@@ -136,6 +167,7 @@ in
"acl_ns2"
"acl_acme"
]
++ lib.optionals (d == "cnx.email") [ "acl_acme_mx1" ];
++ lib.optionals (d == "cnx.email") [ "acl_acme_mx1" ]
++ lib.optionals (d == "cnx.network") [ "acl_acme_web01" ];
}) domains;
}
+22
View File
@@ -0,0 +1,22 @@
{ config, ... }:
let
hosts = import ../../modules/hosts.nix;
in
{
imports = [
../../modules/static-ipv6.nix
../../modules/monitoring/exporters.nix
../../modules/web-proxy.nix
];
clan.core.sops.defaultGroups = [ "admins" ];
# Public IPv6 (from modules/hosts.nix); SLAAC doesn't bring it up here.
cnx.staticIPv6 = {
enable = true;
address = hosts.${config.networking.hostName}.ipv6;
};
time.timeZone = "Etc/GMT-8"; # UTC+8 (Singapore, fixed offset, no DST)
services.timesyncd.enable = true;
}
+50
View File
@@ -0,0 +1,50 @@
# ---
# schema = "single-disk"
# [placeholders]
# mainDisk = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_108706511"
# ---
# This file was automatically generated!
# CHANGING this configuration requires wiping and reinstalling the machine
{
boot.loader.grub.efiSupport = true;
boot.loader.grub.efiInstallAsRemovable = true;
boot.loader.grub.enable = true;
disko.devices = {
disk = {
main = {
name = "main-ddd46ebf135244608078712d6ec76691";
device = "/dev/disk/by-id/scsi-0QEMU_QEMU_HARDDISK_108706511";
type = "disk";
content = {
type = "gpt";
partitions = {
"boot" = {
size = "1M";
type = "EF02"; # for grub MBR
priority = 1;
};
ESP = {
type = "EF00";
size = "500M";
content = {
type = "filesystem";
format = "vfat";
mountpoint = "/boot";
mountOptions = [ "umask=0077" ];
};
};
root = {
size = "100%";
content = {
type = "filesystem";
format = "ext4";
mountpoint = "/";
};
};
};
};
};
};
};
}
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
# Shared TSIG secret for the dedicated acme_web01 key.
#
# This key lets web01 — and only web01 — write _acme-challenge.cnx.network TXT
# records on ns1 to obtain its wildcard (*.cnx.network) TLS cert via ACME DNS-01.
# ns1 scopes it with acl_acme_web01 (attached only to the cnx.network zone) so the
# credential can touch nothing else. ns1 renders this secret into a Knot key file;
# web01 into a lego rfc2136 env file; both must carry the same secret, hence one
# shared generator with a per-host renderer that depends on it. Imported by ns1
# and (via web-proxy.nix) web01.
{ pkgs, ... }:
{
clan.core.vars.generators.dns-acme-web01-secret = {
share = true;
files."secret".secret = true;
runtimeInputs = [ pkgs.openssl ];
# 32 random bytes, base64 — a valid hmac-sha256 TSIG secret.
script = ''openssl rand -base64 32 | tr -d '\n' > "$out"/secret'';
};
}
+4 -1
View File
@@ -20,7 +20,10 @@ mx1 IN AAAA 2a01:4ff:2f0:1963::1
mail IN CNAME mx1.cnx.email.
@ IN MX 10 mx1.cnx.email.
@ IN TXT "v=spf1 mx -all"
_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:postmaster@cnx.email"
; Aggregate (rua) + forensic (ruf) reports go to the dmarc@cnx.email mailbox,
; which parsedmarc on control polls and feeds into Grafana. fo=1 asks reporters
; to send a forensic report on any SPF/DKIM failure.
_dmarc IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@cnx.email; ruf=mailto:dmarc@cnx.email; fo=1"
; ---- DANE / TLSA ----
; "3 1 1" = DANE-EE, SPKI, SHA-256: the digest of mx1's certificate public key.
+7
View File
@@ -25,3 +25,10 @@ control IN AAAA fd06:1bad:ece2:92ad:ba99:9306:1bad:ece2
;@ IN A <web-ipv4>
;www IN CNAME cnx.network.
monitor IN A 5.223.66.36
; ---- web01 (public reverse proxy / TLS termination) ----
; Serves a wildcard *.cnx.network TLS cert (ACME DNS-01) and forwards to internal
; services over the mesh. Add a vhost in modules/web-proxy.nix and a CNAME here.
web01 IN A 5.223.55.246
web01 IN AAAA 2a01:4ff:2f0:2d8f::1
grafana IN CNAME web01.cnx.network.
+24
View File
@@ -44,6 +44,26 @@ let
(mailPort "443" "MTA-STS policy (HTTPS)")
];
# web01 is a public reverse proxy with TLS termination. 443 serves the proxy;
# 80 only carries Caddy's HTTP->HTTPS redirect (the cert uses ACME DNS-01, not
# HTTP-01). Admin rides the mesh.
webRules = [
{
direction = "in";
protocol = "tcp";
port = "80";
source_ips = world;
description = "HTTP (redirect to HTTPS)";
}
{
direction = "in";
protocol = "tcp";
port = "443";
source_ips = world;
description = "HTTPS (reverse proxy / TLS termination)";
}
];
dnsRules = [
{
direction = "in";
@@ -74,4 +94,8 @@ in
zerotier
ping
];
"clan-web01" = webRules ++ [
zerotier
ping
];
}
+4
View File
@@ -25,4 +25,8 @@
ipv4 = "5.223.65.38";
ipv6 = "2a01:4ff:2f0:1963::1";
};
web01 = {
ipv4 = "5.223.55.246";
ipv6 = "2a01:4ff:2f0:2d8f::1";
};
}
+26
View File
@@ -0,0 +1,26 @@
# Shared credential for the dmarc@cnx.email mailbox.
#
# DMARC aggregate/forensic reports are delivered to dmarc@cnx.email on mx1;
# parsedmarc on control fetches them over IMAPS across the mesh and needs the
# *plaintext* passphrase, while mx1's mailserver only needs the sha-512 hash.
# clan vars secrets are per-machine, so this generator is shared (share = true)
# to make the same value available on both hosts. Files are root-owned: SNM reads
# the hash as root, and parsedmarc's ExecStartPre reads the passphrase as root.
# Imported by mx1 (via mail.nix) and control (via monitoring/parsedmarc.nix).
{ pkgs, ... }:
{
clan.core.vars.generators.mail-dmarc-cred = {
share = true;
files."passphrase".secret = true; # read by parsedmarc on control
files."hash".secret = true; # consumed by the mailserver on mx1
runtimeInputs = [
pkgs.xkcdpass
pkgs.mkpasswd
];
script = ''
pass="$(xkcdpass --numwords=4 --delimiter=- --case=lower)-$((RANDOM % 90 + 10))"
printf '%s' "$pass" > "$out"/passphrase
printf '%s' "$pass" | mkpasswd -s -m sha-512 > "$out"/hash
'';
};
}
+23 -7
View File
@@ -60,15 +60,27 @@ let
}) accounts
);
loginAccounts = lib.listToAttrs (
map (addr: {
name = addr;
value.hashedPasswordFile = config.clan.core.vars.generators.${genName addr}.files."hash".path;
}) accounts
);
loginAccounts =
lib.listToAttrs (
map (addr: {
name = addr;
value.hashedPasswordFile = config.clan.core.vars.generators.${genName addr}.files."hash".path;
}) accounts
)
// {
# DMARC report inbox (rua/ruf target in the cnx.email zone). Its password
# comes from the *shared* mail-dmarc-cred generator instead of the per-machine
# set above, so parsedmarc on control can read the same passphrase over the
# mesh. Retrieve it with: clan vars get mx1 mail-dmarc-cred/passphrase
"dmarc@cnx.email".hashedPasswordFile =
config.clan.core.vars.generators.mail-dmarc-cred.files."hash".path;
};
in
{
imports = [ ./dns/acme-mx1-secret.nix ];
imports = [
./dns/acme-mx1-secret.nix
./mail-dmarc-cred.nix
];
clan.core.vars.generators = passwdGenerators // {
# Render the shared acme_mx1 TSIG secret into a lego rfc2136 env file. lego
@@ -117,6 +129,10 @@ in
# Keep the private key fixed across renewals so the DANE TLSA "3 1 1"
# record (public-key digest, published in the zone) stays valid.
extraLegoRenewFlags = [ "--reuse-key" ];
# Caddy serves the MTA-STS endpoint from explicit cert file paths, so it
# won't notice a renewal on its own — reload it whenever the cert changes.
# (Merges with the postfix/dovecot reloads SNM wires up for this cert.)
reloadServices = [ "caddy.service" ];
};
};
+7 -1
View File
@@ -13,7 +13,13 @@ let
readVar =
machine: file: builtins.readFile "${dir}/vars/per-machine/${machine}/zerotier/${file}/value";
hosts = lib.genAttrs [ "control" "ns1" "ns2" "mx1" ] (m: readVar m "zerotier-ip");
hosts = lib.genAttrs [
"control"
"ns1"
"ns2"
"mx1"
"web01"
] (m: readVar m "zerotier-ip");
# RFC 4193 prefix of this ZeroTier network: fd + the 8-byte network id + the
# 0x9993 marker. The network id is a public var on the controller (control).
+194
View File
@@ -0,0 +1,194 @@
{
"uid": "cnx-uptime",
"title": "CNX Uptime",
"tags": ["uptime", "availability", "cnx"],
"timezone": "browser",
"schemaVersion": 39,
"version": 1,
"refresh": "30s",
"time": { "from": "now-24h", "to": "now" },
"templating": { "list": [] },
"annotations": { "list": [] },
"panels": [
{
"type": "row",
"title": "Uptime",
"id": 1,
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 0 }
},
{
"type": "stat",
"title": "Host status",
"description": "Whether VictoriaMetrics is currently able to scrape each host's node_exporter. UP means the host (and its mesh path) is reachable; DOWN means the scrape failed. One tile per machine.",
"id": 2,
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"gridPos": { "h": 6, "w": 12, "x": 0, "y": 1 },
"fieldConfig": {
"defaults": {
"color": { "mode": "thresholds" },
"thresholds": {
"mode": "absolute",
"steps": [{ "color": "green", "value": null }]
},
"noValue": "no data",
"mappings": [
{
"type": "value",
"options": {
"0": { "text": "DOWN", "color": "red", "index": 0 },
"1": { "text": "UP", "color": "green", "index": 1 }
}
}
]
},
"overrides": []
},
"options": {
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"colorMode": "background",
"graphMode": "none",
"textMode": "value_and_name",
"orientation": "auto"
},
"targets": [
{
"refId": "A",
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"expr": "up{job=\"node\"}",
"legendFormat": "{{instance}}",
"instant": true
}
]
},
{
"type": "stat",
"title": "Current uptime",
"description": "Time since each host last booted (now - node_boot_time_seconds). A value that drops back to near zero means the host rebooted.",
"id": 3,
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"gridPos": { "h": 6, "w": 12, "x": 12, "y": 1 },
"fieldConfig": {
"defaults": {
"unit": "dtdurations",
"color": { "mode": "fixed", "fixedColor": "text" },
"noValue": "no data"
},
"overrides": []
},
"options": {
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"colorMode": "none",
"graphMode": "none",
"textMode": "value_and_name",
"orientation": "auto"
},
"targets": [
{
"refId": "A",
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"expr": "time() - node_boot_time_seconds{job=\"node\"}",
"legendFormat": "{{instance}}",
"instant": true
}
]
},
{
"type": "bargauge",
"title": "Availability over window",
"description": "Fraction of successful scrapes over the selected time range, per host (avg of up over $__range). 100% means every scrape in the window succeeded; dips reveal flapping or outages. Red below 99%.",
"id": 4,
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 7 },
"fieldConfig": {
"defaults": {
"unit": "percent",
"min": 0,
"max": 100,
"color": { "mode": "thresholds" },
"thresholds": {
"mode": "absolute",
"steps": [
{ "color": "red", "value": null },
{ "color": "yellow", "value": 99 },
{ "color": "green", "value": 99.9 }
]
},
"noValue": "no data"
},
"overrides": []
},
"options": {
"displayMode": "gradient",
"orientation": "horizontal",
"showUnfilled": true,
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
}
},
"targets": [
{
"refId": "A",
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"expr": "avg_over_time(up{job=\"node\"}[$__range]) * 100",
"legendFormat": "{{instance}}",
"instant": true
}
]
},
{
"type": "timeseries",
"title": "Uptime over time",
"description": "Host uptime across the window. The line should climb steadily; a reset to zero marks a reboot.",
"id": 5,
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 7 },
"fieldConfig": {
"defaults": { "unit": "s", "custom": { "fillOpacity": 0 } },
"overrides": []
},
"targets": [
{
"refId": "A",
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"expr": "time() - node_boot_time_seconds{job=\"node\"}",
"legendFormat": "{{instance}}"
}
]
},
{
"type": "timeseries",
"title": "Up/down history",
"description": "1 while a host's node_exporter was scrapeable, 0 while it was not. Gaps to zero are outages or lost mesh connectivity.",
"id": 6,
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"gridPos": { "h": 6, "w": 24, "x": 0, "y": 15 },
"fieldConfig": {
"defaults": {
"unit": "short",
"min": 0,
"max": 1,
"custom": { "fillOpacity": 20, "lineInterpolation": "stepAfter" }
},
"overrides": []
},
"targets": [
{
"refId": "A",
"datasource": { "type": "prometheus", "uid": "victoriametrics" },
"expr": "up{job=\"node\"}",
"legendFormat": "{{instance}}"
}
]
}
]
}
+60
View File
@@ -0,0 +1,60 @@
# DMARC report analyzer, imported by control only. parsedmarc fetches the
# aggregate/forensic reports that land in the dmarc@cnx.email mailbox on mx1,
# parses the XML, and stores results in a local Elasticsearch; the official
# parsedmarc dashboard + an Elasticsearch datasource are auto-provisioned into
# the Grafana instance that server.nix already runs on this host.
#
# IMAP runs over the ZeroTier mesh, not the public net: we pin mx1.cnx.email to
# its mesh address in /etc/hosts so TLS still validates against the public
# Let's Encrypt cert (primary domain mx1.cnx.email) while the bytes stay on the
# overlay. The mailbox passphrase is the shared mail-dmarc-cred secret; parsedmarc
# reads it as root in its ExecStartPre, so root-owned (clan default) is fine.
{ config, lib, ... }:
let
mesh = import ../mesh-hosts.nix { inherit config lib; };
in
{
imports = [ ../mail-dmarc-cred.nix ];
# Elasticsearch 7.x is under the (unfree) Elastic License; allow just this one
# package rather than opening allowUnfree globally.
nixpkgs.config.allowUnfreePredicate = pkg: lib.getName pkg == "elasticsearch";
# Keep mx1's IMAP traffic on the mesh while presenting the public cert name.
networking.hosts.${mesh.hosts.mx1} = [ "mx1.cnx.email" ];
services.parsedmarc = {
enable = true;
provision = {
# Local Elasticsearch on 127.0.0.1:9200 (loopback; no firewall change).
# datasource + dashboard default to true once ES and Grafana are both on.
elasticsearch = true;
# GeoIP needs a MaxMind account/license key; skip it (reports still parse,
# just without source-IP geolocation).
geoIp = false;
grafana = {
datasource = true;
dashboard = true;
};
};
settings = {
imap = {
host = "mx1.cnx.email";
port = 993;
ssl = true;
user = "dmarc@cnx.email";
password = {
_secret = config.clan.core.vars.generators.mail-dmarc-cred.files."passphrase".path;
};
};
mailbox = {
watch = true; # IMAP IDLE: process reports as they arrive
delete = false; # archive processed reports, don't delete
};
general = {
save_aggregate = true;
save_forensic = true;
};
};
};
}
+1
View File
@@ -46,6 +46,7 @@ in
(target "ns1" (v6 mesh.hosts.ns1) 9100)
(target "ns2" (v6 mesh.hosts.ns2) 9100)
(target "mx1" (v6 mesh.hosts.mx1) 9100)
(target "web01" (v6 mesh.hosts.web01) 9100)
];
}
{
+73
View File
@@ -0,0 +1,73 @@
# Public reverse proxy with TLS termination for web01. Caddy fronts internal
# services and forwards to them over the ZeroTier mesh, never the public net.
# The cert is a single wildcard (*.cnx.network) obtained via ACME DNS-01, so
# adding a vhost needs no new issuance. Public ports: 443 for the proxy and 80
# only for Caddy's HTTP->HTTPS redirect (issuance never uses inbound HTTP).
{
config,
lib,
pkgs,
...
}:
let
mesh = import ./mesh-hosts.nix { inherit config lib; };
hosts = import ./hosts.nix;
certName = "cnx.network";
in
{
imports = [ ./dns/acme-web01-secret.nix ];
# Render the shared acme_web01 TSIG secret into a lego rfc2136 env file. lego
# (via security.acme below) uses it to write _acme-challenge.cnx.network TXT
# records on ns1, which authorizes the acme_web01 key for exactly that owner.
clan.core.vars.generators.dns-acme-web01-rfc2136 = {
files."rfc2136.env".secret = true; # root-owned; systemd reads it as root
dependencies = [ "dns-acme-web01-secret" ];
script = ''
printf 'RFC2136_NAMESERVER=${hosts.ns1.ipv4}:53\nRFC2136_TSIG_ALGORITHM=hmac-sha256.\nRFC2136_TSIG_KEY=acme_web01\nRFC2136_TSIG_SECRET=%s\n' \
"$(cat "$in"/dns-acme-web01-secret/secret)" > "$out"/rfc2136.env
'';
};
security.acme = {
acceptTerms = true;
defaults.email = "postmaster@cnx.email";
# One wildcard cert for every vhost this proxy serves, via DNS-01 (so issuance
# never depends on inbound HTTP). Port 80 is open only for Caddy's
# HTTP->HTTPS redirect, not for ACME.
certs.${certName} = {
domain = "*.cnx.network";
extraDomainNames = [ "cnx.network" ];
dnsProvider = "rfc2136";
environmentFile = config.clan.core.vars.generators.dns-acme-web01-rfc2136.files."rfc2136.env".path;
# ns1 is the only nameserver that accepts the acme_web01 UPDATE; check
# propagation against it directly rather than a public resolver.
dnsResolver = "${hosts.ns1.ipv4}:53";
# Caddy reads the cert from explicit file paths (tls directive below), so it
# won't notice a renewal on its own — reload it whenever the cert changes.
reloadServices = [ "caddy.service" ];
};
};
# The lego-issued cert is owned group=acme; Caddy needs to read the key.
users.users.caddy.extraGroups = [ "acme" ];
# Reverse proxy. The explicit `tls cert key` points Caddy at the wildcard cert
# and disables its automatic ACME, so no extra issuance happens. Backends are
# dialed over the mesh by their ZeroTier address (mesh.hosts.<name>).
services.caddy = {
enable = true;
virtualHosts."grafana.cnx.network".extraConfig = ''
tls /var/lib/acme/${certName}/cert.pem /var/lib/acme/${certName}/key.pem
reverse_proxy http://[${mesh.hosts.control}]:3000
'';
};
# 443 serves the proxy; 80 only carries Caddy's automatic HTTP->HTTPS redirect
# (the Hetzner cloud firewall also scopes these in
# modules/hetzner-firewall-rules.nix). Admin still rides the mesh.
networking.firewall.allowedTCPPorts = [
80
443
];
}
+6
View File
@@ -0,0 +1,6 @@
[
{
"publickey": "age1yey6gxgsyl4tj6ek0tve2pckt6qersqspk66ukkzum8mrr6zppqsj4jn3m",
"type": "age"
}
]
+1
View File
@@ -0,0 +1 @@
../../../groups/admins
+18
View File
@@ -0,0 +1,18 @@
{
"data": "ENC[AES256_GCM,data:u+O5nWbFlvp6SGyHJggfkCLCT0ZuDy89e/VGGQNdt3yYzgdNmnrtd+2q+Ft3MtoOSSCLvStriGQzfLhcqEgqGgt3PqfIzCO1IG4=,iv:GyrZ1XUiOZe1I1Z/HebTy2NM2tfDHxIH5zGVk7HD+xQ=,tag:js6fbXWajVZSxt0hmnnA5g==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWenArV1pZMURzNElTeGlC\nRSttUFRwM2E5d2htVDlFcTkwVDIrV2JxQjE0CmE0NUZ4UERHdHpqYk9uK01GOTFQ\ndW5UNlRrY0hvU2pNQmpSanh5RG5YbVkKLS0tIFdYQmkva1NORG80U3dDSWszZTlO\nOXViWUxMTVR1NE00cjdpVXpVS1J5YU0KHBkeKAJZDc+R1GLKwDYLyQBlEW7tPnMh\nf3tsUvtD0flqPAXNeDgyOmKufP7U6oDy/OriFC9+zYQbWyEEc6CZHg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBL05xT1BJ\nSldCSkFhaFErWDNMeXMvRksvekkwNUZLZFVtSmUydVRrNG9JTwpFaHNsVThZN2gw\nMlNxUXhnN2xYNFluK1hadGxzMFZuaWR3cVFRYW9mWndVCi0tLSBUUmRMSnJCeTRM\nUVdKY3hzWVRkQkFuQ3FaRDVZSEp1b2N1ajg5RnlhT3VRCjX/vWj0We88ATiz808w\nz60RL0BvDGJ6m1BNmqAdtfCCClH33YXQBGrKT2E5elvOTl0iOCrT7HPjzXxJZXuw\nkKg=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:29Z",
"mac": "ENC[AES256_GCM,data:uD+L3op6ZPtvmLreJ7S4GE6bQuItV87w1LTMFvjI1Kb5+Z0sXlL0TpYO8WLx8X0yaL3HddwlmBKYQGp/OlRPqZMFDbQuK25oeKB54jfm6YDn66rrMQJl1FOw68fLJaHYNjNelEg/bj2WG7YpfZBoWO67MW6F+44Rg4XF85w/1x0=,iv:X9TmEL5JkcC9waLumWpgpBwp3YWLMslZi++dv2HZ0mk=,tag:i7c1CxT1Xv/+T/jY9E0cdg==,type:str]",
"version": "3.12.1"
}
}
+1
View File
@@ -0,0 +1 @@
../../../users/berwn
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../../sops/machines/ns1
@@ -0,0 +1,22 @@
{
"data": "ENC[AES256_GCM,data:hunVccO40N4RQ5oOB/yJi9CFCYAMGoYkjPCG7pRXng6Rd2vqE9Dx2CmmAV3w1gkFm0Bxk29QIIZA25bL3Y2sAE8h0xG3myNOKUg9M6cSisoSy6NwtBJjl3AEjeOaQ18k6PhBB/d2/qo6a++d,iv:NPZKfBy7O8Zp2rlj8ZB2uQx3alzwGrWOoio7XOZtvvM=,tag:WDtFUT/TA8vIcKuX58oaUQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1fanu282vm7njjweqhrpcfcwpttuhce8js4tsyfry98l0neaqpewqs5s7nt",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuMyt0eFBJOWplVXV2NXhD\nbGF6RjJhdi9MSUMrdGlHNnBOcXB3MG5pQ1drCmFnZm9jTVZ0dWFrME9iSmtNMUFv\nNDlDaU5nc3dLQ25QRUpVNkh3Wmk4RWMKLS0tIHozSTNHQXhmRnpsUEF1UTd0SFdP\nT2xTLzRCQVhNcm5FOURieGk2SHhzam8K3E5swVSS2+69kE3lbRnc88melsTUKyH6\nZMvsAVYy1Fwy+wfo5UJzlpXux5+5Lv05eSrpOvWj9aA+fjHG8UdRZQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsK3gwRS9nRXFYbE44bDRm\nSWJBb1NFSnBoT2JlQUZra25TOEpuY1FESjJVCndMSHQvYUszN3UyZDUzTi85OFVN\nQUR3aC9JK2tZZ2FuTEJyeFNvc0ZnWTgKLS0tIGphVlorTDhwYTJNbnRzOXNOZXJG\nM2t1VElJZzY5dEJCUDFuU1lTcUpCbWcK0fyj4CB9Y0kYDrIyvWidAwRSzCUbFcWi\nRnIukpyLwJzMIt4M5tIisxbvX/Eer9TfSXK8blNZ+fvCwr+qyEZgPQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBdXFaM1Nj\nRkl3OUFXczg4bGRuNmwwMm9WaFVrQ05aYWFTMWoyaENQSmdPTQpqa0JIb1Zva3ZJ\nZTBjZSsrNHpzdzVBRjg5MnNMSFo2aXR0eXRpVXY3dys4Ci0tLSBBTDBPZzdMNWw5\neGttaWxnT3A5ZnV0RnczRnI3OXdiWm9Mc2UvRE1YaElNCrrZWEZzx3kzwX3p9z14\nEh5eB7NBDqMUnnIzdaz7cgD/SKeKbBAKXAeCpyUvE/EEqyh8PCLKNG3J1dmb7XRp\n+rc=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:43Z",
"mac": "ENC[AES256_GCM,data:TRwxqjf/HiVuuLe0weRJEDvpPUyapQAxs2m3LFmIMdWv43XQh2MCV95IwegFDnZHe/qd9V+TsvobeXoYeJalCIFrqwW9HphqeaKpWuUw/+IuvLtH11Jm6a1Pxe6fDt75Y28YgZYJt8QSH7qaSkrCANmeoYIVBAeI77byYQqHS3o=,iv:ryK76YC1j0UvgkY28f+v9cRwjeDvlpSxHcOCUiYhu/o=,tag:nNuL3CmYWRcCBDA4scy8dA==,type:str]",
"version": "3.12.1"
}
}
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../../sops/machines/web01
@@ -0,0 +1,22 @@
{
"data": "ENC[AES256_GCM,data:xE+wW3x5ZFqFbP7Q1RuG8zSZPgV/J/Rw+92NBI6U8c0OR5KQ9Gr+mnW323g5oUPU+bUod0eBh5Iv/ciYenBYwhIbANHFzr6ZO8qt7n1JMzwjLezfuVI21R09PdS/x1rjyvqGvOr9XQYZYCIYOLShXtEqjl6jkvZrbZ1qkpdyiUqsR/dqnTRsrmMlaYVGQ/WeR7l9FOp02DyonYT8R2X0jIKy99H+9g==,iv:t1mOOLJyCyRi5f83mG0kRZJdxKFKVTIIaP1JOoRDFkc=,tag:oVDO11HTbk/r0cFSwVh/kw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArTE9OVjh5SzhZeGhobGls\nR1hJOEsrcTRjMU5GYnpsM1BldTRCZ0J5T0FZCmJKRzNUN0JZZnFPVTRmWGZDSnhF\nYnVER0VIaUxTTWxMTGlCb0hSR2Z4NjQKLS0tIDBpMFF6NWhxR3Rsd3UyVWdvRDEr\nSi80YjdHSFBuZmJQMmZVc1J2YUxLN1kK7ApaZOgNt/lqZDJreBLUXgQnsdOk5x/3\nTeVlKGYlLug7X7IsgyND09rWiaaM1mICXaA5tahdWwsyoFEfu5n4Iw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yey6gxgsyl4tj6ek0tve2pckt6qersqspk66ukkzum8mrr6zppqsj4jn3m",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsNnM0T3p6K28zM3FBZVJn\nVXZMSmhncCtaUHpySEJVSDNIbWtZc1F2VFJzCmcrNlpPQXhpdU12NGxibklQUmJW\nT1JCajZTOE43VWU5Q1NKR2lVbmtjUUEKLS0tIEN0cm5LajdCS3FPMFRSR3IwbUE4\nTHB4anBXZ0JraVkvQ3hNcE9zLzV5YkkKofqjv0Oe3y56HXO0SZG7G6A6vatuE3Jv\n3bGnRwCo6MCz9DMpTU/bKrGnmpQhHMYoGK5DmFhV21nH6Kwh+bnqjw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBaEZpUTBI\nTTJ4WjNQclBabEs0SDFsbTBUaEI2eldOblR3eEp3ckRwaVJSVgpQY3YwNDJyUDRC\nTWpjN0pWTDJxZm5aaWI0aThpcUtWemdCTFRjZUtRcWFnCi0tLSBjVFc0WWMvOEZW\nNjJyeGxvZUtjMlhXMU5PWndJbnVxZDZZTEFhQWM2YmI0CnA0SDzXPJb+K6NxR45E\ns+t5k+20F8cGyemSgmBb/RWB0vxA9HYpMpUWJsll0oMxT54lRtsziANTPAPMyr1J\n7ZU=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:44Z",
"mac": "ENC[AES256_GCM,data:IdjbnUrkcU+mXUBSwE/gtW0ACBVXkXr+qI3gOyY7RlWnD8wxAiMQY2TIM8edmrY7fc39G9c8cwx/p6HpLUJXNEeXUZzDdoXO0HqOl8Fxs6LZtykzTt4zGldbEYdpguuyV0aIxT7C9OI10GRaa0RjpP0XPpr4wc0/CT9/F8Q22qI=,iv:lhEreXIvuE7SBQIgZ0cFGbAYLdb1Ez6hH2v3O8+jOUY=,tag:GfcOGiZqVBPxbagNtjLEQQ==,type:str]",
"version": "3.12.1"
}
}
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
$6$2/XqJoWZP62VbWNk$I3QeJOZoDBueIsymuifFs4ey7dXOLfl5rp4g15DKmGvD4WuueYiTQRxBY4mxbDRL19uL8U02NJ07JpfMs/vBL.
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1,18 @@
{
"data": "ENC[AES256_GCM,data:hZuIBcV9zWv27qrGxi6vU9rq8x+MKYizx5SGKZ0sCCU3CvI=,iv:E3CNJCCVgei6+iKnUNCbKFhtCLqs8uQZtkFqYeP56so=,tag:IELHXoZI/7i4h4OLbxTmeg==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlL09jYjIwTWVnQUJIMHc1\nRHhJUGg3YVkzbHc5SG5PV3RSUkhwdCtBYjNVCmx3d1ZzYm5aYTdGSnAzTGRGeWFo\ncWU4V0NjVExjOE9iT2VkY2lTUGpWT3MKLS0tIDg3eXYrbTQyTDIvcFVxYVBpZkx3\nL2RKcWFoMzVGd0pvMDdoYThHYWpqWWcKr4KSWWSMlPkSJPWFYIApOnLNNbmSQx1J\nw0sAKKmmKHQbxfgNFaAKBHXILvTG3mqKOaJnN/t9G9ncUcPnrAYXQg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBKzRUZVMx\nMkF6L2JVaG9HT0dJUmFBY2xKaEZtbTZBWU1MOWVRZU1ocnRybwpQdHZJbXpZc0FQ\nbUU5ai9Nc3VDUGxMbGJFcG52bG9iN0MzM21OKzZFMlZjCi0tLSBKRVZpQWhJNFVC\nSnhJVVJySUg4QkVqcXVKSGErbG9PeXdGbjRXbWs4ZzkwCgJrL+X4olZNxWBX5EbD\nmVjYUXC/UZBAOZYThCSpKRSUc8Ri9wIvzwwOn2VLxPNuMfA+u40e3V+iDQI2D5vC\nCes=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:30Z",
"mac": "ENC[AES256_GCM,data:amqgVdVVIBhmukvno/wTgC9rn3vJPhjM1bIkk9IMzooX+58wVnOsbaYCmyNekLZzP+9CimILFChXZomuXlHfCAt7q70b1DB6paRMeR1FKzeW83xCsjf+AylZj7y5x4zQelHTHppUKA5gUPjhjDUAx3qvpY/kgdEm8Zy1MhlEb58=,iv:GyZ+eGkk1aBiUftC9UOdNSipymR3teotW1ZEN2RDB3o=,tag:UifamkVXfYpuZc4O1DhsKA==,type:str]",
"version": "3.12.1"
}
}
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILejqOdcr/7ttLRY0JEv6HcZ9x+pJd7p4T6yQRQ3VvW3
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../../sops/machines/web01
@@ -0,0 +1,22 @@
{
"data": "ENC[AES256_GCM,data:HuCJOdq4/WjX8oYQrjGWIMYykxm4LDoQEpT1FS6pa0oapRKg0a7ayqvKZSK+gXyLS5RjM/qWLtPCQgfUkILIPiXmSXCRElkgVhIE0H1msmbBraXhg3RdScjF7nJVHFdzWcZyh6LSNzgHk7GOCl5CEhK4/FPzYLSLOzd34J0g3QjXhlsDDe6fe8VAHNeBikbj/8hsqWhzQqeenJqNIat6TfxgknedmqhhgnuwPc0Zp99peHOc/qcErn4NENsSNqqCBO03yxhuipjb4yahGjHcMHe2qDVyU6/h0HlRsi7tjyQ6QJCmNUoAbhJfnC7ybWMRvOWKbafMw4NKA2yzV3nr6Z+HaE5cz2f7s4CkMHnue+npjARahSdPHm8rKEV/4z20t/bLTEmH2gyfrIo8PtyCLeOEuc4eb9DoGGgZaoVmFpJEx9Oy3dgXAA16VvB1jpcwp48F3ODW/MPEMCzvmvyENP6ERzgLWfsx+HfMt1UnNECnVHbgQ1toEzGrurQYKGyg0AO9,iv:TAstH1iU+msI9ORXZVfLU88iBY+/EoW+dHwi7WrbPmM=,tag:vPACqxlMZCtV44dWmhVC5Q==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0TndoeEwwT1YyNG02cXdT\nWFNabUpBM25ZcDJ3V1NtcG5rTlJuaHkvbFZZCm1lNXRRS3NUa2lUa3VRYTZ1MVBF\nUzhtc3czWG9nS2R0OTlzUU1BdE54azgKLS0tIFRUZ0JUZ3gvRHoyK3l5OER5dS8v\nZGs0cXQ5TVBDQTRMaXJUK1lmRHFZS3cKljcBSKYg/dJk5RQda+H5GWwCBSuZiFyX\nGUkV6NQ/ae9BJ8QChI64Ur3t8uRW5m3nWtc85faxK6HRKx8owW7BLQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yey6gxgsyl4tj6ek0tve2pckt6qersqspk66ukkzum8mrr6zppqsj4jn3m",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtSFVXbnJjcXFrcWs5WEZK\nUVI1Y3pCNzFqOWNJVkNpRHQzY3NoN0F3dXgwCkFxOTZnbHJ5eUpaWDJFczNsd2lH\nVjZmcEpwbUhKVzNETnp0MHdsaEVkTXcKLS0tIExzeGFRQ0lxSUt6MFVqcUNXbVdE\nNHdNa2ZsWDBPanQ3aWFabGVhUVlJc0EK3owAjyU++LLO9gzei7YxQVkFFGUOKjAe\nHwB1fMOdaxynbSahrLDiLTqg+Mgpa2HibX42KJZaz9x7eZ0BZRja1w==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBMVh6V0ZX\nYXplbk9XcG5ScmdkQlZhMnlHeWFuVzdMeFQ4YkM4SmIrRUdRYgpPU0R4SDRZeTdt\nV1R6cEhDM3dyMG9Ga1pTSjRBYWxCV0RKOEhVWGxXY1RvCi0tLSA1MnRzei9EakNw\ncHI3Z0Q5T0ZGRG1yUTg2S2QyL2FyeVpIaldtVVpGZEtJCtlzVqD4YdLxn3doApaQ\ny1CtiPrYJCmxpwAlmDdD7JtI09uteTHTvoEJ3mww0vq4ubBw8es7DarrMVStyvWO\nn3s=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:30Z",
"mac": "ENC[AES256_GCM,data:19FtQfyusFAikxdNVh2LUTMv/ak5TKXPf7OrjW37GDfsc9nFF2OxxqAWEo+20CacWXA1AGBvCLZYqVUdPwLSHMOlhsWqI8SNrmbW0cb9DcX30qaTtz9HO7tipfAuAf/0ZtE1Z1NIpRoaMwm8kn6fzzn0jGZ29W3jnKa8o/XmqIA=,iv:ip4q/5SA3Gch5tgl2KUetDF0faBMLtnKr0tziQTCSqM=,tag:yGvWmvuMDZqkwNzQHJ3GNg==,type:str]",
"version": "3.12.1"
}
}
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../../sops/machines/web01
@@ -0,0 +1,22 @@
{
"data": "ENC[AES256_GCM,data:51hcHMIxXU3+SepHjw5Pr6C5hcBq2OpcoCIGnokGxudRpeR85yjhBrG7PXgmRvUEN+8JDe4QgvLxNtwk1cLBAFKjAZlDmI67ONf+zRIzlPKEEM1Zt4rjpbncpc1zWPdnLGJuyHU6PdX6aQ==,iv:fmgInavAI5dFqmvPaVmxCQBJOOkPDPCQm75NRNVZD0I=,tag:yp2d9VRiJyCfSTA9dzFuww==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2c2VPUzRXMUN4MkN5VEtG\nQ0ZsaERON1RxOHdPV2ExU0tTSWhhS3NHS3cwCklXczlsRWVwYTZYcDMrazc3OW44\nMHlxbk5TNXVhcUdjcklHQWl5VDdieXcKLS0tIFE1Zll4N0VDcmE2UytHTDE1QnZN\ncXdDS2ZKbU83ZFBCc0xpTmNBWmdaeGcKYxXG0owNFBP018n4PDYoDLzHG+Z5sSoz\nPjKV/aNQZvn2qRAulXD2lembRZvEEsViBETfnOFV3zNqmWSuKQ20sg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yey6gxgsyl4tj6ek0tve2pckt6qersqspk66ukkzum8mrr6zppqsj4jn3m",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQcDh6OUkwbVpzQnF1Vjcv\nRnd2eUp5d2lXeGhUS1lIU1VsOE5hOFZJb0NvClRUdEpsZEdyb3lBTi9DNTN5eUo1\ndDdTT05xY2kzTW1DUVgzbDBUZHIxTGsKLS0tIGFNQjhadnkzSWRvWkMxMnlvR2xV\nUDVkTWdMZlVMQmdVUzRsOGovc1g1QnMK9ciVz6d+sV5QelnGzduoKO3l9rZhE6H0\nDgZ6I4ebONSXr87CYzlZ/ZJmaQ1Gca/qppdvmONtNYZdcUvcxJWaVQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBdXVuWVNk\nc0h4b21GQVlrb2hHOVRqdUZUbnpLa0R4MXJzZ2VIblhYaXBxcworY0RMNVN4aEVZ\nYWJMc05YYVdRVENLQjhQMllPVEhkNHgvcDhUOWN6RjlVCi0tLSAxRWJkWkdWQmtU\naHNkRWNoL0RCcEpyS1VvNFZvV01BTGFSWHZHc1poUUU4Cls9GVVnlzcQp/Si7blT\nsw7EOLeqWsap9pnZrNUzOZ5CAGH4pIryJtbnTJdR4RC/ohWFGZoIPd+MYghpA8Uh\nVa4=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:30Z",
"mac": "ENC[AES256_GCM,data:Q6OM/6Xsqj9R/rWmbxKBmIZ2z0F556uBjWwGBiN/MXprPYJpQ+bqxwB1E9U+t/xDDAprn5zKRB7emXAc1DYr00SfAFdJL0WQF79t38+b4YJD+uxaXTGT2czhDODMofNwhpUJ2YrC4IWDwt1ZKJcWSIYG2rQevKaL9chjakC1ZPU=,iv:VsQMopPCsJ9W1IDzUuNv1U0Iv5vpwZ3EXhkuqVV8+RU=,tag:ujcjDgd2wTC8xHcqzMLqkA==,type:str]",
"version": "3.12.1"
}
}
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1,18 @@
{
"data": "ENC[AES256_GCM,data:gE+MLYLJ8S1o3zKYTL/ZDCbNObr0eaGpDjoqOTg87nDceyjOpvF28Ii9,iv:cZyTOtPH6NR5kAfkvU5vuLk9agyU+3csRH+qLbh3ixQ=,tag:RV/At3rf8P3CRpp7ipStAw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpTlYzUWMrQ3A2b3FLUzNl\nenRkb2lvRXkrT3dOaU5ndzRUNmN2c0FwSUdZCmdjVlhhb0I2M2FMVUpBU3U4Rmpu\nL2tHVUlDMjZYcE1jYUd2UXY5eDZhOU0KLS0tIGMxRWFDMFUzU1ZWT0ZkT2ViQmJM\nNVNXRUxuaDJ5TEZiRzdjbmRtV2o1WXMKaTjenRv6FOScMa0bVI2mGAk4rIazF0jt\naqGv8DHMxfBBeG713V+qEKLTOeQOaGalffIOPARD+LAaDJpJ5p8PNw==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBalF2OE91\nL0dRME9ONXZUTWV0MEhFWmYveGp6NzhlMGZyaGczeTB0T2JXUwoweGxFN3hUbkp2\nRTduNXBNbW52Q3QvU283aEgyOGVuaWZvb2dvWGd4cFVJCi0tLSBpd2FIRCtYd0F6\nZ050YTRGQktrNkliNWovZXhSUEYzbzhFclJUWS9XeGxrClGhlUZvZtllc7DQMkHv\nQawFKfC4ghyi3VzKsE0eAF9qZFACcFnT2lAni+q+gyFjoprseEqpGvFSzkVZ5f41\nge4=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:30Z",
"mac": "ENC[AES256_GCM,data:eyHBLejUSyGReOi853jnzlvcPs8Ps/PpsE+iQ19LX/G7jAqTcfA1mcJwnRj4DKpFFVKVY5D/nA3RZh9k1sOIPfNVRYW54OUxhx5MegBr+aPuv3v5STAMoEzppbcRmrpEIk5WCMnW6IF5WWgxDi9cUveGw91ydelgr+2nEAaPTQI=,iv:vn3Xi/QibbShdqAvO73gyiCxAfDDeNm7/VKKI3qKtTc=,tag:oN+cz82HeQ8ynjEi0MTQTg==,type:str]",
"version": "3.12.1"
}
}
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
25.11
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../../sops/machines/web01
@@ -0,0 +1,22 @@
{
"data": "ENC[AES256_GCM,data:5DOEg1faBwKP6NOJqDakx0u0AxaTgFUWuQOLaVtWVyqgsmB3ewr1u43GrDTTSuGiUkE2sdFlOMOtfie5ILby,iv:p7MJS3sPuuPzS1kHDfB1aqLBYhhMEDdxalJiItCXzKE=,tag:a8H2LCON5H/yGgsc5oiruQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByMkhGVGVzNkVkS2FjNXNC\nK2IvWG9kcHI2MUtOK3hRaG5IQkJYUnJ1WmpJCk91UnlIRjQyOFY5R09vSXhRcG84\neVdOc0tnNUM3WmlDZ2tDL3NQMHBDNjQKLS0tIGp3L1dxVGs4V0RoUTc3SVVaQnIr\naDYrUjkyS1Z4NzBGaEJQV2tLdEZWaFUK/w0UJTSjPqd0eStX05t4eXGQl4k0b7aV\nMAoP3HpayNBpS2K6s+U/L2siXNL7kOhV9JK5oy/bHhOg77wDTyPIxA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yey6gxgsyl4tj6ek0tve2pckt6qersqspk66ukkzum8mrr6zppqsj4jn3m",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6MGYxNmlLQktCK0VoS2hw\nRlBFRFErWk5YR0U3a0JqdkVMaTJCWmRrTDNRCjZ4V0hBcnhPSFNpVXhiQnp2Y2ty\nQitnbFVQbHp4V2pnMkFGUi9BRlV4QUUKLS0tIHp1SERLcWRjUmVxQTBOQytFWmIx\nZzkvTlp0WTF6QVBEQS92YlVvRWV6R3cK1bcu6p2WzjUdvEt2oObNhcTsCQ3cRspN\nAuTK/yJuVkpO5e5Fdqv5FDAnBbXSIu6u5ETao+w22wx3KifwBLoU/Q==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBNU56eDhu\nY3N2bUdPSjIzREYrMTEySjRKbU9EanZ1d2k2RjhuNy9GMWN0ZgpYUWNidUFqM09u\nRkllRWRPNmU1bXo0d0VkZHllVitXUjF1THZEakZxeTFzCi0tLSBZTG9KRm9rcFJZ\nZnRNMWRiSjUvZVJrOVE3OXJNUnJYcjFBREpFY3JrRi9jCszy3Qg2juzFSa4M8KPP\nGQOPoECn2M6JTnM28zFVsBQTM4TlDKvqhWvF7Mcg7H5WwaoPcx/jh9IDpn9HLTzt\nH/k=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:32Z",
"mac": "ENC[AES256_GCM,data:WKZbfq9lZpMbt9ukGW1T17F1qwSmjI8b1uJ3Eq1j9KOL4g+GOLvQnVQ7EkW125Q+A4HGplBCswFyKDGugmnIX9GgHYQ60In/uqQCoZ+b+LWBUMPbDKnMeBxHjbfR9utU0rT9dSyGuYUryeYZp0TTfGXfKvUbPMlwQHKENVoAx5U=,iv:CHzy62kFQAWoT+bbYELgQYAen0naknow+xFmvK5CMak=,tag:VVsC5hJ6Fh79/EX/9yqIIA==,type:str]",
"version": "3.12.1"
}
}
+1
View File
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../../sops/machines/web01
@@ -0,0 +1,22 @@
{
"data": "ENC[AES256_GCM,data:Nsf/majWr/OSPQ2X0GcAyimYqpNp+z12EijFGnXk4sicyDqH4dxagVcMBFhnvme0JOJ0mXPpKfgEVBYjYr7NbSffnwrOwPzXfxdlWnw8r6SoW7JI9jkfdll0kDcdt15s,iv:cjGPpl38zogCLrcrSMUckPHzGkSMelGY1XZw8M++mmw=,tag:e+QxoLPnagcMFoGAh+gqgw==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEcnRpWTZPdjR2akMwTmJG\nNnFrV2pVK0dReEZVM3lGbktYM0l5Qi83T0ZnCmxQV0xmaE5ocmNQNG5kZzVNRW1R\nMFI3M3Ira2prU1V2ZysrQWxlMktJaVkKLS0tIDhBa0J5eHRKT2xGUWxHeTlDcDky\nQ1NnQ2hhbURuMDJKRkp5alV1WmJpNHMK4nrPd4VvBXyd1/uhrVDMnPTe9GNs82X8\n6ygCzPoTdsQ1jDTVE/UeOY0D2ZjVJz4e9aU1mFXokgpbyKsAdAPlfQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yey6gxgsyl4tj6ek0tve2pckt6qersqspk66ukkzum8mrr6zppqsj4jn3m",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4c2VGVkZvWUR5QU5jUEVY\nWHk2N1FQemZ0STZKenJCaEw3SXVvKzVNYWhrCitlWDNMQkpuOUF2K1pBK3ZIankz\nZk5ZUXNtaEprNTFsOEFyQnZ4YUwyNlkKLS0tIDhYbmxubjhyR1Z3QlpIaWVweTFJ\nd2ZaKzBuUUtFWnRRSEdrNmduYUc0QmMKubs2U1/kAmkygXxQYL+YDd75pelKQDmf\nFr9nrhUTINGwVjbFQpj2BUchCH6Q6AhGJpzdW3mY4LFya/u2WkadjQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBem0yRC91\ndWNjbDZQSHdUZktTMGhiaFhjT25DMUxEM3FaUGtrVWYwekhvMApaU2FaVWNtbHpO\nY09HZmNhU2hXSmpUb3Qya00zaU1ISzNtSFoyVm83aXNjCi0tLSBndEhHdVFsZDZi\nbHBYUEIyME9yTjBJT0ZoNENuZ05DUEl2dGpUbWFaYmE4ChNBrn1NivTKAu37u6oy\nJt6nl0dFa784h80w6dWOxV+ot6SRo6gnmlacgUM4F/mq+p4VmARToPeve9uu5nXb\nglw=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:32Z",
"mac": "ENC[AES256_GCM,data:N9XkxT8QdxqjX33ESP+UZc8fGI2rSl2jwuV1kgLx1u5VM7khpQyiv7fVNkKjPiZp+O1flkrxTFAS1z2ZPzkcjnF2+qYjREuRUr1y7yrRb48i7o5NLzhHPPbRodwhLuJAurEiWBfRuMceuEaztIpYS7nXUCyyW68qX4s2Mbuj36c=,iv:9FRDNRU0kfKuixxDmuojNS1a4VXs/V29eVhIHFquUEY=,tag:cqrb71HvPoQg1i5svTf52w==,type:str]",
"version": "3.12.1"
}
}
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
../../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../../sops/machines/web01
@@ -0,0 +1,22 @@
{
"data": "ENC[AES256_GCM,data:x2yLufbE0itvC3labeOTHECNtcss8VCrYcTEUkPA0zus9s1FAv918DXtrPaTbblJrxsZaVF2IGMu5W1IxIc0pDZOeP44EbfXJHgHSq4z09csz+42pRAnzW6ogVhb9AouLQnELiRuWCBmKiyXGHPjtLYEouve1B2ExaHQcR40F/uU4PX4K03nbY4uljR9lRMO0NFBMS+8/T+7h58UJKFEzaxiVpvpmt9o0SetO74V7KOg/mPnV22I6+mo7H0AwdXRsawAps7AJsFGZbS2cnX2/nwnEjljAxW0hhJJJCHYRKljZS9mUWL/AxKFtlt8YzNX+o8OyMu7wcEH1emUg/Qp1gtq7hI8vUMjOYORYZuk,iv:4CMDEFFEk2DqTSVnIVVtOdE1Cz5IjOtMSEOXRZ/egWs=,tag:8MMFVTh0WGgrY81EelxkxQ==,type:str]",
"sops": {
"age": [
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLRG8rQVNQSUg2YVJZZFV1\nV09odWFNbnNSWFBnUXgzc2dHMEV1WS8xUTF3Cm5kMTM3STlYaXNXYXg5NXhxdFVP\nQk95V2E0R2NFTEI4ZkE1eFVJbC8rWkEKLS0tIElIRzQ0MS9nRzZGN0hveU1vS0Jp\nbTl3V0NreXpiK09jOWlPeVJaTTFDalEK6KXNLyh+XnsNRtQWgTW1UZii5SkzUZRg\ndO8Kg5dOeI3nreELnoQfQsq80PwFHxJTUsUaddOyFfP85+25GGpniA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yey6gxgsyl4tj6ek0tve2pckt6qersqspk66ukkzum8mrr6zppqsj4jn3m",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2U0U0aVh0SkIyakZxNTVv\nZFEycU9SU0ZodzdPMUhBck1jVzBjeHFqRUdvCkszNFpjRmxwcnVqNFFZdTlhM3dQ\nRDBGWEtwTTNMV2plbksrajhjc1JlTVkKLS0tIGlMcktHdk5yWSs5N2tRT1Y1SzJl\nVjkvMUphcFh4Ry9vREhvWVIybjFUYlUKDRvpu7GEOR6MJ4QgiSe1W1CoqbHTuMx/\nccqLkJHhPqSP6PZP3RO9XWNWOMaqp654G05vO+VJ3sHiTJyrx/XeiQ==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBcGkwZ1Nk\nQm1JT2FpMUxZWnFXVU82bUpJbVdqalBsQ1ZUM1VqM041aFNxQQowWUEvNXhKQjh6\nMTllM0EwYkQwZ3RpUThPTDdkbi9lTjJUQmpJTDRuV1hZCi0tLSBncERXNk84T3FG\nTTNXcEtuTko3YzdGdm5HcXZyek5pQThjd1NaVkppYkVzCkcNa/kkb6DZR1hdvkl2\nNpjc4x9V0ORwZ0b+L07kML1CKTyfuUNgr57dxsolagydEVSZNGW0WMG2lolNwod/\nGJs=\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:33Z",
"mac": "ENC[AES256_GCM,data:IIDRaejzWhEhfeHtViHaGDMALaflIipzdmMiLzJygHS8epNOBuRWQOLn9nDsL8reUgU7ezODaK7wuSy6gPbzUnS7FGYXkbLd+PVx5+fJgqha4nY/0WBNplmgdm02B+MqpSFC47ChB62uzKXZmuU6Jf/inRelf+csCGBadU3yayk=,iv:O15ueEPeugmO25bjwJHOkn3IVT8yQuw/2sz6q88n/Jw=,tag:d4Hl3U31sRxE8LaVMgfVrw==,type:str]",
"version": "3.12.1"
}
}
@@ -0,0 +1 @@
../../../../../../sops/users/berwn
@@ -0,0 +1 @@
fd06:1bad:ece2:92ad:ba99:93c6:5eb7:bfbd
@@ -0,0 +1 @@
../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../sops/machines/ns1
@@ -0,0 +1 @@
../../../../../sops/machines/web01
@@ -0,0 +1,27 @@
{
"data": "ENC[AES256_GCM,data:zuuXCjHZTXCZLD6lB6UFw9BE8VOEXmRW3w6QBDREkH5PieT7myP8kn4zroQ=,iv:Hb5uNJRORGExiqm9+oPjxZjAq8vcsStqFqslNnixuFA=,tag:aQ4NT5ayG95E4ROKyfLZXA==,type:str]",
"sops": {
"age": [
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBcXNUZm1u\nK3A5dlVwS3M0c0xmb1dzK2xCa0hvcGJ4SSsva3FWcGRTZUJ3bQo2Wmw1VFRtSDFL\nMzkwQVRHSlpuenRsR3h1czVUZVRiU3owN3dTS0V5M2NnCi0tLSBvMWRBaWppbFl6\nU01GNVFwYS8yemR6RGVsRTRQY3g4VzhpRGh2L2h0NnVJCj44SxR5IyUAAnegpO/a\n9sPCmmzSrJNELMn3uH/HDV58LZfvIWCNl6QC/op6pF/n9l6wRv2dQPc3+9LlXPKr\neaU=\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1fanu282vm7njjweqhrpcfcwpttuhce8js4tsyfry98l0neaqpewqs5s7nt",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1bmh3b3lMKyt3eGpGSXVq\nb1c1enhIcXpxaDcweE9ZeDNMS2VXejdpUG53CkRUK2x1OGc3Vld2bjVxd1RPM1VS\nNW9UZC8zSnJZdTJEeGJLV3VrRUQzSjQKLS0tIFNnVFJ6MzJkaXE1U2pJRnBpdXB2\neTFWOW1ZTTQ5a2xZNFNMTmN4K0RabFEKQuA6j2XigQsjrx7MzwXZmaROxXVKzrkL\nZl+kOkFj0J3MWHIwWPrUlCnP5u/7Eb/UYOU8tkJ2DD1CzH4vansR1g==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1yey6gxgsyl4tj6ek0tve2pckt6qersqspk66ukkzum8mrr6zppqsj4jn3m",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1UXpvcXNnbmhXTVFDd3FF\nVGpMaElTNXdZY0xzdkRRQUw4dXVEMm1xNGs0Cmp2bkExUkZCSDVwOWZBMzlPdUdO\nUU13SnpKYVR2eWxGUzhWeFBTeVJTRTAKLS0tIEtIekNoT2V0bFRzZnhRYzdud0VR\nUTROdmpHNVYzbmlYNVB4aTlnZ2U2VzAKUJrNHqx4LLbbmUEuTedviDDgGEDMXna3\nasaL1fU7G1XMTMHOIM9200JzEPW0P13pO6D65t/bueeljyZy8wlnAA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkNXRSZWdpanBiZ285V09X\ncWs4Z0tVZDNRaktNejR3ZTFKTDFxcEFLOFVVCnoxbXdocWR5aE9saUlzL0RCWDRt\nZTFlKzFQR3NaQWR4MUFMUHVPMmhseEUKLS0tIEtHVWtiZ1RadzdzdURHQmdRd1JI\nNXViS1ZMcjhsazBwai83Smd5VFRXdmMKA8XLlBHBfmzzkEZhbOVpcOPQkgYHzpzT\nloG7LOjEt/BA20I8nhuIIZ3InCEwFXmhFzfmSKadXFZxvX75OsMZ4A==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T19:26:29Z",
"mac": "ENC[AES256_GCM,data:b9Id+7Sh9fCl4iWhLwiEMjiAIEKEz5L7c4eiFynxjPTyCY9RTEeBwTPOh1Fk1czV0TuKNvwlAkPlkpKBNFWGeEopBQtxUx/Gm1fmNJq25oRuLPqRMd1P/8JrkWOoMwL4pbQsnnOeQSy8SJf4044/jANFyTzC6qou/uIDqMLM2Zc=,iv:OGxOAE2whJBjJHABLPq1gC0DXEUzaqCkAWmRxhRc4lo=,tag:EzbEUdUpRSXxDmGIO/BeuA==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.12.1"
}
}
+1
View File
@@ -0,0 +1 @@
../../../../../sops/users/berwn
+1
View File
@@ -0,0 +1 @@
../../../../../sops/groups/admins
+1
View File
@@ -0,0 +1 @@
../../../../../sops/machines/control
+1
View File
@@ -0,0 +1 @@
../../../../../sops/machines/mx1
+27
View File
@@ -0,0 +1,27 @@
{
"data": "ENC[AES256_GCM,data:TVA1K0kNdCNqn7UK/nmN1foDVvIZrfrEmIOvpvvmhylcn3nB2Q6xxrSJX1/ZqHTraiWyCJz1IautGEC+sgerQcqEVZAB7vNzFmsCpSB0Jn8yPVwLJa0Cm3FYzRP+OgfSZnPO23KhTRIo538=,iv:HOJl2gZ2uRCi+g+CEjbPiIOyXgbMbjXXgzJpfyHbq1k=,tag:npy5FtIFP0t5Uyrv4jnjaA==,type:str]",
"sops": {
"age": [
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBcXljWmt4\ncm51cERhUzNGb1ozOHlaRWxWQWRvK2EzTDZyVFM4SUt0a3pHYwpJcVhEbVA4ZG1W\nVFhKTmRJWmoxS1VCMVQ5eU96UitVT1RjTVdUQURDWUpNCi0tLSA0YUplRC9TM0hl\nbytVK2I3Ykx0MnlZZ3VEdjVOV3F4YWtEZlRHdUR2SGZRCh2eDQ405D5dEtwCDcLG\nOrafgI9hqOs1VrDCRaLLOXtMqaKqTulx2QJXo3g+DYYEQF1Y5GymorVQQ+G1laAk\neWA=\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtWFpTeE91TnVxWktDQTZE\nZ2srWjVHMW9FbFEyMVI1MnhQd1B3bmlrNERVCnc5NCt3WXZmTWRnSVU1WTN1M2Jh\nTkowTFhtaHRoZ1d6TGhmcjhPeElHVU0KLS0tIDdPZGdzWVVmclpwR0xVeHo0Wi9u\neFQ4VmJPM3BMa2k0djZZdWdMUUZaOUkKIm6HbSrqL4uK3As5GyQU0mB15buQiRh6\najLYI5vyEJlrlnQjBcPLRPsyIZxknpeN8MFxv/qcTnwfbKi09cyVFg==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1env5y2eey0p3dggs8tydwmtyhtwqylpg7spuququ4vvax6arzp2qjnm4tx",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3VCs2SHFBUEZLQk1zZGZs\nNEJSbm84SGl4RDAwVXExZnN6STFhMWVqK1UwCmtwd1NMcEc1ZFVNZ0JjQ1lwams3\nL004alNiU25PTXdiT1VLMW5jOUUwcUUKLS0tIFZoMXBQZjlDbDJ5V1d6YTFRejNI\nQnpDaW8xc1JJMkhlVWx0RTRhQkdXYUUKg2uxS1E+l/jcagYhb4NK2dldHKKLp+OF\nzhQzC3ojTIfYUt7UvyKsV8g2WtZMR1cRp3FN1EmWTl3nPbcHpvbH1Q==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1l5hw95p5h4sthrgn0usms9yfkwwmcvv34tjgrtv9s4e6x39chacshgxavs",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKRE5RcjdEV3lzTmFsR2J5\nSGNoWWc4VE1XcFBLUm8yaDhPM09EVDlUSFhFCmg2MTZtYXdEOVZhbG5HdVpxZVFZ\nUzhCeEtxTVczeVZFVTFSTG5JTmg0b00KLS0tIDFZN1VBNDJudThwTWthQWp3bkhS\nQXR6ci83R0xBSGoyNkxTc0wrZ0NsRm8KPElamuJDwJPOVeULVoaKD5fkylDtdK3J\ndx8JTmtlCFkMkzDZXpwK8esia2Bo7cQpDHu4Yc4iAKDAJ7t9XH7p2Q==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T20:27:56Z",
"mac": "ENC[AES256_GCM,data:MhfFhySK9UVMASYqP9/AO5Bt+1kmu9xn2Q219ca6k7r0pn8QlvBMKl4HIZswrNiw0hNvv7ot1i3bU4HxKU6uB/92FGRVf8xNqX0r7MQVnQI9AjyG4q5K+jsJjT6l0Dx24Qaq1GdIMfaTiv3IgBzyZEJL5YltRMN8kaRTMEUccAk=,iv:LXO8ejJXTdAkAIXCm0VDsyspggk0Hhd5TRaqT80qBDQ=,tag:mOKQ5rzBawpDpAzlGJXD1Q==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.12.1"
}
}
+1
View File
@@ -0,0 +1 @@
../../../../../sops/users/berwn
+1
View File
@@ -0,0 +1 @@
../../../../../sops/groups/admins
@@ -0,0 +1 @@
../../../../../sops/machines/control
+1
View File
@@ -0,0 +1 @@
../../../../../sops/machines/mx1
@@ -0,0 +1,27 @@
{
"data": "ENC[AES256_GCM,data:AJiMGrwgpkBQNVjRBmQtIMKIzekwEnM1JIhcB3NESxpF,iv:IzEz5KPAh8dz3HbmvhDQXE3KjwdAdGbNDIidXbcnb3k=,tag:kbKD+jB1eKZf66RA5lme9w==,type:str]",
"sops": {
"age": [
{
"recipient": "age1yubikey1qd859y9ehz2ya8j2cftwrtmdeqhuk7r7yc52zp64wpff6068gwrac3q6nsa",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHBpdi1wMjU2IHFWcTVydyBBMThKYWUw\nTkRJYnQwSkNKRDkyZjl5WWtCbHJybDhGVnN0UWtndFhYOGdNSApYanRIWjNYbTU0\nRGhWVjhaWXdUNUtrNDBxTHcxMkNOZ2N2cVJpamI4TzZnCi0tLSBLMXFKekI5c0Jw\nK0U0OE10ZDRZcXl0dkdLQkpFSFdVOXNUZUg3RnAxMG9nCp8Uz1VIRO4qE9tCsRiq\nGL7j1HueqGu6D0199K+do9zTZ9uL14c0x8E8wS/pq/N+m+3VunPYGp9PikF+tQaI\neec=\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1hlzrpqqgndcthq5m5yj9egfgyet2fzrxwa6ynjzwx2r22uy6m3hqr3rd06",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGT3lUSVdlN1JYZGFyWU9k\nN01CbzZGaWpPdlpuZnYyVDNnR0p4N2I2VDFrCjlXRkhSZDBsZ0JOb0RlWi9yRnRi\nd3AwaEFKMUdpTWN3cmVBbG1jV2pwT0EKLS0tIGFBVUthWnRJVWZjTms2MHgvbVFo\nVEZabjAzUHFVYzZYTS9kVzR1WUpybE0KMTGxK1qQNpvf9U8l5YqVjaCHQ8s8anRe\nPZx5T4Ta//1KLy6JYBGgM9M7ERSCPUeCyvak72xhrn/HDzyAqw6q7Q==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1env5y2eey0p3dggs8tydwmtyhtwqylpg7spuququ4vvax6arzp2qjnm4tx",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1Qit5ZWYyNE4zamhCYTZK\nSUZwc2RtT0djc0EvcFJ6TGR6Z1hkbmx5bzI0CnlvQW9VbkJxcSsyYTNuMy9hSzBQ\nczErRHI4aHI1dUw1blBmS1NkZExrVU0KLS0tIFVIRFR0bVZlQktUek1TWGtWUlUw\nVHZ3RnhLR3psVUlEekhqNDhLOERyQnMK+cW9OS188o733AIJ09oipjkptkVCrfcf\n0xz+GDFafYljp+tzarkpnnoSmgJmi5zAaJrlTuOpD+a6DPy/wd22UA==\n-----END AGE ENCRYPTED FILE-----\n"
},
{
"recipient": "age1l5hw95p5h4sthrgn0usms9yfkwwmcvv34tjgrtv9s4e6x39chacshgxavs",
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjM29MSlY4ejRCM0h0T1lN\nWkpZYnN3RGpQYS9NTmtNQitJbDBxZjRKWXd3Cmx0djlUNGxNUHRXYWpoajUza01J\nbWJFOW9KRUZDOVZOK0x6emVjNEFTZE0KLS0tIDR5ekVYcDhxKzd1b0hvcSsydmY3\ndXdKSmVmYWdFdFlKWlpsZHVUSFV0TkUKjc4O5XbDFQAIO3ha6tT7RIpVlkZf+sok\n0Opsatn6fQAcAcafaVvR2O6n13bIRxBs/2yBnpsNd+NtGQxV2pGO0w==\n-----END AGE ENCRYPTED FILE-----\n"
}
],
"lastmodified": "2026-06-20T20:27:56Z",
"mac": "ENC[AES256_GCM,data:deviYdP99xcgUlpHc81m8+XBT32zPOrinBIfs4XBzmVmMPXJIh3pBIBOpsafOiPAAjX55g0frtI12ho+y8bvJ8TE1G1Wj9t8Fl/xJEnVDAFgJHMooZNJuhnnDWDCZpXQnOJXUYIwMcuND3Kzwjps4RwH/CYpvK4ITktKZrJZ18k=,iv:oqUv9mFdi0/MWu5YWyNNH9LaUhgi8oVSuWUeRKHWiZc=,tag:+Bk9kMbpXWA8mZM4axpllQ==,type:str]",
"unencrypted_suffix": "_unencrypted",
"version": "3.12.1"
}
}
+1
View File
@@ -0,0 +1 @@
../../../../../sops/users/berwn