Compare commits
5 Commits
415a050f6a
...
d8bbf08c7a
| Author | SHA1 | Date | |
|---|---|---|---|
| d8bbf08c7a | |||
| e6036d9d1b | |||
| f7b64617b9 | |||
| 60db8c60b0 | |||
| b8bea27a9c |
+18
-6
@@ -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
@@ -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,11 +7,12 @@ 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` |
|
||||
| `web01` | Public reverse proxy (TLS termination) | `5.223.55.246` | `2a01:4ff:2f0:2d8f::1` |
|
||||
|
||||
## Access
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ in
|
||||
../../modules/monitoring/server.nix
|
||||
../../modules/monitoring/blackbox.nix
|
||||
../../modules/monitoring/alerts.nix
|
||||
../../modules/monitoring/parsedmarc.nix
|
||||
../../modules/docs.nix
|
||||
];
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
'';
|
||||
};
|
||||
}
|
||||
+15
-3
@@ -60,15 +60,27 @@ let
|
||||
}) accounts
|
||||
);
|
||||
|
||||
loginAccounts = lib.listToAttrs (
|
||||
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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/groups/admins
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/machines/control
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/machines/mx1
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/users/berwn
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/groups/admins
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/machines/control
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../../../sops/users/berwn
|
||||
Reference in New Issue
Block a user