diff --git a/.sops.yaml b/.sops.yaml index 8958b8f..6d9e951 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -4,7 +4,7 @@ # for a more complex example. keys: - &bitwarden age14grjcxaq4h55yfnjxvnqhtswxhj9sfdcvyas4lwvpa8py27pjy2sv3g6v7 # nixos age key - - &dominik age16veg3fmvpfm7a89a9fc8dvvsxmsthlm70nfxqspr6t8vnf9wkcwsvdq38d + - &dominik age1exny8unxynaw03yu8ppahu5z28uermghr8ag34e7kdqnaduq9stsyettzz - &dominik2 age1v6p8dan2t3w9h94fz4flldl32082j3s9x6zqq7u5j66keth9aphsd6pvch - &git-server age106n5n3rrrss45eqqzz8pq90la3kqdtnw63uw0sfa2mahk5xpe30sxs5x58 - &web-02 age1gjm4c3swt8u88e36gf2qlg3syxfc0ly94u64c42f2tsf24npw4csa6e4fw @@ -94,12 +94,13 @@ creation_rules: - *netboot - *fw - *fw-new - - path_regex: utils/modules/plausible/[^/]+\.yaml$ + - path_regex: utils/modules/attic-cache/[^/]+\.yaml$ key_groups: - age: - *bitwarden - *dominik - *dominik2 + - *nb - path_regex: utils/modules/promtail/[^/]+\.yaml$ key_groups: - age: diff --git a/hosts/nb/configuration.nix b/hosts/nb/configuration.nix index 2236ff3..115c2a9 100644 --- a/hosts/nb/configuration.nix +++ b/hosts/nb/configuration.nix @@ -15,9 +15,10 @@ in { [ "${impermanence}/nixos.nix" ./utils/bento.nix - + ./utils/modules/sops.nix ./utils/modules/nur.nix + ./utils/modules/attic-cache ./modules/appimage.nix ./modules/desktop ./modules/development diff --git a/hosts/web-arm/modules/atticd.nix b/hosts/web-arm/modules/atticd.nix index c33c146..227f49c 100644 --- a/hosts/web-arm/modules/atticd.nix +++ b/hosts/web-arm/modules/atticd.nix @@ -27,29 +27,25 @@ in { # API endpoint configuration api-endpoint = "https://${atticHost}/"; - # Allow automatic registration (set to false for production if you want to control access) - allow-registration = false; - # Require tokens for all operations require-proof-of-possession = true; + # Chunking settings for large uploads chunking = { - # Minimum chunk size: 16 MiB - min-size = 16 * 1024 * 1024; - # Average chunk size: 64 MiB - avg-size = 64 * 1024 * 1024; - # Maximum chunk size: 256 MiB - max-size = 256 * 1024 * 1024; + nar-size-threshold = 65536; + min-size = 16384; + avg-size = 65536; + max-size = 262144; }; # Garbage collection garbage-collection = { # GC interval in seconds (12 hours) - interval = 12 * 60 * 60; + interval = "12 hours"; # Delete unreferenced chunks after 7 days - default-retention-period = 7 * 24 * 60 * 60; + default-retention-period = "6 months"; }; # Storage configuration @@ -57,7 +53,7 @@ in { # Use local filesystem storage type = "local"; # Store in /var/lib/atticd - path = "/var/lib/atticd/storage"; + path = "/var/lib/atticd-storage"; }; # Optional: S3-compatible storage (commented out) @@ -70,7 +66,8 @@ in { # Database configuration database = { - url = "postgresql://atticd@/atticd?host=/run/postgresql"; + # url = "postgresql://atticd@/atticd?host=/run/postgresql"; + url = "postgresql:///atticd?host=/run/postgresql&user=atticd"; }; # Compression @@ -82,33 +79,34 @@ in { }; }; + # Create state directory with proper permissions - systemd.services.atticd = { - serviceConfig = { - StateDirectory = "atticd"; - StateDirectoryMode = "0750"; - # Security hardening - PrivateTmp = true; - ProtectSystem = "strict"; - ProtectHome = true; - NoNewPrivileges = true; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - LockPersonality = true; - ProtectProc = "invisible"; - ProtectClock = true; - ProtectKernelLogs = true; - ProtectControlGroups = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectHostname = true; - SystemCallFilter = "@system-service"; - SystemCallErrorNumber = "EPERM"; - # Resource limits - LimitNOFILE = 65536; - }; - }; + # systemd.services.atticd = { + # serviceConfig = { + # StateDirectory = "atticd"; + # StateDirectoryMode = "0750"; + # # Security hardening + # PrivateTmp = true; + # ProtectSystem = "strict"; + # ProtectHome = true; + # NoNewPrivileges = true; + # RestrictNamespaces = true; + # RestrictRealtime = true; + # RestrictSUIDSGID = true; + # LockPersonality = true; + # ProtectProc = "invisible"; + # ProtectClock = true; + # ProtectKernelLogs = true; + # ProtectControlGroups = true; + # ProtectKernelModules = true; + # ProtectKernelTunables = true; + # ProtectHostname = true; + # SystemCallFilter = "@system-service"; + # SystemCallErrorNumber = "EPERM"; + # # Resource limits + # LimitNOFILE = 65536; + # }; + # }; # Nginx reverse proxy configuration services.nginx.virtualHosts."${atticHost}" = { @@ -193,11 +191,18 @@ in { services.postgresql.ensureDatabases = [ "atticd" ]; services.postgresqlBackup.databases = [ "atticd" ]; + + services.borgbackup.jobs.default.exclude = [ - "/var/lib/atticd" + "/var/lib/atticd-storage" ]; - fileSystems."/var/lib/atticd/storage" = { + systemd.tmpfiles.rules = [ + "d /var/lib/atticd-storage 0755 atticd atticd -" + ]; + + environment.systemPackages = [ pkgs.cifs-utils ]; + fileSystems."/var/lib/atticd-storage" = { device = "//u149513.your-backup.de/u149513-sub9/"; fsType = "cifs"; options = let diff --git a/hosts/web-arm/modules/blackbox-exporter.nix b/hosts/web-arm/modules/blackbox-exporter.nix index a9ded44..6ba61c9 100644 --- a/hosts/web-arm/modules/blackbox-exporter.nix +++ b/hosts/web-arm/modules/blackbox-exporter.nix @@ -24,6 +24,7 @@ in { config = { services.blackbox-exporter = { blacklistDomains = [ + "attic.cloonar.com" "autoconfig.cloonar.com" "cloonar.dev" "loki.cloonar.com" diff --git a/hosts/web-arm/secrets.yaml b/hosts/web-arm/secrets.yaml index 5ad9fc9..903206d 100644 --- a/hosts/web-arm/secrets.yaml +++ b/hosts/web-arm/secrets.yaml @@ -21,7 +21,7 @@ victoria-nginx-password: ENC[AES256_GCM,data:+rKDzML5eQX47JF1i/ZU9jwdeLgRXPyzwSC nextcloud-adminpass: ENC[AES256_GCM,data:/vt17v+aaucz8sq/uYUA0hlj1urKNYcmCN0LbgGAMhWoTiTwzYr5FzrygOuZWZBeaAFH1pWItTZRXj74OX8XqutLPlYDg/jZqLszU0/9HgSBoHb5ZnPUpzIjNI9dpMttPphpo5TVrYKoh/vR3OWjJa3ObcpGLdvMQc1r8ABEvvg=,iv:0xW7++80CwZy0O4J3bFElqp0ZMC+RpO5kcczshM1pzg=,tag:PJj5PHfkoHE8jRbS4mpq6Q==,type:str] nextcloud-secrets: ENC[AES256_GCM,data:FwP+z4B03m0VEFEb8c/UwBKMcWXo+2dnlBAuO4SCVXNBLdq3IK+e8gGzKima+sac+WZ3k3ncPAqyIomBLwEmIUB/24xYx4SL6AddwDoyytZbVDv5Zt7Vpvy6aheOvARoqez3pWMaC+rW11JFVw==,iv:BT9eGRUhHMbwkhuQ+cC32zHICRbm2hQQeVfIHrCB+JM=,tag:GNpdz1QYEcfVvmkjFJY1vg==,type:str] nextcloud-smb-credentials: ENC[AES256_GCM,data:Ra1iVCP/Y1G87oDrn01JxorTQy6d80POKIVEbHPttrd6x5QgEvvyWIz6rCiK4mEH,iv:6wXHBSwq9P+tHrkB82ZReFXsUOF0rDi2hpZ8jXLU7OE=,tag:Fu4RB0hPyHFpN6YLTtfGDQ==,type:str] -atticd: ENC[AES256_GCM,data:a7ueVdAc5OH43JQI+hhVGbBBaeKo2SIqB6TlNAGLg1qIP/z7FfZbxrxvGhrtqhuMfkcJurhnQAGmj2e16eqH9uC3GSM4Hltc64IsZQE=,iv:tl08AndTPAoZjYO5dZgwjNrb8gTpMUJtygCqVNNWZTE=,tag:f9yFk+q5Naowvj6nIT7Wag==,type:str] +atticd: ENC[AES256_GCM,data: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,iv:0p5WHQ3GelBseeTSR0vpwoUSK5MFlWe1jCZ26hd2Zek=,tag:p3GuWRhCNjYPhgJW+DXAWg==,type:str] atticd-smb-credentials: ENC[AES256_GCM,data:QbCHw+Y//9r60zlP3yceWnYME+rNom4NWnuxwV+d5zzPtzkd377hmqMFPHcbUuJti2KQ3ww6RtFbv02SbNBqahrVwBNSmowr0D7suw==,iv:5xIAW3O0EDuKGtbQSSphLJuWjqbpRnD7B2rypC6Qu3w=,tag:op+NMyWSp2bmrGNkQ/glkw==,type:str] pushover-api-token: ENC[AES256_GCM,data:itcWlyaJi+saBmhLabOOgbOej9yxQgCIiwU9uuOg,iv:dnD12MPZsENogsnCMGpZe1F0cC4eFfefSx7sP9Fl9Mw=,tag:lk1+pkvNab6yG0Sv/+TVIQ==,type:str] pushover-user-key: ENC[AES256_GCM,data:swXKXMAeCyYbBQNAEEpDTJXjdNmFFVWnhExAqfnn,iv:AZd6phibpwEX97U/SzeiRoFFL3TviSONwOWkPsXdcKc=,tag:+mzfrxHpTWOzb3bEzN3D5Q==,type:str] @@ -67,7 +67,7 @@ sops: QVNnMUNpcjg5YnhvbjIxUVVXNE44d1UK+X4arcItFuQPzFHX/1L8+KiU+MHmqBdK nqJ+vibancZRxkBEE4fKbbOWS3kdcU+uWhk1nXkVlaz8Bq6qtctSqw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-10-14T17:59:28Z" - mac: ENC[AES256_GCM,data:5dAFYstFhWXVjY7zjA42G4dH4R7fDzp+5oZrWZ6RXD9GmXhrZiHQE+KBDf2LsBQk1YiF+voNHBTBFT8TZ5FXWxxjsh/XIehWJTDL6XCsRxRuOhUovePxU6ZZj4VrGPTVELXo1zORdPu08VBcrStb2FX8fA5csAXkt6p0yYWctfc=,iv:uo+YpMTognBequ3yFkYM0v2J8Ysf356FtuCi+6GPlPo=,tag:qhJy1I5Dk+Hr8x4KT17coA==,type:str] + lastmodified: "2025-10-14T19:34:03Z" + mac: ENC[AES256_GCM,data:PTPwZoW6KTL6CHodLVi4stn37JLg2jIBtsGE7CsW0VkVroNo/5wVvFj2xl0Zzcj3u5y3xwFMt4qo6orqyor0sTHKZA6KiwcqHlwvlJAqY1VQD//L/+NggBvLOyhwrmi3Wokokfdn0ysPrDaS6lHyvAGixWZWhIiNr0X03KKvQTY=,iv:xZkh0ZfsC1spN36+1xoFbZwuIYWZmVONPzCTDATi7VM=,tag:fSUMNytbRaJC1UZzCXsFAQ==,type:str] unencrypted_suffix: _unencrypted version: 3.11.0 diff --git a/scripts/update-secrets-keys b/scripts/update-secrets-keys new file mode 100755 index 0000000..c23d0b1 --- /dev/null +++ b/scripts/update-secrets-keys @@ -0,0 +1,170 @@ +#!/usr/bin/env bash +set -Euo pipefail + +# Script to update sops keys for all secrets.yaml files in the project +# Uses .sops.yaml configuration to determine encryption keys + +AGE_KEY_FILE="" +DRY_RUN=false +VERBOSE=false + +# Parse options +while [[ $# -gt 0 ]]; do + case $1 in + -k|--age-key-file) + AGE_KEY_FILE="$2" + shift 2 + ;; + -n|--dry-run) + DRY_RUN=true + shift + ;; + -v|--verbose) + VERBOSE=true + shift + ;; + -h|--help) + cat <&2 + echo "Use --help for usage information." >&2 + exit 1 + ;; + esac +done + +# Check if 'sops' command is available +if ! command -v sops > /dev/null; then + echo "ERROR: 'sops' command not found. Please ensure it is installed and in your PATH." >&2 + echo "Install with: nix-shell -p sops" >&2 + exit 1 +fi + +# Determine the absolute directory where the script itself is located +SCRIPT_DIR=$(dirname "$(readlink -f "$0")") +PROJECT_ROOT=$(readlink -f "$SCRIPT_DIR/..") + +# Check if .sops.yaml exists +SOPS_CONFIG="$PROJECT_ROOT/.sops.yaml" +if [ ! -f "$SOPS_CONFIG" ]; then + echo "ERROR: .sops.yaml not found at '$SOPS_CONFIG'" >&2 + exit 1 +fi + +# Export age key file if provided +if [ -n "$AGE_KEY_FILE" ]; then + if [ ! -f "$AGE_KEY_FILE" ]; then + echo "ERROR: Age key file not found at '$AGE_KEY_FILE'" >&2 + exit 1 + fi + export SOPS_AGE_KEY_FILE="$AGE_KEY_FILE" + if [ "$VERBOSE" = true ]; then + echo "INFO: Using age key file: $AGE_KEY_FILE" + fi +elif [ -z "${SOPS_AGE_KEY_FILE:-}" ]; then + echo "WARNING: SOPS_AGE_KEY_FILE not set. You may not be able to decrypt secrets." >&2 + echo " Use --age-key-file to specify a key file, or set SOPS_AGE_KEY_FILE environment variable." >&2 +fi + +# Find all secrets.yaml files +echo "INFO: Searching for secrets.yaml files in $PROJECT_ROOT..." +mapfile -t SECRET_FILES < <(find "$PROJECT_ROOT" -name "secrets.yaml" -type f | sort) + +if [ ${#SECRET_FILES[@]} -eq 0 ]; then + echo "WARNING: No secrets.yaml files found in the project." >&2 + exit 0 +fi + +echo "INFO: Found ${#SECRET_FILES[@]} secrets.yaml file(s)" +if [ "$VERBOSE" = true ] || [ "$DRY_RUN" = true ]; then + for file in "${SECRET_FILES[@]}"; do + relative_path="${file#$PROJECT_ROOT/}" + echo " - $relative_path" + done +fi + +if [ "$DRY_RUN" = true ]; then + echo "INFO: Dry-run mode enabled. No files will be modified." + exit 0 +fi + +# Update keys for each file +UPDATED_COUNT=0 +FAILED_COUNT=0 +SKIPPED_COUNT=0 + +for file in "${SECRET_FILES[@]}"; do + relative_path="${file#$PROJECT_ROOT/}" + + if [ "$VERBOSE" = true ]; then + echo "INFO: Updating keys for: $relative_path" + else + echo -n "Updating $relative_path... " + fi + + # Check if file is encrypted with sops + if ! grep -q "^sops:" "$file" 2>/dev/null; then + echo "SKIP (not encrypted)" + ((SKIPPED_COUNT++)) + continue + fi + + # Run sops updatekeys + if sops updatekeys --yes "$file" 2>&1 | { + if [ "$VERBOSE" = true ]; then + cat + else + grep -v "^$" || true + fi + }; then + if [ "$VERBOSE" != true ]; then + echo "OK" + fi + ((UPDATED_COUNT++)) + else + EXIT_STATUS=$? + echo "FAILED (exit code: $EXIT_STATUS)" >&2 + ((FAILED_COUNT++)) + fi +done + +# Summary +echo "" +echo "===== Summary =====" +echo "Total files found: ${#SECRET_FILES[@]}" +echo "Successfully updated: $UPDATED_COUNT" +echo "Failed: $FAILED_COUNT" +echo "Skipped: $SKIPPED_COUNT" + +if [ $FAILED_COUNT -gt 0 ]; then + exit 1 +fi + +echo "INFO: All secrets.yaml files have been updated successfully." +exit 0 diff --git a/utils/modules/attic-cache/default.nix b/utils/modules/attic-cache/default.nix new file mode 100644 index 0000000..1b65bbc --- /dev/null +++ b/utils/modules/attic-cache/default.nix @@ -0,0 +1,87 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cacheUrl = "https://attic.cloonar.com"; + cacheName = "cloonar-nixos"; + publicKey = "cloonar-nixos:u0S8Q3CShMkXeBk/eo8iooqrcSBTwNGBxQDS9HfkseE="; + authTokenFile = config.sops.secrets.attic_auth_token.path; + + # Post-build hook script that pushes to Attic + atticPushHook = pkgs.writeShellScript "attic-push-hook" '' + #!${pkgs.bash}/bin/bash + set -euo pipefail + + # Load configuration from sops secrets at runtime + ATTIC_CACHE="${cacheName}" + ATTIC_URL="${cacheUrl}" + + # Check if we have the required configuration + if [[ -z "$ATTIC_CACHE" ]] || [[ -z "$ATTIC_URL" ]]; then + echo "Attic cache not configured, skipping push" >&2 + exit 0 + fi + + # Read the auth token from sops if available + ATTIC_AUTH_TOKEN=$(cat "${authTokenFile}") + + # Function to check if a path exists in cache + path_in_cache() { + local path="$1" + ${pkgs.attic-client}/bin/attic cache info "$ATTIC_CACHE" "$path" &>/dev/null + } + + # Function to push a path to cache + push_to_cache() { + local path="$1" + echo "Pushing $path to Attic cache..." >&2 + if ${pkgs.attic-client}/bin/attic push "$ATTIC_CACHE" "$path"; then + echo "Successfully pushed $path" >&2 + else + echo "Failed to push $path (non-fatal)" >&2 + fi + } + + # Read paths from stdin (provided by Nix post-build-hook) + while IFS= read -r path; do + if [[ -e "$path" ]]; then + # Check if already in cache before pushing + if ! path_in_cache "$path"; then + push_to_cache "$path" + else + echo "Path $path already in cache, skipping" >&2 + fi + fi + done + + echo "Attic cache push completed" >&2 + ''; + +in { + sops.secrets.attic_auth_token = { + sopsFile = ./secrets.yaml; + }; + + # Install attic client + environment.systemPackages = with pkgs; [ + attic-client + ]; + + # Configure Nix settings + nix.settings = { + substituters = [ cacheUrl ]; + trusted-public-keys = [ publicKey ]; + post-build-hook = atticPushHook; + }; + + # Create a systemd service for manual cache operations + systemd.services.attic-push-closure = { + description = "Push a closure to Attic cache"; + serviceConfig = { + Type = "oneshot"; + ExecStart = "${pkgs.bash}/bin/bash -c '${pkgs.attic-client}/bin/attic push ${cacheName} $CLOSURE_PATH'"; + EnvironmentFile = authTokenFile; + }; + }; +} diff --git a/utils/modules/attic-cache/secrets.yaml b/utils/modules/attic-cache/secrets.yaml new file mode 100644 index 0000000..8a41058 --- /dev/null +++ b/utils/modules/attic-cache/secrets.yaml @@ -0,0 +1,34 @@ +attic_auth_token: ENC[AES256_GCM,data:O9wRQe+llEvCE/9mx7VckgCY/5/ZryUFz+0qpgauFRsnNWiB31yOTXo1sOn1lPldGpfsSpUZnGDTLvg5S6mzZ9UYdhDTcSk6V+E9YV5wXLFJv6HGVVI7TVhkSSBIUrxx8sbQvC/hYQ+YQ0zzfreaIz7eMVbHgk+FNnNr3pFNcLYLTacugvMOyZDwkEJcKIFMcWj+zCGu90s3W7LutfudJ37LB4M9sU1Ifjj46NGTe3fAj+lmS1IyJ+2ZUlVoQd4pCbWB0wm3bTpwjJhDYhjQj5gJPuMjBQcCpP7uBvelcmBo+8V/LJ9HY6pRFxPlp48+tOwlGGrzb5WyqWPE3sP3F2eQj4EnlQoULrfi6ARO0xO4qs0FJhN2YhvHJYRyd9leNWNLIe1SdRQ9PK5ksvuoM1rTlbgrPotPYa1PkfmgFuWBMwI+hBf0+DMJtZxJpVES3WAcOuibZukeA5lvQ+AAFTpHRW8AiZF2ry3gWxStLsUrqNQTTt1gZQq6WrHbYbXr3DCuTXxqVLX4mXO1Slbm7JLxni7Sn5nCfUiKCAmFdxuL0L22RMa5yd9+7+wdcFJfhqu9pZ8U5KoTMuaJKnxp0KISog3gDVAfxkrrtfhLnHtJkkLB+/Aa3Ypqowle9iAq1I0IdH6Nzwl63C2nbqPafL5mcXkFMwPktHlkqrflUl/QKnJqBBvcgThdHZIbsQUq2xo589cpvDLouWL2xUHNpIqWotowF5m4n/iN53i6/cJayNpLWMEWWLtslXtG1CN7arjoYYJOuEqdzkqTjornSU7Q1kF6/eLgB8e2BVnMKfBT59F4sX2c6kuK0QXPohcpLWI1ZEYxnSv/44W0i/Ij5NvqZOQ1pEsyMIlPbuh37khw1gv+fMKrbEUUyquzHTX7DEGYEECzWjHQ3/WeDuRmiHlrZC/3StMf9888qm5v2yw/Vk5rQwNY1nbeTf8yWg47qKi2GgSSdsqrUrW5yWLs4MWKF2cSSDMC/kbgvGkHoS9KVI5dBGJhGuAf98tzOBO/UO39X0TjTzcay0AQ27/r8+QeIimviaZO41/GQOjoMzzSDHGxWEf2Nf/40nrM5Vcqj3I6hvRFE4u2m6jxCMqCqsIuy9avW8EuZyC6zJMoHSe/lUnYrx4tSUf3VhN85o6QSSJqfIFUN0jPQwNFpsz3X+A=,iv:X6xSygAtem7ekQruSZirdW/LKwf0kw+/Iq35wAcNyyQ=,tag:gRuPBxM5VeoJHimC6sbSow==,type:str] +sops: + age: + - recipient: age14grjcxaq4h55yfnjxvnqhtswxhj9sfdcvyas4lwvpa8py27pjy2sv3g6v7 + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2ZnRYdjlOZHB3ZWNkVG42 + OWZDdGNjNmNoQmozeGlxSHBJSXNWTjc2VUE0ClZISko5d0piR3RRMGNNSVZjc2Rr + NnZHZWtCQytNeG5FeGQyRVBCcE9tdzAKLS0tIFdaVXBWK1ppYUpaQVJTUzVUOUR4 + Nmd6KzN5Unh2bFdyaEd6aTluUEt6aFEKfxYq7UwQOwSGUpXnS8+8EsqA8mk3a2oT + eCssbrBsKvjkqOMvDNieBah5h5k13r5JJKHIENkJK6rhTUkvxJUdaw== + -----END AGE ENCRYPTED FILE----- + - recipient: age1exny8unxynaw03yu8ppahu5z28uermghr8ag34e7kdqnaduq9stsyettzz + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuZDI4V2RBWUIvVzhEUzBX + Tng2MTAyOHl1TDhnVTY3OG1YUkZLem1TSGd3Ckorbi9wRTlodFZnVkpkUDgwdTRi + ZUZOUFFMUENzQzQvbk9XNnZsWVRIRjgKLS0tIGxoUUYvTUsyZ3BweGlrdzRhSUxr + YzRBbEZZMyt2VVpiTFJQUi8vS1BpMXcK8zmi27Kvp+0ujLQ+UEnq90bHjq5j+EWu + CnaKbqpQzCm+7TphBDR7tmUj2QoS2P0EXwub3DZtjZv6lnyMeD2DXQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age1v6p8dan2t3w9h94fz4flldl32082j3s9x6zqq7u5j66keth9aphsd6pvch + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvMldwQzhMOXhWcUYvSDFT + d29kRFNWZzZ2TkNIeFBTVk5HNjZMdmlOQWdBCkpmUjJDdHdXRzVZUzlVVGM2ak1l + dnlHMURTUjR3MEhwd2RLbGsvWkRIbncKLS0tIHNVQUl3QXBwUEM5ZzUyczlHUXA3 + UzVENGtNSnZVcDQvR1hDR2oyZDh5KzAKhg+AQNdiJM/RvCdMNLH5er25U+yvcnM2 + 4Z0rOkkYsT6TerZHLllbm5AAyOLnKUn4PhZFMvKvGhVbc1Xg9t2XDg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-10-14T20:22:06Z" + mac: ENC[AES256_GCM,data:dt+rZ7GTlooTFhQOxRQvVpqKJksEJC5I5vsjSQ6GWPsi4EewGl2NY2gyjF6bVjYj6DHWuw/Kp79KGzJajmlYtQFdL54ydjaJUz4oMhoKO3xR4TxshW9XYEfOWavlMVqHHZQ6mPR1pyWQkonzwyni9ug8XmOJ0cN2OmZmKwdWzZQ=,iv:6AJocLlXZcNGG3nuXLc+ycfm6OA/oZOUFqFw4OoBetU=,tag:Qpa1RKS1/nqbDiAL5Jrb7w==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0