diff --git a/hosts/amzebs-01/EMAIL_SETUP.md b/hosts/amzebs-01/EMAIL_SETUP.md new file mode 100644 index 0000000..63849a6 --- /dev/null +++ b/hosts/amzebs-01/EMAIL_SETUP.md @@ -0,0 +1,350 @@ +# Email Setup for amzebs-01 (amz.at) + +This host is configured to send emails via Laravel with DKIM signing. + +## Configuration Overview + +- **Postfix**: Localhost-only SMTP server (no external access) +- **Rspamd**: DKIM signing with host-specific key +- **Domain**: amz.at +- **DKIM Selector**: amzebs-01 +- **Secret Management**: DKIM private key stored in sops + +## Initial Setup (Before First Deployment) + +### 1. Generate DKIM Key Pair + +You need to generate a DKIM key pair locally first. You'll need `rspamd` package installed. + +#### Option A: Using rspamd (if installed locally) + +```bash +# Create a temporary directory +mkdir -p /tmp/dkim-gen + +# Generate the key pair +rspamadm dkim_keygen -s amzebs-01 -d amz.at -k /tmp/dkim-gen/amz.at.amzebs-01.key +``` + +This will output: +- **Private key** saved to `/tmp/dkim-gen/amz.at.amzebs-01.key` +- **Public key** printed to stdout (starts with `v=DKIM1; k=rsa; p=...`) + +#### Option B: Using OpenSSL (alternative) + +```bash +# Create temporary directory +mkdir -p /tmp/dkim-gen + +# Generate private key (2048-bit RSA) +openssl genrsa -out /tmp/dkim-gen/amz.at.amzebs-01.key 2048 + +# Extract public key in the correct format for DNS +openssl rsa -in /tmp/dkim-gen/amz.at.amzebs-01.key -pubout -outform PEM | \ + grep -v '^-----' | tr -d '\n' > /tmp/dkim-gen/public.txt + +# Display the DNS record value +echo "v=DKIM1; k=rsa; p=$(cat /tmp/dkim-gen/public.txt)" +``` + +**Save the public key output!** You'll need it for DNS configuration later. + +### 2. Add DKIM Private Key to Sops Secrets + +Now you need to encrypt and add the private key to your secrets file. + +#### Step 1: View the private key + +```bash +cat /tmp/dkim-gen/amz.at.amzebs-01.key +``` + +#### Step 2: Edit the secrets file + +```bash +cd /home/dominik/projects/cloonar/cloonar-nixos/hosts/amzebs-01 +sops secrets.yaml +``` + +#### Step 3: Add the key to secrets.yaml + +In the sops editor, add a new key called `rspamd-dkim-key` with the **entire private key content** including the BEGIN/END markers: + +```yaml +rspamd-dkim-key: | + -----BEGIN PRIVATE KEY----- + MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC... + (paste the entire key content here) + ... + -----END PRIVATE KEY----- +``` + +**Important:** +- Make sure to use the pipe `|` character for multiline content +- Keep the proper indentation (2 spaces before each line of the key) +- Include the full BEGIN/END markers + +#### Step 4: Save and exit + +Save the file in sops (it will be encrypted automatically). + +#### Step 5: Clean up temporary files + +```bash +rm -rf /tmp/dkim-gen +``` + +### 3. Verify Secret is Encrypted + +Check that the secret is properly encrypted: + +```bash +cat hosts/amzebs-01/secrets.yaml +``` + +You should see encrypted content, not the plain private key. + +### 4. Extract Public Key for DNS (if needed later) + +If you didn't save the public key earlier, you can extract it after deployment: + +```bash +# On the server after deployment +sudo cat /var/lib/rspamd/dkim/amz.at.amzebs-01.key | \ + openssl rsa -pubout -outform PEM 2>/dev/null | \ + grep -v '^-----' | tr -d '\n' +``` + +Then format it as: +``` +v=DKIM1; k=rsa; p= +``` + +## Deployment + +### 1. Deploy Configuration + +After adding the DKIM private key to sops, deploy the configuration: + +```bash +# Build and switch on the remote host +nixos-rebuild switch --flake .#amzebs-01 --target-host amzebs-01 --use-remote-sudo +``` + +Or if deploying locally on the server: + +```bash +sudo nixos-rebuild switch +``` + +### 2. Verify Deployment + +Check that the services are running: + +```bash +# Check rspamd-dkim-setup service +systemctl status rspamd-dkim-setup + +# Check that rspamd is running +systemctl status rspamd + +# Check that postfix is running +systemctl status postfix + +# Verify DKIM key was deployed +ls -la /var/lib/rspamd/dkim/amz.at.amzebs-01.key +``` + +## DNS Configuration + +Add the following DNS records to your `amz.at` domain: + +#### SPF Record +``` +Type: TXT +Name: @ +Value: v=spf1 mx a:amzebs-01.amz.at ~all +``` + +#### DKIM Record +``` +Type: TXT +Name: amzebs-01._domainkey +Value: [Your public key from step 1 above] +``` + +The DKIM record will look something like: +``` +v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... +``` + +#### DMARC Record +``` +Type: TXT +Name: _dmarc +Value: v=DMARC1; p=quarantine; rua=mailto:postmaster@amz.at; ruf=mailto:postmaster@amz.at; fo=1 +``` + +**Explanation:** +- `p=quarantine`: Failed messages should be quarantined (you can change to `p=reject` after testing) +- `rua=mailto:...`: Aggregate reports sent to this address +- `ruf=mailto:...`: Forensic reports sent to this address +- `fo=1`: Generate forensic reports for any failure + +## Laravel Configuration + +Update your Laravel application's `.env` file: + +#### Option A: Using sendmail (Recommended) +```env +MAIL_MAILER=sendmail +MAIL_FROM_ADDRESS=noreply@amz.at +MAIL_FROM_NAME="${APP_NAME}" +``` + +#### Option B: Using SMTP +```env +MAIL_MAILER=smtp +MAIL_HOST=127.0.0.1 +MAIL_PORT=25 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_ENCRYPTION=null +MAIL_FROM_ADDRESS=noreply@amz.at +MAIL_FROM_NAME="${APP_NAME}" +``` + +**Note**: Laravel can use ANY email address with @amz.at domain. All will be DKIM signed automatically. + +## Testing Email + +### Test from Command Line + +```bash +# Send a test email +echo "Test email body" | mail -s "Test Subject" test@example.com -aFrom:test@amz.at +``` + +### Check Postfix Queue + +```bash +# View mail queue +mailq + +# View logs +journalctl -u postfix -f +``` + +### Check Rspamd Logs + +```bash +# View rspamd logs +journalctl -u rspamd -f +``` + +### Test DKIM Signature + +Send an email to a Gmail account or use an email testing service like: +- https://www.mail-tester.com/ +- https://mxtoolbox.com/emailhealth/ + +They will show you: +- If DKIM signature is valid +- If SPF passes +- If DMARC passes +- Your spam score + +## Verification Commands + +```bash +# Check if Postfix is running +systemctl status postfix + +# Check if Rspamd is running +systemctl status rspamd + +# Check if Postfix is listening on localhost only +ss -tlnp | grep master + +# View DKIM public key again +systemctl start rspamd-show-dkim +journalctl -u rspamd-show-dkim + +# Check if DKIM key exists +ls -la /var/lib/rspamd/dkim/ +``` + +## Security Notes + +1. **Localhost-only**: Postfix is configured to listen ONLY on 127.0.0.1 +2. **No authentication**: Not needed since only local processes can connect +3. **No firewall changes**: No external ports opened for email +4. **DKIM signing**: All outgoing emails are automatically signed with DKIM +5. **Host-specific key**: Using selector "amzebs-01" allows multiple hosts to send for amz.at + +## Troubleshooting + +### Email not being sent + +1. Check Postfix status: `systemctl status postfix` +2. Check queue: `mailq` +3. Check logs: `journalctl -u postfix -n 100` + +### DKIM not signing + +1. Check Rspamd status: `systemctl status rspamd` +2. Check if key exists: `ls -la /var/lib/rspamd/dkim/amz.at.amzebs-01.key` +3. Check Rspamd logs: `journalctl -u rspamd -n 100` + +### Permission errors + +```bash +# Ensure proper ownership +chown -R rspamd:rspamd /var/lib/rspamd/dkim/ +chmod 600 /var/lib/rspamd/dkim/*.key +``` + +### Rotate DKIM key + +```bash +# 1. Generate new key pair locally (follow "Initial Setup" steps) +# 2. Update the rspamd-dkim-key in secrets.yaml with new key +# 3. Deploy the configuration +nixos-rebuild switch + +# 4. Restart the setup service to copy new key +systemctl restart rspamd-dkim-setup + +# 5. Restart rspamd to use new key +systemctl restart rspamd + +# 6. Update DNS with new public key +# 7. Wait for DNS propagation before removing old DNS record +``` + +## Related Files + +- Postfix config: `hosts/amzebs-01/modules/postfix.nix` +- Rspamd config: `hosts/amzebs-01/modules/rspamd.nix` +- Main config: `hosts/amzebs-01/configuration.nix` +- Secrets file: `hosts/amzebs-01/secrets.yaml` (encrypted) + +## Sops Secret Configuration + +The DKIM private key is stored as a sops secret with the following configuration: + +```nix +sops.secrets.rspamd-dkim-key = { + owner = "rspamd"; + group = "rspamd"; + mode = "0400"; +}; +``` + +This ensures: +- Only the rspamd user can read the key +- The key is decrypted at boot time by sops-nix +- The key is encrypted in version control +- The key persists across rebuilds + +The key is automatically copied from the sops secret path to `/var/lib/rspamd/dkim/amz.at.amzebs-01.key` by the `rspamd-dkim-setup.service` on every boot. diff --git a/hosts/amzebs-01/configuration.nix b/hosts/amzebs-01/configuration.nix index 9ccb1e1..11336ed 100644 --- a/hosts/amzebs-01/configuration.nix +++ b/hosts/amzebs-01/configuration.nix @@ -8,6 +8,8 @@ ./modules/web/stack.nix ./modules/laravel-storage.nix ./modules/blackbox-exporter.nix + ./modules/postfix.nix + ./modules/rspamd.nix ./utils/modules/autoupgrade.nix ./utils/modules/promtail diff --git a/hosts/amzebs-01/modules/postfix.nix b/hosts/amzebs-01/modules/postfix.nix new file mode 100644 index 0000000..ed4bca1 --- /dev/null +++ b/hosts/amzebs-01/modules/postfix.nix @@ -0,0 +1,30 @@ +{ pkgs +, lib +, config +, ... +}: +{ + services.postfix = { + enable = true; + hostname = "amzebs-01.amz.at"; + domain = "amz.at"; + + config = { + # Listen only on localhost for security + # Laravel will send via localhost, no external access needed + inet_interfaces = "loopback-only"; + + # Compatibility + compatibility_level = "2"; + + # Only accept mail from localhost + mynetworks = "127.0.0.0/8 [::1]/128"; + + # Larger message size limits for attachments + mailbox_size_limit = "202400000"; # ~200MB + message_size_limit = "51200000"; # ~50MB + + # Milter configuration is handled automatically by rspamd.postfix.enable + }; + }; +} diff --git a/hosts/amzebs-01/modules/rspamd.nix b/hosts/amzebs-01/modules/rspamd.nix new file mode 100644 index 0000000..fa3dd80 --- /dev/null +++ b/hosts/amzebs-01/modules/rspamd.nix @@ -0,0 +1,84 @@ +{ pkgs +, config +, ... +}: +let + domain = "amz.at"; + selector = "amzebs-01"; + + localConfig = pkgs.writeText "local.conf" '' + logging { + level = "notice"; + } + + # DKIM signing configuration with host-specific selector + dkim_signing { + path = "/var/lib/rspamd/dkim/${domain}.${selector}.key"; + selector = "${selector}"; + allow_username_mismatch = true; + } + + # ARC signing (Authenticated Received Chain) + arc { + path = "/var/lib/rspamd/dkim/${domain}.${selector}.key"; + selector = "${selector}"; + allow_username_mismatch = true; + } + + # Add authentication results to headers + milter_headers { + use = ["authentication-results"]; + authenticated_headers = ["authentication-results"]; + } + ''; +in +{ + services.rspamd = { + enable = true; + extraConfig = '' + .include(priority=1,duplicate=merge) "${localConfig}" + ''; + + # Enable Postfix milter integration + postfix.enable = true; + }; + + # Copy DKIM key from sops secret to rspamd directory + systemd.services.rspamd-dkim-setup = { + description = "Setup DKIM key from sops secret for ${domain}"; + wantedBy = [ "multi-user.target" ]; + before = [ "rspamd.service" ]; + after = [ "sops-nix.service" ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + + script = '' + DKIM_DIR="/var/lib/rspamd/dkim" + DKIM_KEY="$DKIM_DIR/${domain}.${selector}.key" + + # Create directory if it doesn't exist + mkdir -p "$DKIM_DIR" + + # Copy key from sops secret + if [ -f "${config.sops.secrets.rspamd-dkim-key.path}" ]; then + cp "${config.sops.secrets.rspamd-dkim-key.path}" "$DKIM_KEY" + chown rspamd:rspamd "$DKIM_KEY" + chmod 600 "$DKIM_KEY" + echo "DKIM key deployed successfully from sops secret" + else + echo "ERROR: DKIM key not found in sops secrets!" + echo "Please ensure rspamd-dkim-key is defined in secrets.yaml" + exit 1 + fi + ''; + }; + + sops.secrets.rspamd-dkim-key = { + owner = "rspamd"; + group = "rspamd"; + mode = "0400"; + }; +} diff --git a/hosts/amzebs-01/secrets.yaml b/hosts/amzebs-01/secrets.yaml index 36c2241..2407a9e 100644 --- a/hosts/amzebs-01/secrets.yaml +++ b/hosts/amzebs-01/secrets.yaml @@ -1,45 +1,46 @@ -borg-passphrase: ENC[AES256_GCM,data:6T00Em+a5TcrmQNvtoCoij5aks6KIZkCAAaPXLirkQlZ6x1p1bX9KXU2ZvBAtVPrUuTeZLPTKqT/iL5Io+WKGw==,iv:gB9cktzKa8khmZZ8xwLS6oEX+Ag3APmf2jIQNLa1g/Y=,tag:sWfVbKQHgaaSRWuqYdpKTQ==,type:str] -borg-ssh-key: ENC[AES256_GCM,data:TrfaVOWlk8NXMEm6xr5+9pv2j8qPQ2dd6jAhHw8uw25ijhiA+eNtQh9YuQj40zw7hj7cQKctZ6pptdGS1OvS0Zoq1r6IJWLJ2UZcYLXDhOX2/TJQbRcooawG5+JiYCMBe6+T1bzgQaDGWKM7l09lq/saycci/ICe6KKQE8d8i0RaKCsCTf6auNiSMgjYBUMezYP0tTMTIZT6lqeHCUqiEkQ32aE7fdFCAF4hU9JkzhUad3BYasJfDKWksPGc2/GrCpx5JHAD4Tp6GbUpTFVCFf0JVFWaAIyYfKsIShO+yks2TIEOkcQbg8VZADbTtAhhEBcvOCS6mVcgpqQRiEfJI3OvG07KhujJa66EKHlaOM2K71RDDVG+KrlPTW2/1Zaz03FDo7QxiOae9u6KkF+GCIMXAiOL6XYAyDMkxssUA6JodFXImWWwqDJe5Af5jIUAIAAGJTDBSl6S+TWP3pJSM+Pfq6OxRJYFeCVrIE2P4aC37x2vi8V7iTPk0EJSm9TmrLbw+Ia5OvrarwzwtZ2u,iv:IVyeqEGhWUamXw8HPwqyvrHcmTcyEOZmm2NRaTdK+qw=,tag:hQb7wk0YeeQxrPFWuMlfGg==,type:str] -mysql-readonly-password: ENC[AES256_GCM,data:KQiL0ZJGkJEqX7wADmY2YucT79Grt+tCQA/aER7llHgqUIvjJHO8C2yw+VI=,iv:M3QchAeKXp7BjP2FfaWgUNiGPs0qQHe9P5lttxO5+Fg=,tag:TPGUWXYQsf40hlVu7PGEEg==,type:str] +borg-passphrase: ENC[AES256_GCM,data:Q2GvEat5EHmshFiya3yNqFTVS+oJv0al+bYMRwysb0yu7F2gCJd000Y3ibA+tUPSL9iSlMSy0cTkesGVEGBt9w==,iv:/kUJXgibF1cyaCPB55/0nKYq9sSva6psxu2P/l7iRN4=,tag:velr9LTfoj7gEWhUmvPtQg==,type:str] +borg-ssh-key: ENC[AES256_GCM,data:0YEvv7QDmGsur0PFMmz5HqDgDCEk0kRaOu1n7GGWAwmmr0K0bVbpKzHw5wMiMnXEBrvj0izo4P4LYGAlAAYn22Bhgi2eN/vdvSO5V5uDV1ep2dV/TN2m3oYgTIgot47YgwBhcNunIUtEsbZuhAsTGL6LFBPJ3OCLKvhXTNTDaajgH/e4CvyxHHl63MBzr0i1ajigl1IKCk2hhZF4Kd1YGBCVZRoNyyNXywihlcFeskNfldW/sd5Qn2nowVf1MEV9n6Il6Zc1FX69WUVy1k+kOT7HJZGq3uDmgwXQgQhqKm1wh5uOlLkGUX6fz/nz+YFzLFMuUVvs34CzbbEFuWmGU+aNQrfCfI1hqwB5s6wVNdpUmigX9AQMQklu85tHFJg1AaRvhA24Cp/GrptggrTThcjwVFoe9NSQouNYn+ImTvlsE4HuDRRFE6YUounGd2lpRd40LsEjwKiLtwBwqG94u4ZOI91+LG6ZqHftRehE9r/CtedLyqtluNyyQyUNKPraUOm9Rrapewsj0ZCZgGQU,iv:xdRUBQlZlwVIog5KgZRmGNxdmhFE9HgnK3Ahfo+zT9k=,tag:McsJKUEGnKXxiv8Tg5zA4A==,type:str] +mysql-readonly-password: ENC[AES256_GCM,data:k2RplkUZPGZlh29KXXdtwe+MCqKzTI/bLdyuEeicdkbGlBk1SGyLF8vW4t8=,iv:a14IrXYVCDqPKGfJSEPP8g19sPvRTx5NT8IVJJeL48s=,tag:GWgU3oa/+u21/L2y3+vOsw==,type:str] +rspamd-dkim-key: ENC[AES256_GCM,data:maOnsx8AQUIjXqHEzHLxtSvAkr9+YCZid9xWaflkffS0gHd/hoHrozHy+rHSjU7Mz7QHYhjUjFY7Hp7wdKQnHpQLJRV96iNPXTXXYtBr7oDL51cq8ozd094FuMeLNSPitV89OHDcM+9h1F4dsdDWPUiw7eoijQeZ8vx1/VCVAp4FVxTFX3qhoMhXlFabiyM85eKMwJG4BdSwqS624f2Z4tvECRp0pBGtd/3r4/EVRDV1qNsiFvH8mi8eyg9xiWDLDrePq4TuWSu1Xc7z0qpDy0o8iAwGhPu9egIyzHEPk07j9U7PpK56C2UCSY0JBm0hkBGbqLXyRklSMytxoKgw4GJykMwNPNXmA9yuLPanxagJB/z8b7X4HTuYhExzQcC6ke/y8xKcxU4qGt8Ayy5v+QoNpdqXIPsZkIuw9uWm6RIgDt2dCaOdI06lesZKjqU/T6EhDfGoGZX7DwQ7uV9xNDM4NW2jsKpUdFKnzPCCe7/jO/ck4P4i8V+6NWDjj4+/BXDNnKJbMcHIHoSvckCGZiginJsbGvSWd0HfbpR7GQAnL3uKB5/HuFAaUkx+dPHmmP2tOBv6vNt+tq+V9i4kQmwAdl8a9KI456tw9vLwXcBDZOO7n4X5H0jc4afoYCnvLxahvbIXm2QNcBYVKxkqBCvoYEMrBjrnujwbQdEfDKQf3g5p8LQwAfCQ3ng+XH/BDF3qMBdsN1u5Di0FQpCDaGKX8pJ1gg+il76fJgSU8ftoaT32hJnLAjal4cgNIxbta2UYQLixUqaWZ8xqvxrSopkWYrlBBUyQh9jMEoTzpxwCsEPQ72qgVcQfJYlMl4WUBwcasfJnySR+qZ22g3fhStpAQ2HuTGhLjTG1QOewYdwDXDhNmcbqZ478Sp1t7qbBx0R7vWFSyYCMlbmLmvzPm6Z3ET7lkfCrMjMNXaQ8cWSF19QaHAfqRwQooLL93yx7U0KHCilEg4bUjsw8MLQNa4A0ohpq6CG4s5O1+di7W4/h71/moggIebFb2eGLJ8BvbkwiVozXI9L77IGd9RswlEjZed18u7fqetS7dyDthhVG2pvya4zZI/cxIq6oJkNr2RIt3NgYChOh0I/17DuSJJ1jAmPB0Evj8QtCCo49ENnyO5cGWn12DZWybwYkg2jQC4aDFA/u5ajTo3wOKdwHj5hgMz/z05Bn2vAdhCGl6uWWNzcNnDiu3/rjqsjOkfkp0hCP7Q==,iv:FORxJ8htcoLIEJihUN7im3dN4jhnigB70InTohtpWwU=,tag:e2DHBd2dn3piCkEdkbHdoA==,type:str] sops: age: - recipient: age14grjcxaq4h55yfnjxvnqhtswxhj9sfdcvyas4lwvpa8py27pjy2sv3g6v7 enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvWjd4K3BueGVxNGs2OC9t - YURtcTIzNytCMDdYd29KenZOdm4vMk9mWEZFCkJrZlVZdkVJeW4rNzc0N3NBY3hM - dE1ORzRHRHlONEQ2dW83R051aE45QVEKLS0tIE0zOVpVbWphNitPaUg0cmxUbW5m - ZHViVHJrOWREb0pYR3hOTm0zSHZ3N0EKeNcZOM+H0XZN3Ji1ubBoHMgycuJFX3+C - YvJ795wSwtXMU+mCDB04tcYPSAI0RC82wGT9r3XLNZgbF/xP0Er3nw== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhQUpWNUgxVnhuTXd2TkF0 + SVVHemFKRWlYczZ0TnBESVNRczhuRUNnUG1BCmJKQ2JZbHhFcXJidHJzci9OaFBm + ZTd0MGhsaVBic3dMb3psUHRCRnR3ODQKLS0tIERrSG1GVTRHdkJpVWpqdTZ4Yytq + OHhlZjV6MjRVbXFsWjlQSU03ZDNwYm8KAswHRSdV0BW/oJyZx63iZRHsF7SZ6PO+ + hajQqmEyfcVfEu39zZzxQ2mtWlOr69I++irOhE3NeiFeJ1yIRQDJEQ== -----END AGE ENCRYPTED FILE----- - recipient: age1exny8unxynaw03yu8ppahu5z28uermghr8ag34e7kdqnaduq9stsyettzz enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWTnpIdHBmMGdBQzk2N0xW - SGlNMUxjYU5SZHJLK0wvWnZyYkEzK04vdWd3CmVGWW50RUQ2K0lLRC90WW9KY1hj - NGVpMEdzaHUyTUVBaDcxb2w5MC9BUjAKLS0tIFdSSjlFTHl1Z3NYNVhxaSs0WkJE - eGVWZHdnMkhaNzlDNlhCa24wZzlvNmsK7pLzsxtlMevP2o9nJOjVgDAjrYdEgRUu - NlJHfO0m9U7fJfeu6XSWQgGYRJm7tSmTZKvsJgTS+pKcynHz8B9rkQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUaUNnY0hpdDAzMTNIUS9D + RmdKbmplUk9DRXlLRXEvSnVjT05sQjcvTnpJCkd6bGRINm5yYUZOUTVzWEdjRmtG + Mmx0ci93N2wvTWV5MzlRVnlYdUxoUWsKLS0tIEVHUlNWYStWTG01RzRrVnNXc3BW + VkRkUXROU3plNmwvTUVhYmhCS2syQkEKKgC0EmUu1u2vZ/SZTnam+h846gZSyY4V + JyMzkws8O5TY9juWdDzXJIU67mIgc4qrWWN3uh8k28JBZGc078b5bg== -----END AGE ENCRYPTED FILE----- - recipient: age1v6p8dan2t3w9h94fz4flldl32082j3s9x6zqq7u5j66keth9aphsd6pvch enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNMk9VL2s0ZmoxSzY3NmFQ - MTZEaml5Q0kxRDFwSEN5dG90SzZmcXZLUjJBClpVNUJEZEdaa09hM1BQUU1jVVQz - M2w4QXdmZnJya2pCTEV1QW9keXgyTWMKLS0tIFA1VWl3RzF5V2FMUE1mZ2NYRnBU - OURWSFZnM0lEMXJEcjVPL3hnZ0pIQ1kKVvoCVQuayH/XRfddMKq2d8TssXOS5e1o - bIL6F+tRBle2UgVuXSMkyggCnvLePA8OxfAdMMg5npSFkPgTZrAYYQ== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoK2JUNVdYTzkvM1BBWXRm + citCNlE4Z1NLdEZ2R0tNZTVSMlFSeGxGOURnClJnYURYa0JZaVprQWdBcmVnOWVj + TGVCK1JWMVlueHJUaTZZYmROM0E5aDAKLS0tIEJxYkdadGtZM250d2d6Ujl2UU9C + YUpkVll2S2RpT0I1UVZiZFRKS1prMEEKp/bGImanJ/58vTQG/gUun/Y2QdmOEi3h + hVS0V2QcfuGgi0/YofLOM3+M6k6ViXw07XfXmR+puvLIHKr2y11x1Q== -----END AGE ENCRYPTED FILE----- - recipient: age1xcgc6u7fmc2trgxtdtf5nhrd7axzweuxlg0ya9jre3sdrg6c6easecue9w enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3QmR3T3FYN2RpR1JrV0w0 - aVMycUJUN1NKME1UKzVsZmpNNTAzTmxUUUZNClhmdUF5N0Q4K09IeVhNOWhNNEc2 - UTNzeGJ4NlpxMUtEaHZDWDZOeHdvSU0KLS0tIFNTaThWbklXeE85c3hSMWZwNTNN - RWFUVXVXWjdsSHM5ZGljd3YyQW5ja2MKvAhwHL5PcLFxuU7MfV/cWtNfzTb9yoqR - 3iD4UJsDDagCIkpvjKods4ydlzh3agOyLHswDSX/WmUur9J5pd4PAg== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDSGdEZnZEaDRpWUJVcnds + VGFSQklvczBZdEdEbXhodW8vME9wMUpVRENjClFZcnVqYkJxdlBiZFhma0tmZjgz + YXlIdlRDTDU4MHg1dzhGVDRJb2FGYVUKLS0tIDBXSWZ2NkxzdEk0ZlFRM00ybFNy + M0doaWl5R2cwU2RxQm5DbWxXeTZ5S2MKwrB3SysmgzCThQOhEVx18dxIfko0+oZY + 9BSZOoFbfuwiLbtpL4J8bzxDvxn6sXxB8EBJH1hbpID53AquWDsxSw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-11-14T11:33:59Z" - mac: ENC[AES256_GCM,data:AnEs3yzpOJ5/wyCL/sHV6U5V7FBhZZlBQeA+mCGfZ25JZAL3Yb6yD6xJhmGC8AqIFS6PIFSWa2r0suDRQAoVO2AwFVwd9Y/TEwjPGnXvWfwB82+mnyLIakyzM/pcLjiMePUqr5nnJ8tWoKzuqs/jQHuMOGkItqwjkVDr9/hx3lc=,iv:kc08z63phDfs7gzruHjnQA9bXAvWMGkE14/0Kyfhuds=,tag:9wedcRCTAv0HMtSap55JOw==,type:str] + lastmodified: "2025-11-19T11:16:25Z" + mac: ENC[AES256_GCM,data:x4yor9G+QirceSYSX1K9GdfyGellT4JCkE09Tl9/mOX8HMOKFAQGknuwwU6SNGg+ciBFk4TdjQnDmVai4T8JQo9W/DLiZ+GKnWO3s+ZLDX30sEF0aMjKa43R5CCPO/Fl2XH96TaPC+8itTJQ6TpBSg51QLPcpqrMljiBNWvEoTU=,iv:Zi9rglAwgsejUmIpLN/1QlL80BSp3HP32k1xkWt2b+o=,tag:2ADk8d2G4OezkQjcV3CZuA==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0