Compare commits
5 Commits
415a050f6a
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| d8bbf08c7a | |||
| e6036d9d1b | |||
| f7b64617b9 | |||
| 60db8c60b0 | |||
| b8bea27a9c |
+18
-6
@@ -61,13 +61,25 @@ requires re-submitting the DS.
|
|||||||
|
|
||||||
## ACME DNS-01
|
## ACME DNS-01
|
||||||
|
|
||||||
A dedicated TSIG key (`acme_ddns`), scoped by `acl_acme` to `TXT` updates at or
|
Certificates are issued by `_acme-challenge` TXT updates that `ns1` accepts over
|
||||||
under `_acme-challenge.<zone>` on `ns1` only. Knot signs the record and transfers
|
TSIG, signs, and transfers to `ns2` (which never needs these keys). Each consumer
|
||||||
it to `ns2`, which never needs this key. Retrieve the client config with:
|
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.
|
||||||
|
|
||||||
```
|
- **`acme_ddns`** (`acl_acme`) — the general key, scoped to `TXT` at or under
|
||||||
clan vars get ns1 dns-acme-tsig/acme.conf
|
`_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
|
## Runbook: stale secondary
|
||||||
|
|
||||||
|
|||||||
+34
-7
@@ -1,6 +1,7 @@
|
|||||||
# Monitoring
|
# 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
|
## Collection
|
||||||
|
|
||||||
@@ -18,8 +19,8 @@ Metrics and dashboards live on `control`, reachable only over the ZeroTier mesh.
|
|||||||
## Storage & scraping
|
## Storage & scraping
|
||||||
|
|
||||||
**VictoriaMetrics** on `control`, bound to `127.0.0.1:8428`, 180-day retention
|
**VictoriaMetrics** on `control`, bound to `127.0.0.1:8428`, 180-day retention
|
||||||
(`modules/monitoring/server.nix`). It scrapes `control` over loopback and `ns1`/
|
(`modules/monitoring/server.nix`). It scrapes `control` over loopback and
|
||||||
`ns2` over the mesh.
|
`ns1`/`ns2`/`mx1`/`web01` over the mesh.
|
||||||
|
|
||||||
> The scraper dials IPv4-only by default, so mesh (IPv6) targets need
|
> The scraper dials IPv4-only by default, so mesh (IPv6) targets need
|
||||||
> `extraOptions = [ "-enableTCP6" ]`. Without it, ns1/ns2 are dropped with
|
> `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
|
## Dashboards
|
||||||
|
|
||||||
**Grafana** on `control` (`:3000`), mesh-only, anonymous access disabled. The
|
**Grafana** on `control` (`:3000`), anonymous access disabled. Reachable directly
|
||||||
admin password is a clan var:
|
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
|
clan vars get control grafana-admin/password
|
||||||
@@ -46,6 +49,30 @@ there is picked up):
|
|||||||
outside-in DNS probes.
|
outside-in DNS probes.
|
||||||
- **CNX Backups** (`backups.json`) — borgbackup job health, time since the last
|
- **CNX Backups** (`backups.json`) — borgbackup job health, time since the last
|
||||||
run, and per-job state. See [Backups](./backups.md).
|
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
|
## Logs
|
||||||
|
|
||||||
@@ -53,8 +80,8 @@ there is picked up):
|
|||||||
(`modules/monitoring/server.nix`). All three hosts ship journald to it via
|
(`modules/monitoring/server.nix`). All three hosts ship journald to it via
|
||||||
systemd's own `services.journald.upload` → the `/insert/journald` endpoint
|
systemd's own `services.journald.upload` → the `/insert/journald` endpoint
|
||||||
(`modules/monitoring/exporters.nix`); no extra agent. `control` uploads over
|
(`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
|
loopback so its logs survive a mesh outage, the other hosts push over the mesh,
|
||||||
9428 is firewall-scoped to the mesh like everything else.
|
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
|
> 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
|
> 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
|
## Machines
|
||||||
|
|
||||||
| Machine | Role | Public IPv4 | Public IPv6 |
|
| Machine | Role | Public IPv4 | Public IPv6 |
|
||||||
| --------- | ------------------------------------- | ---------------- | ----------------------- |
|
| --------- | -------------------------------------- | ---------------- | ----------------------- |
|
||||||
| `control` | ZeroTier controller, monitoring, docs | `77.42.68.181` | `2a01:4f9:c013:e6d0::1` |
|
| `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` |
|
| `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` |
|
| `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` |
|
| `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
|
## Access
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ in
|
|||||||
../../modules/monitoring/server.nix
|
../../modules/monitoring/server.nix
|
||||||
../../modules/monitoring/blackbox.nix
|
../../modules/monitoring/blackbox.nix
|
||||||
../../modules/monitoring/alerts.nix
|
../../modules/monitoring/alerts.nix
|
||||||
|
../../modules/monitoring/parsedmarc.nix
|
||||||
../../modules/docs.nix
|
../../modules/docs.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,10 @@ mx1 IN AAAA 2a01:4ff:2f0:1963::1
|
|||||||
mail IN CNAME mx1.cnx.email.
|
mail IN CNAME mx1.cnx.email.
|
||||||
@ IN MX 10 mx1.cnx.email.
|
@ IN MX 10 mx1.cnx.email.
|
||||||
@ IN TXT "v=spf1 mx -all"
|
@ 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 ----
|
; ---- DANE / TLSA ----
|
||||||
; "3 1 1" = DANE-EE, SPKI, SHA-256: the digest of mx1's certificate public key.
|
; "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
|
}) accounts
|
||||||
);
|
);
|
||||||
|
|
||||||
loginAccounts = lib.listToAttrs (
|
loginAccounts =
|
||||||
|
lib.listToAttrs (
|
||||||
map (addr: {
|
map (addr: {
|
||||||
name = addr;
|
name = addr;
|
||||||
value.hashedPasswordFile = config.clan.core.vars.generators.${genName addr}.files."hash".path;
|
value.hashedPasswordFile = config.clan.core.vars.generators.${genName addr}.files."hash".path;
|
||||||
}) accounts
|
}) 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
|
in
|
||||||
{
|
{
|
||||||
imports = [ ./dns/acme-mx1-secret.nix ];
|
imports = [
|
||||||
|
./dns/acme-mx1-secret.nix
|
||||||
|
./mail-dmarc-cred.nix
|
||||||
|
];
|
||||||
|
|
||||||
clan.core.vars.generators = passwdGenerators // {
|
clan.core.vars.generators = passwdGenerators // {
|
||||||
# Render the shared acme_mx1 TSIG secret into a lego rfc2136 env file. lego
|
# 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