diff --git a/.sops.yaml b/.sops.yaml index 862a376..460b37f 100644 --- a/.sops.yaml +++ b/.sops.yaml @@ -1,10 +1,12 @@ keys: - &primary_gpg D3067BE844D3FC49535A47B29396B8BA6FBB14DE + - &laptop_ssh_pubkey age1xrzl49tvnatuu55xu5av6xcxyhrakd7mkzl5kz30kqqaxvh2m3sqax8jeu - &vps_ssh_pubkey age1acgqxvyczgsamz53z3v0gmahzfxlg9tscwnrgcxrfndgxhsvn3vs4ss5tk creation_rules: - - path_regex: secrets/secrets.yaml$ + - path_regex: secrets/.*\.(yaml|json)$ key_groups: - pgp: - *primary_gpg age: - - *vps_ssh_pubkey \ No newline at end of file + - *vps_ssh_pubkey + - *laptop_ssh_pubkey diff --git a/hosts/laptop/akkoma/akkoma-static.nix b/hosts/laptop/akkoma/akkoma-static.nix new file mode 100644 index 0000000..8555a89 --- /dev/null +++ b/hosts/laptop/akkoma/akkoma-static.nix @@ -0,0 +1,30 @@ +{ pkgs, config, lib, ... }: +let + imperativeStaticPath = "/data/akkoma/static_i"; + declarativeStaticPath = "/data/akkoma/static_d"; + mergedStaticPath = "/data/akkoma/static"; + declarativeStaticFiles = let cfg = config.services.akkoma; in with lib; pkgs.runCommandLocal "declarative-akkoma-static" { } '' + ${concatStringsSep "\n" (mapAttrsToList (key: val: '' + mkdir -p $out/frontends/${escapeShellArg val.name}/ + ln -s ${escapeShellArg val.package} $out/frontends/${escapeShellArg val.name}/${escapeShellArg val.ref} + '') cfg.frontends)} + + ${optionalString (cfg.extraStatic != null) + (concatStringsSep "\n" (mapAttrsToList (key: val: '' + mkdir -p "$out/$(dirname ${escapeShellArg key})" + ln -s ${escapeShellArg val} $out/${escapeShellArg key} + '') cfg.extraStatic))} + ''; +in +{ + environment.systemPackages = with pkgs; [ mergerfs ]; + systemd.tmpfiles.rules = [ + "d ${imperativeStaticPath} 700 akkoma akkoma -" + "L+ ${declarativeStaticPath} - - - - ${toString declarativeStaticFiles}" + ]; + fileSystems."${mergedStaticPath}" = { + fsType = "fuse.mergerfs"; + device = "${imperativeStaticPath}:${declarativeStaticPath}"; + options = [ "cache.files=off" "dropcacheonclose=true" "category.create=epff" ]; + }; +} \ No newline at end of file diff --git a/hosts/laptop/akkoma/akkoma.nix b/hosts/laptop/akkoma/akkoma.nix new file mode 100644 index 0000000..ff17a81 --- /dev/null +++ b/hosts/laptop/akkoma/akkoma.nix @@ -0,0 +1,53 @@ +{ pkgs, lib, config, ... }: +let + inherit ((pkgs.formats.elixirConf {}).lib) mkMap mkAtom mkRaw mkTuple; +in +{ + services.akkoma = { + enable = true; + initSecrets = false; + patches.configurableFromDatabase = true; + # frontends.mastodon = { + # package = ; + # name = "mastodon-fe"; + # ref = "stable"; + # }; + extraPackages = with pkgs; [ zip unzip exiftool ffmpeg_5-headless graphicsmagick-imagemagick-compat ]; + config = { + ":pleroma".":instance" = { + name = "My Akkoma instance"; + description = "Akkoma instance description"; + email = "user@localhost"; + registration_open = false; + federating = false; + upload_dir = "/data/uploads"; + static_dir = "/data/akkoma/static"; + }; + ":pleroma"."Pleroma.Web.Endpoint" = { + url.host = config.myAkkomaContainerOptions.domain; + http.ip = config.myAkkomaContainerOptions.localAddress; + http.port = config.myAkkomaContainerOptions.localPort; + }; + + ":pleroma"."Pleroma.Uploaders.Local".uploads = "/data/uploads"; + + ":pleroma".":mrf".policies = map mkRaw [ + "Pleroma.Web.ActivityPub.MRF.ObjectAgePolicy" + "Pleroma.Web.ActivityPub.MRF.TagPolicy" + "Pleroma.Web.ActivityPub.MRF.SimplePolicy" + ]; + ":pleroma".":mrf_simple".accept = [ + (mkTuple ["good.instance" "good!"]) + ]; + + + ":pleroma"."Pleroma.Web.Endpoint".secret_key_base = { _secret = "/run/secrets/akkotest/key-base"; }; + ":pleroma"."Pleroma.Web.Endpoint".signing_salt = { _secret = "/run/secrets/akkotest/signing-salt"; }; + ":pleroma"."Pleroma.Web.Endpoint".live_view.signing_salt = { _secret = "/run/secrets/akkotest/liveview-salt"; }; + ":web_push_encryption".":vapid_details".private_key = { _secret = "/run/secrets/akkotest/vapid-private"; }; + ":web_push_encryption".":vapid_details".public_key = { _secret = "/run/secrets/akkotest/vapid-public"; }; + ":joken".":default_signer" = { _secret = "/run/secrets/akkotest/jwt-signer"; }; + + }; + }; +} \ No newline at end of file diff --git a/hosts/laptop/akkoma/akkontainer.nix b/hosts/laptop/akkoma/akkontainer.nix new file mode 100644 index 0000000..4144cde --- /dev/null +++ b/hosts/laptop/akkoma/akkontainer.nix @@ -0,0 +1,45 @@ +{ lib, config, ... }: +let + cfg = config.myAkkomaContainerOptions; +in +with lib; +{ + options.myAkkomaContainerOptions = { + enable = mkEnableOption "akkoma container tweaks"; + hostAddress = mkOption { + type = types.str; + }; + localAddress = mkOption { + type = types.str; + }; + localPort = mkOption { + type = types.int; + }; + domain = mkOption { + type = types.str; + }; + isContainer = mkOption { + type = types.uniq types.bool; + default = false; + }; + containerName = mkOption { + type = types.uniq types.str; + }; + }; + + + config = mkIf (cfg.enable && (!cfg.isContainer)) { + containers.${cfg.containerName}.config = + { config, pkgs, ... }: + { + myAkkomaContainerOptions = with cfg; { + isContainer = true; + inherit hostAddress; + inherit localAddress; + inherit localPort; + inherit domain; + # inherit containerName; + }; + }; + }; +} \ No newline at end of file diff --git a/hosts/laptop/akkotest.nix b/hosts/laptop/akkotest.nix new file mode 100644 index 0000000..094cc96 --- /dev/null +++ b/hosts/laptop/akkotest.nix @@ -0,0 +1,141 @@ +{ config, pkgs, lib, ... }: +let + hostAddress = "192.168.100.10"; + localAddress = "192.168.100.11"; + localPort = 4000; + domain = "akkotest.local"; +in +{ + imports = [ + ./akkoma/akkontainer.nix + ]; + + networking.extraHosts = '' + 127.0.0.1 ${domain} + ''; + services.nginx = { + enable = true; + virtualHosts."${domain}" = { + serverName = "${domain}"; + forceSSL = true; + sslCertificate = "/data/selfcerts/nginx-selfsigned.crt"; + sslCertificateKey = "/data/selfcerts/nginx-selfsigned.key"; + locations."/" = { + proxyPass = "http://${localAddress}:${toString localPort}"; + proxyWebsockets = true; + recommendedProxySettings = true; + }; + }; + }; + sops.secrets = + let + sopsFile = ../../secrets/akkotest.yaml; + format = "yaml"; + sopsPrefix = "akkotest"; + mkSopsSecret = secretList: builtins.listToAttrs(map + (name: { + name = "${sopsPrefix}/${name}"; + value = { + inherit sopsFile; + inherit format; + }; + }) + secretList); + in mkSopsSecret [ + "vapid-private" + "vapid-public" + "liveview-salt" + "signing-salt" + "jwt-signer" + "key-base" + ]; + # sops.secrets."akkotest/vapid-private" = { + # sopsFile = ../../secrets/akkotest.yaml; + # format = "yaml"; + # }; + + myAkkomaContainerOptions = { + enable = true; + hostAddress = "192.168.100.10"; + localAddress = "192.168.100.11"; + localPort = 4000; + domain = "akkotest.local"; + containerName = "akkotest"; + }; + + containers.akkotest = + let + outerConfig = config; + hostDataPrefix = "/data/akkotest"; + containerDataPrefix = "/data/akkotest"; + in + { + ephemeral = true; + privateNetwork = true; + inherit hostAddress; + inherit localAddress; + allowedDevices = [ + { + modifier = "rwm"; + node = "/dev/fuse"; + } + ]; + bindMounts."/dev/fuse" = {}; + bindMounts.static = { + hostPath = "/data/static_i_akkotest"; + mountPoint = "/data/akkoma/static_i"; + isReadOnly = false; + }; + bindMounts.db = { + hostPath = "/data/postgresql_akkotest"; + mountPoint = "/data/postgresql"; + isReadOnly = false; + }; + bindMounts.uploads = { + hostPath = "/data/uploads_akkotest"; + mountPoint = "/data/uploads"; + isReadOnly = false; + }; + bindMounts.secrets = { + hostPath = "/data/secrets_akkotest"; + mountPoint = "/var/akkosecrets"; + isReadOnly = true; + }; + bindMounts."/run/secrets/akkotest" = { + isReadOnly = true; + }; + + config = + { config, pkgs, ... }: + { + imports = [ + ./akkoma/akkontainer.nix + ./akkoma/akkoma.nix + ./akkoma/akkoma-static.nix + ../../modules/akkoma-patches.nix + ]; + # myAkkomaContainerOptions = outerConfig.myAkkomaContainerOptions.mkInnerConfig; + # myAkkomaContainerOptions = { + # inherit hostAddress; + # inherit localAddress; + # inherit localPort; + # inherit domain; + # isContainer = true; + # }; + environment.systemPackages = with pkgs; [ zip unzip ]; + systemd.tmpfiles.rules = [ + "d /data/postgresql 700 postgres postgres -" + # "d /data/uploads 700 akkoma akkoma -" + "d /var/akkosecrets 500 akkoma akkoma -" + ]; + services.postgresql = { + enable = true; + package = pkgs.postgresql_15; + dataDir = "/data/postgresql"; + }; + networking.firewall.allowedTCPPorts = [ + localPort + ]; + }; + }; +} \ No newline at end of file diff --git a/hosts/laptop/configuration.nix b/hosts/laptop/configuration.nix index a9b9f82..fd71807 100644 --- a/hosts/laptop/configuration.nix +++ b/hosts/laptop/configuration.nix @@ -9,6 +9,9 @@ let in { + imports = [ + ./akkotest.nix + ]; # boot.kernelPackages = pkgs.linuxPackages_zen; # Use the systemd-boot EFI boot loader. @@ -291,7 +294,6 @@ in defaultSopsFile = ../../secrets/secrets.yaml; defaultSopsFormat = "yaml"; secrets.example_key = {}; - gnupg.home = "/home/lgm/.gnupg"; }; # OnlyKey @@ -360,13 +362,25 @@ in # Enable the OpenSSH daemon. # services.openssh.enable = true; + services.openssh = { + enable = true; + settings.PermitRootLogin = "no"; + }; + # Open ports in the firewall. networking.firewall.trustedInterfaces = [ "p2p-wl+" ]; networking.firewall.allowedTCPPorts = [ 5900 5905 7236 7250 ]; networking.firewall.allowedUDPPorts = [ 5900 5905 7236 5353 ]; + # Or disable the firewall altogether. # networking.firewall.enable = false; + # enable NAT for the containers + networking.nat.enable = true; + networking.nat.internalInterfaces = ["ve-+"]; + networking.nat.externalInterface = "wlp3s0"; + networking.networkmanager.unmanaged = [ "interface-name:ve-*" ]; + # Copy the NixOS configuration file and link it from the resulting system # (/run/current-system/configuration.nix). This is useful in case you # accidentally delete configuration.nix. diff --git a/secrets/akkotest.yaml b/secrets/akkotest.yaml new file mode 100644 index 0000000..970c2d8 --- /dev/null +++ b/secrets/akkotest.yaml @@ -0,0 +1,48 @@ +akkotest: + vapid-private: ENC[AES256_GCM,data:Of0qz0YsKY0Q/TwaNIKdyc8aLNFqxWkgFjFpn5sKScJ2hecyV5xfU5s/Ng==,iv:S0vJxcxMndplwDTid9oGyrPBermHcQmUbu+a5Q/CvMQ=,tag:vnagolGScz+fiq9+nPyEvQ==,type:str] + vapid-public: ENC[AES256_GCM,data:l5w8ojDzVVJVyUswtfBzyzXfRB1KgmWUl9tBioCI8aC6l0cNEzcHZXhmMXyLhz8BH27TDpoCb44a/v0toLNs/jSPzWmoFsaDYZQSUZrnVSAZeydE/OC+,iv:J6Qd31qCr6Oz4+kXRlawDcBrb8rQlJMs0JbehwtBi4E=,tag:7iLoLx1SY2hUQCOA2ed2Og==,type:str] + liveview-salt: ENC[AES256_GCM,data:BflmnDSJhOs=,iv:VFfe37XjZ2oWO0QEj15l30wPdyjy2xKC9tmNWEaP6lo=,tag:JkfDKToZ+vm4KcSj/kHM9g==,type:str] + signing-salt: ENC[AES256_GCM,data:qxjCrBTh7x4=,iv:e4eHvm5LJG/5S4Xr4Nulp6lAG/1rcIMddMg/TTe1Cyk=,tag:w1Ue/NSWVAr4jEkIMzY2Hg==,type:str] + jwt-signer: ENC[AES256_GCM,data:OzbstTTfsNKBWWd9vVXSw9zF2TDd009uDujKU22Am6gmbWbVzGZQM8/OtqBZWxxTwaETFPBSYoaYJJ0ApsJC3A==,iv:ZPCAHddIY8t1TCnsSkRirRJae/RPjEcsB0XsQeyC8As=,tag:K5MTMTix2akG47bgRhrmeA==,type:str] + key-base: ENC[AES256_GCM,data:zCCK4Q48giugC+elH8P8XSvZ8wpzzCF7UhB8mhOeC7xg2sgjPYEmU+l33fh9zh1H5/g3XP0pnbNGIS9iqiDeqA==,iv:oZsZwvxczuqL4Dy0Z8BPazdJTCQmcSu1vq2c/DxuoFs=,tag:6x5vWgH+iQi5GFSU+P3FRA==,type:str] +sops: + kms: [] + gcp_kms: [] + azure_kv: [] + hc_vault: [] + age: + - recipient: age1acgqxvyczgsamz53z3v0gmahzfxlg9tscwnrgcxrfndgxhsvn3vs4ss5tk + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSY09sNEw3WS9WV1VEZkFt + bkRjZ1ZDdE9DNjVVa0QzM0s0OUdwRjB2NndRCkRZSXZtakRaZ2pnM0hOSFhhVXBM + eUZ4U01YSjF4cnZnVG8rUHY0Z0Vra1UKLS0tIDkybmxnN3VWNnZDb3ZwaUVGN3lK + alcyWWJ5U1RROGxPWGhqRE5rcEpiM3MK0YKdW3lVHlxZ58clXOsnnwhRVpUZlFt9 + aXbiXfaytXSwYxC3802GxBQ9rzcPTXjKtVRsNuuN8Hjb1tBVF1AprA== + -----END AGE ENCRYPTED FILE----- + - recipient: age1xrzl49tvnatuu55xu5av6xcxyhrakd7mkzl5kz30kqqaxvh2m3sqax8jeu + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRWUNoRzd5TTFCejBjeG93 + b3ZMajI1QTgwMmU1WkgyWVl5WExYbU9CNW1JCmtwbDFKYlozeHFmbmFVd09TQVky + emJiamhPRXNSMnpHY1oxeGVBZ2hTNFkKLS0tIFdtNlovR3NrdFcyWFBPbGJMVU9U + RmtjUzFoR29sWkxSa0ROajVlMnZuY28KMXXUC35xOmLOUq5ig6MKO/5ru59IG51m + oO0u0GZKTwUuDnZZAZOWRv0EtYJeINg9OiRx26MtzEF2EOiEmoCijw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-02-02T19:42:16Z" + mac: ENC[AES256_GCM,data:qVTXB7Kc1FkZ8ROEdZtTHTPptlCE2ks+2ASHpQo5snSjAB0jSIB6XGJyWO3L309yoNwOws/Gizo/xgd5KRb8E9YSCDCLZmpcqzRPFtEQLXtL6LHvT5j5VM2nrBomux/UMepF0Mx5jrOpx9t+OpijbLklKgHdLb+5fJCkBYPo8gk=,iv:IX/rQA1QBfLSzmYDNGf/QMycyjeLnFrUb6hZ2KrksAk=,tag:MIksNpq0Mo6V46/saoi8jg==,type:str] + pgp: + - created_at: "2024-02-02T19:39:09Z" + enc: |- + -----BEGIN PGP MESSAGE----- + + hF4DrTkQq20WUVESAQdAaBk1uZPkNd6VhFh7iVJIuimqtN1lMSUyYCQVbnpV0Fsw + w/SuftIivVW/yx02QCWjHB+/inM2+Dak6dKoEsHvrI8BICwJ2uCW20GoWYe3yxyD + 1GgBCQIQfVa86L/5k3CB7HijrMN7PQ13of3loSDy6C0cGSwJa8RzQ1+9peK5oJB7 + xe5Q88HX14opZ4feWOPxMj4cnp5HlnjMveiWNivs+jquzFvwdYZskp6w8CgiUVxw + FpTSRCEuVKb2tQ== + =Nxri + -----END PGP MESSAGE----- + fp: D3067BE844D3FC49535A47B29396B8BA6FBB14DE + unencrypted_suffix: _unencrypted + version: 3.8.1 diff --git a/secrets/secrets.yaml b/secrets/secrets.yaml index af3c283..31370f1 100644 --- a/secrets/secrets.yaml +++ b/secrets/secrets.yaml @@ -1,5 +1,7 @@ example_key: ENC[AES256_GCM,data:r6+IirxYwXxv1IaYgw==,iv:ngakIM2iaUMBgug9+QqQ2h6uPM9Xze/3PM2GRm79JV8=,tag:TwmNkg0WqSMqgh8VU238Xg==,type:str] foo: ENC[AES256_GCM,data:IlVV,iv:uK2Zkxo39WYw5Q9xnmVV/JhSRejQA9sGnYasX3CtSog=,tag:e1tYkCVVmyTpiCPAnQp6ng==,type:str] +akkotest: + vapid-private: ENC[AES256_GCM,data:3YpD,iv:AlFxKiU6v+ixU9eYBXcucBTnbpqfRN9dGiyoG8LWBDQ=,tag:FpzjnqbEbCoe9e27+AzZYw==,type:str] sops: kms: [] gcp_kms: [] @@ -9,25 +11,34 @@ sops: - recipient: age1acgqxvyczgsamz53z3v0gmahzfxlg9tscwnrgcxrfndgxhsvn3vs4ss5tk enc: | -----BEGIN AGE ENCRYPTED FILE----- - YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQL1YyalhGRXJnc1cxU0tx - NHRnWlBYYmZwV29aWUk1K0hhS3VRKzhEMTE4Ck9rTUQvQ0UvbllBMDEzenJEQURq - Sk9Lc1c5NHhYTG1LRGpZWVN3Qk16RGMKLS0tIFBhdEJUOEY4VVQ5UllGUXZWYVhy - OGJjR3NkQk1Ucyt5K3YraEZXdVFKODAK057dWbQGPrASAUqhaKmbsyt4DfjelZcI - 27Y9PpknTb+2W0DshjGzpcM6qZVlys98JRfM/0Hc5ZmYdj1rhfFR0Q== + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBna0xHODNSb0JDSDZ3WDhs + VTZpYUhhcG1tYlNMcWdMcG1mRDVob2t4V1RnCnZYQk9MTWlsWUh3VXBhUVJnK0dU + c3MwUzVSNE5tMUxyRzdoYzF3WFhXYmsKLS0tIHU3NjZ2YWUyZWRaYjhnSmQrMWpw + WjhrK0FXQitRL0xoMnhrcjV1S1JCTm8KQdLRej29Cz0+khG4BH19aSAroUHssoog + io99sSfbp4CyQDuS74f9wY2Lw6IkxAED7WJ3wic9+AiGje4lkYMSGg== -----END AGE ENCRYPTED FILE----- - lastmodified: "2024-01-21T18:39:47Z" - mac: ENC[AES256_GCM,data:7J5iBhY7b8nNrM4tviSk8+ur2ldAa8NNFU2ai7kjuU0puqq3oYX2l/pkjY7/rIue92HoQ8PVaLUnm2j73gCrCiZSJ5Cp4Tbue1mPfG7V+RA6OCOIS5MUsY5dBNtUSaDAoUohuwMTPAXwf7oE+OYENqTJGgWdFFR/IUgHF4uIPKY=,iv:f2uq6sLx7kW/EN2zZzl6RYUg8lQ4JNuhfQXsjTzDeCc=,tag:T2dn3EUISNZFaYm+eX6wDA==,type:str] + - recipient: age1xrzl49tvnatuu55xu5av6xcxyhrakd7mkzl5kz30kqqaxvh2m3sqax8jeu + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2V3Q1Sks0dkd5UjJSdkEy + RVZBVjdwK2I2RmJLV0N5VUYvbXBiNURoNHo4CjdPaUVZVGRna3lHckNaeW0reGhH + TWFKV05BZG1uY3pYK0FVdnVmSC9sYmMKLS0tIHp6VnI0dzNmZFA5Z2ZUcVpOS3JE + akR2TDhuMlZpME5CdEtXU3pnMko3OWsKKAPBenvI1PncIn4xKsTCfUZqMqJW9FMC + Vjal1esPEepo3pNuhe66ek4qKJgOJC8DYeR2WU1RpdPQtDCv97kdFg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2024-02-02T18:40:22Z" + mac: ENC[AES256_GCM,data:JzAG3PuD3yWrYZLBtXoYXy0fwr0hiUWtwBlu1gbQz5zKstNOjymL661St/Yo+pXGK7MlpSMg4E9tParQS28vVc4xRLSvzv1JHzwfC21jCGSWKFRjMbJl/XGp63S6n2aYOw+uPeVd5HGsWcNWutiABlAUwneF5VNBmal+c3KLuzs=,iv:9Xaq9CmpBXyYlrE5wKB0gBmzG9q4zwsAqLoBy/t+q0c=,tag:eZtfvMbUveaMYln1PDdMug==,type:str] pgp: - - created_at: "2024-01-21T18:06:27Z" + - created_at: "2024-02-02T18:51:08Z" enc: |- -----BEGIN PGP MESSAGE----- - hF4DrTkQq20WUVESAQdACf7D7i9i3JL3mhfBBYfj5+YgqsabixPitpX3vU1lsDQw - VHzfVAwc/dZZpbKQtOQq3qCV1Cq8UqbHJ/PDXiqgTMWUA6OAw+v82BxTsMR/c0r1 - 1GgBCQIQ3qRPn6jKLT9cCPiyayxqyv+r1meT9A4t1j8e5ul2P6tqUJALSeyvydHA - iPKyS7DlVQ7uI4HTO9pd7Kj+JhwckFaxgZNVMqWicsTf0tCMd6+iJ3366bmetNYv - osKqKz9/c4ZF/A== - =Hv+Y + hF4DrTkQq20WUVESAQdA/Hd4Aw+qyPYFMaBU5galOCTT+U6SWhVo5uSQ7ICWkkMw + ptkDbATrDtYEPW57RDdLGMzq1uvX3lYi2G4q8NM0LgUhin4gXwe1x2mvFHmx5ZZA + 1GgBCQIQ6nLOvPLFNb+EUaonzHxfi/KfW2Lq2k1snphyz4DOvY18A3KvHtZe1FFk + HnrOGHcbLEJiKdZ8MgppZjSI4Z7MLgBpPlqBqZLbpEP9kS7Jf57XfLCMUyYqeCL0 + uWljeHo6znN7xQ== + =ycR6 -----END PGP MESSAGE----- fp: D3067BE844D3FC49535A47B29396B8BA6FBB14DE unencrypted_suffix: _unencrypted