diff options
Diffstat (limited to 'hosts/surtr')
69 files changed, 2624 insertions, 668 deletions
diff --git a/hosts/surtr/audiobookshelf.nix b/hosts/surtr/audiobookshelf.nix new file mode 100644 index 00000000..728851a4 --- /dev/null +++ b/hosts/surtr/audiobookshelf.nix | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | { config, ... }: | ||
| 2 | |||
| 3 | { | ||
| 4 | config = { | ||
| 5 | security.acme.rfc2136Domains = { | ||
| 6 | "audiobookshelf.yggdrasil.li" = { | ||
| 7 | restartUnits = ["nginx.service"]; | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | services.nginx = { | ||
| 12 | upstreams."audiobookshelf" = { | ||
| 13 | servers = { | ||
| 14 | "[2a03:4000:52:ada:4:1::]:28982" = {}; | ||
| 15 | }; | ||
| 16 | extraConfig = '' | ||
| 17 | keepalive 8; | ||
| 18 | ''; | ||
| 19 | }; | ||
| 20 | virtualHosts = { | ||
| 21 | "audiobookshelf.yggdrasil.li" = { | ||
| 22 | kTLS = true; | ||
| 23 | http3 = true; | ||
| 24 | forceSSL = true; | ||
| 25 | sslCertificate = "/run/credentials/nginx.service/audiobookshelf.yggdrasil.li.pem"; | ||
| 26 | sslCertificateKey = "/run/credentials/nginx.service/audiobookshelf.yggdrasil.li.key.pem"; | ||
| 27 | sslTrustedCertificate = "/run/credentials/nginx.service/audiobookshelf.yggdrasil.li.chain.pem"; | ||
| 28 | extraConfig = '' | ||
| 29 | charset utf-8; | ||
| 30 | ''; | ||
| 31 | |||
| 32 | locations = { | ||
| 33 | "/".extraConfig = '' | ||
| 34 | proxy_pass http://audiobookshelf; | ||
| 35 | |||
| 36 | proxy_http_version 1.1; | ||
| 37 | proxy_set_header Upgrade $http_upgrade; | ||
| 38 | proxy_set_header Connection "upgrade"; | ||
| 39 | |||
| 40 | proxy_redirect off; | ||
| 41 | proxy_set_header Host $host; | ||
| 42 | proxy_set_header X-Real-IP $remote_addr; | ||
| 43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| 44 | proxy_set_header X-Forwarded-Host $server_name; | ||
| 45 | proxy_set_header X-Forwarded-Proto $scheme; | ||
| 46 | |||
| 47 | client_max_body_size 0; | ||
| 48 | proxy_request_buffering off; | ||
| 49 | proxy_buffering off; | ||
| 50 | ''; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | }; | ||
| 54 | }; | ||
| 55 | |||
| 56 | systemd.services.nginx = { | ||
| 57 | serviceConfig = { | ||
| 58 | LoadCredential = [ | ||
| 59 | "audiobookshelf.yggdrasil.li.key.pem:${config.security.acme.certs."audiobookshelf.yggdrasil.li".directory}/key.pem" | ||
| 60 | "audiobookshelf.yggdrasil.li.pem:${config.security.acme.certs."audiobookshelf.yggdrasil.li".directory}/fullchain.pem" | ||
| 61 | "audiobookshelf.yggdrasil.li.chain.pem:${config.security.acme.certs."audiobookshelf.yggdrasil.li".directory}/chain.pem" | ||
| 62 | ]; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | }; | ||
| 66 | } | ||
diff --git a/hosts/surtr/bifrost/default.nix b/hosts/surtr/bifrost/default.nix index fbfde757..52ab43f5 100644 --- a/hosts/surtr/bifrost/default.nix +++ b/hosts/surtr/bifrost/default.nix | |||
| @@ -18,7 +18,7 @@ in { | |||
| 18 | ListenPort = 51822; | 18 | ListenPort = 51822; |
| 19 | }; | 19 | }; |
| 20 | wireguardPeers = [ | 20 | wireguardPeers = [ |
| 21 | { AllowedIPs = [ "2a03:4000:52:ada:4:1::/96" ]; | 21 | { AllowedIPs = [ "2a03:4000:52:ada:4:1::/96" "2a03:4000:52:ada:6::/80" ]; |
| 22 | PublicKey = trim (readFile ../../vidhar/network/bifrost/vidhar.pub); | 22 | PublicKey = trim (readFile ../../vidhar/network/bifrost/vidhar.pub); |
| 23 | } | 23 | } |
| 24 | ]; | 24 | ]; |
| @@ -34,6 +34,8 @@ in { | |||
| 34 | routes = [ | 34 | routes = [ |
| 35 | { Destination = "2a03:4000:52:ada:4::/80"; | 35 | { Destination = "2a03:4000:52:ada:4::/80"; |
| 36 | } | 36 | } |
| 37 | { Destination = "2a03:4000:52:ada:6::/80"; | ||
| 38 | } | ||
| 37 | ]; | 39 | ]; |
| 38 | linkConfig = { | 40 | linkConfig = { |
| 39 | RequiredForOnline = false; | 41 | RequiredForOnline = false; |
diff --git a/hosts/surtr/changedetection-io.nix b/hosts/surtr/changedetection-io.nix new file mode 100644 index 00000000..bfdedee1 --- /dev/null +++ b/hosts/surtr/changedetection-io.nix | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | { config, ... }: | ||
| 2 | |||
| 3 | { | ||
| 4 | config = { | ||
| 5 | security.acme.rfc2136Domains = { | ||
| 6 | "changedetection.yggdrasil.li" = { | ||
| 7 | restartUnits = ["nginx.service"]; | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | services.nginx = { | ||
| 12 | upstreams."changedetection-io" = { | ||
| 13 | servers = { | ||
| 14 | "[2a03:4000:52:ada:4:1::]:5001" = {}; | ||
| 15 | }; | ||
| 16 | extraConfig = '' | ||
| 17 | keepalive 8; | ||
| 18 | ''; | ||
| 19 | }; | ||
| 20 | virtualHosts = { | ||
| 21 | "changedetection.yggdrasil.li" = { | ||
| 22 | kTLS = true; | ||
| 23 | http3 = true; | ||
| 24 | forceSSL = true; | ||
| 25 | sslCertificate = "/run/credentials/nginx.service/changedetection.yggdrasil.li.pem"; | ||
| 26 | sslCertificateKey = "/run/credentials/nginx.service/changedetection.yggdrasil.li.key.pem"; | ||
| 27 | sslTrustedCertificate = "/run/credentials/nginx.service/changedetection.yggdrasil.li.chain.pem"; | ||
| 28 | extraConfig = '' | ||
| 29 | charset utf-8; | ||
| 30 | ''; | ||
| 31 | |||
| 32 | locations = { | ||
| 33 | "/".extraConfig = '' | ||
| 34 | proxy_pass http://changedetection-io; | ||
| 35 | |||
| 36 | proxy_http_version 1.1; | ||
| 37 | proxy_set_header Upgrade $http_upgrade; | ||
| 38 | proxy_set_header Connection "upgrade"; | ||
| 39 | |||
| 40 | proxy_redirect off; | ||
| 41 | proxy_set_header Host $host; | ||
| 42 | proxy_set_header X-Real-IP $remote_addr; | ||
| 43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| 44 | proxy_set_header X-Forwarded-Host $server_name; | ||
| 45 | proxy_set_header X-Forwarded-Proto $scheme; | ||
| 46 | |||
| 47 | client_max_body_size 0; | ||
| 48 | proxy_request_buffering off; | ||
| 49 | proxy_buffering off; | ||
| 50 | ''; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | }; | ||
| 54 | }; | ||
| 55 | |||
| 56 | systemd.services.nginx = { | ||
| 57 | serviceConfig = { | ||
| 58 | LoadCredential = [ | ||
| 59 | "changedetection.yggdrasil.li.key.pem:${config.security.acme.certs."changedetection.yggdrasil.li".directory}/key.pem" | ||
| 60 | "changedetection.yggdrasil.li.pem:${config.security.acme.certs."changedetection.yggdrasil.li".directory}/fullchain.pem" | ||
| 61 | "changedetection.yggdrasil.li.chain.pem:${config.security.acme.certs."changedetection.yggdrasil.li".directory}/chain.pem" | ||
| 62 | ]; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | }; | ||
| 66 | } | ||
diff --git a/hosts/surtr/default.nix b/hosts/surtr/default.nix index 223e1f10..fb2d5b62 100644 --- a/hosts/surtr/default.nix +++ b/hosts/surtr/default.nix | |||
| @@ -4,9 +4,11 @@ with lib; | |||
| 4 | 4 | ||
| 5 | { | 5 | { |
| 6 | imports = with flake.nixosModules.systemProfiles; [ | 6 | imports = with flake.nixosModules.systemProfiles; [ |
| 7 | tmpfs-root qemu-guest openssh rebuild-machines zfs | 7 | tmpfs-root qemu-guest openssh rebuild-machines zfs zswap |
| 8 | ./zfs.nix ./dns ./tls ./http ./bifrost ./matrix ./postgresql | 8 | ./zfs.nix ./dns ./tls ./http ./bifrost ./matrix ./postgresql |
| 9 | ./prometheus ./email ./vpn ./borg.nix ./etebase | 9 | ./prometheus ./email ./vpn ./borg.nix ./etebase ./immich.nix |
| 10 | ./paperless.nix ./hledger.nix ./audiobookshelf.nix ./kimai.nix | ||
| 11 | ./changedetection-io.nix ./vikunja.nix | ||
| 10 | ]; | 12 | ]; |
| 11 | 13 | ||
| 12 | config = { | 14 | config = { |
| @@ -14,9 +16,6 @@ with lib; | |||
| 14 | system = "x86_64-linux"; | 16 | system = "x86_64-linux"; |
| 15 | }; | 17 | }; |
| 16 | 18 | ||
| 17 | networking.hostId = "a64cf4d7"; | ||
| 18 | environment.etc."machine-id".text = "a64cf4d793ab0a0ed3892ead609fc0bc"; | ||
| 19 | |||
| 20 | boot = { | 19 | boot = { |
| 21 | loader.grub = { | 20 | loader.grub = { |
| 22 | enable = true; | 21 | enable = true; |
| @@ -24,7 +23,6 @@ with lib; | |||
| 24 | device = "/dev/vda"; | 23 | device = "/dev/vda"; |
| 25 | }; | 24 | }; |
| 26 | 25 | ||
| 27 | |||
| 28 | tmp.useTmpfs = true; | 26 | tmp.useTmpfs = true; |
| 29 | 27 | ||
| 30 | zfs.devNodes = "/dev"; # /dev/vda2 does not show up in /dev/disk/by-id | 28 | zfs.devNodes = "/dev"; # /dev/vda2 does not show up in /dev/disk/by-id |
| @@ -38,6 +36,9 @@ with lib; | |||
| 38 | fsType = "vfat"; | 36 | fsType = "vfat"; |
| 39 | }; | 37 | }; |
| 40 | }; | 38 | }; |
| 39 | swapDevices = [ | ||
| 40 | { label = "swap"; } | ||
| 41 | ]; | ||
| 41 | 42 | ||
| 42 | networking = { | 43 | networking = { |
| 43 | hostName = "surtr"; | 44 | hostName = "surtr"; |
| @@ -153,20 +154,7 @@ with lib; | |||
| 153 | options = "--delete-older-than 30d"; | 154 | options = "--delete-older-than 30d"; |
| 154 | }; | 155 | }; |
| 155 | 156 | ||
| 156 | security.dhparams = { | 157 | services.dbus.implementation = "dbus"; |
| 157 | enable = true; | ||
| 158 | defaultBitSize = 4096; | ||
| 159 | params = { | ||
| 160 | nginx = {}; | ||
| 161 | coturn = {}; | ||
| 162 | }; | ||
| 163 | stateful = true; | ||
| 164 | }; | ||
| 165 | |||
| 166 | zramSwap = { | ||
| 167 | enable = true; | ||
| 168 | algorithm = "zstd"; | ||
| 169 | }; | ||
| 170 | 158 | ||
| 171 | systemd.sysusers.enable = false; | 159 | systemd.sysusers.enable = false; |
| 172 | system.etc.overlay.mutable = true; | 160 | system.etc.overlay.mutable = true; |
diff --git a/hosts/surtr/dns/Gupfile b/hosts/surtr/dns/Gupfile index ac96f620..70674cce 100644 --- a/hosts/surtr/dns/Gupfile +++ b/hosts/surtr/dns/Gupfile | |||
| @@ -1,2 +1,2 @@ | |||
| 1 | key.gup: | 1 | key.gup: |
| 2 | keys/*.yaml \ No newline at end of file | 2 | keys/* \ No newline at end of file |
diff --git a/hosts/surtr/dns/default.nix b/hosts/surtr/dns/default.nix index 53df798e..4bb7059a 100644 --- a/hosts/surtr/dns/default.nix +++ b/hosts/surtr/dns/default.nix | |||
| @@ -46,7 +46,12 @@ in { | |||
| 46 | 46 | ||
| 47 | systemd.services.knot = { | 47 | systemd.services.knot = { |
| 48 | unitConfig.RequiresMountsFor = [ "/var/lib/knot" ]; | 48 | unitConfig.RequiresMountsFor = [ "/var/lib/knot" ]; |
| 49 | serviceConfig.LoadCredential = map ({name, ...}: "${name}.yaml:${config.sops.secrets.${name}.path}") knotKeys; | 49 | serviceConfig = { |
| 50 | LoadCredential = map ({name, ...}: "${name}.yaml:${config.sops.secrets.${name}.path}") knotKeys; | ||
| 51 | BindPaths = let | ||
| 52 | dkimBindPath = domain: "/var/lib/rspamd/dkim/${domain}.txt:/var/lib/dkim/${domain}.txt"; | ||
| 53 | in map dkimBindPath ["yggdrasil.li" "141.li" "kleen.li" "praseodym.org" "kleen.consulting" "bouncy.email" "surtr.yggdrasil.li"]; | ||
| 54 | }; | ||
| 50 | }; | 55 | }; |
| 51 | 56 | ||
| 52 | services.knot = { | 57 | services.knot = { |
| @@ -157,7 +162,7 @@ in { | |||
| 157 | ${concatMapStringsSep "\n" mkZone [ | 162 | ${concatMapStringsSep "\n" mkZone [ |
| 158 | { domain = "yggdrasil.li"; | 163 | { domain = "yggdrasil.li"; |
| 159 | addACLs = { "yggdrasil.li" = ["ymir_acme_acl"]; }; | 164 | addACLs = { "yggdrasil.li" = ["ymir_acme_acl"]; }; |
| 160 | acmeDomains = ["surtr.yggdrasil.li" "yggdrasil.li" "etesync.yggdrasil.li" "app.etesync.yggdrasil.li"]; | 165 | acmeDomains = ["surtr.yggdrasil.li" "yggdrasil.li" "etesync.yggdrasil.li" "immich.yggdrasil.li" "app.etesync.yggdrasil.li" "paperless.yggdrasil.li" "hledger.yggdrasil.li" "audiobookshelf.yggdrasil.li" "kimai.yggdrasil.li" "changedetection.yggdrasil.li" "vikunja.yggdrasil.li" "online.yggdrasil.li" "pw.bouncy.email"]; |
| 161 | } | 166 | } |
| 162 | { domain = "nights.email"; | 167 | { domain = "nights.email"; |
| 163 | addACLs = { "nights.email" = ["ymir_acme_acl"]; }; | 168 | addACLs = { "nights.email" = ["ymir_acme_acl"]; }; |
| @@ -169,15 +174,9 @@ in { | |||
| 169 | { domain = "kleen.li"; | 174 | { domain = "kleen.li"; |
| 170 | addACLs = { "kleen.li" = ["ymir_acme_acl"]; }; | 175 | addACLs = { "kleen.li" = ["ymir_acme_acl"]; }; |
| 171 | } | 176 | } |
| 172 | { domain = "xmpp.li"; | ||
| 173 | addACLs = { "xmpp.li" = ["ymir_acme_acl"]; }; | ||
| 174 | } | ||
| 175 | { domain = "synapse.li"; | 177 | { domain = "synapse.li"; |
| 176 | acmeDomains = ["element.synapse.li" "turn.synapse.li" "synapse.li"]; | 178 | acmeDomains = ["element.synapse.li" "turn.synapse.li" "synapse.li"]; |
| 177 | } | 179 | } |
| 178 | { domain = "dirty-haskell.org"; | ||
| 179 | addACLs = { "dirty-haskell.org" = ["ymir_acme_acl"]; }; | ||
| 180 | } | ||
| 181 | { domain = "praseodym.org"; | 180 | { domain = "praseodym.org"; |
| 182 | addACLs = { "praseodym.org" = ["ymir_acme_acl"]; }; | 181 | addACLs = { "praseodym.org" = ["ymir_acme_acl"]; }; |
| 183 | } | 182 | } |
diff --git a/hosts/surtr/dns/key.gup b/hosts/surtr/dns/key.gup index 32d4f7d6..5b5058b3 100644 --- a/hosts/surtr/dns/key.gup +++ b/hosts/surtr/dns/key.gup | |||
| @@ -3,4 +3,4 @@ | |||
| 3 | keyName=${${2:t}%.yaml}_key | 3 | keyName=${${2:t}%.yaml}_key |
| 4 | 4 | ||
| 5 | keymgr -t ${keyName} > $1 | 5 | keymgr -t ${keyName} > $1 |
| 6 | sops -p '7ED22F4AA7BB55728B643DC5471B7D88E4EF66F8,30D3453B8CD02FE2A3E7C78C0FB536FB87AE8F51' --input-type=binary --output-type=binary -e -i $1 \ No newline at end of file | 6 | sops --input-type=binary --output-type=binary -e -i $1 |
diff --git a/hosts/surtr/dns/keys/audiobookshelf.yggdrasil.li_acme b/hosts/surtr/dns/keys/audiobookshelf.yggdrasil.li_acme new file mode 100644 index 00000000..e3af9966 --- /dev/null +++ b/hosts/surtr/dns/keys/audiobookshelf.yggdrasil.li_acme | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:5BLk/MZtQsLjpdKGiZjtOH1soIXB05MkEoPWyr5m27ho7H5udDjRZE0/OjvSlMzQNjFNJc+OwbeHwaJ8sPLCnXqoFHJXikAmi0gpdFC0uN0JGYCBT1EaK7j6yVHyiqFXo6xwVSCO/zP/fbjItiuqU+B4llGx5N2I4HQqRLFoW/35PZazkR15xI1zo8LeC8T+jm16apFQw2Ih/RqsJK7XlHqnXq9SzeA2qhgkCbJf6aJ6zDS7eQVFt7qHh2mVtV7Al++bZiIkJiNJ5SJO1ck18w2t9HwXBhfMFKXvfFW0I6kKur1qSJk=,iv:rxm5PwOzXDaK+nj2k3bUqlYbIFFA49ispyfamtQqU/A=,tag:7dOua39f+0JsLldLRLr1NQ==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwV1hIcWNNRVJXOG1xYlFK\nb1VxWG03dGVmS3dmQTltUTR0VmEzYjRFanlBCnE1M1BTZjNCQnpsNkU5ZlR5T3BR\nOHliWUV2bXMrK0w1K3JXbUE0dEhKdzgKLS0tIDdkUEZ4QUE0NUN2TXFYcklybjBS\nRVpxV2J6U1BnUng1dytWTGRkd0FrRGcKVaMCzcrX+BQqbmh95JEk3lRdfnv9uO8n\nwotKxp/+xX7GEF42BOzJ/mWcgyVjABlnWeVyaRxfpbCUrmNuFYO6XA==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkZmRFR0gwc1pjVVorK0t6\nVHU4U0xob09Dd2J5QUJXbndZdWp3cytpYWhRCnFnMlZ0cjNGdXN1RWEvQlVHSE1M\nMEdzSjlEb2NkaE1zMEJJOTlCMC9FVFEKLS0tIGJiTEJSRVZZbVUzZVFGeXQwYm1w\ndWVYQVdoVlJnRENTYzhnQm1BcWVRdW8K0ECfLVQBQuZWFFFjdHLcJBz+CDzsOOwh\nOA38qxHD4EWfXR1c3G8RDbow7nB2MGc1Zohc7qhtuTj2wL0qhVKWqA==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2025-05-09T17:07:16Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:K5I6YXQXCUPHFBNVlXIdLLKqiNPVZh95KoHni2m16SdAvTyBab79SZ5xNvotrtKXp0iISCogEgdMm+OWbxYywEiZ+sUsxgx6RE5nAXruZOiAwzuyUr88qgCHTBZnKzgaDZlbYOgWB+LCzr8s5JbcTD4G6/RaXYyqmx7igygubHA=,iv:Zbij4eoDqoP5XYhAsDGBGqlcP5ACQAY/QngTmrJYRzs=,tag:WYxhUEZwmXkQmnpyOuP2Bg==,type:str]", | ||
| 16 | "unencrypted_suffix": "_unencrypted", | ||
| 17 | "version": "3.10.2" | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/hosts/surtr/dns/keys/changedetection.yggdrasil.li_acme b/hosts/surtr/dns/keys/changedetection.yggdrasil.li_acme new file mode 100644 index 00000000..dcc7f85b --- /dev/null +++ b/hosts/surtr/dns/keys/changedetection.yggdrasil.li_acme | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:QWZAer8xKZvAGl3HxaIdsOT1n3os4EDyQoZOU3YzwDpPfweVRhhBfyAg7M6rMRj8K8ffkkRWatDmgyHV1R43GfNyb1sLjqdqPysYXxC8KlP22WlT+1xstQ2q1KYmeN6VEKF0q+QOMMPRvwQbSQ0eC4mXcE+WgQSTVywjab9hQuc8vin69RbFxbhepxYLXT1rzQpLlxFmUNZBcLpSqsHkSDa2B0d4j2kIvSl2BuUgb3QJwgyNS5pGbnfyVfmus7p5+/pVFCe5EwTVjwgpn/cpIB0mu1Bbt9r0EvCkYXI6wKcLDVbfdV7KsA==,iv:wjHpcClpybzCIi3JhxgXTd5nW9y223pJn2rBde/2cy8=,tag:etfnmj+HhIKeZMGjxE5jiw==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlWkk2Z0FUNlNoaFVaSFEr\nSE54eUpHaTNzTTdjaytJemtQUW1mWjJNUGhzCkU1OGlNb3pidVFKalVCZUhBODNi\nMjcxR0xLUDRwYkZ5V2I1Q3Z6Y2pmRWMKLS0tIGNzaGNiTEMvdEhBMDRZY2pDQzNu\nWkpkcVNYVjJZQS9QRHEyOUx6RVpQVjAKKGjVrfeovCIml2hExydC9Cd7PyungtpJ\nCdXfrvzP/OtoBSiEDQGC2VafwKkZ98dQqVRnfVApDoxdVQ8vIrxmKQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTbUNBV1NYZEtKaDlzUVBF\nU2IrZ3dSWS9keVE1ak9qWkppc1hOY3JpMjEwCmNUbVJJMFNObmptVGQ0K1ovanVm\nc1dzN0VRVThyVWxPWTFLbldPQnE3Z2sKLS0tIEdWRENRRFROSm5SQ04yTG1wZWJ2\nNDMxK1ArYmdiQWJZV0d2TElZcFZLNVEKtmVrSIOcP4Ek1WW85f2/dNVYQMz9XqZ3\n0J04kqvkHZuM8PiBDg2l2rSh0xhHz3xb1iBhAddLXEjeEfy6o9HKyg==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2025-12-08T12:46:12Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:waY6IDfabZ8B8069liXh7RXjgUTpOdr4U9VQK5xYRujAlI//Ea5lM2ODHJ7PrAkZsK0TGB9ezN8SA5QpxYZwOcpxg45jNbTALxZsZMEzrtCy4wSiBdiLvRoTXvwMZsnsaQEGk2ij2rEqNEOYYBFapBoIz2w5kbEZrrhVRHSkNME=,iv:tpU++qliONinepku/gdPJQ/h2NdyNw3GY+RV+6UM07U=,tag:yieMw3BOC134zAIqb1Fvjg==,type:str]", | ||
| 16 | "version": "3.11.0" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/dns/keys/hledger.yggdrasil.li_acme b/hosts/surtr/dns/keys/hledger.yggdrasil.li_acme new file mode 100644 index 00000000..b3f4cfb6 --- /dev/null +++ b/hosts/surtr/dns/keys/hledger.yggdrasil.li_acme | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:lCj8VYJL9z29FJ154XQtxKQLwwitCRGy4krJ6u8yw2FMzoHprEpFgm33+mFspxSKk/It2G8cfTGMZSeVkYJEHb66HNKHl0A2Fz3hwjpRjh1MZAw0wiZJlnS/LNqoGstQ2PJmTQTW3aJRMoT1GS7q/gSp/3rqySA5EOm0GgUiA3Vi7nGpkBenKDEbQbcIBXRdMOk66BCdiz5XGm/1VLQQLO9oVwY2KBnLaZSISohyGVhbIy7GT2ygoWHHxHn0c5CRVNvGNwesM1gO1NnTFrISLMWSrsDPaAtQ,iv:fa8LFjzqsf2ccfbEe5MOmerb7FzXb4xr24y1GWIMT1Q=,tag:7oQ54DKBb76Pbw1lmEHt+Q==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "kms": null, | ||
| 5 | "gcp_kms": null, | ||
| 6 | "azure_kv": null, | ||
| 7 | "hc_vault": null, | ||
| 8 | "age": [ | ||
| 9 | { | ||
| 10 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzcHJLRHh0VkpDNDU3cGZS\nMWFlVWpFemZ2RnpnSllDWU1EWGoyWUxyejNzClBGandzaFI5NXY1bG51Y3VxRk9r\nc29NbXBOaEZDblBuaVowemQydkxBdjgKLS0tICtVb2xkMmh4T0Q0cU4xQnBzZExI\namFRUnRYTWIyQ3RHNUVHWTFrUzhhK1UKqmATNmxlhkxM5PP1U6w7fSYVA8AgIRAt\nJ9WZrTffQfXMdw4RmjWcoVHFH39Fe4SteedxliCCcqjkjgSEB4Rgow==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | }, | ||
| 13 | { | ||
| 14 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 15 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjWlhpQWI4c0x0ZXRGYVE2\nR1dHZzZud0ZxQWsrREhJWUowWE1zem5FVFI0CkJBUnIwY1FGS3N2VnpuSkZjRllZ\ncVgyeVg4cTVjRitzL0RKb0ZQb3BsOEkKLS0tIGs3SDBkamVBNDhQUlh5dmVVZXJs\nM3VKdlFKc21GcFY0UUtiaHFvYWI4V0kKKuWYEncxe9NT2ZS3X3+l/gT4BQOrdCg8\nj2jGL+Yzy/356GO3PFTn2HHLam6KWDKaYB5TlK/zSohfUt5giQH2Lw==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 16 | } | ||
| 17 | ], | ||
| 18 | "lastmodified": "2025-02-19T17:13:51Z", | ||
| 19 | "mac": "ENC[AES256_GCM,data:XsBdMCBjB+YuBMZQrjJ5uZtaYKSqsdWVvm+IEoJflCKPIhPk2rBZ3nY8KngXFbq2fWgsYyTM83kb2trEGIEHUPuERt+mgfCI3bSlylriwgsDWihCjyBecNE+BbdXE0+YcNl8pIwBU4M+3f2StQMH22YamToLJ9i9kfKcBrirDuU=,iv:VTIdBVY3kVBMYWhYUmrP2vZ9rpH90DzF68y1aDf2EAs=,tag:YkL+nw6LNXAceZtx9vgf6A==,type:str]", | ||
| 20 | "pgp": null, | ||
| 21 | "unencrypted_suffix": "_unencrypted", | ||
| 22 | "version": "3.9.4" | ||
| 23 | } | ||
| 24 | } \ No newline at end of file | ||
diff --git a/hosts/surtr/dns/keys/immich.yggdrasil.li_acme b/hosts/surtr/dns/keys/immich.yggdrasil.li_acme new file mode 100644 index 00000000..c31234bd --- /dev/null +++ b/hosts/surtr/dns/keys/immich.yggdrasil.li_acme | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:1i27jx1E4nn8/iXEN90tnQve0MX0HcXyYZoQfga1djcESDARd7kX78jncqnSdEMJPIQCyq2zmvOwEiAwyofIjSBSW2teoxD1PybSZdyvKwOnwLqpVWxgw6LORUoN5c1y4+WmnQa1SJ0a1WJwZ3cFRa3LP5JPbZzmNCZWEg+yGwVHNMsmrBSrjLRFC1NPIfX69lWGZl5VIMw2/SoSMDcOsSURWIpVSEYe9LNrc4/cKQQC/rmpXBg9ekIa8xd7NQTcDZA42bDIBQxJzqkUNV3JeIrl0C+eQw==,iv:MEDhvUvy0PfcLGim06VXkiIGgkNgaQcYqGhJraaGC6M=,tag:43CdGFe5JXOsMCHrvgl+BA==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "kms": null, | ||
| 5 | "gcp_kms": null, | ||
| 6 | "azure_kv": null, | ||
| 7 | "hc_vault": null, | ||
| 8 | "age": [ | ||
| 9 | { | ||
| 10 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLOU5OL0xxVVE2dzVOYnhP\nMUlhYlpyZGZSamU4QkpObHJLS1NJdjdwcmtjCks0OElnaHZvb3BSNnYySnVPcEUx\nazdNVUpZZGRNOVNBVTVUNUdnaC9DM00KLS0tIHUxU2dHMCt4d3hJbXlSNzBKUk1W\na05uZVRwVlMrbEZ2WEkvUy9PUVhmWXcKemRLnCC2mAkCEbZ3bC+iZmIWQCQsI+ew\ni4mmc/mUkGx8/61SR571NXIKmxSx2U5L2IK1pIKy6G/xMkPq+wDgUQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | }, | ||
| 13 | { | ||
| 14 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 15 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5VnNUV2lRR292ZmpNeU51\nQ2YxcnVnd21ybGdpd0I1QlJuSEQwNGZYTDJrCml0YUdxaWJHTEFNYWVIY01jWGk2\nZEJSQ0VZcVV1bU9VZ3dBbUh3a0N1ekUKLS0tIFhvNnRqcnRUZFNYOVhuWkFrZ3Vk\nMjU0YnNDODJRYk9lVENLUU9KU2dkWm8KHqtuNtC39S4oiQFRhNT2OOUOY9KQvDYW\nvtcdR8MSZDE7jsqgLgGS/8lIc0GBbIwYWghgFsLmn2Bkdh2q/VuO9w==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 16 | } | ||
| 17 | ], | ||
| 18 | "lastmodified": "2025-01-03T15:31:39Z", | ||
| 19 | "mac": "ENC[AES256_GCM,data:NKUbtcQf2DfALfm9kwiirmwD3slfTh4HNIg8BT/xbySHfwsaFtmlZTkhavBNr+b5snR8opATVXnJPAoykxXq8q4G1yDeitnTw6x9KfwgyZKpbJANMTBZEwK+CnZbqYRas1bFC88+D0yWI1yUnle+NPQ8VUj+KxCiUNuWO80mWhE=,iv:2a7CawUQujcZuR1pmsm9L2KGKcrBRAOxiIWEKCkTCEM=,tag:j8caxyN2fvx2FnWXHkWKcw==,type:str]", | ||
| 20 | "pgp": null, | ||
| 21 | "unencrypted_suffix": "_unencrypted", | ||
| 22 | "version": "3.9.2" | ||
| 23 | } | ||
| 24 | } \ No newline at end of file | ||
diff --git a/hosts/surtr/dns/keys/kimai.yggdrasil.li_acme b/hosts/surtr/dns/keys/kimai.yggdrasil.li_acme new file mode 100644 index 00000000..bdfb135a --- /dev/null +++ b/hosts/surtr/dns/keys/kimai.yggdrasil.li_acme | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:sKFt4pH0Xn7Qm6JFMg/2N7Ht7jtMJukfN+U3dQaoYXPbhRJ+heEtDpXV/WP4AlfbfpIOgTPW3mcmQCwKFNhS00vEsQA4728FfXZzDDmZCa3hwg51wDbL7XUOr0OePgzi86lt0Q193K6CkGqEAa1vFIb//ElEfBYIwdATbmcoAsM3mHhz58X7c1qf8LNuB93o/1N2xXXZI3NWOhOjlviTc2DAhffXDwlMJSYUhldnwtDKmLM1mooJzLgm2p9w7gRD7WPqEqZFq9uFDK69P9uX5T9hFHg=,iv:rAE4sYxxLou4tyD4RWTp3LjQP0cya95coy1MvwfEK/U=,tag:u4SSk8SZFlj0ks7d6tDocw==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2KzdNUWhEcDB6QmtUTnVh\nNS9Nc2I4UjAzekxhRXo1UmY3SklPejV1TURJCm9NY2lVOERoMDFKTU56Mmh1NHEr\naGV4M1RoVldHV0xyc3Z0MnVqakpjMFUKLS0tIEYxSk9OUm9kMkdtcG5POWRGQVkx\nY1FEaXYwMGo0L0Z0aTVTZDA5aUFDWEUKJ+e/7lR/rNPNVnIy+wkiKiAYMxWp4L7q\nwnSTx451vSnxv9j3JWB43Y7XQC08cisWDj06ULw8FnEbKYOvTYj9mQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwOTU3dUEzaXM5T1VkbDRO\nMm14OG1mUkk2bDRhdnBsMHBkc3kvUzlyNlQwCktFSHJhMnhoQ2J6bC9vUHNLWTRC\nRFpYeHo3N2xjWUhjQnRwQ2Nrc1pRUmsKLS0tIDdPeFBVdkxDd1JWSmcxQ0tLMTBD\ncHU3VExZOUhYUlJvbGNoK3FMK2VIbGMKFk94P9aBY04CPIi983f3Aalgh4fnU+/K\n2mxawSMf9jz8704N5XJfmr2hwNy8hqLIn8bjsEMAPTfE1YBGga4w0g==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2025-05-24T09:42:23Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:diCeJGvBmM0Ng722eKoFwDe7pqZrdLPSLn5j9LfdaFI64BAbSbA5bAq4NFXqdJ1vttarD2A5rEafYoXUxP8228x2GhNyWUGW5AWgBjVPUc59gjs4wYKR5HlkVMIadhTwNheEyoEjrxX40GNBgCG7X3ocOtOYKbKECp433gdAPDg=,iv:d+yJMWj2RyFnveo2ZNrpNeV+amXM+H7vdC0A2F7mwjA=,tag:yjibG2iusdprp0ORghYWhw==,type:str]", | ||
| 16 | "unencrypted_suffix": "_unencrypted", | ||
| 17 | "version": "3.10.2" | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/hosts/surtr/dns/keys/online.yggdrasil.li_acme b/hosts/surtr/dns/keys/online.yggdrasil.li_acme new file mode 100644 index 00000000..9c166f38 --- /dev/null +++ b/hosts/surtr/dns/keys/online.yggdrasil.li_acme | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:Ic4cQrF3bU55P8q4lFDL0fe0NJyoJ2K8VN1U7Lgq/y9+W2PcaGM0AjuPGP3K5SOMyVU6xUiN5T9vfRA+c7ztRBmEZYWu5/p7l9tajqMyCozzZ5ctYGEFAk5bwfuXf9Y4cGP+vh6dA6ktbewN8HzajQwHAd5ADcICzwXVD4CATcTPOgaUG9pDZZRqmRnfDzC22j6nKQQN494+5xj8cRFnx96LYN0nZUyVO5F5XxaWV+SkT0tJBhHuGNF85r/k3pVXmqRYgaQl6y4LNkzOSXGCy5jtu8QrPg==,iv:uQkkw/9KK4JHHcSgfnyV/VaW/dzqNhsz4eVOc4NimGU=,tag:/Xi7TzBBM7j2SEqV1Ah4yQ==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBVFJ5K28xSjd0VGJvWldV\nRGxqUVQ5RDI5bi9kbXYyZXo0WG42N3BmdlY0CnU1TkpZT1V1Z1VMMUp4cFZnZGJh\nTTYvd3ZMVjd1Z3YrbDBQdnpQcGdtKzAKLS0tIHEzN2laV0JzTHhlbjNKb1ZuL1Bl\nOFpuQkQxaHhLdTlhSSs1aTZhTGlZVFEKAHrcAKrtdCfQKfhaDpQKQVPpMqZCEunT\nvuvRdxMvA5T4mX3vHEJ5WKXQ8C49krfMYT9QoSy5v2OeazTOPW/XMA==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiSTRTZGhNamxTSlg2VERI\ndnBtWFlZV2hzOTgyZmFldG9xU2dJalhTaERZCms0NVlJWWVqdjdNMkNFQXRRa0o3\nZHRvTE9BK3lWbHZTWkJ1SXE0NmlJR0kKLS0tIC9BclpLNlFrb0kxRlRibWVOSWdL\nRFUvd0N6ZFpnd25yME1WSXo3Mit6Yk0Kqpyx2tzblU0hLMaLQpuGaMDzC7ZlgIFU\n3szVfhlLHuLfqDzpxTshPrPOQs+q7RvUJ+I1NeztlpGw239/+c4U5Q==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2026-05-15T11:50:25Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:fPcwi5HyrkY6HM90O3c9curi87X8MIWtNKF9lxQvFxPCMRVewDPteBvMgjCKDSM7RTGJVdDWnCyKTH6PXJwxGCuvOSv1CqSKreVPnNvilRETE+NLjwyQsAkgdZFDMofOvk1FhjI8gZ2aJg0yDwBvZMtaF694DhR4QVldXY2q8DA=,iv:Rs6KxSJwOSFrr7CEIs/9DED34tXbrCWfSn69KjiKSAE=,tag:tmKwx1y6LftEQBZWSs8qFQ==,type:str]", | ||
| 16 | "version": "3.12.2" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/dns/keys/paperless.yggdrasil.li_acme b/hosts/surtr/dns/keys/paperless.yggdrasil.li_acme new file mode 100644 index 00000000..bc4640db --- /dev/null +++ b/hosts/surtr/dns/keys/paperless.yggdrasil.li_acme | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:wOl8KLHD0H+btq0A3UreyVF9bOXZsiTwWJkVH8GubyIQDyiDC8vQm+dfv0rz8TwcBWYpC4aMIPPflG2HsdYO4rKGQ/nBmWmxhNXjpnyRo8iKM1BGb5bxNe4eVcUVhI60NuRJDRLmtDp+0rYGT/MVYp0/mHBINsQCXWBPDoaN2PI2GSnRag/x0wcL27xgH6NDd8glcdCN5nCAPDvazA3LialkXXv7/cceA5Q/Ee6HGzPP0w212/UvBm07Z5tXnHiy5cTbAGTUBfIqC8n501jtaQhpMh/yzA1R8KwUrw==,iv:bLzsthCaanNikNS2Es4J1++E5lijEbjyW5hU4zzNBcg=,tag:eWfZ3AtcSAGv8jWXzqlAwQ==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "kms": null, | ||
| 5 | "gcp_kms": null, | ||
| 6 | "azure_kv": null, | ||
| 7 | "hc_vault": null, | ||
| 8 | "age": [ | ||
| 9 | { | ||
| 10 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNYWZKOHd2UmxWYVlIamk4\nZ04zQnAwcDdsSDBDWUZnekNva3BzRERyWXljCmNvUU1Fczc2aUN6VGl6NEJ6MGIx\nWHVpeVluWnRnbjNadGxkSmYyNE1rZzQKLS0tIGpkYVZQRDJGS21ZZHdlRk1MMm02\nQ09aanNXSWltNi9QeUNtUVQ2UEZybmMK6/qcNYLMcyKTmtROX+ZsRqDxMXwkXiAV\ndsdsWJ5+zSJuK5SEIh0fqEZ/t4pxnMcr1WieETgLSd+w0sNQS7EKPQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | }, | ||
| 13 | { | ||
| 14 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 15 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByRjdJOHdjamRHVjlZOTNV\nbTBuam5vNERIWTB6T0JkR2pLUnlQN1BGbUJNClhrZ2hPRWZtT3BERFNwdmNEMmVu\nT0dxcjNkNGIvMVJQWENoUmRhTGd6SXcKLS0tIDV6WDd1bks4K1VuVkgybjdMd0w0\nMHBsT3FmOWU0WnJsM2diQm1sTU1ON2MKtf5HZ0S1cLMx98vDKRKamS7aHIJZ0OnA\nzH4VoeVm+PKsOeqVfY+gMHLdaMEWLKYsz3B8bxIoL5pvnCdT1QAN2A==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 16 | } | ||
| 17 | ], | ||
| 18 | "lastmodified": "2025-02-13T19:23:42Z", | ||
| 19 | "mac": "ENC[AES256_GCM,data:o7zNTjkohzAouYpJUGqf8DUfYf4/g3GZgc+4cf+PjI0OF8uc1WDCPvliBFe6pf/8QMhV5DFWd2SfszWnpnQhtiIVG/2BEk5sw3P6r/SUbSErakFYHueVQKp+9rdxK6uKcHUYhO46E332AwIxTuvNeHtSBMxx0kAwQPuuD/u3L4A=,iv:aiM0sGyGMk5lfBOpB2bDFCY+UfWwyUNixieww6eOSLs=,tag:MI7xJ7RsyZgQfF1SBVVmcQ==,type:str]", | ||
| 20 | "pgp": null, | ||
| 21 | "unencrypted_suffix": "_unencrypted", | ||
| 22 | "version": "3.9.4" | ||
| 23 | } | ||
| 24 | } \ No newline at end of file | ||
diff --git a/hosts/surtr/dns/keys/pw.bouncy.email_acme b/hosts/surtr/dns/keys/pw.bouncy.email_acme new file mode 100644 index 00000000..68e01632 --- /dev/null +++ b/hosts/surtr/dns/keys/pw.bouncy.email_acme | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:+IqTJv5QETPts+voCd9wD0FjPWRL9llgavSm813UBmdThx8xIvqYx782vjsAR7tkbhUJAvD2XD5YEO32oJ7z0+qrotOHUE0uB0CmY6TTU1UmURwssQmbDCDrHyVhTHd341cLjCXJ7baWOwd3MSw39yGjOeKCo/JdqXW+2JQWiSJjinZo6TgXG7eY2LQdqSVdQVizPBtYWyxpREps9RH7/yJn1FGp7XrG1YvzYCUyWgAKGj9r8v7c9GLcvBP2hx4zYoD3fAP0SKWYKf2t9/M=,iv:CfPWjBxTTiYLneHvNfjadZyip0NHZObnbKqSLTeWuLo=,tag:ZqSjmTdI2hJ+zdgbTkgYAw==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvUi9EZzlnTU1WemR0dVpp\nTlpxZi9FcTB1UWd0UG41UExvWnZRZWhiaFZVCjc3M2VnUmJrY1l0aXhGUGZtZ1ho\nMVB6bUNCRTVjMjE0UlFIM1NlRy9VTzgKLS0tIGdzT1czUnNnMjlwQXBXZHU4Mzhy\nSHJGVy9mZVZHZWFtYk4zZ2pHWEdLYmsKuNt8C+avCnHtxpVTbzaZS2rbnE+rvqec\n1wY88lWTU+nf3Ek97JOuQeeKhtERiQ6LsrMx2gzCGIbRUdI/cIGLCg==\n-----END AGE ENCRYPTED FILE-----\n", | ||
| 7 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyU3I1cXBkQUl3dW0zbENF\nK2lLcUhLVFk2ZWZ3VWl5SDVCeFJBNGNZNVJ3CkpLKzFPWFB3Y0hpN1VybkJyL29I\nem03bjF3Qk1xdTl3YnJZQUV1c2xjSXcKLS0tIDlYT0FMNXo2Qmd2Q2xkM0Zwd3Jj\naTNDcnNXODJ2bHJpOWxqWm1qWGJ2aFEKjIAE/9N3+6AAnX4E3qOWBG+gwCF1Wn+F\ncyoBEkYIwXyMmbNgoWA2Z/nZkiqm4ANUwnGioGabiMkL/hBqGTajtQ==\n-----END AGE ENCRYPTED FILE-----\n", | ||
| 11 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2026-06-06T13:54:42Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:rLOlH1N92+yzfIRSPg7GSo8SxYtjGcDbGc80nh3N6xZr7G3Fk3/EUVNfMk6YHjf8aFnCf2Odaht3hWQ2dsb5RrwAIQEyCD5/S/xdlEnJFfh6zGEFg79utL+HUB/hmYynnmuXPkDLCeRqKgbUQ2flHYZUqHkScyzqQkyFnKfzTas=,iv:bw1AoNNxlYN4Xk2bWHRB9e9gv1CiKdvFOTYX588DNP0=,tag:kfNW3HUBJSDh5vBZ6iGicQ==,type:str]", | ||
| 16 | "version": "3.13.1" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/dns/keys/vikunja.yggdrasil.li_acme b/hosts/surtr/dns/keys/vikunja.yggdrasil.li_acme new file mode 100644 index 00000000..69956047 --- /dev/null +++ b/hosts/surtr/dns/keys/vikunja.yggdrasil.li_acme | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:dchG/V5uJVuj1P35Zj9YHwAEqwHeiqGS9zPt+M9V9E3uelugJN2rTe/pnnUzw6piIsdfwmJA4qaNddGbw6Tx9bQbuJxm9wbAm+M+lYokQ1fonQIlm+tZ1dEeBQO00lXidIxbdMcAaKDyGvceexoYOMwg1UYCBl+osu5bCFjxrekYARITec2mPAU2wjjkJ91rsFvp5dvngGfwSu1Yks3ZhdbIUeJx85FjRsi0Wn5m91R8MYE8GFf5OdAbTolsW9TpHbjpVCzuLVXVqaX3Y5PR+OkSND+gta8B,iv:QjRPkiQ1vGNumjBS9r9KIxUWzapsDG8qU7RzUnd9msI=,tag:8y26IM2TJfFl6Nh4mIqLtQ==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQbmp1MmRtemNNQmtZSGN0\nZXhURWNYbkg0QS9iL1B5cndQdGthdVJPTFhzCjZ6M2JQWWhFNFFWYkIvOUY4WmUx\nblo5QkF5SldlWGhnTnQxdzBpM1Nad1UKLS0tIEE4Q3dEV081UlA4N3RMZ0szUHcv\nUm1qN09wYndHNCtFR2NWUVZWUnNRTlUKM8wfNY8Vq6Jn3Yc9n5qpYOqrHyATF0F3\nq2ZpnuDJpyUamfCTeJX2jBmTlYAw90ykmhY1IRqyW52sEY+D376pKw==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhY3hDZEZ2OTg5SkxoeTVk\nbjU1amlTZndxeStxZnVnTWxHOXpqUUhpREE4CitZdVNYcGIyMFo2RTVSUzVobmZX\ncmJDSzRSTWxaME1Qb05WZWM4eHV4Z0kKLS0tIGtMM3FhdkxqTzdFYUVkNHZ3cERt\nV21pcndweHZ5cnNkako5NkJiQ3dFZWMKY3LgLjExrq+nrirJ9PRjkPVJ1YyUjB4y\nfsz/1TPciefIWoqeCsRp+iWWwyb88Dpuv4qTqgrzncHOpw2gEmNurw==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2026-01-01T14:25:23Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:4ohI9Bb16Si871wcBYfINkKDhpQs6AOE8KWlmCoKsGK1pawyKNdeXTfeB/171eT/6XRklLY3e9lTobuh2sYvVDhSzrzqlDfo4Rhq/M3/fsgvyRJItKeTrfnD4LxSX4D+H7N5t9gP1Tjt1cdEDL6GgzbIksMnpdL9K1f6vgludcI=,iv:a3v5bWHhXD5XV2Hwe3AJB5YG/8mznn/ukZOHbJO5AW8=,tag:7vYNT9omLnnyxwVUYVBfSA==,type:str]", | ||
| 16 | "version": "3.11.0" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/dns/zones/consulting.kleen.soa b/hosts/surtr/dns/zones/consulting.kleen.soa index 9aecf908..99a88c7b 100644 --- a/hosts/surtr/dns/zones/consulting.kleen.soa +++ b/hosts/surtr/dns/zones/consulting.kleen.soa | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | $ORIGIN kleen.consulting. | 1 | $ORIGIN kleen.consulting. |
| 2 | $TTL 3600 | 2 | $TTL 3600 |
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( |
| 4 | 2023020100 ; serial | 4 | 2026032100 ; serial |
| 5 | 10800 ; refresh | 5 | 10800 ; refresh |
| 6 | 3600 ; retry | 6 | 3600 ; retry |
| 7 | 604800 ; expire | 7 | 604800 ; expire |
| @@ -21,7 +21,7 @@ $TTL 3600 | |||
| 21 | @ IN MX 0 mailin.kleen.consulting. | 21 | @ IN MX 0 mailin.kleen.consulting. |
| 22 | @ IN TXT "v=spf1 a:mailout.kleen.consulting -all" | 22 | @ IN TXT "v=spf1 a:mailout.kleen.consulting -all" |
| 23 | 23 | ||
| 24 | surtr._domainkey IN CNAME surtr._domainkey.yggdrasil.li. | 24 | $INCLUDE /var/lib/dkim/kleen.consulting.txt |
| 25 | _dmarc IN TXT "v=DMARC1;p=reject;sp=reject;pct=100;adkim=s;aspf=s;rua=mailto:postmaster@kleen.consulting;ruf=mailto:postmaster@kleen.consulting" | 25 | _dmarc IN TXT "v=DMARC1;p=reject;sp=reject;pct=100;adkim=s;aspf=s;rua=mailto:postmaster@kleen.consulting;ruf=mailto:postmaster@kleen.consulting" |
| 26 | 26 | ||
| 27 | _acme-challenge IN NS ns.yggdrasil.li. | 27 | _acme-challenge IN NS ns.yggdrasil.li. |
diff --git a/hosts/surtr/dns/zones/email.bouncy.soa b/hosts/surtr/dns/zones/email.bouncy.soa index 2b319a93..074f3ba2 100644 --- a/hosts/surtr/dns/zones/email.bouncy.soa +++ b/hosts/surtr/dns/zones/email.bouncy.soa | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | $ORIGIN bouncy.email. | 1 | $ORIGIN bouncy.email. |
| 2 | $TTL 3600 | 2 | $TTL 3600 |
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( |
| 4 | 2024070901 ; serial | 4 | 2026060600 ; serial |
| 5 | 10800 ; refresh | 5 | 10800 ; refresh |
| 6 | 3600 ; retry | 6 | 3600 ; retry |
| 7 | 604800 ; expire | 7 | 604800 ; expire |
| @@ -20,7 +20,7 @@ $TTL 3600 | |||
| 20 | @ IN MX 0 mailin.bouncy.email. | 20 | @ IN MX 0 mailin.bouncy.email. |
| 21 | @ IN TXT "v=spf1 a:mailout.bouncy.email -all" | 21 | @ IN TXT "v=spf1 a:mailout.bouncy.email -all" |
| 22 | 22 | ||
| 23 | surtr._domainkey IN CNAME surtr._domainkey.yggdrasil.li. | 23 | $INCLUDE /var/lib/dkim/bouncy.email.txt |
| 24 | _dmarc IN TXT "v=DMARC1;p=reject;sp=reject;pct=100;adkim=s;aspf=s;rua=mailto:postmaster@bouncy.email;ruf=mailto:postmaster@bouncy.email" | 24 | _dmarc IN TXT "v=DMARC1;p=reject;sp=reject;pct=100;adkim=s;aspf=s;rua=mailto:postmaster@bouncy.email;ruf=mailto:postmaster@bouncy.email" |
| 25 | 25 | ||
| 26 | _acme-challenge IN NS ns.yggdrasil.li. | 26 | _acme-challenge IN NS ns.yggdrasil.li. |
| @@ -71,6 +71,14 @@ _acme-challenge.spm IN NS ns.yggdrasil.li. | |||
| 71 | 71 | ||
| 72 | spm IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | 72 | spm IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" |
| 73 | 73 | ||
| 74 | pw IN A 202.61.241.61 | ||
| 75 | pw IN AAAA 2a03:4000:52:ada:: | ||
| 76 | pw IN MX 0 mailin.bouncy.email. | ||
| 77 | pw IN TXT "v=spf1 redirect=bouncy.email" | ||
| 78 | _acme-challenge.pw IN NS ns.yggdrasil.li. | ||
| 79 | |||
| 80 | pw IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | ||
| 81 | |||
| 74 | _mta-sts IN TXT "v=STSv1; id=2022100600" | 82 | _mta-sts IN TXT "v=STSv1; id=2022100600" |
| 75 | _smtp._tls IN TXT "v=TLSRPTv1; rua=mailto:postmaster@bouncy.email" | 83 | _smtp._tls IN TXT "v=TLSRPTv1; rua=mailto:postmaster@bouncy.email" |
| 76 | mta-sts IN A 202.61.241.61 | 84 | mta-sts IN A 202.61.241.61 |
diff --git a/hosts/surtr/dns/zones/email.nights.soa b/hosts/surtr/dns/zones/email.nights.soa index 913a88d4..34209a99 100644 --- a/hosts/surtr/dns/zones/email.nights.soa +++ b/hosts/surtr/dns/zones/email.nights.soa | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | $ORIGIN nights.email. | 1 | $ORIGIN nights.email. |
| 2 | $TTL 3600 | 2 | $TTL 3600 |
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( |
| 4 | 2023013000 ; serial | 4 | 2025060700 ; serial |
| 5 | 10800 ; refresh | 5 | 10800 ; refresh |
| 6 | 3600 ; retry | 6 | 3600 ; retry |
| 7 | 604800 ; expire | 7 | 604800 ; expire |
| @@ -27,11 +27,7 @@ $TTL 3600 | |||
| 27 | 27 | ||
| 28 | _acme-challenge IN NS ns.yggdrasil.li. | 28 | _acme-challenge IN NS ns.yggdrasil.li. |
| 29 | 29 | ||
| 30 | ymir._domainkey IN TXT ( | 30 | ymir._domainkey IN CNAME ymir._domainkey.yggdrasil.li. |
| 31 | "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" | ||
| 32 | "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24" | ||
| 33 | "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ==" | ||
| 34 | ) | ||
| 35 | 31 | ||
| 36 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. | 32 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. |
| 37 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. | 33 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. |
diff --git a/hosts/surtr/dns/zones/li.141.soa b/hosts/surtr/dns/zones/li.141.soa index d42b4719..bf650a27 100644 --- a/hosts/surtr/dns/zones/li.141.soa +++ b/hosts/surtr/dns/zones/li.141.soa | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | $ORIGIN 141.li. | 1 | $ORIGIN 141.li. |
| 2 | $TTL 3600 | 2 | $TTL 3600 |
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( |
| 4 | 2024102100 ; serial | 4 | 2026032101 ; serial |
| 5 | 10800 ; refresh | 5 | 10800 ; refresh |
| 6 | 3600 ; retry | 6 | 3600 ; retry |
| 7 | 604800 ; expire | 7 | 604800 ; expire |
| @@ -45,11 +45,8 @@ ymir IN AAAA 2a03:4000:6:d004:: | |||
| 45 | ymir IN MX 0 ymir.yggdrasil.li | 45 | ymir IN MX 0 ymir.yggdrasil.li |
| 46 | ymir IN TXT "v=spf1 redirect=ymir.yggdrasil.li" | 46 | ymir IN TXT "v=spf1 redirect=ymir.yggdrasil.li" |
| 47 | 47 | ||
| 48 | ymir._domainkey IN TXT ( | 48 | ymir._domainkey IN CNAME ymir._domainkey.yggdrasil.li. |
| 49 | "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" | 49 | $INCLUDE /var/lib/dkim/141.li.txt |
| 50 | "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24" | ||
| 51 | "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ==" | ||
| 52 | ) | ||
| 53 | 50 | ||
| 54 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. | 51 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. |
| 55 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. | 52 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. |
| @@ -59,5 +56,3 @@ _infinoted._tcp IN SRV 5 0 6523 ymir.yggdrasil.li. | |||
| 59 | _submission._tcp IN SRV 5 0 25 ymir.yggdrasil.li. | 56 | _submission._tcp IN SRV 5 0 25 ymir.yggdrasil.li. |
| 60 | _imap._tcp IN SRV 5 0 143 ymir.yggdrasil.li. | 57 | _imap._tcp IN SRV 5 0 143 ymir.yggdrasil.li. |
| 61 | _imaps._tcp IN SRV 5 0 993 ymir.yggdrasil.li. | 58 | _imaps._tcp IN SRV 5 0 993 ymir.yggdrasil.li. |
| 62 | |||
| 63 | _factorio._udp IN SRV 5 0 34197 game01.yggdrasil.li. | ||
diff --git a/hosts/surtr/dns/zones/li.kleen.soa b/hosts/surtr/dns/zones/li.kleen.soa index a1c7d35a..cfaaa1f1 100644 --- a/hosts/surtr/dns/zones/li.kleen.soa +++ b/hosts/surtr/dns/zones/li.kleen.soa | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | $ORIGIN kleen.li. | 1 | $ORIGIN kleen.li. |
| 2 | $TTL 3600 | 2 | $TTL 3600 |
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( |
| 4 | 2023013000 ; serial | 4 | 2026032101 ; serial |
| 5 | 10800 ; refresh | 5 | 10800 ; refresh |
| 6 | 3600 ; retry | 6 | 3600 ; retry |
| 7 | 604800 ; expire | 7 | 604800 ; expire |
| @@ -27,11 +27,8 @@ $TTL 3600 | |||
| 27 | 27 | ||
| 28 | _acme-challenge IN NS ns.yggdrasil.li. | 28 | _acme-challenge IN NS ns.yggdrasil.li. |
| 29 | 29 | ||
| 30 | ymir._domainkey IN TXT ( | 30 | ymir._domainkey IN CNAME ymir._domainkey.yggdrasil.li. |
| 31 | "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" | 31 | $INCLUDE /var/lib/dkim/kleen.li.txt |
| 32 | "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24" | ||
| 33 | "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ==" | ||
| 34 | ) | ||
| 35 | 32 | ||
| 36 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. | 33 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. |
| 37 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. | 34 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. |
diff --git a/hosts/surtr/dns/zones/li.synapse.soa b/hosts/surtr/dns/zones/li.synapse.soa index 086d4a85..247cf025 100644 --- a/hosts/surtr/dns/zones/li.synapse.soa +++ b/hosts/surtr/dns/zones/li.synapse.soa | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | $ORIGIN synapse.li. | 1 | $ORIGIN synapse.li. |
| 2 | $TTL 3600 | 2 | $TTL 3600 |
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( |
| 4 | 2023092100 ; serial | 4 | 2025060701 ; serial |
| 5 | 10800 ; refresh | 5 | 10800 ; refresh |
| 6 | 3600 ; retry | 6 | 3600 ; retry |
| 7 | 604800 ; expire | 7 | 604800 ; expire |
diff --git a/hosts/surtr/dns/zones/li.xmpp.soa b/hosts/surtr/dns/zones/li.xmpp.soa deleted file mode 100644 index a9e98fb4..00000000 --- a/hosts/surtr/dns/zones/li.xmpp.soa +++ /dev/null | |||
| @@ -1,43 +0,0 @@ | |||
| 1 | $ORIGIN xmpp.li. | ||
| 2 | $TTL 3600 | ||
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | ||
| 4 | 2023013000 ; serial | ||
| 5 | 10800 ; refresh | ||
| 6 | 3600 ; retry | ||
| 7 | 604800 ; expire | ||
| 8 | 3600 ; min TTL | ||
| 9 | ) | ||
| 10 | IN NS ns.yggdrasil.li. | ||
| 11 | IN NS ns.inwx.de. | ||
| 12 | IN NS ns2.inwx.de. | ||
| 13 | IN NS ns3.inwx.eu. | ||
| 14 | |||
| 15 | @ IN CAA 128 issue "letsencrypt.org; validationmethods=dns-01" | ||
| 16 | @ IN CAA 128 iodef "mailto:caa@yggdrasil.li" | ||
| 17 | |||
| 18 | @ IN A 188.68.51.254 | ||
| 19 | @ IN AAAA 2a03:4000:6:d004:: | ||
| 20 | @ IN MX 0 ymir.yggdrasil.li. | ||
| 21 | @ IN TXT "v=spf1 redirect=yggdrasil.li" | ||
| 22 | |||
| 23 | * IN A 188.68.51.254 | ||
| 24 | * IN AAAA 2a03:4000:6:d004:: | ||
| 25 | * IN MX 0 ymir.yggdrasil.li. | ||
| 26 | * IN TXT "v=spf1 redirect=yggdrasil.li" | ||
| 27 | |||
| 28 | _acme-challenge IN NS ns.yggdrasil.li. | ||
| 29 | |||
| 30 | ymir._domainkey IN TXT ( | ||
| 31 | "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" | ||
| 32 | "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24" | ||
| 33 | "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ==" | ||
| 34 | ) | ||
| 35 | |||
| 36 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. | ||
| 37 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. | ||
| 38 | |||
| 39 | _infinoted._tcp IN SRV 5 0 6523 ymir.yggdrasil.li. | ||
| 40 | |||
| 41 | _submission._tcp IN SRV 5 0 25 ymir.yggdrasil.li. | ||
| 42 | _imap._tcp IN SRV 5 0 143 ymir.yggdrasil.li. | ||
| 43 | _imaps._tcp IN SRV 5 0 993 ymir.yggdrasil.li. | ||
diff --git a/hosts/surtr/dns/zones/li.yggdrasil.soa b/hosts/surtr/dns/zones/li.yggdrasil.soa index 092d23ec..4eb30d74 100644 --- a/hosts/surtr/dns/zones/li.yggdrasil.soa +++ b/hosts/surtr/dns/zones/li.yggdrasil.soa | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | $ORIGIN yggdrasil.li. | 1 | $ORIGIN yggdrasil.li. |
| 2 | $TTL 3600 | 2 | $TTL 3600 |
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( |
| 4 | 2024102100 ; serial | 4 | 2026051501 ; serial |
| 5 | 10800 ; refresh | 5 | 10800 ; refresh |
| 6 | 3600 ; retry | 6 | 3600 ; retry |
| 7 | 604800 ; expire | 7 | 604800 ; expire |
| @@ -46,7 +46,7 @@ surtr IN TXT "v=spf1 a:surtr.yggdrasil.li -all" | |||
| 46 | vpn IN A 185.243.10.86 | 46 | vpn IN A 185.243.10.86 |
| 47 | vpn IN AAAA 2a03:4000:20:259:: | 47 | vpn IN AAAA 2a03:4000:20:259:: |
| 48 | 48 | ||
| 49 | surtr._domainkey.surtr IN CNAME surtr._domainkey.yggdrasil.li. | 49 | $INCLUDE /var/lib/dkim/surtr.yggdrasil.li.txt surtr.yggdrasil.li. |
| 50 | _dmarc.surtr IN TXT "v=DMARC1;p=reject;sp=reject;pct=100;adkim=s;aspf=s;rua=mailto:postmaster@yggdrasil.li;ruf=mailto:postmaster@yggdrasil.li" | 50 | _dmarc.surtr IN TXT "v=DMARC1;p=reject;sp=reject;pct=100;adkim=s;aspf=s;rua=mailto:postmaster@yggdrasil.li;ruf=mailto:postmaster@yggdrasil.li" |
| 51 | 51 | ||
| 52 | _acme-challenge.surtr IN NS ns.yggdrasil.li. | 52 | _acme-challenge.surtr IN NS ns.yggdrasil.li. |
| @@ -69,12 +69,76 @@ _acme-challenge.app.etesync IN NS ns.yggdrasil.li. | |||
| 69 | 69 | ||
| 70 | app.etesync IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | 70 | app.etesync IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" |
| 71 | 71 | ||
| 72 | immich IN A 202.61.241.61 | ||
| 73 | immich IN AAAA 2a03:4000:52:ada:: | ||
| 74 | immich IN MX 0 surtr.yggdrasil.li | ||
| 75 | immich IN TXT "v=spf1 redirect=surtr.yggdrasil.li" | ||
| 76 | _acme-challenge.immich IN NS ns.yggdrasil.li. | ||
| 77 | |||
| 78 | immich IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | ||
| 79 | |||
| 80 | paperless IN A 202.61.241.61 | ||
| 81 | paperless IN AAAA 2a03:4000:52:ada:: | ||
| 82 | paperless IN MX 0 surtr.yggdrasil.li | ||
| 83 | paperless IN TXT "v=spf1 redirect=surtr.yggdrasil.li" | ||
| 84 | _acme-challenge.paperless IN NS ns.yggdrasil.li. | ||
| 85 | |||
| 86 | paperless IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | ||
| 87 | |||
| 88 | hledger IN A 202.61.241.61 | ||
| 89 | hledger IN AAAA 2a03:4000:52:ada:: | ||
| 90 | hledger IN MX 0 surtr.yggdrasil.li | ||
| 91 | hledger IN TXT "v=spf1 redirect=surtr.yggdrasil.li" | ||
| 92 | _acme-challenge.hledger IN NS ns.yggdrasil.li. | ||
| 93 | |||
| 94 | hledger IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | ||
| 95 | |||
| 96 | audiobookshelf IN A 202.61.241.61 | ||
| 97 | audiobookshelf IN AAAA 2a03:4000:52:ada:: | ||
| 98 | audiobookshelf IN MX 0 surtr.yggdrasil.li | ||
| 99 | audiobookshelf IN TXT "v=spf1 redirect=surtr.yggdrasil.li" | ||
| 100 | _acme-challenge.audiobookshelf IN NS ns.yggdrasil.li. | ||
| 101 | |||
| 102 | audiobookshelf IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | ||
| 103 | |||
| 104 | kimai IN A 202.61.241.61 | ||
| 105 | kimai IN AAAA 2a03:4000:52:ada:: | ||
| 106 | kimai IN MX 0 surtr.yggdrasil.li | ||
| 107 | kimai IN TXT "v=spf1 redirect=surtr.yggdrasil.li" | ||
| 108 | _acme-challenge.kimai IN NS ns.yggdrasil.li. | ||
| 109 | |||
| 110 | kimai IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | ||
| 111 | |||
| 112 | changedetection IN A 202.61.241.61 | ||
| 113 | changedetection IN AAAA 2a03:4000:52:ada:: | ||
| 114 | changedetection IN MX 0 surtr.yggdrasil.li | ||
| 115 | changedetection IN TXT "v=spf1 redirect=surtr.yggdrasil.li" | ||
| 116 | _acme-challenge.changedetection IN NS ns.yggdrasil.li. | ||
| 117 | |||
| 118 | changedetection IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | ||
| 119 | |||
| 120 | vikunja IN A 202.61.241.61 | ||
| 121 | vikunja IN AAAA 2a03:4000:52:ada:: | ||
| 122 | vikunja IN MX 0 surtr.yggdrasil.li | ||
| 123 | vikunja IN TXT "v=spf1 redirect=surtr.yggdrasil.li" | ||
| 124 | _acme-challenge.vikunja IN NS ns.yggdrasil.li. | ||
| 125 | |||
| 126 | vikunja IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" | ||
| 127 | |||
| 128 | online IN A 202.61.241.61 | ||
| 129 | online IN AAAA 2a03:4000:52:ada:: | ||
| 130 | online IN MX 0 surtr.yggdrasil.li | ||
| 131 | online IN TXT "v=spf1 redirect=surtr.yggdrasil.li" | ||
| 132 | _acme-challenge.online IN NS ns.yggdrasil.li. | ||
| 133 | |||
| 72 | vidhar IN AAAA 2a03:4000:52:ada:4:1:: | 134 | vidhar IN AAAA 2a03:4000:52:ada:4:1:: |
| 73 | vidhar IN MX 0 ymir.yggdrasil.li | 135 | vidhar IN MX 0 ymir.yggdrasil.li |
| 74 | vidhar IN TXT "v=spf1 redirect=yggdrasil.li" | 136 | vidhar IN TXT "v=spf1 redirect=yggdrasil.li" |
| 75 | 137 | ||
| 76 | mailout IN A 188.68.51.254 | 138 | mailout IN A 188.68.51.254 |
| 77 | mailout IN AAAA 2a03:4000:6:d004:: | 139 | mailout IN AAAA 2a03:4000:6:d004:: |
| 140 | mailout IN A 202.61.241.61 | ||
| 141 | mailout IN AAAA 2a03:4000:52:ada:: | ||
| 78 | mailout IN MX 0 ymir.yggdrasil.li | 142 | mailout IN MX 0 ymir.yggdrasil.li |
| 79 | mailout IN TXT "v=spf1 redirect=yggdrasil.li" | 143 | mailout IN TXT "v=spf1 redirect=yggdrasil.li" |
| 80 | 144 | ||
| @@ -83,10 +147,7 @@ ymir._domainkey IN TXT ( | |||
| 83 | "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24" | 147 | "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24" |
| 84 | "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ==" | 148 | "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ==" |
| 85 | ) | 149 | ) |
| 86 | 150 | $INCLUDE /var/lib/dkim/yggdrasil.li.txt | |
| 87 | surtr._domainkey IN TXT ( "v=DKIM1;k=rsa;" | ||
| 88 | "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwEspNBXjTjPpCqSMkcBUJnSThqMcHwvDP3mOnv8wpDrGTN+1eJ1fzso5GHooGNt0kWHOpcoVwsMDIk81SR3zzNKYWqM40KvQ2ElNJqS5VDIfnxppiG9H5Nu3M7In5jv7OTSKsEi5eDzWqqvaHn6YjNQuKHQsJsAB1zUKoR1gqpvwJlV3tnhfQEl1O3qt0tG1c6JvgZ8R8szrk9" | ||
| 89 | "uNZzu90PDQY9UH4K1nu+INwlMgz9hzgJHIoNJOdB+1gmvnsI4MgmT/otxwKia/UoddN3Gcu7DO1gjFi5cwOA+zOgMnzzWUbys0Q3loCKp9EYgWUJQ9CCh5U4x4/GpV2VeEJ/0GYQIDAQAB" ) | ||
| 90 | 151 | ||
| 91 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. | 152 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. |
| 92 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. | 153 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. |
| @@ -96,6 +157,3 @@ _infinoted._tcp IN SRV 5 0 6523 ymir.yggdrasil.li. | |||
| 96 | _submission._tcp IN SRV 5 0 25 ymir.yggdrasil.li. | 157 | _submission._tcp IN SRV 5 0 25 ymir.yggdrasil.li. |
| 97 | _imap._tcp IN SRV 5 0 143 ymir.yggdrasil.li. | 158 | _imap._tcp IN SRV 5 0 143 ymir.yggdrasil.li. |
| 98 | _imaps._tcp IN SRV 5 0 993 ymir.yggdrasil.li. | 159 | _imaps._tcp IN SRV 5 0 993 ymir.yggdrasil.li. |
| 99 | |||
| 100 | game01 IN A 94.16.107.151 | ||
| 101 | game01 IN AAAA 2a03:4000:50:13d:34ee:a2ff:fed0:328f | ||
diff --git a/hosts/surtr/dns/zones/org.dirty-haskell.soa b/hosts/surtr/dns/zones/org.dirty-haskell.soa deleted file mode 100644 index 27f0d7f9..00000000 --- a/hosts/surtr/dns/zones/org.dirty-haskell.soa +++ /dev/null | |||
| @@ -1,34 +0,0 @@ | |||
| 1 | $ORIGIN dirty-haskell.org. | ||
| 2 | $TTL 3600 | ||
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | ||
| 4 | 2023013000 ; serial | ||
| 5 | 10800 ; refresh | ||
| 6 | 3600 ; retry | ||
| 7 | 604800 ; expire | ||
| 8 | 3600 ; min TTL | ||
| 9 | ) | ||
| 10 | IN NS ns.yggdrasil.li. | ||
| 11 | IN NS ns.inwx.de. | ||
| 12 | IN NS ns2.inwx.de. | ||
| 13 | IN NS ns3.inwx.eu. | ||
| 14 | |||
| 15 | @ IN CAA 128 issue "letsencrypt.org; validationmethods=dns-01" | ||
| 16 | @ IN CAA 128 iodef "mailto:caa@yggdrasil.li" | ||
| 17 | |||
| 18 | @ IN A 188.68.51.254 | ||
| 19 | @ IN AAAA 2a03:4000:6:d004:: | ||
| 20 | @ IN MX 10 ymir.yggdrasil.li. | ||
| 21 | @ IN TXT "v=spf1 redirect=yggdrasil.li" | ||
| 22 | |||
| 23 | * IN A 188.68.51.254 | ||
| 24 | * IN AAAA 2a03:4000:6:d004:: | ||
| 25 | * IN MX 0 ymir.yggdrasil.li. | ||
| 26 | * IN TXT "v=spf1 redirect=yggdrasil.li" | ||
| 27 | |||
| 28 | _acme-challenge IN NS ns.yggdrasil.li. | ||
| 29 | |||
| 30 | ymir._domainkey IN TXT ( | ||
| 31 | "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" | ||
| 32 | "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24" | ||
| 33 | "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ==" | ||
| 34 | ) | ||
diff --git a/hosts/surtr/dns/zones/org.praseodym.soa b/hosts/surtr/dns/zones/org.praseodym.soa index df505b4c..5bd627a4 100644 --- a/hosts/surtr/dns/zones/org.praseodym.soa +++ b/hosts/surtr/dns/zones/org.praseodym.soa | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | $ORIGIN praseodym.org. | 1 | $ORIGIN praseodym.org. |
| 2 | $TTL 3600 | 2 | $TTL 3600 |
| 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( | 3 | @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( |
| 4 | 2023013000 ; serial | 4 | 2026032103 ; serial |
| 5 | 10800 ; refresh | 5 | 10800 ; refresh |
| 6 | 3600 ; retry | 6 | 3600 ; retry |
| 7 | 604800 ; expire | 7 | 604800 ; expire |
| @@ -32,11 +32,8 @@ surtr IN AAAA 2a03:4000:52:ada:: | |||
| 32 | surtr IN MX 0 ymir.yggdrasil.li | 32 | surtr IN MX 0 ymir.yggdrasil.li |
| 33 | surtr IN TXT "v=spf1 redirect=yggdrasil.li" | 33 | surtr IN TXT "v=spf1 redirect=yggdrasil.li" |
| 34 | 34 | ||
| 35 | ymir._domainkey IN TXT ( | 35 | ymir._domainkey IN CNAME ymir._domainkey.yggdrasil.li. |
| 36 | "v=DKIM1;k=rsa;p=MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq3cCKlk+VPhyAanLZTM0BCzUT/+fmxHioZcFk0uJk1akBYj7BRofR7eVNcLKpm3rwYMQgE+9vJH9p8SV6tws9EcWc8SMCqqGZlREYM7PmLDiTSK/vjCzkygfgFCb0EBNsY2A/fpP4rTeoxrbcBSvMkq97iY5rwyw4wXZVZXLiDaCj23s8POoxTk1ClqUJZJQ5x2" | 36 | $INCLUDE /var/lib/dkim/praseodym.org.txt |
| 37 | "qzrC0RfN5kLZ9A7Gq2jB09vNxpXHYqABA0bJv88JiZM7hfkp9IafJZ+yCVMaBcJs4DAxnTjNAuFD9gm+qSFVY8+yeXqL6Qjo5PbruhyZRBW8RgRYT8t5n07XRglMGKKGMwOGLanrltcyXqB+GsDZBD36RAAwjFadnxdpDyRv4SgRP7ff2tKRrORYpmpN+mKdqw5j3J/nP6bXV1oAkyh9XQkPEIDi81WT87EZziTElDzVp6A2qFOxqucAovoRk24" | ||
| 38 | "7vlsns1FApFRsp9mja0UZNObyKD1M6tP9Ep7lS76tFGMk+WDvXRJH5LEsyCpu7sSyl1r/O0M4K+KldRCqLlZd7rf8F5P8T0dn1azk05g7F4p0N/y9GNdzXbPZ9u0eZdI7SEdh8ZoOZp7NVZiBFfbWLSS5ZtyA2kbBa4i7GJ/cuAbEKOmqAkeQPiu96TGIcyjkXjS6mTPI+9UmKZYZC+OM8XdJ02y5KRoonCc19ZS8CAwEAAQ==" | ||
| 39 | ) | ||
| 40 | 37 | ||
| 41 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. | 38 | _xmpp-client._tcp IN SRV 5 0 5222 ymir.yggdrasil.li. |
| 42 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. | 39 | _xmpp-server._tcp IN SRV 5 0 5269 ymir.yggdrasil.li. |
diff --git a/hosts/surtr/email/ccert-policy-server/.envrc b/hosts/surtr/email/ccert-policy-server/.envrc new file mode 100644 index 00000000..2c909235 --- /dev/null +++ b/hosts/surtr/email/ccert-policy-server/.envrc | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | use flake | ||
| 2 | |||
| 3 | [[ -d ".venv" ]] || ( uv venv && uv sync ) | ||
| 4 | . .venv/bin/activate | ||
diff --git a/hosts/surtr/email/ccert-policy-server/.gitignore b/hosts/surtr/email/ccert-policy-server/.gitignore new file mode 100644 index 00000000..4ccfae70 --- /dev/null +++ b/hosts/surtr/email/ccert-policy-server/.gitignore | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | .venv | ||
| 2 | **/__pycache__ | ||
diff --git a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py index 00182523..45619fb0 100644 --- a/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py +++ b/hosts/surtr/email/ccert-policy-server/ccert_policy_server/__main__.py | |||
| @@ -28,12 +28,14 @@ class PolicyHandler(StreamRequestHandler): | |||
| 28 | 28 | ||
| 29 | allowed = False | 29 | allowed = False |
| 30 | user = None | 30 | user = None |
| 31 | relay_eligible = False | ||
| 31 | if self.args['sasl_username']: | 32 | if self.args['sasl_username']: |
| 32 | user = self.args['sasl_username'] | 33 | user = self.args['sasl_username'] |
| 33 | if self.args['ccert_subject']: | 34 | if self.args['ccert_subject']: |
| 34 | user = self.args['ccert_subject'] | 35 | user = self.args['ccert_subject'] |
| 36 | relay_eligible = True | ||
| 35 | 37 | ||
| 36 | if user: | 38 | if user and '@' in self.args['sender']: |
| 37 | with self.server.db_pool.connection() as conn: | 39 | with self.server.db_pool.connection() as conn: |
| 38 | local, domain = self.args['sender'].split(sep='@', maxsplit=1) | 40 | local, domain = self.args['sender'].split(sep='@', maxsplit=1) |
| 39 | extension = None | 41 | extension = None |
| @@ -44,10 +46,16 @@ class PolicyHandler(StreamRequestHandler): | |||
| 44 | 46 | ||
| 45 | with conn.cursor() as cur: | 47 | with conn.cursor() as cur: |
| 46 | cur.row_factory = namedtuple_row | 48 | cur.row_factory = namedtuple_row |
| 47 | cur.execute('SELECT "mailbox"."mailbox" as "user", "local", "extension", "domain" FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True) | 49 | |
| 48 | for record in cur: | 50 | if relay_eligible: |
| 49 | logger.debug('Received result: %s', record) | 51 | cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "relay_access" ON "mailbox".id = "relay_access"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("domain" = %(domain)s OR %(domain)s ilike CONCAT(\'%%_.\', "domain"))) as "exists"', params = {'user': user, 'domain': domain}) |
| 50 | allowed = True | 52 | if (row := cur.fetchone()) is not None: |
| 53 | allowed = row.exists | ||
| 54 | |||
| 55 | if not allowed: | ||
| 56 | cur.execute('SELECT EXISTS(SELECT true FROM "mailbox" INNER JOIN "mailbox_mapping" ON "mailbox".id = "mailbox_mapping"."mailbox" WHERE "mailbox"."mailbox" = %(user)s AND ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s) as "exists"', params = {'user': user, 'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare=True) | ||
| 57 | if (row := cur.fetchone()) is not None: | ||
| 58 | allowed = row.exists | ||
| 51 | 59 | ||
| 52 | action = '550 5.7.0 Sender address not authorized for current user' | 60 | action = '550 5.7.0 Sender address not authorized for current user' |
| 53 | if allowed: | 61 | if allowed: |
diff --git a/hosts/surtr/email/ccert-policy-server/poetry.lock b/hosts/surtr/email/ccert-policy-server/poetry.lock deleted file mode 100644 index acd354e8..00000000 --- a/hosts/surtr/email/ccert-policy-server/poetry.lock +++ /dev/null | |||
| @@ -1,169 +0,0 @@ | |||
| 1 | # This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. | ||
| 2 | |||
| 3 | [[package]] | ||
| 4 | name = "psycopg" | ||
| 5 | version = "3.1.8" | ||
| 6 | description = "PostgreSQL database adapter for Python" | ||
| 7 | category = "main" | ||
| 8 | optional = false | ||
| 9 | python-versions = ">=3.7" | ||
| 10 | files = [ | ||
| 11 | {file = "psycopg-3.1.8-py3-none-any.whl", hash = "sha256:b1500c42063abaa01d30b056f0b300826b8dd8d586900586029a294ce74af327"}, | ||
| 12 | {file = "psycopg-3.1.8.tar.gz", hash = "sha256:59b4a71536b146925513c0234dfd1dc42b81e65d56ce5335dff4813434dbc113"}, | ||
| 13 | ] | ||
| 14 | |||
| 15 | [package.dependencies] | ||
| 16 | typing-extensions = ">=4.1" | ||
| 17 | tzdata = {version = "*", markers = "sys_platform == \"win32\""} | ||
| 18 | |||
| 19 | [package.extras] | ||
| 20 | binary = ["psycopg-binary (>=3.1.6,<=3.1.8)"] | ||
| 21 | c = ["psycopg-c (>=3.1.6,<=3.1.8)"] | ||
| 22 | dev = ["black (>=22.3.0)", "dnspython (>=2.1)", "flake8 (>=4.0)", "mypy (>=0.990)", "types-setuptools (>=57.4)", "wheel (>=0.37)"] | ||
| 23 | docs = ["Sphinx (>=5.0)", "furo (==2022.6.21)", "sphinx-autobuild (>=2021.3.14)", "sphinx-autodoc-typehints (>=1.12)"] | ||
| 24 | pool = ["psycopg-pool"] | ||
| 25 | test = ["mypy (>=0.990)", "pproxy (>=2.7)", "pytest (>=6.2.5)", "pytest-asyncio (>=0.17)", "pytest-cov (>=3.0)", "pytest-randomly (>=3.5)"] | ||
| 26 | |||
| 27 | [[package]] | ||
| 28 | name = "psycopg-binary" | ||
| 29 | version = "3.1.8" | ||
| 30 | description = "PostgreSQL database adapter for Python -- C optimisation distribution" | ||
| 31 | category = "main" | ||
| 32 | optional = false | ||
| 33 | python-versions = ">=3.7" | ||
| 34 | files = [ | ||
| 35 | {file = "psycopg_binary-3.1.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f32684b4fc3863190c4b9c141342b2cbdb81632731b9c68e6946d772ba0560f2"}, | ||
| 36 | {file = "psycopg_binary-3.1.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37212244817b3cc7193ee4b5d60765c020ead5e53589c935d249bfb96452878b"}, | ||
| 37 | {file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f2563db6e44372f593a76c94452ce476306e0fb508e092f3fab4d9091a9974"}, | ||
| 38 | {file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b36fcc67d8b23935ee871a6331c9631ecfdb11452a64f34b8ecb9642de43aec8"}, | ||
| 39 | {file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8bb9f577a09e799322008e574a1671c5b2645e990f954be2b7dae669e3779750"}, | ||
| 40 | {file = "psycopg_binary-3.1.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac81e68262b03163ca977f34448b4cadbc49db929146406b4706fe2141d76d1"}, | ||
| 41 | {file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fbfc9ae4edfb76c14d09bd70d6f399eb935008bbb3bc4cd6a4ab76645ba3443e"}, | ||
| 42 | {file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8602836138bc209aa5f9821c8e8439466f151c3ec4fcdbc740697e49cff1b920"}, | ||
| 43 | {file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:9cf94411f5a9064cf4ab1066976a7bce44f970f9603a01585c1040465eb312f9"}, | ||
| 44 | {file = "psycopg_binary-3.1.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a8fee8d846f9614331bd764850b4c1363730d36e88e14aa28ec4639318fd2093"}, | ||
| 45 | {file = "psycopg_binary-3.1.8-cp310-cp310-win_amd64.whl", hash = "sha256:2d5ae85c6037e45862e304d39ec24a24ddebc7d2b5b3601155dddc07c19c0cdc"}, | ||
| 46 | {file = "psycopg_binary-3.1.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17d187743d8ca63d24fa724bfee76e50b6473f1fef998cebcd35348b0d5936de"}, | ||
| 47 | {file = "psycopg_binary-3.1.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3762e73b6743139c5258d8b3a294edb309c691ba4f172c9f272315501390e7c2"}, | ||
| 48 | {file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87973d064a72bc2716309381b713f49f57c48100fb1f046943b780a04bc011f6"}, | ||
| 49 | {file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f8400d400f64f659a897d1ef67212012524cc44882bd24387515df9bb723364"}, | ||
| 50 | {file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f45766ce8e74eb456d8672116e936391e67290c50fd0cc1b41876b61261869b6"}, | ||
| 51 | {file = "psycopg_binary-3.1.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33ecf37c6348232073ea62b0630655479021f855635f72b4170693032993cdaf"}, | ||
| 52 | {file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:10b8f1f96f5e8f02a60ba76dab315d3e71cb76c18ff49aa18bbf48a8089c3202"}, | ||
| 53 | {file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:58cb0d007768dbccb67783baacf1c4016c7be8a494339a514321edee3d3b787a"}, | ||
| 54 | {file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:59d8dbea1bc3dbbc819c0320cb2b641dc362389b096098c62172f49605f58284"}, | ||
| 55 | {file = "psycopg_binary-3.1.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4325cee1641c25719bcf063f7683e909cb8cc9932ace3f8bf20ce112e47ce743"}, | ||
| 56 | {file = "psycopg_binary-3.1.8-cp311-cp311-win_amd64.whl", hash = "sha256:064502d191d7bc32a48670cc605ce49abcdb5e01e2697ee3fe546cff330fb8ae"}, | ||
| 57 | {file = "psycopg_binary-3.1.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5fd8492931865cc7181169b2dbf472377a5b5808f001e73f5c25b05bb61e9622"}, | ||
| 58 | {file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4d1a4ea2ca20f0bc944bc28e4addb80e6a22ac60a85fc7035e57c88e96f3a18"}, | ||
| 59 | {file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c27be5ddf4a05146ae7fb8429e9367dad0dc278a7d0e2f5094dd533195c4f8a1"}, | ||
| 60 | {file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa8ca48a35be0f9880ed2093c213f07d318fa9389a2b9194196c239e41a77841"}, | ||
| 61 | {file = "psycopg_binary-3.1.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf59e1d06f420930fc4c16a42ed6476c60c83976c82e53012dbca45f009d5978"}, | ||
| 62 | {file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:cb3013b76cbab4a903f3b9c87f4518335627cb05fd89f9e04520c1743c2b919b"}, | ||
| 63 | {file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:db84eaa9e2d13e37a97dcd39d2fe78e0a3052c9aa67b5f0b4f3d346a155f4d21"}, | ||
| 64 | {file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:2c3d268cf2dbb79e52a555c2e7b26c6df2d014f3fb918d512ffc25ecc9c54582"}, | ||
| 65 | {file = "psycopg_binary-3.1.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0fe6205af5f63ee6e4816b267bf06add5934a259cddcf7dfdfc8ed738f5127b2"}, | ||
| 66 | {file = "psycopg_binary-3.1.8-cp37-cp37m-win_amd64.whl", hash = "sha256:f99806a5b9a5ba5cb5f46a0fa0440cd721556e0af09a7cadcc39e27ae9b1807e"}, | ||
| 67 | {file = "psycopg_binary-3.1.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0cc5d5a9b0acbf38e0b4de1c701d235f0cb750ef3de528dedfdbab1a367f2396"}, | ||
| 68 | {file = "psycopg_binary-3.1.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:478ecbb774398e5df6ee365a4d0a77f382a65f140e76720909804255c7801d4a"}, | ||
| 69 | {file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b40b56c5b3ffa8481f7bebb08473602ddb8e2e86ba25bf9261ba428eb7887175"}, | ||
| 70 | {file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:37df8714837d2c701ba4c54462a189b95d1a4439d4d147fb71018560e9a60547"}, | ||
| 71 | {file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29a38b48cbec8484d83efea4d1d0707e49a3c51a2273cfbaa3d9ba280d3df7d9"}, | ||
| 72 | {file = "psycopg_binary-3.1.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c1a2209ef4df25f4ed8d91924bd4d9c7028d254e61216366c4b894c8a6ea4f88"}, | ||
| 73 | {file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:858a794c2d5e984627503581f03cc68cef97ee080993b7b6a0b7b30cb4fac107"}, | ||
| 74 | {file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:574c8b7b51e8d5c06f27125fc218d1328c018c0c1ad8f1202033aa6897b8ee99"}, | ||
| 75 | {file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e3dc783eedde10f966039ecc5f96f7df25c288ea4f6795d28b990f312c33ff09"}, | ||
| 76 | {file = "psycopg_binary-3.1.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:94f9e7ccbfdba1c4f5de80b615187eb47a351ab64a9123d87aea4bf347c1e1d8"}, | ||
| 77 | {file = "psycopg_binary-3.1.8-cp38-cp38-win_amd64.whl", hash = "sha256:1425c2cc4cfd4778d9dee578541f11546a93fc2f5c558a0411c94026a1cf94c7"}, | ||
| 78 | {file = "psycopg_binary-3.1.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e68e8b8077cd45dd2683fcd9a384e7672b400e26c0c7d04dac0cf0763c12be78"}, | ||
| 79 | {file = "psycopg_binary-3.1.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:60b22dd46e4e4f678379cf3388468171c2ecea74e90b1332d173ffa8cd83315f"}, | ||
| 80 | {file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61a1ccef7e0bf6128a7818c9d22cc850cf7649cee9541e82e4a8c080a734024d"}, | ||
| 81 | {file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e7a7b41eba96c7b9648efee57298f1aa0d96e081dea76489f52113536981712"}, | ||
| 82 | {file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a161785b1c8e26cd8e8d5436fa39ba2a8af590c17f1741aae11f8076a08485e6"}, | ||
| 83 | {file = "psycopg_binary-3.1.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a978d2bea09265eb6ebcd1b8a3aa05ea4118aa4013cb9669e12a8656975385cd"}, | ||
| 84 | {file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:251d2e6dca112dd359c029f422a025d75e78f2f2af4a2aceff506fdc5120f5f9"}, | ||
| 85 | {file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a1f052642a54eda53786fa8b72fca2e48ceaf0fc2f3e8709c87694fd7c45ac50"}, | ||
| 86 | {file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:73747e6a5dfb05500ff3857f9b9ee50e4f4f663250454d773b98d818545f10fa"}, | ||
| 87 | {file = "psycopg_binary-3.1.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:811d870ca9e97875db92f9b346492c4fa7a9edd74dce3604015dd13389fef46a"}, | ||
| 88 | {file = "psycopg_binary-3.1.8-cp39-cp39-win_amd64.whl", hash = "sha256:8a0f425171e95379f1fe93b41d67c6dfe85b6b635944facf07ca26ff7fa8ab1d"}, | ||
| 89 | ] | ||
| 90 | |||
| 91 | [[package]] | ||
| 92 | name = "psycopg-pool" | ||
| 93 | version = "3.1.7" | ||
| 94 | description = "Connection Pool for Psycopg" | ||
| 95 | category = "main" | ||
| 96 | optional = false | ||
| 97 | python-versions = ">=3.7" | ||
| 98 | files = [ | ||
| 99 | {file = "psycopg-pool-3.1.7.tar.gz", hash = "sha256:d02741dc48303495f4021900630442af87d6b1c3bfd1a3ece54cc11aa43d7dde"}, | ||
| 100 | {file = "psycopg_pool-3.1.7-py3-none-any.whl", hash = "sha256:ca1f2c366b5910acd400e16e812912827c57836af638c1717ba495111d22073b"}, | ||
| 101 | ] | ||
| 102 | |||
| 103 | [package.dependencies] | ||
| 104 | typing-extensions = ">=3.10" | ||
| 105 | |||
| 106 | [[package]] | ||
| 107 | name = "sdnotify" | ||
| 108 | version = "0.3.2" | ||
| 109 | description = "A pure Python implementation of systemd's service notification protocol (sd_notify)" | ||
| 110 | category = "main" | ||
| 111 | optional = false | ||
| 112 | python-versions = "*" | ||
| 113 | files = [ | ||
| 114 | {file = "sdnotify-0.3.2.tar.gz", hash = "sha256:73977fc746b36cc41184dd43c3fe81323e7b8b06c2bb0826c4f59a20c56bb9f1"}, | ||
| 115 | ] | ||
| 116 | |||
| 117 | [[package]] | ||
| 118 | name = "systemd-python" | ||
| 119 | version = "235" | ||
| 120 | description = "Python interface for libsystemd" | ||
| 121 | category = "main" | ||
| 122 | optional = false | ||
| 123 | python-versions = "*" | ||
| 124 | files = [ | ||
| 125 | {file = "systemd-python-235.tar.gz", hash = "sha256:4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a"}, | ||
| 126 | ] | ||
| 127 | |||
| 128 | [[package]] | ||
| 129 | name = "systemd-socketserver" | ||
| 130 | version = "1.0" | ||
| 131 | description = "Socket server implementation that works with systemd socket activation" | ||
| 132 | category = "main" | ||
| 133 | optional = false | ||
| 134 | python-versions = ">=3" | ||
| 135 | files = [ | ||
| 136 | {file = "systemd_socketserver-1.0-py3-none-any.whl", hash = "sha256:987a8bfbf28d959e7c2966c742ad7bad482f05e121077defcf95bb38267db9a8"}, | ||
| 137 | ] | ||
| 138 | |||
| 139 | [package.dependencies] | ||
| 140 | systemd-python = "*" | ||
| 141 | |||
| 142 | [[package]] | ||
| 143 | name = "typing-extensions" | ||
| 144 | version = "4.5.0" | ||
| 145 | description = "Backported and Experimental Type Hints for Python 3.7+" | ||
| 146 | category = "main" | ||
| 147 | optional = false | ||
| 148 | python-versions = ">=3.7" | ||
| 149 | files = [ | ||
| 150 | {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, | ||
| 151 | {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, | ||
| 152 | ] | ||
| 153 | |||
| 154 | [[package]] | ||
| 155 | name = "tzdata" | ||
| 156 | version = "2023.3" | ||
| 157 | description = "Provider of IANA time zone data" | ||
| 158 | category = "main" | ||
| 159 | optional = false | ||
| 160 | python-versions = ">=2" | ||
| 161 | files = [ | ||
| 162 | {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"}, | ||
| 163 | {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"}, | ||
| 164 | ] | ||
| 165 | |||
| 166 | [metadata] | ||
| 167 | lock-version = "2.0" | ||
| 168 | python-versions = "^3.9" | ||
| 169 | content-hash = "caba2a43081cb7820a3d1243e0c4aae70e0604405fbe1601cea99bd93a2f1429" | ||
diff --git a/hosts/surtr/email/ccert-policy-server/pyproject.toml b/hosts/surtr/email/ccert-policy-server/pyproject.toml index 97a18c65..518bd4f9 100644 --- a/hosts/surtr/email/ccert-policy-server/pyproject.toml +++ b/hosts/surtr/email/ccert-policy-server/pyproject.toml | |||
| @@ -1,20 +1,30 @@ | |||
| 1 | [tool.poetry] | 1 | [project] |
| 2 | name = "ccert_policy_server" | 2 | name = "ccert_policy_server" |
| 3 | version = "0.0.0" | 3 | version = "0.0.0" |
| 4 | authors = ["Gregor Kleen <gkleen@yggdrasil.li>"] | ||
| 5 | description = "" | 4 | description = "" |
| 5 | authors = [{ name = "Gregor Kleen", email = "gkleen@yggdrasil.li" }] | ||
| 6 | requires-python = ">=3.12,<4" | ||
| 7 | classifiers = [ | ||
| 8 | "Programming Language :: Python :: 3", | ||
| 9 | "Programming Language :: Python :: 3.12", | ||
| 10 | "Programming Language :: Python :: 3.13", | ||
| 11 | "Programming Language :: Python :: 3.14", | ||
| 12 | ] | ||
| 13 | dependencies = [ | ||
| 14 | "sdnotify>=0.3.2,<0.4", | ||
| 15 | "systemd-socketserver>=1.0,<2", | ||
| 16 | "psycopg>=3.3,<4", | ||
| 17 | "psycopg-pool>=3.3,<4", | ||
| 18 | "psycopg-binary>=3.3.3,<4", | ||
| 19 | ] | ||
| 6 | 20 | ||
| 7 | [tool.poetry.scripts] | 21 | [project.scripts] |
| 8 | ccert-policy-server = "ccert_policy_server.__main__:main" | 22 | ccert-policy-server = "ccert_policy_server.__main__:main" |
| 9 | 23 | ||
| 10 | [tool.poetry.dependencies] | ||
| 11 | python = "^3.9" | ||
| 12 | sdnotify = "^0.3.2" | ||
| 13 | systemd-socketserver = "^1.0" | ||
| 14 | psycopg = "^3.1.8" | ||
| 15 | psycopg-pool = "^3.1.7" | ||
| 16 | psycopg-binary = "^3.1.8" | ||
| 17 | |||
| 18 | [build-system] | 24 | [build-system] |
| 19 | requires = ["poetry-core>=1.0.0"] | 25 | requires = ["uv_build>=0.10.9,<0.11.0"] |
| 20 | build-backend = "poetry.core.masonry.api" \ No newline at end of file | 26 | build-backend = "uv_build" |
| 27 | |||
| 28 | [tool.uv.build-backend] | ||
| 29 | module-root = "." | ||
| 30 | module-name = ["ccert_policy_server"] | ||
diff --git a/hosts/surtr/email/ccert-policy-server/uv.lock b/hosts/surtr/email/ccert-policy-server/uv.lock new file mode 100644 index 00000000..0024400b --- /dev/null +++ b/hosts/surtr/email/ccert-policy-server/uv.lock | |||
| @@ -0,0 +1,130 @@ | |||
| 1 | version = 1 | ||
| 2 | revision = 3 | ||
| 3 | requires-python = ">=3.12, <4" | ||
| 4 | |||
| 5 | [[package]] | ||
| 6 | name = "ccert-policy-server" | ||
| 7 | version = "0.0.0" | ||
| 8 | source = { editable = "." } | ||
| 9 | dependencies = [ | ||
| 10 | { name = "psycopg" }, | ||
| 11 | { name = "psycopg-binary" }, | ||
| 12 | { name = "psycopg-pool" }, | ||
| 13 | { name = "sdnotify" }, | ||
| 14 | { name = "systemd-socketserver" }, | ||
| 15 | ] | ||
| 16 | |||
| 17 | [package.metadata] | ||
| 18 | requires-dist = [ | ||
| 19 | { name = "psycopg", specifier = ">=3.3,<4" }, | ||
| 20 | { name = "psycopg-binary", specifier = ">=3.3.3,<4" }, | ||
| 21 | { name = "psycopg-pool", specifier = ">=3.3,<4" }, | ||
| 22 | { name = "sdnotify", specifier = ">=0.3.2,<0.4" }, | ||
| 23 | { name = "systemd-socketserver", specifier = ">=1.0,<2" }, | ||
| 24 | ] | ||
| 25 | |||
| 26 | [[package]] | ||
| 27 | name = "psycopg" | ||
| 28 | version = "3.3.3" | ||
| 29 | source = { registry = "https://pypi.org/simple" } | ||
| 30 | dependencies = [ | ||
| 31 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, | ||
| 32 | { name = "tzdata", marker = "sys_platform == 'win32'" }, | ||
| 33 | ] | ||
| 34 | sdist = { url = "https://files.pythonhosted.org/packages/d3/b6/379d0a960f8f435ec78720462fd94c4863e7a31237cf81bf76d0af5883bf/psycopg-3.3.3.tar.gz", hash = "sha256:5e9a47458b3c1583326513b2556a2a9473a1001a56c9efe9e587245b43148dd9", size = 165624, upload-time = "2026-02-18T16:52:16.546Z" } | ||
| 35 | wheels = [ | ||
| 36 | { url = "https://files.pythonhosted.org/packages/c8/5b/181e2e3becb7672b502f0ed7f16ed7352aca7c109cfb94cf3878a9186db9/psycopg-3.3.3-py3-none-any.whl", hash = "sha256:f96525a72bcfade6584ab17e89de415ff360748c766f0106959144dcbb38c698", size = 212768, upload-time = "2026-02-18T16:46:27.365Z" }, | ||
| 37 | ] | ||
| 38 | |||
| 39 | [[package]] | ||
| 40 | name = "psycopg-binary" | ||
| 41 | version = "3.3.3" | ||
| 42 | source = { registry = "https://pypi.org/simple" } | ||
| 43 | wheels = [ | ||
| 44 | { url = "https://files.pythonhosted.org/packages/90/15/021be5c0cbc5b7c1ab46e91cc3434eb42569f79a0592e67b8d25e66d844d/psycopg_binary-3.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6698dbab5bcef8fdb570fc9d35fd9ac52041771bfcfe6fd0fc5f5c4e36f1e99d", size = 4591170, upload-time = "2026-02-18T16:48:55.594Z" }, | ||
| 45 | { url = "https://files.pythonhosted.org/packages/f1/54/a60211c346c9a2f8c6b272b5f2bbe21f6e11800ce7f61e99ba75cf8b63e1/psycopg_binary-3.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:329ff393441e75f10b673ae99ab45276887993d49e65f141da20d915c05aafd8", size = 4670009, upload-time = "2026-02-18T16:49:03.608Z" }, | ||
| 46 | { url = "https://files.pythonhosted.org/packages/c1/53/ac7c18671347c553362aadbf65f92786eef9540676ca24114cc02f5be405/psycopg_binary-3.3.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:eb072949b8ebf4082ae24289a2b0fd724da9adc8f22743409d6fd718ddb379df", size = 5469735, upload-time = "2026-02-18T16:49:10.128Z" }, | ||
| 47 | { url = "https://files.pythonhosted.org/packages/7f/c3/4f4e040902b82a344eff1c736cde2f2720f127fe939c7e7565706f96dd44/psycopg_binary-3.3.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:263a24f39f26e19ed7fc982d7859a36f17841b05bebad3eb47bb9cd2dd785351", size = 5152919, upload-time = "2026-02-18T16:49:16.335Z" }, | ||
| 48 | { url = "https://files.pythonhosted.org/packages/0c/e7/d929679c6a5c212bcf738806c7c89f5b3d0919f2e1685a0e08d6ff877945/psycopg_binary-3.3.3-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5152d50798c2fa5bd9b68ec68eb68a1b71b95126c1d70adaa1a08cd5eefdc23d", size = 6738785, upload-time = "2026-02-18T16:49:22.687Z" }, | ||
| 49 | { url = "https://files.pythonhosted.org/packages/69/b0/09703aeb69a9443d232d7b5318d58742e8ca51ff79f90ffe6b88f1db45e7/psycopg_binary-3.3.3-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9d6a1e56dd267848edb824dbeb08cf5bac649e02ee0b03ba883ba3f4f0bd54f2", size = 4979008, upload-time = "2026-02-18T16:49:27.313Z" }, | ||
| 50 | { url = "https://files.pythonhosted.org/packages/cc/a6/e662558b793c6e13a7473b970fee327d635270e41eded3090ef14045a6a5/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73eaaf4bb04709f545606c1db2f65f4000e8a04cdbf3e00d165a23004692093e", size = 4508255, upload-time = "2026-02-18T16:49:31.575Z" }, | ||
| 51 | { url = "https://files.pythonhosted.org/packages/5f/7f/0f8b2e1d5e0093921b6f324a948a5c740c1447fbb45e97acaf50241d0f39/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:162e5675efb4704192411eaf8e00d07f7960b679cd3306e7efb120bb8d9456cc", size = 4189166, upload-time = "2026-02-18T16:49:35.801Z" }, | ||
| 52 | { url = "https://files.pythonhosted.org/packages/92/ec/ce2e91c33bc8d10b00c87e2f6b0fb570641a6a60042d6a9ae35658a3a797/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:fab6b5e37715885c69f5d091f6ff229be71e235f272ebaa35158d5a46fd548a0", size = 3924544, upload-time = "2026-02-18T16:49:41.129Z" }, | ||
| 53 | { url = "https://files.pythonhosted.org/packages/c5/2f/7718141485f73a924205af60041c392938852aa447a94c8cbd222ff389a1/psycopg_binary-3.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a4aab31bd6d1057f287c96c0effca3a25584eb9cc702f282ecb96ded7814e830", size = 4235297, upload-time = "2026-02-18T16:49:46.726Z" }, | ||
| 54 | { url = "https://files.pythonhosted.org/packages/57/f9/1add717e2643a003bbde31b1b220172e64fbc0cb09f06429820c9173f7fc/psycopg_binary-3.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:59aa31fe11a0e1d1bcc2ce37ed35fe2ac84cd65bb9036d049b1a1c39064d0f14", size = 3547659, upload-time = "2026-02-18T16:49:52.999Z" }, | ||
| 55 | { url = "https://files.pythonhosted.org/packages/03/0a/cac9fdf1df16a269ba0e5f0f06cac61f826c94cadb39df028cdfe19d3a33/psycopg_binary-3.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:05f32239aec25c5fb15f7948cffdc2dc0dac098e48b80a140e4ba32b572a2e7d", size = 4590414, upload-time = "2026-02-18T16:50:01.441Z" }, | ||
| 56 | { url = "https://files.pythonhosted.org/packages/9c/c0/d8f8508fbf440edbc0099b1abff33003cd80c9e66eb3a1e78834e3fb4fb9/psycopg_binary-3.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c84f9d214f2d1de2fafebc17fa68ac3f6561a59e291553dfc45ad299f4898c1", size = 4669021, upload-time = "2026-02-18T16:50:08.803Z" }, | ||
| 57 | { url = "https://files.pythonhosted.org/packages/04/05/097016b77e343b4568feddf12c72171fc513acef9a4214d21b9478569068/psycopg_binary-3.3.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e77957d2ba17cada11be09a5066d93026cdb61ada7c8893101d7fe1c6e1f3925", size = 5467453, upload-time = "2026-02-18T16:50:14.985Z" }, | ||
| 58 | { url = "https://files.pythonhosted.org/packages/91/23/73244e5feb55b5ca109cede6e97f32ef45189f0fdac4c80d75c99862729d/psycopg_binary-3.3.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:42961609ac07c232a427da7c87a468d3c82fee6762c220f38e37cfdacb2b178d", size = 5151135, upload-time = "2026-02-18T16:50:24.82Z" }, | ||
| 59 | { url = "https://files.pythonhosted.org/packages/11/49/5309473b9803b207682095201d8708bbc7842ddf3f192488a69204e36455/psycopg_binary-3.3.3-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae07a3114313dd91fce686cab2f4c44af094398519af0e0f854bc707e1aeedf1", size = 6737315, upload-time = "2026-02-18T16:50:35.106Z" }, | ||
| 60 | { url = "https://files.pythonhosted.org/packages/d4/5d/03abe74ef34d460b33c4d9662bf6ec1dd38888324323c1a1752133c10377/psycopg_binary-3.3.3-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d257c58d7b36a621dcce1d01476ad8b60f12d80eb1406aee4cf796f88b2ae482", size = 4979783, upload-time = "2026-02-18T16:50:42.067Z" }, | ||
| 61 | { url = "https://files.pythonhosted.org/packages/f0/6c/3fbf8e604e15f2f3752900434046c00c90bb8764305a1b81112bff30ba24/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:07c7211f9327d522c9c47560cae00a4ecf6687f4e02d779d035dd3177b41cb12", size = 4509023, upload-time = "2026-02-18T16:50:50.116Z" }, | ||
| 62 | { url = "https://files.pythonhosted.org/packages/9c/6b/1a06b43b7c7af756c80b67eac8bfaa51d77e68635a8a8d246e4f0bb7604a/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8e7e9eca9b363dbedeceeadd8be97149d2499081f3c52d141d7cd1f395a91f83", size = 4185874, upload-time = "2026-02-18T16:50:55.97Z" }, | ||
| 63 | { url = "https://files.pythonhosted.org/packages/2b/d3/bf49e3dcaadba510170c8d111e5e69e5ae3f981c1554c5bb71c75ce354bb/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:cb85b1d5702877c16f28d7b92ba030c1f49ebcc9b87d03d8c10bf45a2f1c7508", size = 3925668, upload-time = "2026-02-18T16:51:03.299Z" }, | ||
| 64 | { url = "https://files.pythonhosted.org/packages/f8/92/0aac830ed6a944fe334404e1687a074e4215630725753f0e3e9a9a595b62/psycopg_binary-3.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4d4606c84d04b80f9138d72f1e28c6c02dc5ae0c7b8f3f8aaf89c681ce1cd1b1", size = 4234973, upload-time = "2026-02-18T16:51:09.097Z" }, | ||
| 65 | { url = "https://files.pythonhosted.org/packages/2e/96/102244653ee5a143ece5afe33f00f52fe64e389dfce8dbc87580c6d70d3d/psycopg_binary-3.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:74eae563166ebf74e8d950ff359be037b85723d99ca83f57d9b244a871d6c13b", size = 3551342, upload-time = "2026-02-18T16:51:13.892Z" }, | ||
| 66 | { url = "https://files.pythonhosted.org/packages/a2/71/7a57e5b12275fe7e7d84d54113f0226080423a869118419c9106c083a21c/psycopg_binary-3.3.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:497852c5eaf1f0c2d88ab74a64a8097c099deac0c71de1cbcf18659a8a04a4b2", size = 4607368, upload-time = "2026-02-18T16:51:19.295Z" }, | ||
| 67 | { url = "https://files.pythonhosted.org/packages/c7/04/cb834f120f2b2c10d4003515ef9ca9d688115b9431735e3936ae48549af8/psycopg_binary-3.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:258d1ea53464d29768bf25930f43291949f4c7becc706f6e220c515a63a24edd", size = 4687047, upload-time = "2026-02-18T16:51:23.84Z" }, | ||
| 68 | { url = "https://files.pythonhosted.org/packages/40/e9/47a69692d3da9704468041aa5ed3ad6fc7f6bb1a5ae788d261a26bbca6c7/psycopg_binary-3.3.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:111c59897a452196116db12e7f608da472fbff000693a21040e35fc978b23430", size = 5487096, upload-time = "2026-02-18T16:51:29.645Z" }, | ||
| 69 | { url = "https://files.pythonhosted.org/packages/0b/b6/0e0dd6a2f802864a4ae3dbadf4ec620f05e3904c7842b326aafc43e5f464/psycopg_binary-3.3.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:17bb6600e2455993946385249a3c3d0af52cd70c1c1cdbf712e9d696d0b0bf1b", size = 5168720, upload-time = "2026-02-18T16:51:36.499Z" }, | ||
| 70 | { url = "https://files.pythonhosted.org/packages/6f/0d/977af38ac19a6b55d22dff508bd743fd7c1901e1b73657e7937c7cccb0a3/psycopg_binary-3.3.3-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:642050398583d61c9856210568eb09a8e4f2fe8224bf3be21b67a370e677eead", size = 6762076, upload-time = "2026-02-18T16:51:43.167Z" }, | ||
| 71 | { url = "https://files.pythonhosted.org/packages/34/40/912a39d48322cf86895c0eaf2d5b95cb899402443faefd4b09abbba6b6e1/psycopg_binary-3.3.3-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:533efe6dc3a7cba5e2a84e38970786bb966306863e45f3db152007e9f48638a6", size = 4997623, upload-time = "2026-02-18T16:51:47.707Z" }, | ||
| 72 | { url = "https://files.pythonhosted.org/packages/98/0c/c14d0e259c65dc7be854d926993f151077887391d5a081118907a9d89603/psycopg_binary-3.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:5958dbf28b77ce2033482f6cb9ef04d43f5d8f4b7636e6963d5626f000efb23e", size = 4532096, upload-time = "2026-02-18T16:51:51.421Z" }, | ||
| 73 | { url = "https://files.pythonhosted.org/packages/39/21/8b7c50a194cfca6ea0fd4d1f276158307785775426e90700ab2eba5cd623/psycopg_binary-3.3.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:a6af77b6626ce92b5817bf294b4d45ec1a6161dba80fc2d82cdffdd6814fd023", size = 4208884, upload-time = "2026-02-18T16:51:57.336Z" }, | ||
| 74 | { url = "https://files.pythonhosted.org/packages/c7/2c/a4981bf42cf30ebba0424971d7ce70a222ae9b82594c42fc3f2105d7b525/psycopg_binary-3.3.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:47f06fcbe8542b4d96d7392c476a74ada521c5aebdb41c3c0155f6595fc14c8d", size = 3944542, upload-time = "2026-02-18T16:52:04.266Z" }, | ||
| 75 | { url = "https://files.pythonhosted.org/packages/60/e9/b7c29b56aa0b85a4e0c4d89db691c1ceef08f46a356369144430c155a2f5/psycopg_binary-3.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e7800e6c6b5dc4b0ca7cc7370f770f53ac83886b76afda0848065a674231e856", size = 4254339, upload-time = "2026-02-18T16:52:10.444Z" }, | ||
| 76 | { url = "https://files.pythonhosted.org/packages/98/5a/291d89f44d3820fffb7a04ebc8f3ef5dda4f542f44a5daea0c55a84abf45/psycopg_binary-3.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:165f22ab5a9513a3d7425ffb7fcc7955ed8ccaeef6d37e369d6cc1dff1582383", size = 3652796, upload-time = "2026-02-18T16:52:14.02Z" }, | ||
| 77 | ] | ||
| 78 | |||
| 79 | [[package]] | ||
| 80 | name = "psycopg-pool" | ||
| 81 | version = "3.3.0" | ||
| 82 | source = { registry = "https://pypi.org/simple" } | ||
| 83 | dependencies = [ | ||
| 84 | { name = "typing-extensions" }, | ||
| 85 | ] | ||
| 86 | sdist = { url = "https://files.pythonhosted.org/packages/56/9a/9470d013d0d50af0da9c4251614aeb3c1823635cab3edc211e3839db0bcf/psycopg_pool-3.3.0.tar.gz", hash = "sha256:fa115eb2860bd88fce1717d75611f41490dec6135efb619611142b24da3f6db5", size = 31606, upload-time = "2025-12-01T11:34:33.11Z" } | ||
| 87 | wheels = [ | ||
| 88 | { url = "https://files.pythonhosted.org/packages/e7/c3/26b8a0908a9db249de3b4169692e1c7c19048a9bc41a4d3209cee7dbb758/psycopg_pool-3.3.0-py3-none-any.whl", hash = "sha256:2e44329155c410b5e8666372db44276a8b1ebd8c90f1c3026ebba40d4bc81063", size = 39995, upload-time = "2025-12-01T11:34:29.761Z" }, | ||
| 89 | ] | ||
| 90 | |||
| 91 | [[package]] | ||
| 92 | name = "sdnotify" | ||
| 93 | version = "0.3.2" | ||
| 94 | source = { registry = "https://pypi.org/simple" } | ||
| 95 | sdist = { url = "https://files.pythonhosted.org/packages/ce/d8/9fdc36b2a912bf78106de4b3f0de3891ff8f369e7a6f80be842b8b0b6bd5/sdnotify-0.3.2.tar.gz", hash = "sha256:73977fc746b36cc41184dd43c3fe81323e7b8b06c2bb0826c4f59a20c56bb9f1", size = 2459, upload-time = "2017-08-02T20:03:44.395Z" } | ||
| 96 | |||
| 97 | [[package]] | ||
| 98 | name = "systemd-python" | ||
| 99 | version = "235" | ||
| 100 | source = { registry = "https://pypi.org/simple" } | ||
| 101 | sdist = { url = "https://files.pythonhosted.org/packages/10/9e/ab4458e00367223bda2dd7ccf0849a72235ee3e29b36dce732685d9b7ad9/systemd-python-235.tar.gz", hash = "sha256:4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a", size = 61677, upload-time = "2023-02-11T13:42:16.588Z" } | ||
| 102 | |||
| 103 | [[package]] | ||
| 104 | name = "systemd-socketserver" | ||
| 105 | version = "1.0" | ||
| 106 | source = { registry = "https://pypi.org/simple" } | ||
| 107 | dependencies = [ | ||
| 108 | { name = "systemd-python" }, | ||
| 109 | ] | ||
| 110 | wheels = [ | ||
| 111 | { url = "https://files.pythonhosted.org/packages/d8/4f/b28b7f08880120a26669b080ca74487c8c67e8b54dcb0467a8f0c9f38ed6/systemd_socketserver-1.0-py3-none-any.whl", hash = "sha256:987a8bfbf28d959e7c2966c742ad7bad482f05e121077defcf95bb38267db9a8", size = 3248, upload-time = "2020-04-26T05:26:40.661Z" }, | ||
| 112 | ] | ||
| 113 | |||
| 114 | [[package]] | ||
| 115 | name = "typing-extensions" | ||
| 116 | version = "4.15.0" | ||
| 117 | source = { registry = "https://pypi.org/simple" } | ||
| 118 | sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } | ||
| 119 | wheels = [ | ||
| 120 | { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, | ||
| 121 | ] | ||
| 122 | |||
| 123 | [[package]] | ||
| 124 | name = "tzdata" | ||
| 125 | version = "2025.3" | ||
| 126 | source = { registry = "https://pypi.org/simple" } | ||
| 127 | sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } | ||
| 128 | wheels = [ | ||
| 129 | { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, | ||
| 130 | ] | ||
diff --git a/hosts/surtr/email/default.nix b/hosts/surtr/email/default.nix index 4196a8bc..d9e6fff9 100644 --- a/hosts/surtr/email/default.nix +++ b/hosts/surtr/email/default.nix | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | { config, pkgs, lib, flakeInputs, ... }: | 1 | { config, pkgs, lib, flake, flakeInputs, ... }: |
| 2 | 2 | ||
| 3 | with lib; | 3 | with lib; |
| 4 | 4 | ||
| @@ -15,30 +15,65 @@ let | |||
| 15 | 15 | ||
| 16 | for file in $out/pipe/bin/*; do | 16 | for file in $out/pipe/bin/*; do |
| 17 | wrapProgram $file \ | 17 | wrapProgram $file \ |
| 18 | --set PATH "${pkgs.coreutils}/bin:${pkgs.rspamd}/bin" | 18 | --set PATH "${makeBinPath (with pkgs; [coreutils rspamd])}" |
| 19 | done | 19 | done |
| 20 | ''; | 20 | ''; |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | ccert-policy-server = | 23 | ccert-policy-server = |
| 24 | with pkgs.poetry2nix; | 24 | let |
| 25 | mkPoetryApplication { | 25 | workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./ccert-policy-server; }; |
| 26 | python = pkgs.python311; | 26 | pythonSet = flake.lib.pythonSet { |
| 27 | 27 | inherit pkgs; | |
| 28 | projectDir = cleanPythonSources { src = ./ccert-policy-server; }; | 28 | python = pkgs.python312; |
| 29 | 29 | overlay = workspace.mkPyprojectOverlay { | |
| 30 | overrides = overrides.withDefaults (self: super: { | 30 | sourcePreference = "wheel"; |
| 31 | systemd-python = super.systemd-python.overridePythonAttrs (oldAttrs: { | 31 | }; |
| 32 | buildInputs = (oldAttrs.buildInputs or []) ++ [ super.setuptools ]; | 32 | }; |
| 33 | }); | 33 | virtualEnv = pythonSet.mkVirtualEnv "ccert-policy-server-env" workspace.deps.default; |
| 34 | }); | 34 | in virtualEnv.overrideAttrs (oldAttrs: { |
| 35 | }; | 35 | meta = (oldAttrs.meta or {}) // { |
| 36 | 36 | mainProgram = "ccert-policy-server"; | |
| 37 | nftables-nologin-script = pkgs.writeScript "nftables-mail-nologin" '' | 37 | }; |
| 38 | #!${pkgs.zsh}/bin/zsh | 38 | }); |
| 39 | internal-policy-server = | ||
| 40 | let | ||
| 41 | workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./internal-policy-server; }; | ||
| 42 | pythonSet = flake.lib.pythonSet { | ||
| 43 | inherit pkgs; | ||
| 44 | python = pkgs.python312; | ||
| 45 | overlay = workspace.mkPyprojectOverlay { | ||
| 46 | sourcePreference = "wheel"; | ||
| 47 | }; | ||
| 48 | }; | ||
| 49 | virtualEnv = pythonSet.mkVirtualEnv "internal-policy-server-env" workspace.deps.default; | ||
| 50 | in virtualEnv.overrideAttrs (oldAttrs: { | ||
| 51 | meta = (oldAttrs.meta or {}) // { | ||
| 52 | mainProgram = "internal-policy-server"; | ||
| 53 | }; | ||
| 54 | }); | ||
| 55 | password-server = | ||
| 56 | let | ||
| 57 | workspace = flakeInputs.uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./password-server; }; | ||
| 58 | pythonSet = flake.lib.pythonSet { | ||
| 59 | inherit pkgs; | ||
| 60 | python = pkgs.python3; | ||
| 61 | overlay = workspace.mkPyprojectOverlay { | ||
| 62 | sourcePreference = "wheel"; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | virtualEnv = pythonSet.mkVirtualEnv "password-server-env" workspace.deps.default; | ||
| 66 | in virtualEnv.overrideAttrs (oldAttrs: { | ||
| 67 | meta = (oldAttrs.meta or {}) // { | ||
| 68 | mainProgram = "password-server"; | ||
| 69 | }; | ||
| 70 | }); | ||
| 39 | 71 | ||
| 72 | nftables-nologin-script = pkgs.resholve.writeScript "nftables-mail-nologin" { | ||
| 73 | inputs = with pkgs; [inetutils nftables gnugrep findutils]; | ||
| 74 | interpreter = lib.getExe pkgs.zsh; | ||
| 75 | } '' | ||
| 40 | set -e | 76 | set -e |
| 41 | export PATH="${lib.makeBinPath (with pkgs; [inetutils nftables])}:$PATH" | ||
| 42 | 77 | ||
| 43 | typeset -a as_sets mnt_bys route route6 | 78 | typeset -a as_sets mnt_bys route route6 |
| 44 | as_sets=(${lib.escapeShellArgs config.services.email.nologin.ASSets}) | 79 | as_sets=(${lib.escapeShellArgs config.services.email.nologin.ASSets}) |
| @@ -51,7 +86,7 @@ let | |||
| 51 | elif [[ "''${line}" =~ "^route6:\s+(.+)$" ]]; then | 86 | elif [[ "''${line}" =~ "^route6:\s+(.+)$" ]]; then |
| 52 | route6+=($match[1]) | 87 | route6+=($match[1]) |
| 53 | fi | 88 | fi |
| 54 | done < <(whois -h whois.radb.net "!i''${as_set},1" | egrep -o 'AS[0-9]+' | xargs -- whois -h whois.radb.net -- -i origin) | 89 | done < <(whois -h whois.radb.net "!i''${as_set},1" | grep -Eo 'AS[0-9]+' | xargs whois -h whois.radb.net -- -i origin) |
| 55 | done | 90 | done |
| 56 | for mnt_by in $mnt_bys; do | 91 | for mnt_by in $mnt_bys; do |
| 57 | while IFS=$'\n' read line; do | 92 | while IFS=$'\n' read line; do |
| @@ -108,22 +143,20 @@ in { | |||
| 108 | services.postfix = { | 143 | services.postfix = { |
| 109 | enable = true; | 144 | enable = true; |
| 110 | enableSmtp = false; | 145 | enableSmtp = false; |
| 111 | hostname = "surtr.yggdrasil.li"; | ||
| 112 | recipientDelimiter = ""; | ||
| 113 | setSendmail = true; | 146 | setSendmail = true; |
| 114 | postmasterAlias = ""; rootAlias = ""; extraAliases = ""; | 147 | postmasterAlias = ""; rootAlias = ""; extraAliases = ""; |
| 115 | destination = []; | 148 | settings.main = { |
| 116 | sslCert = "/run/credentials/postfix.service/surtr.yggdrasil.li.pem"; | 149 | recpipient_delimiter = ""; |
| 117 | sslKey = "/run/credentials/postfix.service/surtr.yggdrasil.li.key.pem"; | 150 | mydestination = []; |
| 118 | networks = []; | 151 | mynetworks = []; |
| 119 | config = let | 152 | myhostname = "surtr.yggdrasil.li"; |
| 120 | relay_ccert = "texthash:${pkgs.writeText "relay_ccert" ""}"; | 153 | |
| 121 | in { | ||
| 122 | smtpd_tls_security_level = "may"; | 154 | smtpd_tls_security_level = "may"; |
| 123 | 155 | ||
| 124 | #the dh params | 156 | smtpd_tls_chain_files = [ |
| 125 | smtpd_tls_dh1024_param_file = toString config.security.dhparams.params."postfix-1024".path; | 157 | "/run/credentials/postfix.service/surtr.yggdrasil.li.full.pem" |
| 126 | smtpd_tls_dh512_param_file = toString config.security.dhparams.params."postfix-512".path; | 158 | ]; |
| 159 | |||
| 127 | #enable ECDH | 160 | #enable ECDH |
| 128 | smtpd_tls_eecdh_grade = "strong"; | 161 | smtpd_tls_eecdh_grade = "strong"; |
| 129 | #enabled SSL protocols, don't allow SSLv2 and SSLv3 | 162 | #enabled SSL protocols, don't allow SSLv2 and SSLv3 |
| @@ -155,21 +188,14 @@ in { | |||
| 155 | 188 | ||
| 156 | smtp_tls_connection_reuse = true; | 189 | smtp_tls_connection_reuse = true; |
| 157 | 190 | ||
| 158 | tls_server_sni_maps = ''texthash:${pkgs.writeText "sni" ( | 191 | tls_server_sni_maps = "inline:{${concatMapStringsSep ", " (domain: "{ ${domain} = /run/credentials/postfix.service/${removePrefix "." domain}.full.pem }") (concatMap (domain: [domain "mailin.${domain}" "mailsub.${domain}" ".${domain}"]) emailDomains)}}"; |
| 159 | concatMapStringsSep "\n\n" (domain: | ||
| 160 | concatMapStringsSep "\n" (subdomain: "${subdomain} /run/credentials/postfix.service/${removePrefix "." subdomain}.full.pem") | ||
| 161 | [domain "mailin.${domain}" "mailsub.${domain}" ".${domain}"] | ||
| 162 | ) emailDomains | ||
| 163 | )}''; | ||
| 164 | 192 | ||
| 165 | smtp_tls_policy_maps = "socketmap:unix:${config.services.postfix-mta-sts-resolver.settings.path}:postfix"; | 193 | smtp_tls_policy_maps = "socketmap:unix:${config.services.postfix-mta-sts-resolver.settings.path}:postfix"; |
| 166 | 194 | ||
| 167 | local_recipient_maps = ""; | 195 | local_recipient_maps = ""; |
| 168 | 196 | ||
| 169 | # 10 GiB | 197 | message_size_limit = 10 * 1024 * 1024 * 1024; |
| 170 | message_size_limit = "10737418240"; | 198 | mailbox_size_limit = 10 * 1024 * 1024 * 1024; |
| 171 | # 10 GiB | ||
| 172 | mailbox_size_limit = "10737418240"; | ||
| 173 | 199 | ||
| 174 | smtpd_delay_reject = true; | 200 | smtpd_delay_reject = true; |
| 175 | smtpd_helo_required = true; | 201 | smtpd_helo_required = true; |
| @@ -184,25 +210,26 @@ in { | |||
| 184 | dbname = email | 210 | dbname = email |
| 185 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' | 211 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' |
| 186 | ''}" | 212 | ''}" |
| 187 | "check_ccert_access ${relay_ccert}" | ||
| 188 | "reject_non_fqdn_helo_hostname" | 213 | "reject_non_fqdn_helo_hostname" |
| 189 | "reject_invalid_helo_hostname" | 214 | "reject_invalid_helo_hostname" |
| 190 | "reject_unauth_destination" | 215 | "reject_unauth_destination" |
| 191 | "reject_unknown_recipient_domain" | 216 | "reject_unknown_recipient_domain" |
| 192 | "reject_unverified_recipient" | 217 | "reject_unverified_recipient" |
| 218 | "check_policy_service unix:/run/postfix-internal-policy.sock" | ||
| 193 | ]; | 219 | ]; |
| 194 | unverified_recipient_reject_code = "550"; | 220 | unverified_recipient_reject_code = "550"; |
| 195 | unverified_recipient_reject_reason = "Recipient address lookup failed"; | 221 | unverified_recipient_reject_reason = "Recipient address lookup failed"; |
| 196 | address_verify_map = "internal:address_verify_map"; | 222 | address_verify_map = "internal:address_verify_map"; |
| 197 | address_verify_positive_expire_time = "1h"; | 223 | address_verify_positive_expire_time = "1h"; |
| 198 | address_verify_positive_refresh_time = "15m"; | 224 | address_verify_positive_refresh_time = "15m"; |
| 199 | address_verify_negative_expire_time = "15s"; | 225 | address_verify_negative_expire_time = "5m"; |
| 200 | address_verify_negative_refresh_time = "5s"; | 226 | address_verify_negative_refresh_time = "1m"; |
| 201 | address_verify_cache_cleanup_interval = "5s"; | 227 | address_verify_cache_cleanup_interval = "12h"; |
| 228 | address_verify_poll_count = "\${stress?15}\${stress:30}"; | ||
| 202 | address_verify_poll_delay = "1s"; | 229 | address_verify_poll_delay = "1s"; |
| 230 | address_verify_sender_ttl = "30045s"; | ||
| 203 | 231 | ||
| 204 | smtpd_relay_restrictions = [ | 232 | smtpd_relay_restrictions = [ |
| 205 | "check_ccert_access ${relay_ccert}" | ||
| 206 | "reject_unauth_destination" | 233 | "reject_unauth_destination" |
| 207 | ]; | 234 | ]; |
| 208 | 235 | ||
| @@ -213,8 +240,8 @@ in { | |||
| 213 | smtpd_client_event_limit_exceptions = ""; | 240 | smtpd_client_event_limit_exceptions = ""; |
| 214 | 241 | ||
| 215 | milter_default_action = "accept"; | 242 | milter_default_action = "accept"; |
| 216 | smtpd_milters = [config.services.opendkim.socket "local:/run/rspamd/rspamd-milter.sock"]; | 243 | smtpd_milters = ["local:/run/rspamd/rspamd-milter.sock" "local:/run/postsrsd/postsrsd-milter.sock"]; |
| 217 | non_smtpd_milters = [config.services.opendkim.socket "local:/run/rspamd/rspamd-milter.sock"]; | 244 | non_smtpd_milters = ["local:/run/rspamd/rspamd-milter.sock"]; |
| 218 | 245 | ||
| 219 | alias_maps = ""; | 246 | alias_maps = ""; |
| 220 | 247 | ||
| @@ -225,6 +252,37 @@ in { | |||
| 225 | bounce_queue_lifetime = "20m"; | 252 | bounce_queue_lifetime = "20m"; |
| 226 | delay_warning_time = "10m"; | 253 | delay_warning_time = "10m"; |
| 227 | 254 | ||
| 255 | failure_template_file = toString (pkgs.writeText "failure.cf" '' | ||
| 256 | Charset: us-ascii | ||
| 257 | From: Mail Delivery System <MAILER-DAEMON> | ||
| 258 | Subject: Undelivered Mail Returned to Sender | ||
| 259 | Postmaster-Subject: Postmaster Copy: Undelivered Mail | ||
| 260 | |||
| 261 | This is the mail system at host $myhostname. | ||
| 262 | |||
| 263 | I'm sorry to have to inform you that your message could not | ||
| 264 | be delivered to one or more recipients. It's attached below. | ||
| 265 | |||
| 266 | The mail system | ||
| 267 | ''); | ||
| 268 | delay_template_file = toString (pkgs.writeText "delay.cf" '' | ||
| 269 | Charset: us-ascii | ||
| 270 | From: Mail Delivery System <MAILER-DAEMON> | ||
| 271 | Subject: Delayed Mail (still being retried) | ||
| 272 | Postmaster-Subject: Postmaster Warning: Delayed Mail | ||
| 273 | |||
| 274 | This is the mail system at host $myhostname. | ||
| 275 | |||
| 276 | #################################################################### | ||
| 277 | # THIS IS A WARNING ONLY. YOU DO NOT NEED TO RESEND YOUR MESSAGE. # | ||
| 278 | #################################################################### | ||
| 279 | |||
| 280 | Your message could not be delivered for more than $delay_warning_time_minutes minute(s). | ||
| 281 | It will be retried until it is $maximal_queue_lifetime_minutes minute(s) old. | ||
| 282 | |||
| 283 | The mail system | ||
| 284 | ''); | ||
| 285 | |||
| 228 | smtpd_discard_ehlo_keyword_address_maps = "cidr:${pkgs.writeText "esmtp_access" '' | 286 | smtpd_discard_ehlo_keyword_address_maps = "cidr:${pkgs.writeText "esmtp_access" '' |
| 229 | # Allow DSN requests from local subnet only | 287 | # Allow DSN requests from local subnet only |
| 230 | 192.168.0.0/16 silent-discard | 288 | 192.168.0.0/16 silent-discard |
| @@ -235,11 +293,6 @@ in { | |||
| 235 | ::/0 silent-discard, dsn | 293 | ::/0 silent-discard, dsn |
| 236 | ''}"; | 294 | ''}"; |
| 237 | 295 | ||
| 238 | sender_canonical_maps = "tcp:localhost:${toString config.services.postsrsd.forwardPort}"; | ||
| 239 | sender_canonical_classes = "envelope_sender"; | ||
| 240 | recipient_canonical_maps = "tcp:localhost:${toString config.services.postsrsd.reversePort}"; | ||
| 241 | recipient_canonical_classes = ["envelope_recipient" "header_recipient"]; | ||
| 242 | |||
| 243 | virtual_mailbox_domains = ''pgsql:${pkgs.writeText "virtual_mailbox_domains.cf" '' | 296 | virtual_mailbox_domains = ''pgsql:${pkgs.writeText "virtual_mailbox_domains.cf" '' |
| 244 | hosts = postgresql:///email | 297 | hosts = postgresql:///email |
| 245 | dbname = email | 298 | dbname = email |
| @@ -254,13 +307,26 @@ in { | |||
| 254 | virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp"; | 307 | virtual_transport = "dvlmtp:unix:/run/dovecot-lmtp"; |
| 255 | smtputf8_enable = false; | 308 | smtputf8_enable = false; |
| 256 | 309 | ||
| 257 | authorized_submit_users = "inline:{ root= postfwd= }"; | 310 | authorized_submit_users = "inline:{ root= postfwd= ${config.services.dovecot2.settings.mail_uid}= }"; |
| 311 | authorized_flush_users = "inline:{ root= }"; | ||
| 312 | authorized_mailq_users = "inline:{ root= }"; | ||
| 258 | 313 | ||
| 259 | postscreen_access_list = ""; | 314 | postscreen_access_list = ""; |
| 260 | postscreen_denylist_action = "drop"; | 315 | postscreen_denylist_action = "drop"; |
| 261 | postscreen_greet_action = "enforce"; | 316 | postscreen_greet_action = "enforce"; |
| 317 | |||
| 318 | sender_bcc_maps = ''pgsql:${pkgs.writeText "sender_bcc_maps.cf" '' | ||
| 319 | hosts = postgresql:///email | ||
| 320 | dbname = email | ||
| 321 | query = SELECT value FROM sender_bcc_maps WHERE key = '%s' | ||
| 322 | ''}''; | ||
| 323 | recipient_bcc_maps = ''pgsql:${pkgs.writeText "recipient_bcc_maps.cf" '' | ||
| 324 | hosts = postgresql:///email | ||
| 325 | dbname = email | ||
| 326 | query = SELECT value FROM recipient_bcc_maps WHERE key = '%s' | ||
| 327 | ''}''; | ||
| 262 | }; | 328 | }; |
| 263 | masterConfig = { | 329 | settings.master = { |
| 264 | "465" = { | 330 | "465" = { |
| 265 | type = "inet"; | 331 | type = "inet"; |
| 266 | private = false; | 332 | private = false; |
| @@ -283,13 +349,12 @@ in { | |||
| 283 | hosts = postgresql:///email | 349 | hosts = postgresql:///email |
| 284 | dbname = email | 350 | dbname = email |
| 285 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) | 351 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) |
| 286 | ''},permit_tls_all_clientcerts,reject}'' | 352 | ''},check_policy_service unix:/run/postfix-internal-policy.sock,permit_tls_all_clientcerts,reject}'' |
| 287 | "-o" "smtpd_relay_restrictions=permit_tls_all_clientcerts,reject" | 353 | "-o" "smtpd_relay_restrictions=permit_tls_all_clientcerts,reject" |
| 288 | "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" | 354 | "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" |
| 289 | "-o" "unverified_sender_reject_code=550" | 355 | "-o" "unverified_sender_reject_code=550" |
| 290 | "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}" | 356 | "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}" |
| 291 | "-o" "milter_macro_daemon_name=surtr.yggdrasil.li" | 357 | "-o" "milter_macro_daemon_name=surtr.yggdrasil.li" |
| 292 | "-o" ''smtpd_milters=${config.services.opendkim.socket}'' | ||
| 293 | ]; | 358 | ]; |
| 294 | }; | 359 | }; |
| 295 | "466" = { | 360 | "466" = { |
| @@ -313,13 +378,12 @@ in { | |||
| 313 | hosts = postgresql:///email | 378 | hosts = postgresql:///email |
| 314 | dbname = email | 379 | dbname = email |
| 315 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) | 380 | query = SELECT action FROM virtual_mailbox_access WHERE lookup = '%s' OR (lookup = regexp_replace('%s', '\+[^@]*@', '@') AND NOT EXISTS (SELECT 1 FROM virtual_mailbox_access WHERE lookup = '%s')) |
| 316 | ''},permit_sasl_authenticated,reject}'' | 381 | ''},check_policy_service unix:/run/postfix-internal-policy.sock,permit_sasl_authenticated,reject}'' |
| 317 | "-o" "smtpd_relay_restrictions=permit_sasl_authenticated,reject" | 382 | "-o" "smtpd_relay_restrictions=permit_sasl_authenticated,reject" |
| 318 | "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" | 383 | "-o" "{smtpd_data_restrictions = check_policy_service unix:/run/postfwd3/postfwd3.sock}" |
| 319 | "-o" "unverified_sender_reject_code=550" | 384 | "-o" "unverified_sender_reject_code=550" |
| 320 | "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}" | 385 | "-o" "unverified_sender_reject_reason={Sender address rejected: undeliverable address}" |
| 321 | "-o" "milter_macro_daemon_name=surtr.yggdrasil.li" | 386 | "-o" "milter_macro_daemon_name=surtr.yggdrasil.li" |
| 322 | "-o" ''smtpd_milters=${config.services.opendkim.socket}'' | ||
| 323 | ]; | 387 | ]; |
| 324 | }; | 388 | }; |
| 325 | subcleanup = { | 389 | subcleanup = { |
| @@ -328,7 +392,10 @@ in { | |||
| 328 | maxproc = 0; | 392 | maxproc = 0; |
| 329 | args = [ | 393 | args = [ |
| 330 | "-o" "header_checks=pcre:${pkgs.writeText "header_checks_submission" '' | 394 | "-o" "header_checks=pcre:${pkgs.writeText "header_checks_submission" '' |
| 395 | if /^Received: / | ||
| 396 | !/by surtr\.yggdrasil\.li/ STRIP | ||
| 331 | /^Received: from [^ ]+ \([^ ]+ [^ ]+\)\s+(.*)$/ REPLACE Received: $1 | 397 | /^Received: from [^ ]+ \([^ ]+ [^ ]+\)\s+(.*)$/ REPLACE Received: $1 |
| 398 | endif | ||
| 332 | ''}" | 399 | ''}" |
| 333 | ]; | 400 | ]; |
| 334 | }; | 401 | }; |
| @@ -364,23 +431,11 @@ in { | |||
| 364 | 431 | ||
| 365 | services.postsrsd = { | 432 | services.postsrsd = { |
| 366 | enable = true; | 433 | enable = true; |
| 367 | domain = "surtr.yggdrasil.li"; | 434 | domains = [ "surtr.yggdrasil.li" ] ++ concatMap (domain: [".${domain}" domain]) emailDomains; |
| 368 | separator = "+"; | 435 | separator = "+"; |
| 369 | excludeDomains = [ "surtr.yggdrasil.li" | 436 | extraConfig = '' |
| 370 | ] ++ concatMap (domain: [".${domain}" domain]) emailDomains; | 437 | socketmap = unix:/run/postsrsd/postsrsd-socketmap.sock |
| 371 | }; | 438 | milter = unix:/run/postsrsd/postsrsd-milter.sock |
| 372 | |||
| 373 | services.opendkim = { | ||
| 374 | enable = true; | ||
| 375 | user = "postfix"; group = "postfix"; | ||
| 376 | socket = "local:/run/opendkim/opendkim.sock"; | ||
| 377 | domains = ''csl:${concatStringsSep "," (["surtr.yggdrasil.li"] ++ emailDomains)}''; | ||
| 378 | selector = "surtr"; | ||
| 379 | configFile = builtins.toFile "opendkim.conf" '' | ||
| 380 | Syslog true | ||
| 381 | MTA surtr.yggdrasil.li | ||
| 382 | MTACommand ${config.security.wrapperDir}/sendmail | ||
| 383 | LogResults true | ||
| 384 | ''; | 439 | ''; |
| 385 | }; | 440 | }; |
| 386 | 441 | ||
| @@ -415,6 +470,8 @@ in { | |||
| 415 | milter = yes; | 470 | milter = yes; |
| 416 | timeout = 120s; | 471 | timeout = 120s; |
| 417 | 472 | ||
| 473 | client_ca_name = "yggdrasil.li"; | ||
| 474 | |||
| 418 | upstream "local" { | 475 | upstream "local" { |
| 419 | default = yes; | 476 | default = yes; |
| 420 | self_scan = yes; | 477 | self_scan = yes; |
| @@ -451,7 +508,13 @@ in { | |||
| 451 | "redis.conf".text = '' | 508 | "redis.conf".text = '' |
| 452 | servers = "${config.services.redis.servers.rspamd.unixSocket}"; | 509 | servers = "${config.services.redis.servers.rspamd.unixSocket}"; |
| 453 | ''; | 510 | ''; |
| 454 | "dkim_signing.conf".text = "enabled = false;"; | 511 | "dkim_signing.conf".text = '' |
| 512 | enabled = true; | ||
| 513 | allow_username_mismatch = true; | ||
| 514 | |||
| 515 | path = "/var/lib/rspamd/dkim/$domain.key"; | ||
| 516 | selector = "mail"; | ||
| 517 | ''; | ||
| 455 | "neural.conf".text = "enabled = false;"; | 518 | "neural.conf".text = "enabled = false;"; |
| 456 | "classifier-bayes.conf".text = '' | 519 | "classifier-bayes.conf".text = '' |
| 457 | enable = true; | 520 | enable = true; |
| @@ -472,242 +535,225 @@ in { | |||
| 472 | spam = true; | 535 | spam = true; |
| 473 | } | 536 | } |
| 474 | ''; | 537 | ''; |
| 538 | "logging.inc".text = '' | ||
| 539 | debug_modules = ["milter", "dkim_signing"]; | ||
| 540 | ''; | ||
| 475 | # "redirectors.inc".text = '' | 541 | # "redirectors.inc".text = '' |
| 476 | # visit.creeper.host | 542 | # visit.creeper.host |
| 477 | # ''; | 543 | # ''; |
| 478 | }; | 544 | }; |
| 479 | }; | 545 | }; |
| 480 | 546 | ||
| 481 | users.groups.${config.services.rspamd.group}.members = [ config.services.postfix.user "dovecot2" ]; | 547 | users.groups.${config.services.rspamd.group}.members = [ config.services.postfix.user config.services.dovecot2.settings.mail_uid ]; |
| 482 | 548 | ||
| 483 | services.redis.servers.rspamd.enable = true; | 549 | services.redis.servers.rspamd.enable = true; |
| 484 | 550 | ||
| 485 | users.groups.${config.services.redis.servers.rspamd.user}.members = [ config.services.rspamd.user ]; | 551 | users.groups.${config.services.redis.servers.rspamd.user}.members = [ config.services.rspamd.user ]; |
| 486 | 552 | ||
| 553 | environment.systemPackages = with pkgs; [ dovecot_pigeonhole ]; | ||
| 487 | services.dovecot2 = { | 554 | services.dovecot2 = { |
| 555 | package = pkgs.dovecot; | ||
| 488 | enable = true; | 556 | enable = true; |
| 489 | enablePAM = false; | 557 | enablePAM = false; |
| 490 | sslServerCert = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.pem"; | 558 | settings = { |
| 491 | sslServerKey = "/run/credentials/dovecot2.service/surtr.yggdrasil.li.key.pem"; | 559 | dovecot_config_version = "2.4.2"; |
| 492 | sslCACert = toString ./ca/ca.crt; | 560 | dovecot_storage_version = "2.4.0"; |
| 493 | mailLocation = "maildir:/var/lib/mail/%u/maildir:UTF-8:INDEX=/var/lib/dovecot/indices/%u"; | ||
| 494 | modules = with pkgs; [ dovecot_pigeonhole dovecot_fts_xapian ]; | ||
| 495 | mailPlugins.globally.enable = [ "fts" "fts_xapian" ]; | ||
| 496 | protocols = [ "lmtp" "sieve" ]; | ||
| 497 | sieve = { | ||
| 498 | extensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation"]; | ||
| 499 | globalExtensions = ["copy" "imapsieve" "variables" "imap4flags" "vacation"]; | ||
| 500 | }; | ||
| 501 | extraConfig = let | ||
| 502 | dovecotSqlConf = pkgs.writeText "dovecot-sql.conf" '' | ||
| 503 | driver = pgsql | ||
| 504 | connect = dbname=email | ||
| 505 | password_query = SELECT (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN NULL ELSE "password" END) as password, (CASE WHEN '%k' = 'valid' AND '%m' = 'EXTERNAL' THEN true WHEN password IS NULL THEN true ELSE NULL END) as nopassword, "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n' | ||
| 506 | user_query = SELECT "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM imap_user WHERE "user" = '%n' | ||
| 507 | iterate_query = SELECT "user" FROM imap_user | ||
| 508 | ''; | ||
| 509 | in '' | ||
| 510 | mail_home = /var/lib/mail/%u | ||
| 511 | |||
| 512 | mail_plugins = $mail_plugins quota | ||
| 513 | |||
| 514 | first_valid_uid = ${toString config.users.users.dovecot2.uid} | ||
| 515 | last_valid_uid = ${toString config.users.users.dovecot2.uid} | ||
| 516 | first_valid_gid = ${toString config.users.groups.dovecot2.gid} | ||
| 517 | last_valid_gid = ${toString config.users.groups.dovecot2.gid} | ||
| 518 | |||
| 519 | ${concatMapStringsSep "\n\n" (domain: | ||
| 520 | concatMapStringsSep "\n" (subdomain: '' | ||
| 521 | local_name ${subdomain} { | ||
| 522 | ssl_cert = </run/credentials/dovecot2.service/${subdomain}.pem | ||
| 523 | ssl_key = </run/credentials/dovecot2.service/${subdomain}.key.pem | ||
| 524 | } | ||
| 525 | '') ["imap.${domain}" domain] | ||
| 526 | ) emailDomains} | ||
| 527 | |||
| 528 | ssl_require_crl = no | ||
| 529 | ssl_verify_client_cert = yes | ||
| 530 | |||
| 531 | ssl_min_protocol = TLSv1.2 | ||
| 532 | ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384 | ||
| 533 | ssl_prefer_server_ciphers = no | ||
| 534 | |||
| 535 | auth_ssl_username_from_cert = yes | ||
| 536 | ssl_cert_username_field = commonName | ||
| 537 | auth_mechanisms = plain login external | ||
| 538 | |||
| 539 | auth_verbose = yes | ||
| 540 | verbose_ssl = yes | ||
| 541 | auth_debug = yes | ||
| 542 | |||
| 543 | service auth { | ||
| 544 | user = dovecot2 | ||
| 545 | } | ||
| 546 | service auth-worker { | ||
| 547 | user = dovecot2 | ||
| 548 | } | ||
| 549 | |||
| 550 | userdb { | ||
| 551 | driver = prefetch | ||
| 552 | } | ||
| 553 | userdb { | ||
| 554 | driver = sql | ||
| 555 | args = ${dovecotSqlConf} | ||
| 556 | } | ||
| 557 | passdb { | ||
| 558 | driver = sql | ||
| 559 | args = ${dovecotSqlConf} | ||
| 560 | } | ||
| 561 | 561 | ||
| 562 | protocol lmtp { | 562 | sql_driver = "pgsql"; |
| 563 | userdb { | 563 | "pgsql /run/postgresql".parameters = { |
| 564 | driver = sql | 564 | dbname = "email"; |
| 565 | args = ${pkgs.writeText "dovecot-sql.conf" '' | 565 | }; |
| 566 | driver = pgsql | ||
| 567 | connect = dbname=email | ||
| 568 | user_query = SELECT DISTINCT ON (extension IS NULL, local IS NULL) "user", quota_rule, 'dovecot2' as uid, 'dovecot2' as gid FROM lmtp_mapping WHERE CASE WHEN extension IS NOT NULL AND local IS NOT NULL THEN ('%n' :: citext) = local || '+' || extension AND domain = ('%d' :: citext) WHEN local IS NOT NULL THEN (local = ('%n' :: citext) OR ('%n' :: citext) ILIKE local || '+%%') AND domain = ('%d' :: citext) WHEN extension IS NOT NULL THEN ('%n' :: citext) ILIKE '%%+' || extension AND domain = ('%d' :: citext) ELSE domain = ('%d' :: citext) END ORDER BY (extension IS NULL) ASC, (local IS NULL) ASC | ||
| 569 | ''} | ||
| 570 | |||
| 571 | skip = never | ||
| 572 | result_failure = return-fail | ||
| 573 | result_internalfail = return-fail | ||
| 574 | } | ||
| 575 | |||
| 576 | mail_plugins = $mail_plugins sieve | ||
| 577 | } | ||
| 578 | 566 | ||
| 579 | mailbox_list_index = yes | 567 | protocols = { |
| 580 | postmaster_address = postmaster@yggdrasil.li | 568 | imap = true; |
| 581 | recipient_delimiter = | 569 | lmtp = true; |
| 582 | auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-+_@ | 570 | sieve = true; |
| 571 | }; | ||
| 583 | 572 | ||
| 584 | service lmtp { | 573 | mail_plugins = { |
| 585 | vsz_limit = 1G | 574 | quota = true; |
| 575 | fts = true; | ||
| 576 | fts_flatcurve = true; | ||
| 577 | }; | ||
| 586 | 578 | ||
| 587 | unix_listener /run/dovecot-lmtp { | 579 | mail_uid = "dovecot2"; |
| 588 | mode = 0600 | 580 | mail_gid = "dovecot2"; |
| 589 | user = postfix | 581 | |
| 590 | group = postfix | 582 | first_valid_uid = config.ids.uids.dovecot2; |
| 591 | } | 583 | last_valid_uid = config.ids.uids.dovecot2; |
| 592 | } | 584 | first_valid_gid = config.ids.gids.dovecot2; |
| 593 | service auth { | 585 | last_valid_gid = config.ids.gids.dovecot2; |
| 594 | vsz_limit = 2G | 586 | |
| 587 | mail_driver = "maildir"; | ||
| 588 | mail_path = "/var/lib/mail/%{user}/maildir"; | ||
| 589 | mail_index_path = "/var/lib/dovecot/indices/%{user}"; | ||
| 590 | ssl_server_ca_file = ./ca/ca.crt; | ||
| 591 | ssl_server_key_file = "/run/credentials/dovecot.service/surtr.yggdrasil.li.key.pem"; | ||
| 592 | ssl_server_cert_file = "/run/credentials/dovecot.service/surtr.yggdrasil.li.pem"; | ||
| 593 | |||
| 594 | mail_home = "/var/lib/mail/%{user}"; | ||
| 595 | |||
| 596 | ssl_server_require_crl = false; | ||
| 597 | ssl_server_request_client_cert = true; | ||
| 598 | |||
| 599 | ssl_min_protocol = "TLSv1.2"; | ||
| 600 | ssl_curve_list = "X25519MLKEM768:X25519"; | ||
| 601 | ssl_cipher_list = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305"; | ||
| 602 | |||
| 603 | auth_ssl_username_from_cert = "yes"; | ||
| 604 | ssl_server_cert_username_field = "commonName"; | ||
| 605 | auth_mechanisms = ["plain" "login" "external"]; | ||
| 606 | |||
| 607 | log_debug = "category=ssl OR category=auth"; | ||
| 608 | auth_verbose = true; | ||
| 609 | |||
| 610 | "service auth-worker".user = "$SET:default_internal_user"; | ||
| 611 | "userdb prefetch" = {}; | ||
| 612 | "userdb sql" = { | ||
| 613 | sql_query = "SELECT \"user\", quota_rule, '${config.services.dovecot2.settings.mail_uid}' as uid, 'dovecot2' as gid FROM imap_user WHERE \"user\" = '%{user | username}'"; | ||
| 614 | sql_iterate_query = "SELECT \"user\" FROM imap_user"; | ||
| 615 | fields = { | ||
| 616 | uid = "$SET:default_internal_user"; | ||
| 617 | gid = "$SET:default_internal_user"; | ||
| 618 | }; | ||
| 619 | }; | ||
| 620 | "passdb sql" = { | ||
| 621 | sql_query = '' | ||
| 622 | SELECT (CASE WHEN '%{cert}' = 'valid' AND '%{mechanism}' = 'EXTERNAL' THEN NULL ELSE "password" END) as password, (CASE WHEN '%{cert}' = 'valid' AND '%{mechanism}' = 'EXTERNAL' THEN true WHEN password IS NULL THEN true ELSE NULL END) as nopassword, "user", quota_rule, '${config.services.dovecot2.settings.mail_uid}' as uid, '${config.services.dovecot2.settings.mail_gid}' as gid FROM imap_user WHERE "user" = '%{user | username}' | ||
| 623 | ''; | ||
| 624 | }; | ||
| 595 | 625 | ||
| 596 | unix_listener /run/dovecot-sasl { | 626 | "protocol lmtp" = { |
| 597 | mode = 0600 | 627 | mail_plugins.sieve = true; |
| 598 | user = postfix | 628 | "userdb sql-lmtp" = { |
| 599 | group = postfix | 629 | driver = "sql"; |
| 600 | } | 630 | sql_query = '' |
| 601 | } | 631 | SELECT DISTINCT ON (extension IS NULL, local IS NULL) "user", quota_rule, '${config.services.dovecot2.settings.mail_uid}' as uid, '${config.services.dovecot2.settings.mail_gid}' as gid FROM lmtp_mapping WHERE CASE WHEN extension IS NOT NULL AND local IS NOT NULL THEN ('%{user | username}' :: citext) = local || '+' || extension AND domain = ('%{user | domain}' :: citext) WHEN local IS NOT NULL THEN (local = ('%{user | username}' :: citext) OR ('%{user | username}' :: citext) ILIKE local || '+%%') AND domain = ('%{user | domain}' :: citext) WHEN extension IS NOT NULL THEN ('%{user | username}' :: citext) ILIKE '%%+' || extension AND domain = ('%{user | domain}' :: citext) ELSE domain = ('%{user | domain}' :: citext) END ORDER BY (extension IS NULL) ASC, (local IS NULL) ASC |
| 632 | ''; | ||
| 602 | 633 | ||
| 603 | namespace inbox { | 634 | skip = "never"; |
| 604 | separator = / | 635 | result_failure = "return-fail"; |
| 605 | inbox = yes | 636 | result_internalfail = "return-fail"; |
| 606 | prefix = | 637 | }; |
| 638 | }; | ||
| 607 | 639 | ||
| 608 | mailbox Trash { | 640 | mailbox_list_index = true; |
| 609 | auto = no | 641 | mailbox_list_utf8 = true; |
| 610 | special_use = \Trash | 642 | postmaster_address = "postmaster@yggdrasil.li"; |
| 611 | } | 643 | recipient_delimiter = null; |
| 612 | mailbox Junk { | 644 | auth_username_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-+_@"; |
| 613 | auto = no | ||
| 614 | special_use = \Junk | ||
| 615 | } | ||
| 616 | mailbox Drafts { | ||
| 617 | auto = no | ||
| 618 | special_use = \Drafts | ||
| 619 | } | ||
| 620 | mailbox Sent { | ||
| 621 | auto = subscribe | ||
| 622 | special_use = \Sent | ||
| 623 | } | ||
| 624 | mailbox "Sent Messages" { | ||
| 625 | auto = no | ||
| 626 | special_use = \Sent | ||
| 627 | } | ||
| 628 | } | ||
| 629 | 645 | ||
| 630 | plugin { | 646 | "service lmtp" = { |
| 631 | quota = count | 647 | vsz_limit = "1G"; |
| 632 | quota_rule = *:storage=1GB | ||
| 633 | quota_rule2 = Trash:storage=+10%% | ||
| 634 | quota_status_overquota = "552 5.2.2 Mailbox is full" | ||
| 635 | quota_status_success = DUNNO | ||
| 636 | quota_status_nouser = DUNNO | ||
| 637 | quota_grace = 10%% | ||
| 638 | quota_max_mail_size = ${config.services.postfix.config.message_size_limit} | ||
| 639 | quota_vsizes = yes | ||
| 640 | } | ||
| 641 | 648 | ||
| 642 | protocol imap { | 649 | "unix_listener /run/dovecot-lmtp" = { |
| 643 | mail_max_userip_connections = 50 | 650 | mode = "0600"; |
| 644 | mail_plugins = $mail_plugins imap_quota imap_sieve | 651 | user = "postfix"; |
| 645 | } | 652 | group = "postfix"; |
| 653 | }; | ||
| 654 | }; | ||
| 655 | "service auth" = { | ||
| 656 | vsz_limit = "2G"; | ||
| 646 | 657 | ||
| 647 | service imap-login { | 658 | "unix_listener /run/dovecot-sasl" = { |
| 648 | inet_listener imap { | 659 | mode = "0600"; |
| 649 | port = 0 | 660 | user = "postfix"; |
| 650 | } | 661 | group = "postfix"; |
| 651 | } | 662 | }; |
| 663 | }; | ||
| 652 | 664 | ||
| 653 | service managesieve-login { | 665 | quota_storage_size = "1G"; |
| 654 | inet_listener sieve { | 666 | "namespace inbox" = { |
| 655 | port = 4190 | 667 | separator = "/"; |
| 656 | } | 668 | inbox = true; |
| 657 | } | ||
| 658 | 669 | ||
| 659 | plugin { | 670 | "mailbox Trash" = { |
| 660 | sieve_plugins = sieve_imapsieve sieve_extprograms | 671 | auto = false; |
| 661 | sieve = file:~/sieve;active=~/dovecot.sieve | 672 | special_use = "\\Trash"; |
| 662 | sieve_redirect_envelope_from = orig_recipient | 673 | quota_storage_percentage = "110"; |
| 663 | sieve_before = /etc/dovecot/sieve_before.d | 674 | }; |
| 675 | "mailbox Junk" = { | ||
| 676 | auto = false; | ||
| 677 | special_use = "\\Junk"; | ||
| 678 | }; | ||
| 679 | "mailbox Drafts" = { | ||
| 680 | auto = false; | ||
| 681 | special_use = "\\Drafts"; | ||
| 682 | }; | ||
| 683 | "mailbox Sent" = { | ||
| 684 | auto = "subscribe"; | ||
| 685 | special_use = "\\Sent"; | ||
| 686 | }; | ||
| 687 | "mailbox \"Sent Messages\"" = { | ||
| 688 | auto = false; | ||
| 689 | special_use = "\\Sent"; | ||
| 690 | }; | ||
| 691 | }; | ||
| 664 | 692 | ||
| 665 | sieve_global_extensions = +vnd.dovecot.pipe +vnd.dovecot.environment | 693 | quota_status_overquota = "552 5.2.2 Mailbox is full"; |
| 666 | sieve_pipe_bin_dir = ${dovecotSievePipeBin}/pipe/bin | 694 | quota_status_success = "DUNNO"; |
| 695 | quota_status_nouser = "DUNNO"; | ||
| 696 | quota_storage_grace = "100M"; | ||
| 697 | quota_mail_size = 10 * 1024 * 1024 * 1024; | ||
| 667 | 698 | ||
| 668 | imapsieve_mailbox1_name = * | 699 | sieve_plugins = { |
| 669 | imapsieve_mailbox1_causes = FLAG | 700 | "sieve_imapsieve" = true; |
| 670 | imapsieve_mailbox1_before = /etc/dovecot/sieve_flag.d/learn-junk.sieve | 701 | "sieve_extprograms" = true; |
| 671 | } | 702 | }; |
| 703 | sieve_redirect_envelope_from = "orig_recipient"; | ||
| 704 | sieve_extensions = { | ||
| 705 | imapsieve = true; | ||
| 706 | vacation-seconds = true; | ||
| 707 | "vnd.dovecot.debug" = true; | ||
| 708 | }; | ||
| 709 | sieve_global_extensions = { | ||
| 710 | "vnd.dovecot.pipe" = true; | ||
| 711 | "vnd.dovecot.environment" = true; | ||
| 712 | }; | ||
| 713 | sieve_pipe_bin_dir = "${dovecotSievePipeBin}/pipe/bin"; | ||
| 672 | 714 | ||
| 673 | plugin { | 715 | "sieve_script before" = { |
| 674 | plugin = fts fts_xapian | 716 | type = "before"; |
| 675 | fts = xapian | 717 | path = "/etc/dovecot/sieve_before.d"; |
| 676 | fts_xapian = partial=2 full=20 attachments=1 verbose=1 | 718 | }; |
| 719 | "sieve_script flag" = { | ||
| 720 | type = "before"; | ||
| 721 | cause.flag = true; | ||
| 722 | path = "/etc/dovecot/sieve_flag.d"; | ||
| 723 | }; | ||
| 724 | "sieve_script personal" = { | ||
| 725 | driver = "file"; | ||
| 726 | path = "~/sieve"; | ||
| 727 | active_path = "~/dovecot.sieve"; | ||
| 728 | }; | ||
| 677 | 729 | ||
| 678 | fts_autoindex = yes | 730 | "fts flatcurve" = { |
| 731 | autoindex = true; | ||
| 732 | }; | ||
| 733 | language_tokenizers = ["generic" "email-address"]; | ||
| 734 | language_filters = ["normalizer-icu" "snowball" "stopwords"]; | ||
| 735 | "language en" = { | ||
| 736 | default = true; | ||
| 737 | filters = ["lowercase" "snowball" "stopwords"]; | ||
| 738 | }; | ||
| 739 | "language de" = {}; | ||
| 679 | 740 | ||
| 680 | fts_enforced = no | 741 | "protocol imap" = { |
| 681 | } | 742 | mail_max_userip_connections = 50; |
| 743 | mail_plugins = { | ||
| 744 | imap_quota = true; | ||
| 745 | imap_sieve = true; | ||
| 746 | }; | ||
| 747 | }; | ||
| 682 | 748 | ||
| 683 | service indexer-worker { | 749 | "service imap-login"."inet_listener imap".port = 0; |
| 684 | vsz_limit = ${toString (1024 * 1024 * 1024)} | 750 | "service managesieve-login"."inet_listener sieve".port = 4190; |
| 685 | } | ||
| 686 | ''; | ||
| 687 | }; | ||
| 688 | 751 | ||
| 689 | systemd.services.dovecot-fts-xapian-optimize = { | 752 | "service indexer-worker".vsz_limit = 1024 * 1024 * 1024; |
| 690 | description = "Optimize dovecot indices for fts_xapian"; | 753 | } // (genAttrs' (concatMap (domain: ["imap.${domain}" domain]) emailDomains) (subdomain: nameValuePair "local_name ${subdomain}" { |
| 691 | requisite = [ "dovecot2.service" ]; | 754 | ssl_server_key_file = "/run/credentials/dovecot.service/${subdomain}.key.pem"; |
| 692 | after = [ "dovecot2.service" ]; | 755 | ssl_server_cert_file = "/run/credentials/dovecot.service/${subdomain}.pem"; |
| 693 | startAt = "*-*-* 22:00:00 Europe/Berlin"; | 756 | })); |
| 694 | serviceConfig = { | ||
| 695 | Type = "oneshot"; | ||
| 696 | ExecStart = "${pkgs.dovecot}/bin/doveadm fts optimize -A"; | ||
| 697 | PrivateDevices = true; | ||
| 698 | PrivateNetwork = true; | ||
| 699 | ProtectKernelTunables = true; | ||
| 700 | ProtectKernelModules = true; | ||
| 701 | ProtectControlGroups = true; | ||
| 702 | ProtectHome = true; | ||
| 703 | ProtectSystem = true; | ||
| 704 | PrivateTmp = true; | ||
| 705 | }; | ||
| 706 | }; | ||
| 707 | systemd.timers.dovecot-fts-xapian-optimize = { | ||
| 708 | timerConfig = { | ||
| 709 | RandomizedDelaySec = 4 * 3600; | ||
| 710 | }; | ||
| 711 | }; | 757 | }; |
| 712 | 758 | ||
| 713 | environment.etc = { | 759 | environment.etc = { |
| @@ -742,46 +788,31 @@ in { | |||
| 742 | ''; | 788 | ''; |
| 743 | }; | 789 | }; |
| 744 | 790 | ||
| 745 | security.dhparams = { | ||
| 746 | params = { | ||
| 747 | "postfix-512".bits = 512; | ||
| 748 | "postfix-1024".bits = 2048; | ||
| 749 | |||
| 750 | "postfix-smtps-512".bits = 512; | ||
| 751 | "postfix-smtps-1024".bits = 2048; | ||
| 752 | }; | ||
| 753 | }; | ||
| 754 | |||
| 755 | security.acme.rfc2136Domains = { | 791 | security.acme.rfc2136Domains = { |
| 756 | "surtr.yggdrasil.li" = { | 792 | "surtr.yggdrasil.li" = { |
| 757 | restartUnits = [ "postfix.service" "dovecot2.service" ]; | 793 | restartUnits = [ "postfix.service" "dovecot.service" ]; |
| 794 | }; | ||
| 795 | "pw.bouncy.email" = { | ||
| 796 | restartUnits = [ "nginx.service" ]; | ||
| 758 | }; | 797 | }; |
| 759 | } // listToAttrs (map (domain: nameValuePair "spm.${domain}" { restartUnits = ["nginx.service"]; }) spmDomains) | 798 | } // listToAttrs (map (domain: nameValuePair "spm.${domain}" { restartUnits = ["nginx.service"]; }) spmDomains) |
| 760 | // listToAttrs (concatMap (domain: [ | 799 | // listToAttrs (concatMap (domain: [ |
| 761 | (nameValuePair domain { restartUnits = ["postfix.service" "dovecot2.service"]; }) | 800 | (nameValuePair domain { restartUnits = ["postfix.service" "dovecot.service"]; }) |
| 762 | (nameValuePair "mailin.${domain}" { restartUnits = ["postfix.service"]; }) | 801 | (nameValuePair "mailin.${domain}" { restartUnits = ["postfix.service"]; }) |
| 763 | (nameValuePair "mailsub.${domain}" { restartUnits = ["postfix.service"]; }) | 802 | (nameValuePair "mailsub.${domain}" { restartUnits = ["postfix.service"]; }) |
| 764 | (nameValuePair "imap.${domain}" { restartUnits = ["dovecot2.service"]; }) | 803 | (nameValuePair "imap.${domain}" { restartUnits = ["dovecot.service"]; }) |
| 765 | (nameValuePair "mta-sts.${domain}" { restartUnits = ["nginx.service"]; }) | 804 | (nameValuePair "mta-sts.${domain}" { restartUnits = ["nginx.service"]; }) |
| 766 | ]) emailDomains); | 805 | ]) emailDomains); |
| 767 | 806 | ||
| 768 | systemd.services.postfix = { | 807 | systemd.services.postfix = { |
| 769 | serviceConfig.LoadCredential = [ | 808 | serviceConfig.LoadCredential = let |
| 770 | "surtr.yggdrasil.li.key.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/key.pem" | 809 | tlsCredential = domain: "${domain}.full.pem:${config.security.acme.certs.${domain}.directory}/full.pem"; |
| 771 | "surtr.yggdrasil.li.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/fullchain.pem" | 810 | in [ |
| 772 | ] ++ concatMap (domain: | 811 | (tlsCredential "surtr.yggdrasil.li") |
| 773 | map (subdomain: "${subdomain}.full.pem:${config.security.acme.certs.${subdomain}.directory}/full.pem") | 812 | ] ++ concatMap (domain: map tlsCredential [domain "mailin.${domain}" "mailsub.${domain}"]) emailDomains; |
| 774 | [domain "mailin.${domain}" "mailsub.${domain}"] | ||
| 775 | ) emailDomains; | ||
| 776 | }; | 813 | }; |
| 777 | 814 | ||
| 778 | systemd.services.dovecot2 = { | 815 | systemd.services.dovecot = { |
| 779 | preStart = '' | ||
| 780 | for f in /etc/dovecot/sieve_flag.d/*.sieve /etc/dovecot/sieve_before.d/*.sieve; do | ||
| 781 | ${pkgs.dovecot_pigeonhole}/bin/sievec $f | ||
| 782 | done | ||
| 783 | ''; | ||
| 784 | |||
| 785 | serviceConfig = { | 816 | serviceConfig = { |
| 786 | LoadCredential = [ | 817 | LoadCredential = [ |
| 787 | "surtr.yggdrasil.li.key.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/key.pem" | 818 | "surtr.yggdrasil.li.key.pem:${config.security.acme.certs."surtr.yggdrasil.li".directory}/key.pem" |
| @@ -802,6 +833,11 @@ in { | |||
| 802 | "unix:/run/spm/server.sock" = {}; | 833 | "unix:/run/spm/server.sock" = {}; |
| 803 | }; | 834 | }; |
| 804 | }; | 835 | }; |
| 836 | upstreams.password-server = { | ||
| 837 | servers = { | ||
| 838 | "unix:/run/email-password-server.sock" = {}; | ||
| 839 | }; | ||
| 840 | }; | ||
| 805 | 841 | ||
| 806 | virtualHosts = listToAttrs (map (domain: nameValuePair "spm.${domain}" { | 842 | virtualHosts = listToAttrs (map (domain: nameValuePair "spm.${domain}" { |
| 807 | forceSSL = true; | 843 | forceSSL = true; |
| @@ -845,17 +881,39 @@ in { | |||
| 845 | charset utf-8; | 881 | charset utf-8; |
| 846 | source_charset utf-8; | 882 | source_charset utf-8; |
| 847 | ''; | 883 | ''; |
| 848 | root = pkgs.runCommand "mta-sts.${domain}" {} '' | 884 | root = pkgs.writeTextFile { |
| 849 | mkdir -p $out/.well-known | 885 | name = "mta-sts.${domain}"; |
| 850 | cp ${pkgs.writeText "mta-sts.${domain}.txt" '' | 886 | destination = "/.well-known/mta-sts.txt"; |
| 887 | text = '' | ||
| 851 | version: STSv1 | 888 | version: STSv1 |
| 852 | mode: enforce | 889 | mode: enforce |
| 853 | max_age: 2419200 | 890 | max_age: 2419200 |
| 854 | mx: mailin.${domain} | 891 | mx: mailin.${domain} |
| 855 | ''} $out/.well-known/mta-sts.txt | 892 | ''; |
| 856 | ''; | 893 | }; |
| 857 | }; | 894 | }; |
| 858 | }) emailDomains); | 895 | }) emailDomains) // { |
| 896 | "pw.bouncy.email" = { | ||
| 897 | forceSSL = true; | ||
| 898 | kTLS = true; | ||
| 899 | http3 = false; | ||
| 900 | sslCertificate = "/run/credentials/nginx.service/pw.bouncy.email.pem"; | ||
| 901 | sslCertificateKey = "/run/credentials/nginx.service/pw.bouncy.email.key.pem"; | ||
| 902 | extraConfig = '' | ||
| 903 | ssl_stapling off; | ||
| 904 | ssl_verify_client optional; | ||
| 905 | ssl_client_certificate ${toString ./ca/ca.crt}; | ||
| 906 | ''; | ||
| 907 | locations."/" = { | ||
| 908 | proxyPass = "http://password-server"; | ||
| 909 | |||
| 910 | extraConfig = '' | ||
| 911 | proxy_set_header SSL-CLIENT-VERIFY $ssl_client_verify; | ||
| 912 | proxy_set_header SSL-CLIENT-S-DN $ssl_client_s_dn; | ||
| 913 | '';} | ||
| 914 | ; | ||
| 915 | }; | ||
| 916 | }; | ||
| 859 | }; | 917 | }; |
| 860 | 918 | ||
| 861 | systemd.services.nginx.serviceConfig.LoadCredential = concatMap (domain: [ | 919 | systemd.services.nginx.serviceConfig.LoadCredential = concatMap (domain: [ |
| @@ -865,12 +923,15 @@ in { | |||
| 865 | "mta-sts.${domain}.key.pem:${config.security.acme.certs."mta-sts.${domain}".directory}/key.pem" | 923 | "mta-sts.${domain}.key.pem:${config.security.acme.certs."mta-sts.${domain}".directory}/key.pem" |
| 866 | "mta-sts.${domain}.pem:${config.security.acme.certs."mta-sts.${domain}".directory}/fullchain.pem" | 924 | "mta-sts.${domain}.pem:${config.security.acme.certs."mta-sts.${domain}".directory}/fullchain.pem" |
| 867 | "mta-sts.${domain}.chain.pem:${config.security.acme.certs."mta-sts.${domain}".directory}/chain.pem" | 925 | "mta-sts.${domain}.chain.pem:${config.security.acme.certs."mta-sts.${domain}".directory}/chain.pem" |
| 868 | ]) emailDomains; | 926 | ]) emailDomains ++ [ |
| 927 | "pw.bouncy.email.key.pem:${config.security.acme.certs."pw.bouncy.email".directory}/key.pem" | ||
| 928 | "pw.bouncy.email.pem:${config.security.acme.certs."pw.bouncy.email".directory}/fullchain.pem" | ||
| 929 | ]; | ||
| 869 | 930 | ||
| 870 | systemd.services.spm = { | 931 | systemd.services.spm = { |
| 871 | serviceConfig = { | 932 | serviceConfig = { |
| 872 | Type = "notify"; | 933 | Type = "notify"; |
| 873 | ExecStart = "${pkgs.spm}/bin/spm-server"; | 934 | ExecStart = getExe' pkgs.spm "spm-server"; |
| 874 | User = "spm"; | 935 | User = "spm"; |
| 875 | Group = "spm"; | 936 | Group = "spm"; |
| 876 | 937 | ||
| @@ -928,7 +989,7 @@ in { | |||
| 928 | serviceConfig = { | 989 | serviceConfig = { |
| 929 | Type = "notify"; | 990 | Type = "notify"; |
| 930 | 991 | ||
| 931 | ExecStart = "${ccert-policy-server}/bin/ccert-policy-server"; | 992 | ExecStart = getExe' ccert-policy-server "ccert-policy-server"; |
| 932 | 993 | ||
| 933 | Environment = [ | 994 | Environment = [ |
| 934 | "PGDATABASE=email" | 995 | "PGDATABASE=email" |
| @@ -961,6 +1022,109 @@ in { | |||
| 961 | }; | 1022 | }; |
| 962 | users.groups."postfix-ccert-sender-policy" = {}; | 1023 | users.groups."postfix-ccert-sender-policy" = {}; |
| 963 | 1024 | ||
| 1025 | systemd.sockets."postfix-internal-policy" = { | ||
| 1026 | requiredBy = ["postfix.service"]; | ||
| 1027 | wants = ["postfix-internal-policy.service"]; | ||
| 1028 | socketConfig = { | ||
| 1029 | ListenStream = "/run/postfix-internal-policy.sock"; | ||
| 1030 | }; | ||
| 1031 | }; | ||
| 1032 | systemd.services."postfix-internal-policy" = { | ||
| 1033 | after = [ "postgresql.service" ]; | ||
| 1034 | bindsTo = [ "postgresql.service" ]; | ||
| 1035 | |||
| 1036 | serviceConfig = { | ||
| 1037 | Type = "notify"; | ||
| 1038 | |||
| 1039 | ExecStart = lib.getExe internal-policy-server; | ||
| 1040 | |||
| 1041 | Environment = [ | ||
| 1042 | "PGDATABASE=email" | ||
| 1043 | ]; | ||
| 1044 | |||
| 1045 | DynamicUser = false; | ||
| 1046 | User = "postfix-internal-policy"; | ||
| 1047 | Group = "postfix-internal-policy"; | ||
| 1048 | ProtectSystem = "strict"; | ||
| 1049 | SystemCallFilter = "@system-service"; | ||
| 1050 | NoNewPrivileges = true; | ||
| 1051 | ProtectKernelTunables = true; | ||
| 1052 | ProtectKernelModules = true; | ||
| 1053 | ProtectKernelLogs = true; | ||
| 1054 | ProtectControlGroups = true; | ||
| 1055 | MemoryDenyWriteExecute = true; | ||
| 1056 | RestrictSUIDSGID = true; | ||
| 1057 | KeyringMode = "private"; | ||
| 1058 | ProtectClock = true; | ||
| 1059 | RestrictRealtime = true; | ||
| 1060 | PrivateDevices = true; | ||
| 1061 | PrivateTmp = true; | ||
| 1062 | ProtectHostname = true; | ||
| 1063 | ReadWritePaths = ["/run/postgresql"]; | ||
| 1064 | }; | ||
| 1065 | }; | ||
| 1066 | users.users."postfix-internal-policy" = { | ||
| 1067 | isSystemUser = true; | ||
| 1068 | group = "postfix-internal-policy"; | ||
| 1069 | }; | ||
| 1070 | users.groups."postfix-internal-policy" = {}; | ||
| 1071 | |||
| 1072 | systemd.sockets."email-password-server" = { | ||
| 1073 | requiredBy = ["postfix.service"]; | ||
| 1074 | wants = ["email-password-server.service"]; | ||
| 1075 | socketConfig = { | ||
| 1076 | ListenStream = "/run/email-password-server.sock"; | ||
| 1077 | }; | ||
| 1078 | }; | ||
| 1079 | systemd.services."email-password-server" = { | ||
| 1080 | after = [ "postgresql.service" ]; | ||
| 1081 | bindsTo = [ "postgresql.service" ]; | ||
| 1082 | |||
| 1083 | serviceConfig = { | ||
| 1084 | Type = "notify"; | ||
| 1085 | |||
| 1086 | ExecStart = getExe' password-server "password-server"; | ||
| 1087 | |||
| 1088 | Environment = [ | ||
| 1089 | "PGDATABASE=email" | ||
| 1090 | ]; | ||
| 1091 | |||
| 1092 | LoadCredential = [ | ||
| 1093 | "secret:${config.sops.secrets."email-password-server-secret".path}" | ||
| 1094 | ]; | ||
| 1095 | |||
| 1096 | DynamicUser = false; | ||
| 1097 | User = "email-password-server"; | ||
| 1098 | Group = "email-password-server"; | ||
| 1099 | ProtectSystem = "strict"; | ||
| 1100 | SystemCallFilter = "@system-service"; | ||
| 1101 | NoNewPrivileges = true; | ||
| 1102 | ProtectKernelTunables = true; | ||
| 1103 | ProtectKernelModules = true; | ||
| 1104 | ProtectKernelLogs = true; | ||
| 1105 | ProtectControlGroups = true; | ||
| 1106 | MemoryDenyWriteExecute = true; | ||
| 1107 | RestrictSUIDSGID = true; | ||
| 1108 | KeyringMode = "private"; | ||
| 1109 | ProtectClock = true; | ||
| 1110 | RestrictRealtime = true; | ||
| 1111 | PrivateDevices = true; | ||
| 1112 | PrivateTmp = true; | ||
| 1113 | ProtectHostname = true; | ||
| 1114 | ReadWritePaths = ["/run/postgresql"]; | ||
| 1115 | }; | ||
| 1116 | }; | ||
| 1117 | users.users."email-password-server" = { | ||
| 1118 | isSystemUser = true; | ||
| 1119 | group = "email-password-server"; | ||
| 1120 | }; | ||
| 1121 | users.groups."email-password-server" = {}; | ||
| 1122 | sops.secrets."email-password-server-secret" = { | ||
| 1123 | format = "binary"; | ||
| 1124 | sopsFile = ./email-password-server-secret; | ||
| 1125 | }; | ||
| 1126 | |||
| 1127 | |||
| 964 | services.postfwd = { | 1128 | services.postfwd = { |
| 965 | enable = true; | 1129 | enable = true; |
| 966 | cache = false; | 1130 | cache = false; |
| @@ -994,7 +1158,7 @@ in { | |||
| 994 | wantedBy = [ "nftables.service" ]; | 1158 | wantedBy = [ "nftables.service" ]; |
| 995 | 1159 | ||
| 996 | timerConfig = { | 1160 | timerConfig = { |
| 997 | OnActiveSec = "20h"; | 1161 | OnCalendar = "4/8:00"; |
| 998 | RandomizedDelaySec = "8h"; | 1162 | RandomizedDelaySec = "8h"; |
| 999 | }; | 1163 | }; |
| 1000 | }; | 1164 | }; |
diff --git a/hosts/surtr/email/email-password-server-secret b/hosts/surtr/email/email-password-server-secret new file mode 100644 index 00000000..10c376ac --- /dev/null +++ b/hosts/surtr/email/email-password-server-secret | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:eQQWZ7AKptyarPz99drDjNC84/7hozMTW/ywlC7D4mDpbzEra7PeSH0PiOBF7uGi9xUf0EVLotJWCAmScFjzsTw=,iv:DKuItQbYFxYQRLRu8AKXFUu5wP3BXc/34UgawfQOuVk=,tag:60PK57Emw0P+RWVZ1UdVPA==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0YUVERm1xSlJtTVFOVG44\nNVJTNE02R3RNUndGZmI2QkJJenFGZVNWU0NZCll3djF3L2pwM2RhdTZtUnBrZTZ6\nSVBwV1JRNzRlcUZFNzEvYjVXeXlDczgKLS0tIERWNEUrRFlNc1MzMVBFWW5SVVZS\nejR5RFBhZEtUVTBHdEJ3M1ZwTnM2cjgKRdmRIsIIIWuLmjQ5NGbdxEkZ4xiJbSvO\nIWUQKzVxcaJQ+6r6IU+Y6+RH8ZoOTJR8jnuEQG0wSDdJflEzz08jsA==\n-----END AGE ENCRYPTED FILE-----\n", | ||
| 7 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHQlhDMmprcW1Mb1RadmZZ\nd0FjTU5KUTZaTW1aTzQ5T0JnZUNna09xYzFjCi85QkQwaWgvSjZ2MWdWSWJTQVhy\nNjAvQXBWc2FKTlhVczVrQUFDYW4rbFUKLS0tIE9FVldDSkwxVDIvSnpoOWFzakdD\nZ0NHZkpPVUNLdmMrUVFFTXREd0xaaFUKZ6vEWHM/oMG1hy0ilaersujGRkfzHobo\nBkmO7bCmdIHe0KEy9g5IebMzyImIa32V83733o2TMMKUqDVmIcFXvw==\n-----END AGE ENCRYPTED FILE-----\n", | ||
| 11 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2026-06-06T13:50:08Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:d0zMcf4lUvjkB0JBzEMCcOZu+3Ln9ll3AbCD9LUrDzWmxuX+j8htj4A6Ss3Ga34AF+KgMU8Cc8LPYwaVNM2StzkQL9sdOKfNFSk1OjLPrCeNDkf/Fl8EeJPqT6lW1bNsaIKX7NDLzYAWgCkwVFzDb9ijYP49GjUNIF+STIYIJfU=,iv:zf4dAqPhWXMaMpkuJzkeo6U0E+tOPt4zOgZ6ixEWfaI=,tag:Py8TvYToKYaKoVGA9uBQPQ==,type:str]", | ||
| 16 | "version": "3.13.1" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/email/internal-policy-server/.envrc b/hosts/surtr/email/internal-policy-server/.envrc new file mode 100644 index 00000000..2c909235 --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/.envrc | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | use flake | ||
| 2 | |||
| 3 | [[ -d ".venv" ]] || ( uv venv && uv sync ) | ||
| 4 | . .venv/bin/activate | ||
diff --git a/hosts/surtr/email/internal-policy-server/.gitignore b/hosts/surtr/email/internal-policy-server/.gitignore new file mode 100644 index 00000000..4ccfae70 --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/.gitignore | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | .venv | ||
| 2 | **/__pycache__ | ||
diff --git a/hosts/surtr/email/internal-policy-server/internal_policy_server/__init__.py b/hosts/surtr/email/internal-policy-server/internal_policy_server/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/internal_policy_server/__init__.py | |||
diff --git a/hosts/surtr/email/internal-policy-server/internal_policy_server/__main__.py b/hosts/surtr/email/internal-policy-server/internal_policy_server/__main__.py new file mode 100644 index 00000000..04f1a59a --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/internal_policy_server/__main__.py | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | from systemd.daemon import listen_fds | ||
| 2 | from sdnotify import SystemdNotifier | ||
| 3 | from socketserver import StreamRequestHandler, ThreadingMixIn | ||
| 4 | from systemd_socketserver import SystemdSocketServer | ||
| 5 | import sys | ||
| 6 | from threading import Thread | ||
| 7 | from psycopg_pool import ConnectionPool | ||
| 8 | from psycopg.rows import namedtuple_row | ||
| 9 | |||
| 10 | import logging | ||
| 11 | |||
| 12 | |||
| 13 | class PolicyHandler(StreamRequestHandler): | ||
| 14 | def handle(self): | ||
| 15 | logger.debug('Handling new connection...') | ||
| 16 | |||
| 17 | self.args = dict() | ||
| 18 | |||
| 19 | line = None | ||
| 20 | while line := self.rfile.readline().removesuffix(b'\n'): | ||
| 21 | if b'=' not in line: | ||
| 22 | break | ||
| 23 | |||
| 24 | key, val = line.split(sep=b'=', maxsplit=1) | ||
| 25 | self.args[key.decode()] = val.decode() | ||
| 26 | |||
| 27 | logger.info('Connection parameters: %s', self.args) | ||
| 28 | |||
| 29 | allowed = False | ||
| 30 | user = None | ||
| 31 | if self.args['sasl_username']: | ||
| 32 | user = self.args['sasl_username'] | ||
| 33 | if self.args['ccert_subject']: | ||
| 34 | user = self.args['ccert_subject'] | ||
| 35 | |||
| 36 | with self.server.db_pool.connection() as conn: | ||
| 37 | local, domain = self.args['recipient'].split(sep='@', maxsplit=1) | ||
| 38 | extension = None | ||
| 39 | if '+' in local: | ||
| 40 | local, extension = local.split(sep='+', maxsplit=1) | ||
| 41 | |||
| 42 | logger.debug('Parsed recipient address: %s', {'local': local, 'extension': extension, 'domain': domain}) | ||
| 43 | |||
| 44 | with conn.cursor() as cur: | ||
| 45 | cur.row_factory = namedtuple_row | ||
| 46 | cur.execute('SELECT id, internal FROM "mailbox_mapping" WHERE ("local" = %(local)s OR "local" IS NULL) AND ("extension" = %(extension)s OR "extension" IS NULL) AND "domain" = %(domain)s', params = {'local': local, 'extension': extension if extension is not None else '', 'domain': domain}, prepare = True) | ||
| 47 | if (row := cur.fetchone()) is not None: | ||
| 48 | if not row.internal: | ||
| 49 | logger.debug('Recipient mailbox is not internal') | ||
| 50 | allowed = True | ||
| 51 | elif user: | ||
| 52 | cur.execute('SELECT EXISTS(SELECT true FROM "mailbox_mapping_access" INNER JOIN "mailbox" ON "mailbox".id = "mailbox_mapping_access"."mailbox" WHERE mailbox_mapping = %(mailbox_mapping)s AND "mailbox"."mailbox" = %(user)s) as "exists"', params = { 'mailbox_mapping': row.id, 'user': user }, prepare = True) | ||
| 53 | if (row := cur.fetchone()) is not None: | ||
| 54 | allowed = row.exists | ||
| 55 | else: | ||
| 56 | logger.debug('Recipient is not local') | ||
| 57 | allowed = True | ||
| 58 | |||
| 59 | action = '550 5.7.0 Recipient mailbox mapping not authorized for current user' | ||
| 60 | if allowed: | ||
| 61 | action = 'DUNNO' | ||
| 62 | |||
| 63 | logger.info('Reached verdict: %s', {'allowed': allowed, 'action': action}) | ||
| 64 | self.wfile.write(f'action={action}\n\n'.encode()) | ||
| 65 | |||
| 66 | class ThreadedSystemdSocketServer(ThreadingMixIn, SystemdSocketServer): | ||
| 67 | def __init__(self, fd, RequestHandlerClass): | ||
| 68 | super().__init__(fd, RequestHandlerClass) | ||
| 69 | |||
| 70 | self.db_pool = ConnectionPool(min_size=1) | ||
| 71 | self.db_pool.wait() | ||
| 72 | |||
| 73 | def main(): | ||
| 74 | global logger | ||
| 75 | logger = logging.getLogger(__name__) | ||
| 76 | console_handler = logging.StreamHandler() | ||
| 77 | console_handler.setFormatter( logging.Formatter('[%(levelname)s](%(name)s): %(message)s') ) | ||
| 78 | if sys.stderr.isatty(): | ||
| 79 | console_handler.setFormatter( logging.Formatter('%(asctime)s [%(levelname)s](%(name)s): %(message)s') ) | ||
| 80 | logger.addHandler(console_handler) | ||
| 81 | logger.setLevel(logging.DEBUG) | ||
| 82 | |||
| 83 | # log uncaught exceptions | ||
| 84 | def log_exceptions(type, value, tb): | ||
| 85 | global logger | ||
| 86 | |||
| 87 | logger.error(value) | ||
| 88 | sys.__excepthook__(type, value, tb) # calls default excepthook | ||
| 89 | |||
| 90 | sys.excepthook = log_exceptions | ||
| 91 | |||
| 92 | fds = listen_fds() | ||
| 93 | servers = [ThreadedSystemdSocketServer(fd, PolicyHandler) for fd in fds] | ||
| 94 | |||
| 95 | if servers: | ||
| 96 | for server in servers: | ||
| 97 | Thread(name=f'Server for fd{server.fileno()}', target=server.serve_forever).start() | ||
| 98 | else: | ||
| 99 | return 2 | ||
| 100 | |||
| 101 | SystemdNotifier().notify('READY=1') | ||
| 102 | |||
| 103 | return 0 | ||
| 104 | |||
| 105 | if __name__ == '__main__': | ||
| 106 | sys.exit(main()) | ||
diff --git a/hosts/surtr/email/internal-policy-server/pyproject.toml b/hosts/surtr/email/internal-policy-server/pyproject.toml new file mode 100644 index 00000000..c697cd01 --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/pyproject.toml | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | [project] | ||
| 2 | name = "internal-policy-server" | ||
| 3 | version = "0.1.0" | ||
| 4 | requires-python = ">=3.12" | ||
| 5 | dependencies = [ | ||
| 6 | "psycopg>=3.2.9", | ||
| 7 | "psycopg-binary>=3.2.9", | ||
| 8 | "psycopg-pool>=3.2.6", | ||
| 9 | "sdnotify>=0.3.2", | ||
| 10 | "systemd-socketserver>=1.0", | ||
| 11 | ] | ||
| 12 | |||
| 13 | [project.scripts] | ||
| 14 | internal-policy-server = "internal_policy_server.__main__:main" | ||
| 15 | |||
| 16 | [build-system] | ||
| 17 | requires = ["hatchling"] | ||
| 18 | build-backend = "hatchling.build" | ||
diff --git a/hosts/surtr/email/internal-policy-server/uv.lock b/hosts/surtr/email/internal-policy-server/uv.lock new file mode 100644 index 00000000..f7a4e729 --- /dev/null +++ b/hosts/surtr/email/internal-policy-server/uv.lock | |||
| @@ -0,0 +1,119 @@ | |||
| 1 | version = 1 | ||
| 2 | revision = 2 | ||
| 3 | requires-python = ">=3.12" | ||
| 4 | |||
| 5 | [[package]] | ||
| 6 | name = "internal-policy-server" | ||
| 7 | version = "0.1.0" | ||
| 8 | source = { editable = "." } | ||
| 9 | dependencies = [ | ||
| 10 | { name = "psycopg" }, | ||
| 11 | { name = "psycopg-binary" }, | ||
| 12 | { name = "psycopg-pool" }, | ||
| 13 | { name = "sdnotify" }, | ||
| 14 | { name = "systemd-socketserver" }, | ||
| 15 | ] | ||
| 16 | |||
| 17 | [package.metadata] | ||
| 18 | requires-dist = [ | ||
| 19 | { name = "psycopg", specifier = ">=3.2.9" }, | ||
| 20 | { name = "psycopg-binary", specifier = ">=3.2.9" }, | ||
| 21 | { name = "psycopg-pool", specifier = ">=3.2.6" }, | ||
| 22 | { name = "sdnotify", specifier = ">=0.3.2" }, | ||
| 23 | { name = "systemd-socketserver", specifier = ">=1.0" }, | ||
| 24 | ] | ||
| 25 | |||
| 26 | [[package]] | ||
| 27 | name = "psycopg" | ||
| 28 | version = "3.2.9" | ||
| 29 | source = { registry = "https://pypi.org/simple" } | ||
| 30 | dependencies = [ | ||
| 31 | { name = "typing-extensions", marker = "python_full_version < '3.13'" }, | ||
| 32 | { name = "tzdata", marker = "sys_platform == 'win32'" }, | ||
| 33 | ] | ||
| 34 | sdist = { url = "https://files.pythonhosted.org/packages/27/4a/93a6ab570a8d1a4ad171a1f4256e205ce48d828781312c0bbaff36380ecb/psycopg-3.2.9.tar.gz", hash = "sha256:2fbb46fcd17bc81f993f28c47f1ebea38d66ae97cc2dbc3cad73b37cefbff700", size = 158122, upload-time = "2025-05-13T16:11:15.533Z" } | ||
| 35 | wheels = [ | ||
| 36 | { url = "https://files.pythonhosted.org/packages/44/b0/a73c195a56eb6b92e937a5ca58521a5c3346fb233345adc80fd3e2f542e2/psycopg-3.2.9-py3-none-any.whl", hash = "sha256:01a8dadccdaac2123c916208c96e06631641c0566b22005493f09663c7a8d3b6", size = 202705, upload-time = "2025-05-13T16:06:26.584Z" }, | ||
| 37 | ] | ||
| 38 | |||
| 39 | [[package]] | ||
| 40 | name = "psycopg-binary" | ||
| 41 | version = "3.2.9" | ||
| 42 | source = { registry = "https://pypi.org/simple" } | ||
| 43 | wheels = [ | ||
| 44 | { url = "https://files.pythonhosted.org/packages/29/6f/ec9957e37a606cd7564412e03f41f1b3c3637a5be018d0849914cb06e674/psycopg_binary-3.2.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:be7d650a434921a6b1ebe3fff324dbc2364393eb29d7672e638ce3e21076974e", size = 4022205, upload-time = "2025-05-13T16:07:48.195Z" }, | ||
| 45 | { url = "https://files.pythonhosted.org/packages/6b/ba/497b8bea72b20a862ac95a94386967b745a472d9ddc88bc3f32d5d5f0d43/psycopg_binary-3.2.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a76b4722a529390683c0304501f238b365a46b1e5fb6b7249dbc0ad6fea51a0", size = 4083795, upload-time = "2025-05-13T16:07:50.917Z" }, | ||
| 46 | { url = "https://files.pythonhosted.org/packages/42/07/af9503e8e8bdad3911fd88e10e6a29240f9feaa99f57d6fac4a18b16f5a0/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96a551e4683f1c307cfc3d9a05fec62c00a7264f320c9962a67a543e3ce0d8ff", size = 4655043, upload-time = "2025-05-13T16:07:54.857Z" }, | ||
| 47 | { url = "https://files.pythonhosted.org/packages/28/ed/aff8c9850df1648cc6a5cc7a381f11ee78d98a6b807edd4a5ae276ad60ad/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:61d0a6ceed8f08c75a395bc28cb648a81cf8dee75ba4650093ad1a24a51c8724", size = 4477972, upload-time = "2025-05-13T16:07:57.925Z" }, | ||
| 48 | { url = "https://files.pythonhosted.org/packages/5c/bd/8e9d1b77ec1a632818fe2f457c3a65af83c68710c4c162d6866947d08cc5/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad280bbd409bf598683dda82232f5215cfc5f2b1bf0854e409b4d0c44a113b1d", size = 4737516, upload-time = "2025-05-13T16:08:01.616Z" }, | ||
| 49 | { url = "https://files.pythonhosted.org/packages/46/ec/222238f774cd5a0881f3f3b18fb86daceae89cc410f91ef6a9fb4556f236/psycopg_binary-3.2.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76eddaf7fef1d0994e3d536ad48aa75034663d3a07f6f7e3e601105ae73aeff6", size = 4436160, upload-time = "2025-05-13T16:08:04.278Z" }, | ||
| 50 | { url = "https://files.pythonhosted.org/packages/37/78/af5af2a1b296eeca54ea7592cd19284739a844974c9747e516707e7b3b39/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:52e239cd66c4158e412318fbe028cd94b0ef21b0707f56dcb4bdc250ee58fd40", size = 3753518, upload-time = "2025-05-13T16:08:07.567Z" }, | ||
| 51 | { url = "https://files.pythonhosted.org/packages/ec/ac/8a3ed39ea069402e9e6e6a2f79d81a71879708b31cc3454283314994b1ae/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:08bf9d5eabba160dd4f6ad247cf12f229cc19d2458511cab2eb9647f42fa6795", size = 3313598, upload-time = "2025-05-13T16:08:09.999Z" }, | ||
| 52 | { url = "https://files.pythonhosted.org/packages/da/43/26549af068347c808fbfe5f07d2fa8cef747cfff7c695136172991d2378b/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1b2cf018168cad87580e67bdde38ff5e51511112f1ce6ce9a8336871f465c19a", size = 3407289, upload-time = "2025-05-13T16:08:12.66Z" }, | ||
| 53 | { url = "https://files.pythonhosted.org/packages/67/55/ea8d227c77df8e8aec880ded398316735add8fda5eb4ff5cc96fac11e964/psycopg_binary-3.2.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:14f64d1ac6942ff089fc7e926440f7a5ced062e2ed0949d7d2d680dc5c00e2d4", size = 3472493, upload-time = "2025-05-13T16:08:15.672Z" }, | ||
| 54 | { url = "https://files.pythonhosted.org/packages/3c/02/6ff2a5bc53c3cd653d281666728e29121149179c73fddefb1e437024c192/psycopg_binary-3.2.9-cp312-cp312-win_amd64.whl", hash = "sha256:7a838852e5afb6b4126f93eb409516a8c02a49b788f4df8b6469a40c2157fa21", size = 2927400, upload-time = "2025-05-13T16:08:18.652Z" }, | ||
| 55 | { url = "https://files.pythonhosted.org/packages/28/0b/f61ff4e9f23396aca674ed4d5c9a5b7323738021d5d72d36d8b865b3deaf/psycopg_binary-3.2.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:98bbe35b5ad24a782c7bf267596638d78aa0e87abc7837bdac5b2a2ab954179e", size = 4017127, upload-time = "2025-05-13T16:08:21.391Z" }, | ||
| 56 | { url = "https://files.pythonhosted.org/packages/bc/00/7e181fb1179fbfc24493738b61efd0453d4b70a0c4b12728e2b82db355fd/psycopg_binary-3.2.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:72691a1615ebb42da8b636c5ca9f2b71f266be9e172f66209a361c175b7842c5", size = 4080322, upload-time = "2025-05-13T16:08:24.049Z" }, | ||
| 57 | { url = "https://files.pythonhosted.org/packages/58/fd/94fc267c1d1392c4211e54ccb943be96ea4032e761573cf1047951887494/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25ab464bfba8c401f5536d5aa95f0ca1dd8257b5202eede04019b4415f491351", size = 4655097, upload-time = "2025-05-13T16:08:27.376Z" }, | ||
| 58 | { url = "https://files.pythonhosted.org/packages/41/17/31b3acf43de0b2ba83eac5878ff0dea5a608ca2a5c5dd48067999503a9de/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8aeefebe752f46e3c4b769e53f1d4ad71208fe1150975ef7662c22cca80fab", size = 4482114, upload-time = "2025-05-13T16:08:30.781Z" }, | ||
| 59 | { url = "https://files.pythonhosted.org/packages/85/78/b4d75e5fd5a85e17f2beb977abbba3389d11a4536b116205846b0e1cf744/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7e4e4dd177a8665c9ce86bc9caae2ab3aa9360b7ce7ec01827ea1baea9ff748", size = 4737693, upload-time = "2025-05-13T16:08:34.625Z" }, | ||
| 60 | { url = "https://files.pythonhosted.org/packages/3b/95/7325a8550e3388b00b5e54f4ced5e7346b531eb4573bf054c3dbbfdc14fe/psycopg_binary-3.2.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fc2915949e5c1ea27a851f7a472a7da7d0a40d679f0a31e42f1022f3c562e87", size = 4437423, upload-time = "2025-05-13T16:08:37.444Z" }, | ||
| 61 | { url = "https://files.pythonhosted.org/packages/1a/db/cef77d08e59910d483df4ee6da8af51c03bb597f500f1fe818f0f3b925d3/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a1fa38a4687b14f517f049477178093c39c2a10fdcced21116f47c017516498f", size = 3758667, upload-time = "2025-05-13T16:08:40.116Z" }, | ||
| 62 | { url = "https://files.pythonhosted.org/packages/95/3e/252fcbffb47189aa84d723b54682e1bb6d05c8875fa50ce1ada914ae6e28/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5be8292d07a3ab828dc95b5ee6b69ca0a5b2e579a577b39671f4f5b47116dfd2", size = 3320576, upload-time = "2025-05-13T16:08:43.243Z" }, | ||
| 63 | { url = "https://files.pythonhosted.org/packages/1c/cd/9b5583936515d085a1bec32b45289ceb53b80d9ce1cea0fef4c782dc41a7/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:778588ca9897b6c6bab39b0d3034efff4c5438f5e3bd52fda3914175498202f9", size = 3411439, upload-time = "2025-05-13T16:08:47.321Z" }, | ||
| 64 | { url = "https://files.pythonhosted.org/packages/45/6b/6f1164ea1634c87956cdb6db759e0b8c5827f989ee3cdff0f5c70e8331f2/psycopg_binary-3.2.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f0d5b3af045a187aedbd7ed5fc513bd933a97aaff78e61c3745b330792c4345b", size = 3477477, upload-time = "2025-05-13T16:08:51.166Z" }, | ||
| 65 | { url = "https://files.pythonhosted.org/packages/7b/1d/bf54cfec79377929da600c16114f0da77a5f1670f45e0c3af9fcd36879bc/psycopg_binary-3.2.9-cp313-cp313-win_amd64.whl", hash = "sha256:2290bc146a1b6a9730350f695e8b670e1d1feb8446597bed0bbe7c3c30e0abcb", size = 2928009, upload-time = "2025-05-13T16:08:53.67Z" }, | ||
| 66 | ] | ||
| 67 | |||
| 68 | [[package]] | ||
| 69 | name = "psycopg-pool" | ||
| 70 | version = "3.2.6" | ||
| 71 | source = { registry = "https://pypi.org/simple" } | ||
| 72 | dependencies = [ | ||
| 73 | { name = "typing-extensions" }, | ||
| 74 | ] | ||
| 75 | sdist = { url = "https://files.pythonhosted.org/packages/cf/13/1e7850bb2c69a63267c3dbf37387d3f71a00fd0e2fa55c5db14d64ba1af4/psycopg_pool-3.2.6.tar.gz", hash = "sha256:0f92a7817719517212fbfe2fd58b8c35c1850cdd2a80d36b581ba2085d9148e5", size = 29770, upload-time = "2025-02-26T12:03:47.129Z" } | ||
| 76 | wheels = [ | ||
| 77 | { url = "https://files.pythonhosted.org/packages/47/fd/4feb52a55c1a4bd748f2acaed1903ab54a723c47f6d0242780f4d97104d4/psycopg_pool-3.2.6-py3-none-any.whl", hash = "sha256:5887318a9f6af906d041a0b1dc1c60f8f0dda8340c2572b74e10907b51ed5da7", size = 38252, upload-time = "2025-02-26T12:03:45.073Z" }, | ||
| 78 | ] | ||
| 79 | |||
| 80 | [[package]] | ||
| 81 | name = "sdnotify" | ||
| 82 | version = "0.3.2" | ||
| 83 | source = { registry = "https://pypi.org/simple" } | ||
| 84 | sdist = { url = "https://files.pythonhosted.org/packages/ce/d8/9fdc36b2a912bf78106de4b3f0de3891ff8f369e7a6f80be842b8b0b6bd5/sdnotify-0.3.2.tar.gz", hash = "sha256:73977fc746b36cc41184dd43c3fe81323e7b8b06c2bb0826c4f59a20c56bb9f1", size = 2459, upload-time = "2017-08-02T20:03:44.395Z" } | ||
| 85 | |||
| 86 | [[package]] | ||
| 87 | name = "systemd-python" | ||
| 88 | version = "235" | ||
| 89 | source = { registry = "https://pypi.org/simple" } | ||
| 90 | sdist = { url = "https://files.pythonhosted.org/packages/10/9e/ab4458e00367223bda2dd7ccf0849a72235ee3e29b36dce732685d9b7ad9/systemd-python-235.tar.gz", hash = "sha256:4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a", size = 61677, upload-time = "2023-02-11T13:42:16.588Z" } | ||
| 91 | |||
| 92 | [[package]] | ||
| 93 | name = "systemd-socketserver" | ||
| 94 | version = "1.0" | ||
| 95 | source = { registry = "https://pypi.org/simple" } | ||
| 96 | dependencies = [ | ||
| 97 | { name = "systemd-python" }, | ||
| 98 | ] | ||
| 99 | wheels = [ | ||
| 100 | { url = "https://files.pythonhosted.org/packages/d8/4f/b28b7f08880120a26669b080ca74487c8c67e8b54dcb0467a8f0c9f38ed6/systemd_socketserver-1.0-py3-none-any.whl", hash = "sha256:987a8bfbf28d959e7c2966c742ad7bad482f05e121077defcf95bb38267db9a8", size = 3248, upload-time = "2020-04-26T05:26:40.661Z" }, | ||
| 101 | ] | ||
| 102 | |||
| 103 | [[package]] | ||
| 104 | name = "typing-extensions" | ||
| 105 | version = "4.13.2" | ||
| 106 | source = { registry = "https://pypi.org/simple" } | ||
| 107 | sdist = { url = "https://files.pythonhosted.org/packages/f6/37/23083fcd6e35492953e8d2aaaa68b860eb422b34627b13f2ce3eb6106061/typing_extensions-4.13.2.tar.gz", hash = "sha256:e6c81219bd689f51865d9e372991c540bda33a0379d5573cddb9a3a23f7caaef", size = 106967, upload-time = "2025-04-10T14:19:05.416Z" } | ||
| 108 | wheels = [ | ||
| 109 | { url = "https://files.pythonhosted.org/packages/8b/54/b1ae86c0973cc6f0210b53d508ca3641fb6d0c56823f288d108bc7ab3cc8/typing_extensions-4.13.2-py3-none-any.whl", hash = "sha256:a439e7c04b49fec3e5d3e2beaa21755cadbbdc391694e28ccdd36ca4a1408f8c", size = 45806, upload-time = "2025-04-10T14:19:03.967Z" }, | ||
| 110 | ] | ||
| 111 | |||
| 112 | [[package]] | ||
| 113 | name = "tzdata" | ||
| 114 | version = "2025.2" | ||
| 115 | source = { registry = "https://pypi.org/simple" } | ||
| 116 | sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } | ||
| 117 | wheels = [ | ||
| 118 | { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, | ||
| 119 | ] | ||
diff --git a/hosts/surtr/email/password-server/.envrc b/hosts/surtr/email/password-server/.envrc new file mode 100644 index 00000000..2c909235 --- /dev/null +++ b/hosts/surtr/email/password-server/.envrc | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | use flake | ||
| 2 | |||
| 3 | [[ -d ".venv" ]] || ( uv venv && uv sync ) | ||
| 4 | . .venv/bin/activate | ||
diff --git a/hosts/surtr/email/password-server/.gitignore b/hosts/surtr/email/password-server/.gitignore new file mode 100644 index 00000000..4ccfae70 --- /dev/null +++ b/hosts/surtr/email/password-server/.gitignore | |||
| @@ -0,0 +1,2 @@ | |||
| 1 | .venv | ||
| 2 | **/__pycache__ | ||
diff --git a/hosts/surtr/email/password-server/password_server/__init__.py b/hosts/surtr/email/password-server/password_server/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/hosts/surtr/email/password-server/password_server/__init__.py | |||
diff --git a/hosts/surtr/email/password-server/password_server/__main__.py b/hosts/surtr/email/password-server/password_server/__main__.py new file mode 100644 index 00000000..f2321080 --- /dev/null +++ b/hosts/surtr/email/password-server/password_server/__main__.py | |||
| @@ -0,0 +1,268 @@ | |||
| 1 | from systemd.daemon import listen_fds | ||
| 2 | from sdnotify import SystemdNotifier | ||
| 3 | import sys | ||
| 4 | import logging | ||
| 5 | from threading import Thread | ||
| 6 | import uvicorn | ||
| 7 | import argparse | ||
| 8 | from functools import partial | ||
| 9 | from inspect import signature | ||
| 10 | from starlette.applications import Starlette | ||
| 11 | from starlette.routing import Route, Mount | ||
| 12 | from starlette.responses import PlainTextResponse, HTMLResponse | ||
| 13 | from starlette.datastructures import State, Secret | ||
| 14 | from starlette.middleware import Middleware | ||
| 15 | from starlette.middleware.authentication import AuthenticationMiddleware | ||
| 16 | from contextlib import asynccontextmanager | ||
| 17 | from pathlib import Path | ||
| 18 | import os | ||
| 19 | from psycopg_pool import ConnectionPool | ||
| 20 | from psycopg.rows import namedtuple_row | ||
| 21 | from starlette.authentication import AuthCredentials, AuthenticationBackend, AuthenticationError, SimpleUser, requires | ||
| 22 | from starlette.requests import HTTPConnection | ||
| 23 | from cryptography.hazmat.primitives import hashes | ||
| 24 | from cryptography.hazmat.primitives.hmac import HMAC | ||
| 25 | from cryptography.hazmat.primitives.kdf.hkdf import HKDF | ||
| 26 | from cryptography.hazmat.primitives.asymmetric import ed25519 | ||
| 27 | from cryptography.hazmat.primitives.kdf.argon2 import Argon2id | ||
| 28 | import jwt | ||
| 29 | from datetime import datetime, timezone, timedelta | ||
| 30 | from base64 import b64encode | ||
| 31 | from xkcdpass import xkcd_password as xp | ||
| 32 | from cryptography.hazmat.primitives import constant_time | ||
| 33 | |||
| 34 | class SSLProxyAuthBackend(AuthenticationBackend): | ||
| 35 | def __init__(self, state): | ||
| 36 | self.state = state | ||
| 37 | |||
| 38 | async def authenticate(self, conn): | ||
| 39 | if 'SSL-CLIENT-VERIFY' not in conn.headers or 'SSL-CLIENT-S-DN' not in conn.headers: | ||
| 40 | return | ||
| 41 | |||
| 42 | if conn.headers['SSL-CLIENT-VERIFY'].lower() == 'none': | ||
| 43 | return | ||
| 44 | |||
| 45 | if conn.headers['SSL-CLIENT-VERIFY'].lower() != 'success': | ||
| 46 | raise AuthenticationError('Requires SSL-CLIENT-VERIFY: success') | ||
| 47 | |||
| 48 | username = conn.headers['SSL-CLIENT-S-DN'].removeprefix('CN=') | ||
| 49 | if not username: | ||
| 50 | raise AuthenticationError('Requires SSL-CLIENT-S-DN: CN=(.+)') | ||
| 51 | |||
| 52 | creds = ["authenticated"] | ||
| 53 | |||
| 54 | with self.state.db_pool.connection() as conn: | ||
| 55 | with conn.cursor() as cur: | ||
| 56 | cur.row_factory = namedtuple_row | ||
| 57 | |||
| 58 | cur.execute('SELECT EXISTS(SELECT true from "mailbox" INNER JOIN "password_admin" ON "mailbox".id = "password_admin"."mailbox" where "mailbox"."mailbox" = %(user)s) as "exists"', params = {'user': username}) | ||
| 59 | if (row := cur.fetchone()) is not None: | ||
| 60 | if row.exists: | ||
| 61 | creds.append("admin") | ||
| 62 | |||
| 63 | return AuthCredentials(creds), SimpleUser(username) | ||
| 64 | |||
| 65 | @requires("admin") | ||
| 66 | def gen_jwt(request): | ||
| 67 | if 'mailbox' not in request.query_params or not request.query_params['mailbox']: | ||
| 68 | return PlainTextResponse('Require GET parameter mailbox', status_code=400) | ||
| 69 | username = request.query_params['mailbox'] | ||
| 70 | |||
| 71 | private_key = derive_jwk(request.app.state.secret) | ||
| 72 | return PlainTextResponse(jwt.encode( | ||
| 73 | { | ||
| 74 | "exp": datetime.now(tz=timezone.utc) + timedelta(days=2), | ||
| 75 | "sub": username, | ||
| 76 | "pw": current_mailbox_password(db_pool=request.app.state.db_pool, username=username, secret=request.app.state.secret), | ||
| 77 | }, | ||
| 78 | private_key, | ||
| 79 | algorithm='EdDSA', | ||
| 80 | )) | ||
| 81 | |||
| 82 | async def handle_reset(request): | ||
| 83 | if request.method == "GET": | ||
| 84 | if 'jwt' not in request.query_params: | ||
| 85 | return PlainTextResponse('Require GET parameter jwt', status_code=400) | ||
| 86 | provided_jwt = request.query_params['jwt'] | ||
| 87 | else: | ||
| 88 | form = await request.form() | ||
| 89 | if 'jwt' not in form: | ||
| 90 | return PlainTextResponse('Requires POST multipart form parameter jwt', status_code=400) | ||
| 91 | provided_jwt = form['jwt'] | ||
| 92 | |||
| 93 | private_key = derive_jwk(request.app.state.secret) | ||
| 94 | claims = jwt.decode( | ||
| 95 | provided_jwt, | ||
| 96 | private_key.public_key(), | ||
| 97 | algorithms=['EdDSA'], | ||
| 98 | ) | ||
| 99 | if 'sub' not in claims: | ||
| 100 | return PlainTextResponse('Requires sub claim within provided jwt', status_code=400) | ||
| 101 | username = claims['sub'] | ||
| 102 | if 'pw' in claims: | ||
| 103 | password_hash = current_mailbox_password(db_pool=request.app.state.db_pool, username=username, secret=request.app.state.secret) | ||
| 104 | if not constant_time.bytes_eq(password_hash.encode('utf-8'), claims['pw'].encode('utf-8')): | ||
| 105 | return PlainTextResponse('Password was changed since jwt was issued', status_code=403) | ||
| 106 | |||
| 107 | if request.method == "GET": | ||
| 108 | wordfile = xp.locate_wordfile() | ||
| 109 | wordlist = xp.generate_wordlist(wordfile=wordfile) | ||
| 110 | new_password = xp.generate_xkcdpassword(wordlist) | ||
| 111 | new_jwt = jwt.encode( | ||
| 112 | { | ||
| 113 | "exp": datetime.now(tz=timezone.utc) + timedelta(hours=1), | ||
| 114 | "sub": username, | ||
| 115 | "pw": current_mailbox_password(db_pool=request.app.state.db_pool, username=username, secret=request.app.state.secret), | ||
| 116 | "new_pw": new_password, | ||
| 117 | }, | ||
| 118 | private_key, | ||
| 119 | algorithm='EdDSA', | ||
| 120 | ) | ||
| 121 | return HTMLResponse("<form method=\"POST\"><dl><dt>New password</dt><dd style=\"font-family: monospace; white-space: pre-wrap\">{new_password}</dd></dl><input type=\"hidden\" name=\"jwt\" value=\"{jwt}\"><button>Accept new password</button></form>".format(new_password=new_password, jwt=new_jwt)) | ||
| 122 | else: | ||
| 123 | if 'new_pw' not in claims: | ||
| 124 | return PlainTextResponse('Requires new_pw claim within provided jwt', status_code=400) | ||
| 125 | new_password = claims['new_pw'] | ||
| 126 | salt = os.urandom(16) | ||
| 127 | kdf = Argon2id( | ||
| 128 | salt=salt, | ||
| 129 | length=32, | ||
| 130 | iterations=3, | ||
| 131 | lanes=1, | ||
| 132 | memory_cost=64 * 1024, | ||
| 133 | ) | ||
| 134 | pw_hash = kdf.derive_phc_encoded(new_password.encode('utf-8')) | ||
| 135 | with request.app.state.db_pool.connection() as conn: | ||
| 136 | with conn.cursor() as cur: | ||
| 137 | cur.execute('UPDATE mailbox SET "password" = %(pw_hash)s WHERE "mailbox" = %(user)s', params = {'user': username, 'pw_hash': "{{ARGON2ID.B64}}{}".format(b64encode(pw_hash.encode('utf-8')).decode('utf-8'))}) | ||
| 138 | return HTMLResponse("<dl><dt>New password</dt><dd style=\"font-family: monospace; white-space: pre-wrap\">{new_password}</dd></dl>".format(new_password=new_password)) | ||
| 139 | |||
| 140 | |||
| 141 | def current_mailbox_password(*, db_pool, username, secret): | ||
| 142 | with db_pool.connection() as conn: | ||
| 143 | with conn.cursor() as cur: | ||
| 144 | cur.row_factory = namedtuple_row | ||
| 145 | |||
| 146 | cur.execute('SELECT password FROM "mailbox" WHERE "mailbox" = %(user)s', params = {'user': username}) | ||
| 147 | row = cur.fetchone() | ||
| 148 | hmac = HMAC(derive_key(secret, b'hmac'), hashes.BLAKE2b(64)) | ||
| 149 | hmac.update((row.password if row.password else '').encode('utf-8') if row else b'') | ||
| 150 | return b64encode(hmac.finalize()).decode('utf-8') | ||
| 151 | |||
| 152 | def derive_key(secret, info, length=32): | ||
| 153 | hkdf = HKDF( | ||
| 154 | algorithm=hashes.BLAKE2b(64), | ||
| 155 | length=length, | ||
| 156 | salt=None, | ||
| 157 | info=info, | ||
| 158 | ) | ||
| 159 | return hkdf.derive(str(secret).encode('utf-8')) | ||
| 160 | |||
| 161 | def derive_jwk(secret): | ||
| 162 | return ed25519.Ed25519PrivateKey.from_private_bytes(derive_key(secret, b'jwk', length=32)) | ||
| 163 | |||
| 164 | def make_app(): | ||
| 165 | state = State() | ||
| 166 | secret_path = Path(os.environ["CREDENTIALS_DIRECTORY"]) / 'secret' | ||
| 167 | with secret_path.open('r') as fh: | ||
| 168 | state.secret = Secret(fh.read().strip()) | ||
| 169 | state.db_pool = ConnectionPool(min_size=1) | ||
| 170 | state.db_pool.wait() | ||
| 171 | |||
| 172 | @asynccontextmanager | ||
| 173 | async def lifespan(app): | ||
| 174 | app.state = state | ||
| 175 | yield | ||
| 176 | |||
| 177 | return Starlette( | ||
| 178 | routes=[ | ||
| 179 | Route('/', handle_reset, methods=["GET", "POST"]), | ||
| 180 | Mount('/jwt', | ||
| 181 | routes=[ | ||
| 182 | Route('/', gen_jwt), | ||
| 183 | ], | ||
| 184 | middleware=[Middleware(AuthenticationMiddleware, backend=SSLProxyAuthBackend(state=state))], | ||
| 185 | ), | ||
| 186 | ], | ||
| 187 | lifespan=lifespan, | ||
| 188 | ) | ||
| 189 | |||
| 190 | def serve(): | ||
| 191 | fds = listen_fds() | ||
| 192 | if fds: | ||
| 193 | app = make_app() | ||
| 194 | for fd in fds: | ||
| 195 | Thread(name=f'Server for fd {fd}', target=partial(uvicorn.run, app=app, fd=fd)).start() | ||
| 196 | else: | ||
| 197 | return 2 | ||
| 198 | |||
| 199 | SystemdNotifier().notify('READY=1') | ||
| 200 | |||
| 201 | def main(): | ||
| 202 | global logger | ||
| 203 | logger = logging.getLogger('uvicorn') | ||
| 204 | console_handler = logging.StreamHandler() | ||
| 205 | console_handler.setFormatter( logging.Formatter('[%(levelname)s](%(name)s): %(message)s') ) | ||
| 206 | if sys.stderr.isatty(): | ||
| 207 | console_handler.setFormatter( logging.Formatter('%(asctime)s [%(levelname)s](%(name)s): %(message)s') ) | ||
| 208 | logger.addHandler(console_handler) | ||
| 209 | logger.setLevel(logging.DEBUG) | ||
| 210 | |||
| 211 | # log uncaught exceptions | ||
| 212 | def log_exceptions(type, value, tb): | ||
| 213 | global logger | ||
| 214 | |||
| 215 | logger.error(value) | ||
| 216 | sys.__excepthook__(type, value, tb) # calls default excepthook | ||
| 217 | |||
| 218 | sys.excepthook = log_exceptions | ||
| 219 | |||
| 220 | def set_default_subparser(self, name, args=None, positional_args=0): | ||
| 221 | """default subparser selection. Call after setup, just before parse_args() | ||
| 222 | name: is the name of the subparser to call by default | ||
| 223 | args: if set is the argument list handed to parse_args() | ||
| 224 | |||
| 225 | , tested with 2.7, 3.2, 3.3, 3.4 | ||
| 226 | it works with 2.6 assuming argparse is installed | ||
| 227 | """ | ||
| 228 | subparser_found = False | ||
| 229 | for arg in sys.argv[1:]: | ||
| 230 | if arg in ['-h', '--help']: # global help if no subparser | ||
| 231 | break | ||
| 232 | else: | ||
| 233 | for x in self._subparsers._actions: | ||
| 234 | if not isinstance(x, argparse._SubParsersAction): | ||
| 235 | continue | ||
| 236 | for sp_name in x._name_parser_map.keys(): | ||
| 237 | if sp_name in sys.argv[1:]: | ||
| 238 | subparser_found = True | ||
| 239 | if not subparser_found: | ||
| 240 | # insert default in last position before global positional | ||
| 241 | # arguments, this implies no global options are specified after | ||
| 242 | # first positional argument | ||
| 243 | if args is None: | ||
| 244 | sys.argv.insert(len(sys.argv) - positional_args, name) | ||
| 245 | else: | ||
| 246 | args.insert(len(args) - positional_args, name) | ||
| 247 | |||
| 248 | argparse.ArgumentParser.set_default_subparser = set_default_subparser | ||
| 249 | |||
| 250 | parser = argparse.ArgumentParser( | ||
| 251 | prog=__name__, | ||
| 252 | ) | ||
| 253 | subparsers = parser.add_subparsers() | ||
| 254 | serve_parser = subparsers.add_parser('serve') | ||
| 255 | serve_parser.set_defaults(cmd = serve) | ||
| 256 | parser.set_default_subparser('serve') | ||
| 257 | args = parser.parse_args() | ||
| 258 | |||
| 259 | return args.cmd( | ||
| 260 | **{ | ||
| 261 | k: v | ||
| 262 | for k, v in vars(args).items() | ||
| 263 | if k in signature(args.cmd).parameters.keys() | ||
| 264 | } | ||
| 265 | ) | ||
| 266 | |||
| 267 | if __name__ == '__main__': | ||
| 268 | sys.exit(main()) | ||
diff --git a/hosts/surtr/email/password-server/pyproject.toml b/hosts/surtr/email/password-server/pyproject.toml new file mode 100644 index 00000000..196d6b3c --- /dev/null +++ b/hosts/surtr/email/password-server/pyproject.toml | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | [project] | ||
| 2 | name = "password-server" | ||
| 3 | version = "0.1.0" | ||
| 4 | requires-python = ">=3.13" | ||
| 5 | dependencies = [ | ||
| 6 | "cryptography>=48.0.0", | ||
| 7 | "psycopg>=3.3.4", | ||
| 8 | "psycopg-binary>=3.3.4", | ||
| 9 | "psycopg-pool>=3.3.1", | ||
| 10 | "pyjwt[crypto]>=2.13.0", | ||
| 11 | "python-multipart>=0.0.32", | ||
| 12 | "sdnotify>=0.3.2", | ||
| 13 | "starlette>=1.2.1", | ||
| 14 | "systemd-python>=235", | ||
| 15 | "uvicorn>=0.49.0", | ||
| 16 | "xkcdpass>=1.30.0", | ||
| 17 | ] | ||
| 18 | |||
| 19 | [project.scripts] | ||
| 20 | password-server = "password_server.__main__:main" | ||
| 21 | |||
| 22 | [build-system] | ||
| 23 | requires = ["uv_build>=0.10.9,<0.11.0"] | ||
| 24 | build-backend = "uv_build" | ||
| 25 | |||
| 26 | [tool.uv.build-backend] | ||
| 27 | module-root = "." | ||
| 28 | module-name = ["password_server"] | ||
diff --git a/hosts/surtr/email/password-server/uv.lock b/hosts/surtr/email/password-server/uv.lock new file mode 100644 index 00000000..b69f382e --- /dev/null +++ b/hosts/surtr/email/password-server/uv.lock | |||
| @@ -0,0 +1,334 @@ | |||
| 1 | version = 1 | ||
| 2 | revision = 3 | ||
| 3 | requires-python = ">=3.13" | ||
| 4 | |||
| 5 | [[package]] | ||
| 6 | name = "anyio" | ||
| 7 | version = "4.13.0" | ||
| 8 | source = { registry = "https://pypi.org/simple" } | ||
| 9 | dependencies = [ | ||
| 10 | { name = "idna" }, | ||
| 11 | ] | ||
| 12 | sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } | ||
| 13 | wheels = [ | ||
| 14 | { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, | ||
| 15 | ] | ||
| 16 | |||
| 17 | [[package]] | ||
| 18 | name = "cffi" | ||
| 19 | version = "2.0.0" | ||
| 20 | source = { registry = "https://pypi.org/simple" } | ||
| 21 | dependencies = [ | ||
| 22 | { name = "pycparser", marker = "implementation_name != 'PyPy'" }, | ||
| 23 | ] | ||
| 24 | sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } | ||
| 25 | wheels = [ | ||
| 26 | { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, | ||
| 27 | { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, | ||
| 28 | { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, | ||
| 29 | { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, | ||
| 30 | { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, | ||
| 31 | { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, | ||
| 32 | { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, | ||
| 33 | { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, | ||
| 34 | { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, | ||
| 35 | { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, | ||
| 36 | { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, | ||
| 37 | { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, | ||
| 38 | { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, | ||
| 39 | { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, | ||
| 40 | { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, | ||
| 41 | { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, | ||
| 42 | { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, | ||
| 43 | { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, | ||
| 44 | { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, | ||
| 45 | { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, | ||
| 46 | { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, | ||
| 47 | { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, | ||
| 48 | { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, | ||
| 49 | { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, | ||
| 50 | { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, | ||
| 51 | { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, | ||
| 52 | { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, | ||
| 53 | { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, | ||
| 54 | { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, | ||
| 55 | { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, | ||
| 56 | { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, | ||
| 57 | { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, | ||
| 58 | { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, | ||
| 59 | { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, | ||
| 60 | ] | ||
| 61 | |||
| 62 | [[package]] | ||
| 63 | name = "click" | ||
| 64 | version = "8.4.1" | ||
| 65 | source = { registry = "https://pypi.org/simple" } | ||
| 66 | dependencies = [ | ||
| 67 | { name = "colorama", marker = "sys_platform == 'win32'" }, | ||
| 68 | ] | ||
| 69 | sdist = { url = "https://files.pythonhosted.org/packages/9b/98/518d8e5081007684232226f475082b30087d0f585e8457db087298259f49/click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96", size = 353007, upload-time = "2026-05-22T04:08:37.769Z" } | ||
| 70 | wheels = [ | ||
| 71 | { url = "https://files.pythonhosted.org/packages/c7/0d/67e5b4109ea4a837e80daa87c2c696711955e40449a97e8926672534def2/click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2", size = 116639, upload-time = "2026-05-22T04:08:35.26Z" }, | ||
| 72 | ] | ||
| 73 | |||
| 74 | [[package]] | ||
| 75 | name = "colorama" | ||
| 76 | version = "0.4.6" | ||
| 77 | source = { registry = "https://pypi.org/simple" } | ||
| 78 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } | ||
| 79 | wheels = [ | ||
| 80 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, | ||
| 81 | ] | ||
| 82 | |||
| 83 | [[package]] | ||
| 84 | name = "cryptography" | ||
| 85 | version = "48.0.0" | ||
| 86 | source = { registry = "https://pypi.org/simple" } | ||
| 87 | dependencies = [ | ||
| 88 | { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, | ||
| 89 | ] | ||
| 90 | sdist = { url = "https://files.pythonhosted.org/packages/9f/a9/db8f313fdcd85d767d4973515e1db101f9c71f95fced83233de224673757/cryptography-48.0.0.tar.gz", hash = "sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920", size = 832984, upload-time = "2026-05-04T22:59:38.133Z" } | ||
| 91 | wheels = [ | ||
| 92 | { url = "https://files.pythonhosted.org/packages/df/3d/01f6dd9190170a5a241e0e98c2d04be3664a9e6f5b9b872cde63aff1c3dd/cryptography-48.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6", size = 8001587, upload-time = "2026-05-04T22:57:36.803Z" }, | ||
| 93 | { url = "https://files.pythonhosted.org/packages/b2/6e/e90527eef33f309beb811cf7c982c3aeffcce8e3edb178baa4ca3ae4a6fa/cryptography-48.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c", size = 4690433, upload-time = "2026-05-04T22:57:40.373Z" }, | ||
| 94 | { url = "https://files.pythonhosted.org/packages/90/04/673510ed51ddff56575f306cf1617d80411ee76831ccd3097599140efdfe/cryptography-48.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3", size = 4710620, upload-time = "2026-05-04T22:57:42.935Z" }, | ||
| 95 | { url = "https://files.pythonhosted.org/packages/14/d5/e9c4ef932c8d800490c34d8bd589d64a31d5890e27ec9e9ad532be893294/cryptography-48.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5", size = 4696283, upload-time = "2026-05-04T22:57:45.294Z" }, | ||
| 96 | { url = "https://files.pythonhosted.org/packages/0c/29/174b9dfb60b12d59ecfc6cfa04bc88c21b42a54f01b8aae09bb6e51e4c7f/cryptography-48.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c", size = 5296573, upload-time = "2026-05-04T22:57:47.933Z" }, | ||
| 97 | { url = "https://files.pythonhosted.org/packages/95/38/0d29a6fd7d0d1373f0c0c88a04ba20e359b257753ac497564cd660fc1d55/cryptography-48.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f", size = 4743677, upload-time = "2026-05-04T22:57:50.067Z" }, | ||
| 98 | { url = "https://files.pythonhosted.org/packages/30/be/eef653013d5c63b6a490529e0316f9ac14a37602965d4903efed1399f32b/cryptography-48.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25", size = 4330808, upload-time = "2026-05-04T22:57:52.301Z" }, | ||
| 99 | { url = "https://files.pythonhosted.org/packages/84/9e/500463e87abb7a0a0f9f256ec21123ecde0a7b5541a15e840ea54551fd81/cryptography-48.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602", size = 4695941, upload-time = "2026-05-04T22:57:54.603Z" }, | ||
| 100 | { url = "https://files.pythonhosted.org/packages/e3/dc/7303087450c2ec9e7fbb750e17c2abfbc658f23cbd0e54009509b7cc4091/cryptography-48.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c", size = 5252579, upload-time = "2026-05-04T22:57:57.207Z" }, | ||
| 101 | { url = "https://files.pythonhosted.org/packages/d0/c0/7101d3b7215edcdc90c45da544961fd8ed2d6448f77577460fa75a8443f7/cryptography-48.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5", size = 4743326, upload-time = "2026-05-04T22:57:59.535Z" }, | ||
| 102 | { url = "https://files.pythonhosted.org/packages/ac/d8/5b833bad13016f562ab9d063d68199a4bd121d18458e439515601d3357ec/cryptography-48.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321", size = 4826672, upload-time = "2026-05-04T22:58:01.996Z" }, | ||
| 103 | { url = "https://files.pythonhosted.org/packages/98/e1/7074eb8bf3c135558c73fc2bcf0f5633f912e6fb87e868a55c454080ef09/cryptography-48.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74", size = 4972574, upload-time = "2026-05-04T22:58:03.968Z" }, | ||
| 104 | { url = "https://files.pythonhosted.org/packages/04/70/e5a1b41d325f797f39427aa44ef8baf0be500065ab6d8e10369d850d4a4f/cryptography-48.0.0-cp311-abi3-win32.whl", hash = "sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4", size = 3294868, upload-time = "2026-05-04T22:58:06.467Z" }, | ||
| 105 | { url = "https://files.pythonhosted.org/packages/f4/ac/8ac51b4a5fc5932eb7ee5c517ba7dc8cd834f0048962b6b352f00f41ebf9/cryptography-48.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7", size = 3817107, upload-time = "2026-05-04T22:58:08.845Z" }, | ||
| 106 | { url = "https://files.pythonhosted.org/packages/6b/84/70e3feea9feea87fd7cbe77efb2712ae1e3e6edf10749dc6e95f4e60e455/cryptography-48.0.0-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec", size = 7986556, upload-time = "2026-05-04T22:58:11.172Z" }, | ||
| 107 | { url = "https://files.pythonhosted.org/packages/89/6e/18e07a618bb5442ba10cf4df16e99c071365528aa570dfcb8c02e25a303b/cryptography-48.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18", size = 4684776, upload-time = "2026-05-04T22:58:13.712Z" }, | ||
| 108 | { url = "https://files.pythonhosted.org/packages/be/6a/4ea3b4c6c6759794d5ee2103c304a5076dc4b19ae1f9fe47dba439e159e9/cryptography-48.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20", size = 4698121, upload-time = "2026-05-04T22:58:16.448Z" }, | ||
| 109 | { url = "https://files.pythonhosted.org/packages/2f/59/6ff6ad6cae03bb887da2a5860b2c9805f8dac969ef01ce563336c49bd1d1/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff", size = 4690042, upload-time = "2026-05-04T22:58:18.544Z" }, | ||
| 110 | { url = "https://files.pythonhosted.org/packages/ca/b4/fc334ed8cfd705aca282fe4d8f5ae64a8e0f74932e9feecb344610cf6e4d/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c", size = 5282526, upload-time = "2026-05-04T22:58:20.75Z" }, | ||
| 111 | { url = "https://files.pythonhosted.org/packages/11/08/9f8c5386cc4cd90d8255c7cdd0f5baf459a08502a09de30dc51f553d38dc/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db", size = 4733116, upload-time = "2026-05-04T22:58:23.627Z" }, | ||
| 112 | { url = "https://files.pythonhosted.org/packages/b8/77/99307d7574045699f8805aa500fa0fb83422d115b5400a064ddd306d7750/cryptography-48.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741", size = 4316030, upload-time = "2026-05-04T22:58:25.581Z" }, | ||
| 113 | { url = "https://files.pythonhosted.org/packages/fd/36/a608b98337af3cb2aff4818e406649d30572b7031918b04c87d979495348/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166", size = 4689640, upload-time = "2026-05-04T22:58:27.747Z" }, | ||
| 114 | { url = "https://files.pythonhosted.org/packages/dd/a6/825010a291b4438aecc1f568bc428189fc1175515223632477c07dc0a6df/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336", size = 5237657, upload-time = "2026-05-04T22:58:29.848Z" }, | ||
| 115 | { url = "https://files.pythonhosted.org/packages/b9/09/4e76a09b4caa29aad535ddc806f5d4c5d01885bd978bd984fbc6ca032cae/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057", size = 4732362, upload-time = "2026-05-04T22:58:32.009Z" }, | ||
| 116 | { url = "https://files.pythonhosted.org/packages/18/78/444fa04a77d0cb95f417dda20d450e13c56ba8e5220fc892a1658f44f882/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae", size = 4819580, upload-time = "2026-05-04T22:58:34.254Z" }, | ||
| 117 | { url = "https://files.pythonhosted.org/packages/38/85/ea67067c70a1fd4be2c63d35eeed82658023021affccc7b17705f8527dd2/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c", size = 4963283, upload-time = "2026-05-04T22:58:36.376Z" }, | ||
| 118 | { url = "https://files.pythonhosted.org/packages/75/54/cc6d0f3deac3e81c7f847e8a189a12b6cdd65059b43dad25d4316abd849a/cryptography-48.0.0-cp314-cp314t-win32.whl", hash = "sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f", size = 3270954, upload-time = "2026-05-04T22:58:38.791Z" }, | ||
| 119 | { url = "https://files.pythonhosted.org/packages/49/67/cc947e288c0758a4e5473d1dcb743037ab7785541265a969240b8885441a/cryptography-48.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12", size = 3797313, upload-time = "2026-05-04T22:58:40.746Z" }, | ||
| 120 | { url = "https://files.pythonhosted.org/packages/f2/63/61d4a4e1c6b6bab6ce1e213cd36a24c415d90e76d78c5eb8577c5541d2e8/cryptography-48.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86", size = 7983482, upload-time = "2026-05-04T22:58:43.769Z" }, | ||
| 121 | { url = "https://files.pythonhosted.org/packages/d5/ac/f5b5995b87770c693e2596559ffafe195b4033a57f14a82268a2842953f3/cryptography-48.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e", size = 4683266, upload-time = "2026-05-04T22:58:46.064Z" }, | ||
| 122 | { url = "https://files.pythonhosted.org/packages/ec/c6/8b14f67e18338fbc4adb76f66c001f5c3610b3e2d1837f268f47a347dbbb/cryptography-48.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f", size = 4696228, upload-time = "2026-05-04T22:58:48.22Z" }, | ||
| 123 | { url = "https://files.pythonhosted.org/packages/ea/73/f808fbae9514bd91b47875b003f13e284c8c6bdfd904b7944e803937eec1/cryptography-48.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7", size = 4689097, upload-time = "2026-05-04T22:58:50.9Z" }, | ||
| 124 | { url = "https://files.pythonhosted.org/packages/93/01/d86632d7d28db8ae83221995752eeb6639ffb374c2d22955648cf8d52797/cryptography-48.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832", size = 5283582, upload-time = "2026-05-04T22:58:53.017Z" }, | ||
| 125 | { url = "https://files.pythonhosted.org/packages/02/e1/50edc7a50334807cc4791fc4a0ce7468b4a1416d9138eab358bfc9a3d70b/cryptography-48.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c", size = 4730479, upload-time = "2026-05-04T22:58:55.611Z" }, | ||
| 126 | { url = "https://files.pythonhosted.org/packages/6f/af/99a582b1b1641ff5911ac559beb45097cf79efd4ead4657f578ef1af2d47/cryptography-48.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a", size = 4326481, upload-time = "2026-05-04T22:58:57.607Z" }, | ||
| 127 | { url = "https://files.pythonhosted.org/packages/90/ee/89aa26a06ef0a7d7611788ffd571a7c50e368cc6a4d5eef8b4884e866edb/cryptography-48.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a", size = 4688713, upload-time = "2026-05-04T22:59:00.077Z" }, | ||
| 128 | { url = "https://files.pythonhosted.org/packages/70/ba/bcb1b0bb7a33d4c7c0c4d4c7874b4a62ae4f56113a5f4baefa362dfb1f0f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a", size = 5238165, upload-time = "2026-05-04T22:59:02.317Z" }, | ||
| 129 | { url = "https://files.pythonhosted.org/packages/c9/70/ca4003b1ce5ca3dc3186ada51908c8a9b9ff7d5cab83cc0d43ee14ec144f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239", size = 4729947, upload-time = "2026-05-04T22:59:05.255Z" }, | ||
| 130 | { url = "https://files.pythonhosted.org/packages/44/a0/4ec7cf774207905aef1a8d11c3750d5a1db805eb380ee4e16df317870128/cryptography-48.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c", size = 4822059, upload-time = "2026-05-04T22:59:07.802Z" }, | ||
| 131 | { url = "https://files.pythonhosted.org/packages/1e/75/a2e55f99c16fcac7b5d6c1eb19ad8e00799854d6be5ca845f9259eae1681/cryptography-48.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4", size = 4960575, upload-time = "2026-05-04T22:59:09.851Z" }, | ||
| 132 | { url = "https://files.pythonhosted.org/packages/b8/23/6e6f32143ab5d8b36ca848a502c4bcd477ae75b9e1677e3530d669062578/cryptography-48.0.0-cp39-abi3-win32.whl", hash = "sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd", size = 3279117, upload-time = "2026-05-04T22:59:12.019Z" }, | ||
| 133 | { url = "https://files.pythonhosted.org/packages/9d/9a/0fea98a70cf1749d41d738836f6349d97945f7c89433a259a6c2642eefeb/cryptography-48.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8", size = 3792100, upload-time = "2026-05-04T22:59:14.884Z" }, | ||
| 134 | ] | ||
| 135 | |||
| 136 | [[package]] | ||
| 137 | name = "h11" | ||
| 138 | version = "0.16.0" | ||
| 139 | source = { registry = "https://pypi.org/simple" } | ||
| 140 | sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } | ||
| 141 | wheels = [ | ||
| 142 | { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, | ||
| 143 | ] | ||
| 144 | |||
| 145 | [[package]] | ||
| 146 | name = "idna" | ||
| 147 | version = "3.18" | ||
| 148 | source = { registry = "https://pypi.org/simple" } | ||
| 149 | sdist = { url = "https://files.pythonhosted.org/packages/cd/63/9496c57188a2ee585e0f1db071d75089a11e98aa86eb99d9d7618fc1edce/idna-3.18.tar.gz", hash = "sha256:ffb385a7e039654cef1ab9ef32c6fafe283c0c0467bba1d9029738ce4a14a848", size = 196711, upload-time = "2026-06-02T14:34:07.794Z" } | ||
| 150 | wheels = [ | ||
| 151 | { url = "https://files.pythonhosted.org/packages/1e/5e/d4e9f1a599fb8e573b7b87160658329fbf28d19eac2718f51fc3def3aa5a/idna-3.18-py3-none-any.whl", hash = "sha256:7f952cbe720b688055e3f87de14f5c3e5fdaa8bc3928985c4077ca689de849a2", size = 65455, upload-time = "2026-06-02T14:34:06.319Z" }, | ||
| 152 | ] | ||
| 153 | |||
| 154 | [[package]] | ||
| 155 | name = "password-server" | ||
| 156 | version = "0.1.0" | ||
| 157 | source = { editable = "." } | ||
| 158 | dependencies = [ | ||
| 159 | { name = "cryptography" }, | ||
| 160 | { name = "psycopg" }, | ||
| 161 | { name = "psycopg-binary" }, | ||
| 162 | { name = "psycopg-pool" }, | ||
| 163 | { name = "pyjwt", extra = ["crypto"] }, | ||
| 164 | { name = "python-multipart" }, | ||
| 165 | { name = "sdnotify" }, | ||
| 166 | { name = "starlette" }, | ||
| 167 | { name = "systemd-python" }, | ||
| 168 | { name = "uvicorn" }, | ||
| 169 | { name = "xkcdpass" }, | ||
| 170 | ] | ||
| 171 | |||
| 172 | [package.metadata] | ||
| 173 | requires-dist = [ | ||
| 174 | { name = "cryptography", specifier = ">=48.0.0" }, | ||
| 175 | { name = "psycopg", specifier = ">=3.3.4" }, | ||
| 176 | { name = "psycopg-binary", specifier = ">=3.3.4" }, | ||
| 177 | { name = "psycopg-pool", specifier = ">=3.3.1" }, | ||
| 178 | { name = "pyjwt", extras = ["crypto"], specifier = ">=2.13.0" }, | ||
| 179 | { name = "python-multipart", specifier = ">=0.0.32" }, | ||
| 180 | { name = "sdnotify", specifier = ">=0.3.2" }, | ||
| 181 | { name = "starlette", specifier = ">=1.2.1" }, | ||
| 182 | { name = "systemd-python", specifier = ">=235" }, | ||
| 183 | { name = "uvicorn", specifier = ">=0.49.0" }, | ||
| 184 | { name = "xkcdpass", specifier = ">=1.30.0" }, | ||
| 185 | ] | ||
| 186 | |||
| 187 | [[package]] | ||
| 188 | name = "psycopg" | ||
| 189 | version = "3.3.4" | ||
| 190 | source = { registry = "https://pypi.org/simple" } | ||
| 191 | dependencies = [ | ||
| 192 | { name = "tzdata", marker = "sys_platform == 'win32'" }, | ||
| 193 | ] | ||
| 194 | sdist = { url = "https://files.pythonhosted.org/packages/db/2f/cb91e5502ec9de1de6f1b76cfbf69531932725361168bb06963620c77e2e/psycopg-3.3.4.tar.gz", hash = "sha256:e21207764952cff81b6b8bdacad9a3939f2793367fdac2987b3aac36a651b5bc", size = 165799, upload-time = "2026-05-01T23:31:55.179Z" } | ||
| 195 | wheels = [ | ||
| 196 | { url = "https://files.pythonhosted.org/packages/5c/e0/7b3dee031daae7743609ce3c746565d4a3ed7c2c186479eb48e34e838c64/psycopg-3.3.4-py3-none-any.whl", hash = "sha256:b6bbc25ccf05c8fad3b061d9db2ef0909a555171b84b07f29458a447253d679a", size = 213001, upload-time = "2026-05-01T23:20:50.816Z" }, | ||
| 197 | ] | ||
| 198 | |||
| 199 | [[package]] | ||
| 200 | name = "psycopg-binary" | ||
| 201 | version = "3.3.4" | ||
| 202 | source = { registry = "https://pypi.org/simple" } | ||
| 203 | wheels = [ | ||
| 204 | { url = "https://files.pythonhosted.org/packages/09/43/13e9c406fbbf354580476e248a16b64802a376873ebe6339e30bb655572d/psycopg_binary-3.3.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fbd1d4ed566895ad2d3bf4ddfd8bae90026930ddf29df3b9d91d32c8c47866a7", size = 4590377, upload-time = "2026-05-01T23:29:18.782Z" }, | ||
| 205 | { url = "https://files.pythonhosted.org/packages/22/be/2923cd7c3683e7afdecf4f10796a18de02f5c5ddc0969aa2ad0a8cdd3bbd/psycopg_binary-3.3.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:75a9067e236f9b9ae3535b66fe99bddb33d39c0de10112e49b9ab11eee53dc31", size = 4669023, upload-time = "2026-05-01T23:29:25.884Z" }, | ||
| 206 | { url = "https://files.pythonhosted.org/packages/96/a0/2c913d6fe13d6a8bd13597d36739bf47af063ad9399e402cfecab16f3c1e/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:b56b603ebcea8aa10b46228b8410ba7f13e7c2ee54389d4d9be0927fd8ce2a70", size = 5467423, upload-time = "2026-05-01T23:29:33.416Z" }, | ||
| 207 | { url = "https://files.pythonhosted.org/packages/e7/38/205d10bc1ad0df4a21c5c51659126bd3ea0ef98fcad1e852f78c249bb9c3/psycopg_binary-3.3.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c677c4ad433cb7150c8cd304a0769ae3bcfbe5ea0676eb53faa7b1443b16d0d3", size = 5151137, upload-time = "2026-05-01T23:29:42.013Z" }, | ||
| 208 | { url = "https://files.pythonhosted.org/packages/36/fc/f0381ddcd45eff3bb70dbca6823a996048d7f507b2ec3fc92c6fabc0fe87/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:26df2717e59c0473e4465a97dfb1b7afebaa479277870fd5784d1436470db47c", size = 6736671, upload-time = "2026-05-01T23:29:51.626Z" }, | ||
| 209 | { url = "https://files.pythonhosted.org/packages/95/40/fa545ae152c24327651e5624e4902121e808270be36c10b12e9939be09bc/psycopg_binary-3.3.4-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dc1f79fd16bb1f3f4421417a514607539f17804d95c7ed617265369d1981cae", size = 4979601, upload-time = "2026-05-01T23:29:56.961Z" }, | ||
| 210 | { url = "https://files.pythonhosted.org/packages/86/e4/2f8a47ee97f90cd2b933d0463081d35631ff419de2b8c984a5f369857de0/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:136f199a407b5348b9b857c504aff60c77622a28482e7195839ce1b51238c4cc", size = 4510513, upload-time = "2026-05-01T23:30:07.243Z" }, | ||
| 211 | { url = "https://files.pythonhosted.org/packages/0e/0e/94e842ff4a7f98ed162580ca2e8b8864b28c1e0350f2443f8ee47f821167/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b6f5a29e9c775b9f12a1a717aa7a2c80f9e1db6f27ba44a5b59c80ac61d2ffcf", size = 4187243, upload-time = "2026-05-01T23:30:15.352Z" }, | ||
| 212 | { url = "https://files.pythonhosted.org/packages/d0/83/fc6c174b672e29b7de996ea77b6cbddf46c891751c3355f6974292baa6b4/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ee17a2cf4943cde261adfad1bbc5bf38d6b3776d7afff74c7cabcbeaeb08c260", size = 3927347, upload-time = "2026-05-01T23:30:21.186Z" }, | ||
| 213 | { url = "https://files.pythonhosted.org/packages/e9/65/768364d4a97a15b1a7f47ba52688c1686f22941d8332a8398cefc468e25f/psycopg_binary-3.3.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5c4ab71be17bdca30cb34c34c4e1496e2f5d6f20c199c12bad226070b22ef9bf", size = 4236393, upload-time = "2026-05-01T23:30:26.211Z" }, | ||
| 214 | { url = "https://files.pythonhosted.org/packages/bd/3b/218efbc9e645becd80cdf651acda05f85cfe546b7a9c0458c7cbc8fe1f74/psycopg_binary-3.3.4-cp313-cp313-win_amd64.whl", hash = "sha256:dbfdb9b6cc79f31104a7b162a2b921b765fcc62af6c00540a167a8de47e4ed38", size = 3564592, upload-time = "2026-05-01T23:30:31.764Z" }, | ||
| 215 | { url = "https://files.pythonhosted.org/packages/48/a6/828c9185701dab71b234c2a76c38a08b098ebfec5020716b4e93807492b5/psycopg_binary-3.3.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:28b7398fdd19db3232c884fb24550bdfe951221f510e195e233299e4c9b78f97", size = 4607292, upload-time = "2026-05-01T23:30:38.962Z" }, | ||
| 216 | { url = "https://files.pythonhosted.org/packages/92/58/5b40dbc9d839045c9dae956960e4fb6d20bcabe6c59a2aa34fc3a371913f/psycopg_binary-3.3.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1fbaa292a3c8bb61b45df1ad3da1908ccee7cb889db9425e3557d9e34e2a4829", size = 4687023, upload-time = "2026-05-01T23:30:47.227Z" }, | ||
| 217 | { url = "https://files.pythonhosted.org/packages/85/a9/793f0ac107a9003b48441d0d1f9f616d96e0f37458dd8dc12528ceff55fb/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:94596f9e7633ee3f6440711d43bb70aa31cc0a46a900ab8b4201a366ace5c9e7", size = 5486985, upload-time = "2026-05-01T23:30:55.517Z" }, | ||
| 218 | { url = "https://files.pythonhosted.org/packages/8f/26/42e8533497e2592334f68ec529cf5f840f7fa4e99575a4bb61aa184dbfbf/psycopg_binary-3.3.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8c0056529e68dbe9184cd4019a1f3d8f3a4ead2f6fc7a5afcf27d3314edd1277", size = 5168745, upload-time = "2026-05-01T23:31:01.904Z" }, | ||
| 219 | { url = "https://files.pythonhosted.org/packages/15/af/b7151776cc08d5935d45c833ec818a9beb417cf7c08239af1aafbdae78ee/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c09aad7051326e7603c14e50636db9c01f78272dc54b3accff03d46370461e6", size = 6761486, upload-time = "2026-05-01T23:31:14.511Z" }, | ||
| 220 | { url = "https://files.pythonhosted.org/packages/d0/ed/c92533b9124712d592cbf1cd6c76da933a2e0acea81dfe1fbe7e735f0cff/psycopg_binary-3.3.4-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:514404ed543efd620c85602b747df2a23cf1241b4067199e1a66f2d2757aaa41", size = 4997427, upload-time = "2026-05-01T23:31:20.901Z" }, | ||
| 221 | { url = "https://files.pythonhosted.org/packages/a2/23/ccadfd0de416aa188356daa199453af24087b042e296088706d190ae0295/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:46893c26858be12cc49ca4226ed6a60b4bfccadd946b3bebb783a60b38788228", size = 4533549, upload-time = "2026-05-01T23:31:26.204Z" }, | ||
| 222 | { url = "https://files.pythonhosted.org/packages/fd/a0/c8f43cee36386f7bc891ab41a9d31ea07cf9826038e732da79f26b1e5f34/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:df1d567fc430f6df15c9fcf67d87685fc49bdb325adc0db5af1adfb2f44eb5c9", size = 4210256, upload-time = "2026-05-01T23:31:33.884Z" }, | ||
| 223 | { url = "https://files.pythonhosted.org/packages/4e/2c/c1547871be3790676e8868b38655496422f94f0978dfb66b74bdba2f1676/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:6b9016b1714da4dd5ecaaa75b82098aa5a0b87854ce9b092e21c27c4ae23e014", size = 3946204, upload-time = "2026-05-01T23:31:39.626Z" }, | ||
| 224 | { url = "https://files.pythonhosted.org/packages/c4/b1/f6670f00fa7ea601584623f6c11602ab92117d83eaff885e0210f6de7418/psycopg_binary-3.3.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:47c656a8a7ba6eb0cff1801a4caaa9c8bdc12d03080e273aff1c8ac39971a77e", size = 4255811, upload-time = "2026-05-01T23:31:44.986Z" }, | ||
| 225 | { url = "https://files.pythonhosted.org/packages/eb/e6/5fff07a70d1f945ed90ae131c3bd76cab32beff7c58c6db15ad5820b6d1f/psycopg_binary-3.3.4-cp314-cp314-win_amd64.whl", hash = "sha256:c37e024c07308cd06cf3ec51bfd0e7f6157585a4d84d1bce4a7f5f7913719bf8", size = 3666849, upload-time = "2026-05-01T23:31:51.165Z" }, | ||
| 226 | ] | ||
| 227 | |||
| 228 | [[package]] | ||
| 229 | name = "psycopg-pool" | ||
| 230 | version = "3.3.1" | ||
| 231 | source = { registry = "https://pypi.org/simple" } | ||
| 232 | dependencies = [ | ||
| 233 | { name = "typing-extensions" }, | ||
| 234 | ] | ||
| 235 | sdist = { url = "https://files.pythonhosted.org/packages/90/82/7a23d26039827ecd4ebe93905651029ddd307c5182ad59296dfb6f67b528/psycopg_pool-3.3.1.tar.gz", hash = "sha256:b10b10b7a175d5cc1592147dc5b7eec8a9e0834eb3ed2c4a92c858e2f51eb63c", size = 31661, upload-time = "2026-05-01T23:31:59.809Z" } | ||
| 236 | wheels = [ | ||
| 237 | { url = "https://files.pythonhosted.org/packages/37/ed/89c2c620af0e1660354cd8aabf9f5b21f911597ce22acb37c805d6c86bc8/psycopg_pool-3.3.1-py3-none-any.whl", hash = "sha256:2af5b432941c4c9ad5c87b3fa410aec910ec8f7c122855897983a06c45f2e4b5", size = 40023, upload-time = "2026-05-01T23:31:53.136Z" }, | ||
| 238 | ] | ||
| 239 | |||
| 240 | [[package]] | ||
| 241 | name = "pycparser" | ||
| 242 | version = "3.0" | ||
| 243 | source = { registry = "https://pypi.org/simple" } | ||
| 244 | sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } | ||
| 245 | wheels = [ | ||
| 246 | { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, | ||
| 247 | ] | ||
| 248 | |||
| 249 | [[package]] | ||
| 250 | name = "pyjwt" | ||
| 251 | version = "2.13.0" | ||
| 252 | source = { registry = "https://pypi.org/simple" } | ||
| 253 | sdist = { url = "https://files.pythonhosted.org/packages/3b/81/58d0ac84e1ef3a3843791d6954d94c0b33d526c75eeb1efbce9d0a4c4077/pyjwt-2.13.0.tar.gz", hash = "sha256:41571c89ca91598c79e8ef18a2d07367d4810fbbd6f637794879baf1b7703423", size = 107515, upload-time = "2026-05-21T19:54:36.618Z" } | ||
| 254 | wheels = [ | ||
| 255 | { url = "https://files.pythonhosted.org/packages/a3/5e/ecf12fdb62546d64385c158514e9b2b671f7832108ef2ecd2020ce0af2d1/pyjwt-2.13.0-py3-none-any.whl", hash = "sha256:66adcc2aff09b3f1bbd95fc1e1577df8ac8723c978552fd43304c8a290ac5728", size = 31274, upload-time = "2026-05-21T19:54:35.362Z" }, | ||
| 256 | ] | ||
| 257 | |||
| 258 | [package.optional-dependencies] | ||
| 259 | crypto = [ | ||
| 260 | { name = "cryptography" }, | ||
| 261 | ] | ||
| 262 | |||
| 263 | [[package]] | ||
| 264 | name = "python-multipart" | ||
| 265 | version = "0.0.32" | ||
| 266 | source = { registry = "https://pypi.org/simple" } | ||
| 267 | sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" } | ||
| 268 | wheels = [ | ||
| 269 | { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, | ||
| 270 | ] | ||
| 271 | |||
| 272 | [[package]] | ||
| 273 | name = "sdnotify" | ||
| 274 | version = "0.3.2" | ||
| 275 | source = { registry = "https://pypi.org/simple" } | ||
| 276 | sdist = { url = "https://files.pythonhosted.org/packages/ce/d8/9fdc36b2a912bf78106de4b3f0de3891ff8f369e7a6f80be842b8b0b6bd5/sdnotify-0.3.2.tar.gz", hash = "sha256:73977fc746b36cc41184dd43c3fe81323e7b8b06c2bb0826c4f59a20c56bb9f1", size = 2459, upload-time = "2017-08-02T20:03:44.395Z" } | ||
| 277 | |||
| 278 | [[package]] | ||
| 279 | name = "starlette" | ||
| 280 | version = "1.2.1" | ||
| 281 | source = { registry = "https://pypi.org/simple" } | ||
| 282 | dependencies = [ | ||
| 283 | { name = "anyio" }, | ||
| 284 | ] | ||
| 285 | sdist = { url = "https://files.pythonhosted.org/packages/25/44/ec35f1b6e83094b997da438a02c8c9b0ade2b1e84cfc48bd4656780760a6/starlette-1.2.1.tar.gz", hash = "sha256:9b9b5ebb992e67d6093741e63c2f59e4f6fff986f81163c087867bd7b924b3f6", size = 2701854, upload-time = "2026-05-31T01:07:51.847Z" } | ||
| 286 | wheels = [ | ||
| 287 | { url = "https://files.pythonhosted.org/packages/1c/54/196d0c1db10af76baa4f64894448505d60d3cdf70ef92cbb35f46a4e4c71/starlette-1.2.1-py3-none-any.whl", hash = "sha256:4de0082d08c8f6764a85a54cf1120d6939507a19905c7768acad2a9f875d2b89", size = 73350, upload-time = "2026-05-31T01:07:50.09Z" }, | ||
| 288 | ] | ||
| 289 | |||
| 290 | [[package]] | ||
| 291 | name = "systemd-python" | ||
| 292 | version = "235" | ||
| 293 | source = { registry = "https://pypi.org/simple" } | ||
| 294 | sdist = { url = "https://files.pythonhosted.org/packages/10/9e/ab4458e00367223bda2dd7ccf0849a72235ee3e29b36dce732685d9b7ad9/systemd-python-235.tar.gz", hash = "sha256:4e57f39797fd5d9e2d22b8806a252d7c0106c936039d1e71c8c6b8008e695c0a", size = 61677, upload-time = "2023-02-11T13:42:16.588Z" } | ||
| 295 | |||
| 296 | [[package]] | ||
| 297 | name = "typing-extensions" | ||
| 298 | version = "4.15.0" | ||
| 299 | source = { registry = "https://pypi.org/simple" } | ||
| 300 | sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } | ||
| 301 | wheels = [ | ||
| 302 | { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, | ||
| 303 | ] | ||
| 304 | |||
| 305 | [[package]] | ||
| 306 | name = "tzdata" | ||
| 307 | version = "2026.2" | ||
| 308 | source = { registry = "https://pypi.org/simple" } | ||
| 309 | sdist = { url = "https://files.pythonhosted.org/packages/ba/19/1b9b0e29f30c6d35cb345486df41110984ea67ae69dddbc0e8a100999493/tzdata-2026.2.tar.gz", hash = "sha256:9173fde7d80d9018e02a662e168e5a2d04f87c41ea174b139fbef642eda62d10", size = 198254, upload-time = "2026-04-24T15:22:08.651Z" } | ||
| 310 | wheels = [ | ||
| 311 | { url = "https://files.pythonhosted.org/packages/ce/e4/dccd7f47c4b64213ac01ef921a1337ee6e30e8c6466046018326977efd95/tzdata-2026.2-py2.py3-none-any.whl", hash = "sha256:bbe9af844f658da81a5f95019480da3a89415801f6cc966806612cc7169bffe7", size = 349321, upload-time = "2026-04-24T15:22:05.876Z" }, | ||
| 312 | ] | ||
| 313 | |||
| 314 | [[package]] | ||
| 315 | name = "uvicorn" | ||
| 316 | version = "0.49.0" | ||
| 317 | source = { registry = "https://pypi.org/simple" } | ||
| 318 | dependencies = [ | ||
| 319 | { name = "click" }, | ||
| 320 | { name = "h11" }, | ||
| 321 | ] | ||
| 322 | sdist = { url = "https://files.pythonhosted.org/packages/c4/1f/fa18009dea8469069cca78a4e877a008ab78f08b064bfc9ab891579077ff/uvicorn-0.49.0.tar.gz", hash = "sha256:ebf4271aa580d9de97f93192d4595176df6e91f9aae919ca73e4fc07df1e66a3", size = 91284, upload-time = "2026-06-03T22:01:30.448Z" } | ||
| 323 | wheels = [ | ||
| 324 | { url = "https://files.pythonhosted.org/packages/88/fa/e1388bbcf24ef3274f45c0c1c7b501fd14971037c1b6ee23610553307497/uvicorn-0.49.0-py3-none-any.whl", hash = "sha256:ba3d14c3ee7e41c6c654c46c9eb489d33213cdd30aa1696eab1374337c13f68f", size = 71376, upload-time = "2026-06-03T22:01:29.037Z" }, | ||
| 325 | ] | ||
| 326 | |||
| 327 | [[package]] | ||
| 328 | name = "xkcdpass" | ||
| 329 | version = "1.30.0" | ||
| 330 | source = { registry = "https://pypi.org/simple" } | ||
| 331 | sdist = { url = "https://files.pythonhosted.org/packages/18/98/bdd7df66d995eab38887a8eb0afb023750b0c590eb7d8545a7b722f683ef/xkcdpass-1.30.0.tar.gz", hash = "sha256:8a3a6b60255da40d0e5c812458280278c82d2c1cb90e48afbd6777dbbf8795c3", size = 2763380, upload-time = "2026-01-11T16:09:15.567Z" } | ||
| 332 | wheels = [ | ||
| 333 | { url = "https://files.pythonhosted.org/packages/6b/be/ea93adc1b4597b62c236d61dc6cf0e26ca8a729cb5afae4dc5acc5b33fa8/xkcdpass-1.30.0-py3-none-any.whl", hash = "sha256:3653a4a1e13de230808bcaf11f8c04207a5d3df8e2f7e1de698e11c262b5b797", size = 2746372, upload-time = "2026-01-12T14:48:30.627Z" }, | ||
| 334 | ] | ||
diff --git a/hosts/surtr/hledger.nix b/hosts/surtr/hledger.nix new file mode 100644 index 00000000..e44933c3 --- /dev/null +++ b/hosts/surtr/hledger.nix | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | { config, ... }: | ||
| 2 | |||
| 3 | { | ||
| 4 | config = { | ||
| 5 | security.acme.rfc2136Domains = { | ||
| 6 | "hledger.yggdrasil.li" = { | ||
| 7 | restartUnits = ["nginx.service"]; | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | services.nginx = { | ||
| 12 | upstreams."hledger" = { | ||
| 13 | servers = { | ||
| 14 | "[2a03:4000:52:ada:4:1::]:5000" = {}; | ||
| 15 | }; | ||
| 16 | extraConfig = '' | ||
| 17 | keepalive 8; | ||
| 18 | ''; | ||
| 19 | }; | ||
| 20 | virtualHosts = { | ||
| 21 | "hledger.yggdrasil.li" = { | ||
| 22 | kTLS = true; | ||
| 23 | http3 = true; | ||
| 24 | forceSSL = true; | ||
| 25 | sslCertificate = "/run/credentials/nginx.service/hledger.yggdrasil.li.pem"; | ||
| 26 | sslCertificateKey = "/run/credentials/nginx.service/hledger.yggdrasil.li.key.pem"; | ||
| 27 | sslTrustedCertificate = "/run/credentials/nginx.service/hledger.yggdrasil.li.chain.pem"; | ||
| 28 | extraConfig = '' | ||
| 29 | charset utf-8; | ||
| 30 | ''; | ||
| 31 | |||
| 32 | locations = { | ||
| 33 | "/".extraConfig = '' | ||
| 34 | proxy_pass http://hledger; | ||
| 35 | |||
| 36 | proxy_http_version 1.1; | ||
| 37 | proxy_set_header Upgrade $http_upgrade; | ||
| 38 | proxy_set_header Connection "upgrade"; | ||
| 39 | |||
| 40 | proxy_redirect off; | ||
| 41 | proxy_set_header Host $host; | ||
| 42 | proxy_set_header X-Real-IP $remote_addr; | ||
| 43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| 44 | proxy_set_header X-Forwarded-Host $server_name; | ||
| 45 | proxy_set_header X-Forwarded-Proto $scheme; | ||
| 46 | |||
| 47 | client_max_body_size 0; | ||
| 48 | proxy_request_buffering off; | ||
| 49 | proxy_buffering off; | ||
| 50 | ''; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | }; | ||
| 54 | }; | ||
| 55 | |||
| 56 | systemd.services.nginx = { | ||
| 57 | serviceConfig = { | ||
| 58 | LoadCredential = [ | ||
| 59 | "hledger.yggdrasil.li.key.pem:${config.security.acme.certs."hledger.yggdrasil.li".directory}/key.pem" | ||
| 60 | "hledger.yggdrasil.li.pem:${config.security.acme.certs."hledger.yggdrasil.li".directory}/fullchain.pem" | ||
| 61 | "hledger.yggdrasil.li.chain.pem:${config.security.acme.certs."hledger.yggdrasil.li".directory}/chain.pem" | ||
| 62 | ]; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | }; | ||
| 66 | } | ||
diff --git a/hosts/surtr/http/default.nix b/hosts/surtr/http/default.nix index f3a7154e..0e13acf7 100644 --- a/hosts/surtr/http/default.nix +++ b/hosts/surtr/http/default.nix | |||
| @@ -2,19 +2,16 @@ | |||
| 2 | { | 2 | { |
| 3 | imports = [ | 3 | imports = [ |
| 4 | ./webdav | 4 | ./webdav |
| 5 | ./online.nix | ||
| 5 | ]; | 6 | ]; |
| 6 | 7 | ||
| 7 | config = { | 8 | config = { |
| 8 | services.nginx = { | 9 | services.nginx = { |
| 9 | enable = true; | 10 | enable = true; |
| 10 | package = pkgs.nginxQuic; | ||
| 11 | recommendedGzipSettings = false; | 11 | recommendedGzipSettings = false; |
| 12 | recommendedProxySettings = true; | 12 | recommendedProxySettings = true; |
| 13 | recommendedTlsSettings = true; | 13 | recommendedTlsSettings = true; |
| 14 | sslDhparam = config.security.dhparams.params.nginx.path; | ||
| 15 | commonHttpConfig = '' | 14 | commonHttpConfig = '' |
| 16 | ssl_ecdh_curve X448:X25519:prime256v1:secp521r1:secp384r1; | ||
| 17 | |||
| 18 | log_format main | 15 | log_format main |
| 19 | '$remote_addr "$remote_user" ' | 16 | '$remote_addr "$remote_user" ' |
| 20 | '"$host" "$request" $status $bytes_sent ' | 17 | '"$host" "$request" $status $bytes_sent ' |
diff --git a/hosts/surtr/http/online.nix b/hosts/surtr/http/online.nix new file mode 100644 index 00000000..daad65d9 --- /dev/null +++ b/hosts/surtr/http/online.nix | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | { config, ... }: | ||
| 2 | { | ||
| 3 | config = { | ||
| 4 | services.nginx.virtualHosts."online.yggdrasil.li" = { | ||
| 5 | forceSSL = true; | ||
| 6 | kTLS = true; | ||
| 7 | http3 = true; | ||
| 8 | sslCertificate = "/run/credentials/nginx.service/online.yggdrasil.li.pem"; | ||
| 9 | sslCertificateKey = "/run/credentials/nginx.service/online.yggdrasil.li.key.pem"; | ||
| 10 | sslTrustedCertificate = "/run/credentials/nginx.service/online.yggdrasil.li.chain.pem"; | ||
| 11 | |||
| 12 | locations."/".extraConfig = '' | ||
| 13 | add_header X-NetworkManager-Status online; | ||
| 14 | add_header Cache-Control "max-age=0, must-revalidate"; | ||
| 15 | return 204; | ||
| 16 | ''; | ||
| 17 | }; | ||
| 18 | security.acme.rfc2136Domains."online.yggdrasil.li" = { | ||
| 19 | restartUnits = ["nginx.service"]; | ||
| 20 | }; | ||
| 21 | systemd.services.nginx.serviceConfig = { | ||
| 22 | LoadCredential = [ | ||
| 23 | "online.yggdrasil.li.key.pem:${config.security.acme.certs."online.yggdrasil.li".directory}/key.pem" | ||
| 24 | "online.yggdrasil.li.pem:${config.security.acme.certs."online.yggdrasil.li".directory}/fullchain.pem" | ||
| 25 | "online.yggdrasil.li.chain.pem:${config.security.acme.certs."online.yggdrasil.li".directory}/chain.pem" | ||
| 26 | ]; | ||
| 27 | }; | ||
| 28 | }; | ||
| 29 | } | ||
diff --git a/hosts/surtr/immich.nix b/hosts/surtr/immich.nix new file mode 100644 index 00000000..61a55e77 --- /dev/null +++ b/hosts/surtr/immich.nix | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | { config, ... }: | ||
| 2 | |||
| 3 | { | ||
| 4 | config = { | ||
| 5 | security.acme.rfc2136Domains = { | ||
| 6 | "immich.yggdrasil.li" = { | ||
| 7 | restartUnits = ["nginx.service"]; | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | services.nginx = { | ||
| 12 | upstreams."immich" = { | ||
| 13 | servers = { | ||
| 14 | "[2a03:4000:52:ada:4:1::]:2283" = {}; | ||
| 15 | }; | ||
| 16 | extraConfig = '' | ||
| 17 | keepalive 8; | ||
| 18 | ''; | ||
| 19 | }; | ||
| 20 | virtualHosts = { | ||
| 21 | "immich.yggdrasil.li" = { | ||
| 22 | kTLS = true; | ||
| 23 | http3 = true; | ||
| 24 | forceSSL = true; | ||
| 25 | sslCertificate = "/run/credentials/nginx.service/immich.yggdrasil.li.pem"; | ||
| 26 | sslCertificateKey = "/run/credentials/nginx.service/immich.yggdrasil.li.key.pem"; | ||
| 27 | sslTrustedCertificate = "/run/credentials/nginx.service/immich.yggdrasil.li.chain.pem"; | ||
| 28 | extraConfig = '' | ||
| 29 | charset utf-8; | ||
| 30 | ''; | ||
| 31 | |||
| 32 | locations = { | ||
| 33 | "/".extraConfig = '' | ||
| 34 | proxy_pass http://immich; | ||
| 35 | |||
| 36 | proxy_http_version 1.1; | ||
| 37 | proxy_set_header Upgrade $http_upgrade; | ||
| 38 | proxy_set_header Connection "upgrade"; | ||
| 39 | |||
| 40 | proxy_redirect off; | ||
| 41 | proxy_set_header Host $host; | ||
| 42 | proxy_set_header X-Real-IP $remote_addr; | ||
| 43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| 44 | proxy_set_header X-Forwarded-Host $server_name; | ||
| 45 | proxy_set_header X-Forwarded-Proto $scheme; | ||
| 46 | |||
| 47 | client_max_body_size 0; | ||
| 48 | proxy_request_buffering off; | ||
| 49 | proxy_buffering off; | ||
| 50 | ''; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | }; | ||
| 54 | }; | ||
| 55 | |||
| 56 | systemd.services.nginx = { | ||
| 57 | serviceConfig = { | ||
| 58 | LoadCredential = [ | ||
| 59 | "immich.yggdrasil.li.key.pem:${config.security.acme.certs."immich.yggdrasil.li".directory}/key.pem" | ||
| 60 | "immich.yggdrasil.li.pem:${config.security.acme.certs."immich.yggdrasil.li".directory}/fullchain.pem" | ||
| 61 | "immich.yggdrasil.li.chain.pem:${config.security.acme.certs."immich.yggdrasil.li".directory}/chain.pem" | ||
| 62 | ]; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | }; | ||
| 66 | } | ||
diff --git a/hosts/surtr/kimai.nix b/hosts/surtr/kimai.nix new file mode 100644 index 00000000..454b3d80 --- /dev/null +++ b/hosts/surtr/kimai.nix | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | { config, ... }: | ||
| 2 | |||
| 3 | { | ||
| 4 | config = { | ||
| 5 | security.acme.rfc2136Domains = { | ||
| 6 | "kimai.yggdrasil.li" = { | ||
| 7 | restartUnits = ["nginx.service"]; | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | services.nginx = { | ||
| 12 | upstreams."kimai" = { | ||
| 13 | servers = { | ||
| 14 | "[2a03:4000:52:ada:6::2]:80" = {}; | ||
| 15 | }; | ||
| 16 | extraConfig = '' | ||
| 17 | keepalive 8; | ||
| 18 | ''; | ||
| 19 | }; | ||
| 20 | virtualHosts = { | ||
| 21 | "kimai.yggdrasil.li" = { | ||
| 22 | kTLS = true; | ||
| 23 | http3 = true; | ||
| 24 | forceSSL = true; | ||
| 25 | sslCertificate = "/run/credentials/nginx.service/kimai.yggdrasil.li.pem"; | ||
| 26 | sslCertificateKey = "/run/credentials/nginx.service/kimai.yggdrasil.li.key.pem"; | ||
| 27 | sslTrustedCertificate = "/run/credentials/nginx.service/kimai.yggdrasil.li.chain.pem"; | ||
| 28 | extraConfig = '' | ||
| 29 | charset utf-8; | ||
| 30 | ''; | ||
| 31 | |||
| 32 | locations = { | ||
| 33 | "/".extraConfig = '' | ||
| 34 | proxy_pass http://kimai; | ||
| 35 | |||
| 36 | proxy_http_version 1.1; | ||
| 37 | proxy_set_header Upgrade $http_upgrade; | ||
| 38 | proxy_set_header Connection "upgrade"; | ||
| 39 | |||
| 40 | proxy_redirect off; | ||
| 41 | proxy_set_header Host $host; | ||
| 42 | proxy_set_header X-Real-IP $remote_addr; | ||
| 43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| 44 | proxy_set_header X-Forwarded-Host $server_name; | ||
| 45 | proxy_set_header X-Forwarded-Proto $scheme; | ||
| 46 | |||
| 47 | client_max_body_size 0; | ||
| 48 | proxy_request_buffering off; | ||
| 49 | proxy_buffering off; | ||
| 50 | |||
| 51 | proxy_read_timeout 300; | ||
| 52 | ''; | ||
| 53 | }; | ||
| 54 | }; | ||
| 55 | }; | ||
| 56 | }; | ||
| 57 | |||
| 58 | systemd.services.nginx = { | ||
| 59 | serviceConfig = { | ||
| 60 | LoadCredential = [ | ||
| 61 | "kimai.yggdrasil.li.key.pem:${config.security.acme.certs."kimai.yggdrasil.li".directory}/key.pem" | ||
| 62 | "kimai.yggdrasil.li.pem:${config.security.acme.certs."kimai.yggdrasil.li".directory}/fullchain.pem" | ||
| 63 | "kimai.yggdrasil.li.chain.pem:${config.security.acme.certs."kimai.yggdrasil.li".directory}/chain.pem" | ||
| 64 | ]; | ||
| 65 | }; | ||
| 66 | }; | ||
| 67 | }; | ||
| 68 | } | ||
diff --git a/hosts/surtr/matrix/default.nix b/hosts/surtr/matrix/default.nix index 7a1b968e..26517cd7 100644 --- a/hosts/surtr/matrix/default.nix +++ b/hosts/surtr/matrix/default.nix | |||
| @@ -291,7 +291,6 @@ with lib; | |||
| 291 | realm = "turn.synapse.li"; | 291 | realm = "turn.synapse.li"; |
| 292 | cert = "/run/credentials/coturn.service/turn.synapse.li.pem"; | 292 | cert = "/run/credentials/coturn.service/turn.synapse.li.pem"; |
| 293 | pkey = "/run/credentials/coturn.service/turn.synapse.li.key.pem"; | 293 | pkey = "/run/credentials/coturn.service/turn.synapse.li.key.pem"; |
| 294 | dh-file = config.security.dhparams.params.coturn.path; | ||
| 295 | relay-ips = ["202.61.241.61" "2a03:4000:52:ada::"]; | 294 | relay-ips = ["202.61.241.61" "2a03:4000:52:ada::"]; |
| 296 | extraConfig = '' | 295 | extraConfig = '' |
| 297 | # for debugging | 296 | # for debugging |
diff --git a/hosts/surtr/paperless.nix b/hosts/surtr/paperless.nix new file mode 100644 index 00000000..7bc4397c --- /dev/null +++ b/hosts/surtr/paperless.nix | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | { config, ... }: | ||
| 2 | |||
| 3 | { | ||
| 4 | config = { | ||
| 5 | security.acme.rfc2136Domains = { | ||
| 6 | "paperless.yggdrasil.li" = { | ||
| 7 | restartUnits = ["nginx.service"]; | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | services.nginx = { | ||
| 12 | upstreams."paperless" = { | ||
| 13 | servers = { | ||
| 14 | "[2a03:4000:52:ada:4:1::]:28981" = {}; | ||
| 15 | }; | ||
| 16 | extraConfig = '' | ||
| 17 | keepalive 8; | ||
| 18 | ''; | ||
| 19 | }; | ||
| 20 | virtualHosts = { | ||
| 21 | "paperless.yggdrasil.li" = { | ||
| 22 | kTLS = true; | ||
| 23 | http3 = true; | ||
| 24 | forceSSL = true; | ||
| 25 | sslCertificate = "/run/credentials/nginx.service/paperless.yggdrasil.li.pem"; | ||
| 26 | sslCertificateKey = "/run/credentials/nginx.service/paperless.yggdrasil.li.key.pem"; | ||
| 27 | sslTrustedCertificate = "/run/credentials/nginx.service/paperless.yggdrasil.li.chain.pem"; | ||
| 28 | extraConfig = '' | ||
| 29 | charset utf-8; | ||
| 30 | ''; | ||
| 31 | |||
| 32 | locations = { | ||
| 33 | "/".extraConfig = '' | ||
| 34 | proxy_pass http://paperless; | ||
| 35 | |||
| 36 | proxy_http_version 1.1; | ||
| 37 | proxy_set_header Upgrade $http_upgrade; | ||
| 38 | proxy_set_header Connection "upgrade"; | ||
| 39 | |||
| 40 | proxy_redirect off; | ||
| 41 | proxy_set_header Host $host; | ||
| 42 | proxy_set_header X-Real-IP $remote_addr; | ||
| 43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| 44 | proxy_set_header X-Forwarded-Host $server_name; | ||
| 45 | proxy_set_header X-Forwarded-Proto $scheme; | ||
| 46 | |||
| 47 | client_max_body_size 0; | ||
| 48 | proxy_request_buffering off; | ||
| 49 | proxy_buffering off; | ||
| 50 | ''; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | }; | ||
| 54 | }; | ||
| 55 | |||
| 56 | systemd.services.nginx = { | ||
| 57 | serviceConfig = { | ||
| 58 | LoadCredential = [ | ||
| 59 | "paperless.yggdrasil.li.key.pem:${config.security.acme.certs."paperless.yggdrasil.li".directory}/key.pem" | ||
| 60 | "paperless.yggdrasil.li.pem:${config.security.acme.certs."paperless.yggdrasil.li".directory}/fullchain.pem" | ||
| 61 | "paperless.yggdrasil.li.chain.pem:${config.security.acme.certs."paperless.yggdrasil.li".directory}/chain.pem" | ||
| 62 | ]; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | }; | ||
| 66 | } | ||
diff --git a/hosts/surtr/postgresql/default.nix b/hosts/surtr/postgresql/default.nix index 583e4443..c43d5983 100644 --- a/hosts/surtr/postgresql/default.nix +++ b/hosts/surtr/postgresql/default.nix | |||
| @@ -89,6 +89,10 @@ in { | |||
| 89 | "d /var/spool/pgbackrest 0750 postgres postgres - -" | 89 | "d /var/spool/pgbackrest 0750 postgres postgres - -" |
| 90 | ]; | 90 | ]; |
| 91 | 91 | ||
| 92 | systemd.services.postgresql.serviceConfig = { | ||
| 93 | ReadWritePaths = [ "/var/spool/pgbackrest" "/var/lib/pgbackrest/archive/surtr" ]; | ||
| 94 | }; | ||
| 95 | |||
| 92 | systemd.services.migrate-postgresql = { | 96 | systemd.services.migrate-postgresql = { |
| 93 | after = [ "postgresql.service" ]; | 97 | after = [ "postgresql.service" ]; |
| 94 | bindsTo = [ "postgresql.service" ]; | 98 | bindsTo = [ "postgresql.service" ]; |
| @@ -276,6 +280,85 @@ in { | |||
| 276 | CREATE VIEW imap_user ("user", "password", quota_rule) AS SELECT mailbox.mailbox AS "user", "password", quota_rule FROM mailbox_quota_rule INNER JOIN mailbox ON mailbox_quota_rule.mailbox = mailbox.mailbox; | 280 | CREATE VIEW imap_user ("user", "password", quota_rule) AS SELECT mailbox.mailbox AS "user", "password", quota_rule FROM mailbox_quota_rule INNER JOIN mailbox ON mailbox_quota_rule.mailbox = mailbox.mailbox; |
| 277 | 281 | ||
| 278 | COMMIT; | 282 | COMMIT; |
| 283 | |||
| 284 | BEGIN; | ||
| 285 | SELECT _v.register_patch('013-internal', ARRAY['000-base'], null); | ||
| 286 | |||
| 287 | ALTER TABLE mailbox_mapping ADD COLUMN internal bool NOT NULL DEFAULT false; | ||
| 288 | CREATE TABLE mailbox_mapping_access ( | ||
| 289 | id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), | ||
| 290 | mailbox_mapping uuid REFERENCES mailbox_mapping(id), | ||
| 291 | mailbox uuid REFERENCES mailbox(id) | ||
| 292 | ); | ||
| 293 | CREATE USER "postfix-internal-policy"; | ||
| 294 | GRANT CONNECT ON DATABASE "email" TO "postfix-internal-policy"; | ||
| 295 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "postfix-internal-policy"; | ||
| 296 | GRANT SELECT ON ALL TABLES IN SCHEMA public TO "postfix-internal-policy"; | ||
| 297 | |||
| 298 | COMMIT; | ||
| 299 | |||
| 300 | BEGIN; | ||
| 301 | SELECT _v.register_patch('014-relay', ARRAY['000-base'], null); | ||
| 302 | |||
| 303 | CREATE TABLE relay_access ( | ||
| 304 | id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), | ||
| 305 | mailbox uuid REFERENCES mailbox(id), | ||
| 306 | domain citext NOT NULL CONSTRAINT domain_non_empty CHECK (domain <> ''') | ||
| 307 | ); | ||
| 308 | |||
| 309 | COMMIT; | ||
| 310 | |||
| 311 | BEGIN; | ||
| 312 | SELECT _v.register_patch('015-relay-unique', ARRAY['000-base', '014-relay'], null); | ||
| 313 | |||
| 314 | CREATE UNIQUE INDEX relay_unique ON relay_access (mailbox, domain); | ||
| 315 | |||
| 316 | COMMIT; | ||
| 317 | |||
| 318 | BEGIN; | ||
| 319 | SELECT _v.register_patch('015-sender_bcc', null, null); | ||
| 320 | |||
| 321 | CREATE TABLE sender_bcc_maps ( | ||
| 322 | id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), | ||
| 323 | key text NOT NULL CONSTRAINT key_not_empty CHECK (key <> '''), | ||
| 324 | value text NOT NULL CONSTRAINT value_not_empty CHECK (value <> '''), | ||
| 325 | CONSTRAINT key_unique UNIQUE (key) | ||
| 326 | ); | ||
| 327 | |||
| 328 | COMMIT; | ||
| 329 | |||
| 330 | BEGIN; | ||
| 331 | SELECT _v.register_patch('016-recipient_bcc', null, null); | ||
| 332 | |||
| 333 | CREATE TABLE recipient_bcc_maps ( | ||
| 334 | id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), | ||
| 335 | key text NOT NULL CONSTRAINT key_not_empty CHECK (key <> '''), | ||
| 336 | value text NOT NULL CONSTRAINT value_not_empty CHECK (value <> '''), | ||
| 337 | CONSTRAINT recipient_bcc_maps_key_unique UNIQUE (key) | ||
| 338 | ); | ||
| 339 | |||
| 340 | COMMIT; | ||
| 341 | |||
| 342 | BEGIN; | ||
| 343 | SELECT _v.register_patch('017-password_admin', ARRAY['000-base'], null); | ||
| 344 | |||
| 345 | CREATE TABLE password_admin ( | ||
| 346 | id uuid PRIMARY KEY NOT NULL DEFAULT gen_random_uuid(), | ||
| 347 | mailbox uuid REFERENCES mailbox(id) | ||
| 348 | ); | ||
| 349 | CREATE USER "email-password-server"; | ||
| 350 | GRANT CONNECT ON DATABASE "email" TO "email-password-server"; | ||
| 351 | ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO "email-password-server"; | ||
| 352 | GRANT SELECT ON ALL TABLES IN SCHEMA public TO "email-password-server"; | ||
| 353 | |||
| 354 | COMMIT; | ||
| 355 | |||
| 356 | BEGIN; | ||
| 357 | SELECT _v.register_patch('018-password_admin', ARRAY['000-base', '017-password_admin'], null); | ||
| 358 | |||
| 359 | GRANT UPDATE ON mailbox TO "email-password-server"; | ||
| 360 | |||
| 361 | COMMIT; | ||
| 279 | ''} | 362 | ''} |
| 280 | 363 | ||
| 281 | psql etebase postgres -eXf ${pkgs.writeText "etebase.sql" '' | 364 | psql etebase postgres -eXf ${pkgs.writeText "etebase.sql" '' |
diff --git a/hosts/surtr/tls/default.nix b/hosts/surtr/tls/default.nix index b1c05888..6621b06d 100644 --- a/hosts/surtr/tls/default.nix +++ b/hosts/surtr/tls/default.nix | |||
| @@ -41,7 +41,7 @@ in { | |||
| 41 | 41 | ||
| 42 | acceptTerms = true; | 42 | acceptTerms = true; |
| 43 | # DNS challenge is slow | 43 | # DNS challenge is slow |
| 44 | preliminarySelfsigned = true; | 44 | # preliminarySelfsigned = true; |
| 45 | defaults = { | 45 | defaults = { |
| 46 | email = "phikeebaogobaegh@141.li"; | 46 | email = "phikeebaogobaegh@141.li"; |
| 47 | # We don't like NIST curves and Let's Encrypt doesn't support | 47 | # We don't like NIST curves and Let's Encrypt doesn't support |
| @@ -58,16 +58,18 @@ in { | |||
| 58 | extraDomainNames = optional domainCfg.wildcard "*.${domain}"; | 58 | extraDomainNames = optional domainCfg.wildcard "*.${domain}"; |
| 59 | dnsResolver = "127.0.0.1:53"; | 59 | dnsResolver = "127.0.0.1:53"; |
| 60 | dnsProvider = "rfc2136"; | 60 | dnsProvider = "rfc2136"; |
| 61 | credentialsFile = pkgs.writeText "${domain}_credentials.env" '' | 61 | environmentFile = pkgs.writeText "${domain}_credentials.env" '' |
| 62 | RFC2136_NAMESERVER=127.0.0.1:53 | 62 | RFC2136_NAMESERVER=127.0.0.1:53 |
| 63 | RFC2136_TSIG_ALGORITHM=hmac-sha256. | 63 | RFC2136_TSIG_ALGORITHM=hmac-sha256. |
| 64 | RFC2136_TSIG_KEY=${domain}_acme_key | 64 | RFC2136_TSIG_KEY=${domain}_acme_key |
| 65 | RFC2136_TSIG_SECRET_FILE=/run/credentials/acme-${domain}.service/${tsigSecretName domain} | ||
| 66 | RFC2136_TTL=0 | 65 | RFC2136_TTL=0 |
| 67 | RFC2136_PROPAGATION_TIMEOUT=60 | 66 | RFC2136_PROPAGATION_TIMEOUT=60 |
| 68 | RFC2136_POLLING_INTERVAL=2 | 67 | RFC2136_POLLING_INTERVAL=2 |
| 69 | RFC2136_SEQUENCE_INTERVAL=1 | 68 | RFC2136_SEQUENCE_INTERVAL=1 |
| 70 | ''; | 69 | ''; |
| 70 | credentialFiles = { | ||
| 71 | RFC2136_TSIG_SECRET_FILE = config.sops.secrets.${tsigSecretName domain}.path; | ||
| 72 | }; | ||
| 71 | dnsPropagationCheck = false; | 73 | dnsPropagationCheck = false; |
| 72 | postRun = mkIf (domainCfg.restartUnits != []) '' | 74 | postRun = mkIf (domainCfg.restartUnits != []) '' |
| 73 | systemctl --no-block try-restart ${escapeShellArgs domainCfg.restartUnits} | 75 | systemctl --no-block try-restart ${escapeShellArgs domainCfg.restartUnits} |
| @@ -79,16 +81,15 @@ in { | |||
| 79 | sops.secrets = mapAttrs' (domain: domainCfg: nameValuePair (tsigSecretName domain) { | 81 | sops.secrets = mapAttrs' (domain: domainCfg: nameValuePair (tsigSecretName domain) { |
| 80 | format = "binary"; | 82 | format = "binary"; |
| 81 | sopsFile = tsigKey domain; | 83 | sopsFile = tsigKey domain; |
| 82 | restartUnits = [ "acme-${domain}.service" ]; | 84 | restartUnits = [ "acme-order-renew${domain}.service" ]; |
| 83 | }) cfg.rfc2136Domains; | 85 | }) cfg.rfc2136Domains; |
| 84 | 86 | ||
| 85 | # Provide appropriate `tsig_key/*` to systemd service performing | 87 | # Provide appropriate `tsig_key/*` to systemd service performing |
| 86 | # certificate provisioning | 88 | # certificate provisioning |
| 87 | systemd.services = mapAttrs' (domain: domainCfg: nameValuePair "acme-${domain}" { | 89 | systemd.services = mapAttrs' (domain: domainCfg: nameValuePair "acme-order-renew-${domain}" { |
| 88 | after = [ "knot.service" ]; | 90 | after = [ "knot.service" ]; |
| 89 | bindsTo = [ "knot.service" ]; | 91 | bindsTo = [ "knot.service" ]; |
| 90 | serviceConfig = { | 92 | serviceConfig = { |
| 91 | LoadCredential = [ "${tsigSecretName domain}:${config.sops.secrets.${tsigSecretName domain}.path}" ]; | ||
| 92 | SystemCallFilter = mkForce [ "@system-service" "~@privileged" "@chown" ]; | 93 | SystemCallFilter = mkForce [ "@system-service" "~@privileged" "@chown" ]; |
| 93 | }; | 94 | }; |
| 94 | }) cfg.rfc2136Domains; | 95 | }) cfg.rfc2136Domains; |
diff --git a/hosts/surtr/tls/tsig_key.gup b/hosts/surtr/tls/tsig_key.gup index 3d81b603..46a3789e 100644 --- a/hosts/surtr/tls/tsig_key.gup +++ b/hosts/surtr/tls/tsig_key.gup | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #!/usr/bin/env zsh | 1 | #!/usr/bin/env zsh |
| 2 | 2 | ||
| 3 | keyFile=../dns/keys/${2:t}_acme.yaml | 3 | keyFile=../dns/keys/${2:t}_acme |
| 4 | gup -u $keyFile | 4 | gup -u $keyFile |
| 5 | sops -d --input-type=binary --output-type=binary ${keyFile} | yq -r '.key[0].secret' > $1 | 5 | sops -d --input-type=binary --output-type=binary ${keyFile} | yq -r '.key[0].secret' > $1 |
| 6 | sops -p '7ED22F4AA7BB55728B643DC5471B7D88E4EF66F8,30D3453B8CD02FE2A3E7C78C0FB536FB87AE8F51' --input-type=binary -e -i $1 \ No newline at end of file | 6 | sops --input-type=binary -e -i $1 |
diff --git a/hosts/surtr/tls/tsig_keys/audiobookshelf.yggdrasil.li b/hosts/surtr/tls/tsig_keys/audiobookshelf.yggdrasil.li new file mode 100644 index 00000000..8dd610dd --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/audiobookshelf.yggdrasil.li | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:r9jhdTlbDnCMq1QLJutn76uz1Ml8MFs7fXYRSiVYh1gafcXXsUZBq5+qqoQI,iv:un/luttuKpCiMf53fa2SRY0ffttGiYwT8DuHCKEnnEI=,tag:SkNULZSulQmP99aB/Ec+Fw==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkZGJzaEsrSU4raHlTVDVB\nczRnWVlSTTRuNXU0T3F1RTkxKytXeVJRdGpFCk9WMzNBR1NaTTMzN3BGQ2JmTjVt\nRU4rSWxCYjJPYVRzLzR0OVRYQm45TUkKLS0tIDNyMnpPN2VKUFFadTkveXRYeWps\nYUNaTjRJLzdWUnREaUVIWkpFV0FTZ2MKJS0K49SdkLW4p67FlgboHy/OVvCiUA7g\nuv5b+yotkQmh5xJwr7CUvwRewqJh56mg1yhWmE8wzpgLZMIjRXcQCQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQQ1h3M1lXTXVNd0d6cmtU\nU2JtUzFFblJudmEycnJONkkwME9wWm5jWVFzCnRYVEFWaVNvSW9GZ05TRWF4L2ho\nanltVytEU3ZOdHk1VHY5aGJDUkdDdmcKLS0tIEtzOFVkbmpjbWN5d0c1VEpxc1Rr\nSzJwclYxeC9TVWNaK2gwUmJSY0x1ZVUKTNivp5iS+1tzVMjMn17/ncvHcELhjQ/B\n0OVz4VpKM2wv6CjEcIMxmchqT8p8GFYVRrKUdqO2GEKOoe8ANtidWA==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2025-05-09T17:07:16Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:SwS+8UQnPgHORobKLu+u2pNaMdKIvR+etUed8btbbne/IX/Wpxt0qyPYXNNGGRkN3KAxTHWjRRdrKU1bkuTU3ER1c94T935ExDESKJLVjzaEF5VSWCqLyUNCMsY2ANw84UES2swK4YI4zF1CP7rD8tKFFld78IWZoeQ7XNGDMRA=,iv:neLvamISgQ5+aqW1iRj9xJoXq1weNNyy7KCFG2+WRQE=,tag:66SDO61WnKU6DVElo9CImg==,type:str]", | ||
| 16 | "unencrypted_suffix": "_unencrypted", | ||
| 17 | "version": "3.10.2" | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/hosts/surtr/tls/tsig_keys/changedetection.yggdrasil.li b/hosts/surtr/tls/tsig_keys/changedetection.yggdrasil.li new file mode 100644 index 00000000..ac332fe5 --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/changedetection.yggdrasil.li | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:OD12OI11EpjWIGtCGzSIeFXIht1tM7YrEbo3XqcxD0XFaZ3CrELJgru9gtN/,iv:SXPNed6CUWCUDomJbx1kOjvxTBoHrgb6tKw9Jb/Qa0M=,tag:RiueVMBSdAF96d6190bwfg==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwR3FGdks2TUtkSUJLcG1v\nbXZmWFZNVmc3a0x5d2tPNmpJVDJPQmIyNkFNClAwNzI0aHE5SFdaQ0RoZnE0ZEx5\nL3IzQTRpd0g4cHJSUHlrbGtRK283SEkKLS0tIDdLVzE0SFgvS0l1eDd5SHVQQ1By\nNmZ1M0cxSnNxTE5OdHBLZ2FFRWhXdUkKTykJ2kRJPrcPwuw3ufNaCJ6pOuvtDUcl\noHizOV+Yco7nhKtINE93mD4xIiER0i5h7lpKOTUGgjzhjJP2DR7ifw==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxNVRmMVIvVVZ4SkVMUC9o\nOVMxekNiZTRJWTExMHU5Q3lOaVFkbnhGT3lrCmM3ZjNSV056WjlTeEZzdHpKL1Fl\nbFF4R1phSitzWlY2dFJuRDFvK09LWm8KLS0tIEZINU5KallPdnZsZEh6WUxJYW1K\ncEV0ZkJVK2JiZ1ZtSTZRQUtiaGFBTEkKC6DQLWqY4WrRCSRrWAqlvjw6lp0Y+XGo\nrwxWMwyEocizMR6i//a5P8RBPnvzAEHbXMobI4mSDyfIdezWUX/QNA==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2025-12-08T12:46:13Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:FLdO6Bz74+aTd9ns8ysbcrNdwogJvnm/sRRTLntf5zAH16MyI+QbsBo2LORWr5O3t24+EfmZBhMsfj/AXvqkcMFjPwIhALQpPjjT2JfAsLFtSUqZRjBNKYkfoLlTUKb083RgDjEUIVGgsZzJLCyFtfZP0NXicTUsUz9mRZCYwYU=,iv:sSPuuoE3qgt+Qhh76rZtSCBnHYLK3AN7IljUDkr14AE=,tag:56rYSDonQwfKjNR5fBgQiA==,type:str]", | ||
| 16 | "version": "3.11.0" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/tls/tsig_keys/hledger.yggdrasil.li b/hosts/surtr/tls/tsig_keys/hledger.yggdrasil.li new file mode 100644 index 00000000..ab6cdd68 --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/hledger.yggdrasil.li | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:Yd70QIj9DE6a5IN+Mf2M5p95vkRMHRg9BXaM686W7BRtthOw9m54/5FK6JWr,iv:cIOIKinkqFFPgTZdewWVY0h6kM5hGfVzuA4iYNhwK5c=,tag:Ds/oI+TOERbIdcGbI4WoEg==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "kms": null, | ||
| 5 | "gcp_kms": null, | ||
| 6 | "azure_kv": null, | ||
| 7 | "hc_vault": null, | ||
| 8 | "age": [ | ||
| 9 | { | ||
| 10 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1NnJ4SmsvSlh3ZlliSm9C\nNG45clh3NEZWZ05jaHhVK0xqTVRFL2wxN1ZrCk5hL2p2ZjhtcDBjTEZscXFTNkY5\nemVZSUUwV2V5cFBTdWo4RWxsM2xROVEKLS0tIDBFSFlkUVJ0ajJEUENlelVFKzVk\ndnJhMURMU2o3WVBKZGNVRXBiNytqUFEKHivcSTYy5D770C0h7RsmLBmkIG9+MDoV\ngJHvfkGzXPKwmDTMKdHbIk+ctI+u0/1jMn/K2Q9OFnOIYxP3gHiFag==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | }, | ||
| 13 | { | ||
| 14 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 15 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArYUNCQ1U2MXpQdmM4SHR0\nTnJWZlFGTUQ1NjVqZ3Z2MGt5NFpBVFp0b0YwCkdseitkbzI1RkZyL3V5Z1pNMG9R\nVnEzRUxrTDQrS3BiMXB1QUFPeUcxZUkKLS0tIGJFODkwNFY3c0tBLzFBNjFiYjJk\nZW82bTdia2F1NHpNSG1IYmhWb1ZCTHMK9ovFx3+x5PrV4y6+RH5XA5DK2wRPXlAt\ncxxpRZIlmnvhZXIeCYE9yhHFmz3uAn0Oib1RUDblca9FlnF9tyYD6g==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 16 | } | ||
| 17 | ], | ||
| 18 | "lastmodified": "2025-02-19T17:13:51Z", | ||
| 19 | "mac": "ENC[AES256_GCM,data:ReRuK9qdZV8AbMzA9Yur0AZW+1RF3aRnfBvsKJkQtXsFdkmJQ4QkRGtL27RmjFdvQ3kXBIyhib7hYA60AJ0amduYrSScY0dtz8AurjyE4f2BGQ9/QeKRBfKXHxLvj4/xWNvS4+PVdGKkKbqIs8isz9n77WQQ3lTHop2K/TjaTuQ=,iv:gUhDK9oeUHdpQ2Fp8mFDIgPFo2JjHE0jjooL7FmvmrE=,tag:2lkwSl3j3oqamdLbM9wbow==,type:str]", | ||
| 20 | "pgp": null, | ||
| 21 | "unencrypted_suffix": "_unencrypted", | ||
| 22 | "version": "3.9.4" | ||
| 23 | } | ||
| 24 | } \ No newline at end of file | ||
diff --git a/hosts/surtr/tls/tsig_keys/immich.yggdrasil.li b/hosts/surtr/tls/tsig_keys/immich.yggdrasil.li new file mode 100644 index 00000000..73104cc1 --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/immich.yggdrasil.li | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:COfmT91I4+yiPhN3Hi7BTqMHyKhdKtwlzT9vNgTZc7FWTHhfuTtCHQo/rhX0,iv:RDs//AT8peUhKwIRdchCScUr/PlEzyMzQPB90S4k3g4=,tag:Lh4BULmQ6+hC+Ed8s9k0Hw==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "kms": null, | ||
| 5 | "gcp_kms": null, | ||
| 6 | "azure_kv": null, | ||
| 7 | "hc_vault": null, | ||
| 8 | "age": [ | ||
| 9 | { | ||
| 10 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGVEQvU29uWnVjMS8xcGp1\nam5hZVN3ejAxaGdpVWNia0VxT0I3dzR4YlV3ClczOGd0ZDJmUDhqb2dEdm5VeUdX\nRlR1WDNYUU9qaTYrRzhYMXBTV1JjV1UKLS0tIHBONU55RWtRSkR6K2NTNFZrUEZj\nbktqY0xBdGtiZWFFV3JUUVZTOC9YV2MKI4Ytz1NZ9+Og0GzIt/bh6L3aJUeR476g\nyRNifW4eOHf4Ne02ElpEoq6woInkxk8Ou/SJVIRmEOhjwm+qbV17gQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | }, | ||
| 13 | { | ||
| 14 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 15 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVOVNydWcyYjFrZDR2WStu\nWkJQd3VTTGtqVzdLVFR1eFdPZXBtVFBzVXc4ClREQVpKeXlhWlBFQzVFL0VGME5K\nUUhoa3A1YWdvSkZVV1FQcUh5L3RoUmMKLS0tIHE4c3A1OTNXVk9xZHJPZTlSMlQ4\nZnZUTXdjUGZuN3NoSEFSSko1aU5aQUEKHcuI2+9q7DsDwRn7mfwcSyC7AixzCC0e\nhqnGaW0HxmtLeOFuSPLdFMhhockCYGEV/907i/X6EImepWC4cf3bqA==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 16 | } | ||
| 17 | ], | ||
| 18 | "lastmodified": "2025-01-03T15:31:40Z", | ||
| 19 | "mac": "ENC[AES256_GCM,data:soDFDk35A1ULzOosZNrbhvtG3NPJDpAtLP3xrDtCBxgSGQ0lWrQ0o3MaKaJoDXQv7g/vYghmSwjH+0In0Ib3OWg0WLAlhwTEsiAn1o4JNRu/wF5aqvazOiDzFu7cyWil4Lsphy5eZgtc4IUp75SlCQc71xlNLoxudPpdcSxNLWg=,iv:jBYUZbiWM5gxFA+ZdpxpZIkz3WfgFi59tXFp242/qr8=,tag:H7ihAryZ8be+BbaqXFhRRg==,type:str]", | ||
| 20 | "pgp": null, | ||
| 21 | "unencrypted_suffix": "_unencrypted", | ||
| 22 | "version": "3.9.2" | ||
| 23 | } | ||
| 24 | } \ No newline at end of file | ||
diff --git a/hosts/surtr/tls/tsig_keys/kimai.yggdrasil.li b/hosts/surtr/tls/tsig_keys/kimai.yggdrasil.li new file mode 100644 index 00000000..b9199975 --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/kimai.yggdrasil.li | |||
| @@ -0,0 +1,19 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:ATcU3Ix7o5d/49rD5H8je1ozTjoghrloMh5DIZ5WE3oYauUAknpGfr9xq92V,iv:vy9YK5Ot7CCjMtgAGVeAUQuaSw4F5kmmZ0GJYV9kCdQ=,tag:F/MXTUM2AI1fGXa9Ewn8yQ==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDMEF0cUdydERYVzJCa3pW\nTlo0NUFON0d5RGJFVnVTNVg3cjNEUERQMEdFClEvQW5odlNEd2F1VTFmMWQrL2RB\ncllFZVpIVVJrNTJsSGF4UEdZMnVmQzAKLS0tIFUrQkkzRVZiOFNiTnFCT1pEYVRM\nQm8wV1JkQ3RrR1dkL0FsNkhsY2kxa1kKGnAo/6oibgXexUU31THdLu6X+pRtrkjD\nZnXGPZ2xaESDVUVEYQPVpNrjt9brZGJBI1BasrkEwHAXMbJC236yYQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3MGs1Z2ZqK2pqWHdVYTJH\naTlncHdPa3Zld0JhQW5Ccmc1SStWSnlDR0JrCmpML2d4TGdldUdoZCtaWVpPZVl0\nVm4waWVBS1orRS90ZS96N0Y2M29LY0UKLS0tIEI1Z2VVbVVxRUpOZEN4NnBRRklC\nQXloelZCb04xbmduTlVuL005TlRGMHMKfLB6zA3sj3HgDBC7VGfGVB6I1zJpt0PV\nkCV2yADgvAA2pT9HPg9IWAEpTPysOBiuE2jPNtFvylZYwTDHoumFnQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2025-05-24T09:42:23Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:0pk1LpWPmX9td/TwJFxwWp5pTDyW78UtHXMDah+V9Tmgi8hH7ONdysgjwpDwS/c4zGnMA3qtobEL286U3//CTXt2qVsiUGLsnngzs2E6yBg8oGMYlGrch4M355Fl5ZxYsc8QLA6qWcuZ4H3QW8PnoqdJixcHoYLoxG01dzh4Bc0=,iv:zchk4enI1D80BkJLji5RLm7OTk3GeF8nYHuwqBxCXIM=,tag:bgkknPMqkSidi6bDFfv6UQ==,type:str]", | ||
| 16 | "unencrypted_suffix": "_unencrypted", | ||
| 17 | "version": "3.10.2" | ||
| 18 | } | ||
| 19 | } | ||
diff --git a/hosts/surtr/tls/tsig_keys/online.yggdrasil.li b/hosts/surtr/tls/tsig_keys/online.yggdrasil.li new file mode 100644 index 00000000..37cb5995 --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/online.yggdrasil.li | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:pZn6ayJ1pCjLLodFAnpw3mgkcBYVdW7t9RYEysbdxfXUaf2jyIWX8h7dgpKO,iv:IWoU9AgUSRRPgD1R/2khVtLudo1GhPZV6C6q6wNZYDA=,tag:lJYqX6YV8z+uC1URFrw3eg==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6WjgyYmUybVJwWW01dnY3\nYjk1dTI0c3pYU2dlSThLc1ZsT0JDeFFzWEIwCncrd3VTN0x3Wi94emdCNlpVWFBW\nSkVYM3pGRE44RHNmOW1HVkRtc2RVN1UKLS0tIE5NWG1TV0pqcm9NekxyRW9LVGhW\nYXY3ZlYwRytoQkwwVENSaFBNejRYelEKpEbY1WDa0iUugYj1PZFt4HidietHmcI/\ncbl8l+h/hbJxuC2UtaMVSlfe3IzJmnwnqpuYAiEm3WaF1LDiPzMWvA==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGNm5KQVhzeGQzNVVnaWFi\nRnBXMEl3UENDTExKeUZqdjk0RUl6V2hZYlZVClk5V3hnbkFycDRqOTlZWjZnRnpy\nSmVGT1BhbjQ1T21hZ3RqZFl5RU9jNVkKLS0tIDhHN1lRZkNjcjdnRHJrNjRlczFk\nQ0o4RUlQSkp1UXRsZmdHQXUxZ1Rwb1UK88VMOotD0qScxCM10cgWHpz577eih5TV\n5SchQznh3icCidYWnAG4i4vvKFDwQBiAE69Yx/3rTYlv/fJYMxpX6Q==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2026-05-15T11:50:25Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:5f+Ge8WZoXp2QvPNi6ghrePo8KDaB93vIbqfllhwQI4kardiWSuaRANygAJC/d/zzok8EiOIiJ4qp8pcJJpW23K9qTT+6ZGJohdywDzk9IoHZ/FsJSHEiS3bxwnPE11n1Ia5xT14RFWPxswJy/YW8Go9sKSmiXuFXEcud4aZ8LU=,iv:2opq4uH+VGnlAcI4ffKrosKe+pVNDmTG+gC3ph6UFEM=,tag:NcYdxYhXCjnkUS5BvfpPXA==,type:str]", | ||
| 16 | "version": "3.12.2" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/tls/tsig_keys/paperless.yggdrasil.li b/hosts/surtr/tls/tsig_keys/paperless.yggdrasil.li new file mode 100644 index 00000000..b1029931 --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/paperless.yggdrasil.li | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:D9l0pklD2KDZ4/TXHtXg00MmCnjCVVBG0AK9j5OxxBCyYseCTckp2P/iPOng,iv:DjvuKWPr/jldfk0eZ5+jWHN0RurdruR4Md7AMAPzRQg=,tag:h0c4m3hpATzzb6a7DVmi9w==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "kms": null, | ||
| 5 | "gcp_kms": null, | ||
| 6 | "azure_kv": null, | ||
| 7 | "hc_vault": null, | ||
| 8 | "age": [ | ||
| 9 | { | ||
| 10 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3S05aS0ZEcVU2T3BIOG13\nSDJLTUp4OG9ZYVluK2gxbUJDSFRaQ0xnS0YwClFkKzByanJGOWFwbTlISndyU0Rx\nN1FJb3FVaUZOVDBsWEdHTVNGaGNtMVkKLS0tIDI1RmxaMlhVd1FPL1dNdlRGK0Nq\nMFpJZTNnWncrbkV5YS82ZnhGRld0UG8KIuf7bC7GVxaGeR7gwC7kGu/wtBppjq4H\nyDT05CYJf9/EE3K5aJpIOlxyqowRs2SINvIVkyd5ggYkkxCctmGXjQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | }, | ||
| 13 | { | ||
| 14 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 15 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUV3ZqTVJkNWdHeTlKK3Vl\nVTdrdzE2Z3YzVmZxelNFMDNMTUJneHNtNzFRCmQxTU84ekV4bFVLajU0ajB6ZzZK\neEpuQTcyS1o4MW9xTU5nMXVUR0gxTmcKLS0tIGVzZC8xYTc1VkU2RzA2NFQ1K2xz\nLzhPVjBUcytWNGRsdnFob3A4aWljelkKFMlmigcEVzelcEiv6WGya1dsIOJYr7YT\naBHgMttV7zzYHLqvIVJSCz+uw2FqDyqN46twmzFC0HSHeiKbvRrHVw==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 16 | } | ||
| 17 | ], | ||
| 18 | "lastmodified": "2025-02-13T19:23:42Z", | ||
| 19 | "mac": "ENC[AES256_GCM,data:0Fcgq0pOZtBBSiK8pUr/jadXMdtbZYFhUbSe+7DQpB8Fo2r8cEoT+Cpcy7tu+l9eXUiDk/tXTBJyMXaW4XWwS/Fe6Zcb95UYaYR1Y6OM9JVPYmwd6QSeC13MwzhYaCDlBiWWq69Zn8grEg7npWo/LS9LK7IEbN7EI8o7QYDI6cw=,iv:C+8ZmVTNWySQ+/6j+YirSwZzoMqXRlgstk47Efxmqps=,tag:Be/6Ve6M/Dcm/6QrbF+JTw==,type:str]", | ||
| 20 | "pgp": null, | ||
| 21 | "unencrypted_suffix": "_unencrypted", | ||
| 22 | "version": "3.9.4" | ||
| 23 | } | ||
| 24 | } \ No newline at end of file | ||
diff --git a/hosts/surtr/tls/tsig_keys/pw.bouncy.email b/hosts/surtr/tls/tsig_keys/pw.bouncy.email new file mode 100644 index 00000000..a2afac85 --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/pw.bouncy.email | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:BPS7FIHRYPT2rRPa/XzpvPTMPqnncW5AMYCxeuAvGuuKi/dhASPboppvY/gS,iv:5g/WoOS3eOx/WK9d/qkiINfBsTduDPAUAJkToocCuHc=,tag:u0hSkteSRnjKEeXCOyIxzA==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxUWV2dVpMRExZRGJsM2ZP\nM1dqUnplai9CRmlMb1dBeXdwMTdNOWVQOEJRCnVYYS9SOU8vWUxSV0xTRmJDaEF4\nUGNzYVgzakhhSXMxMHgxQUxwMjU3bzgKLS0tIHVSVGdyRndseFRGblU5Z1J1L3ZK\nMlBnTVRVdHdheThWU2Urc0pZaE5WR3MKBUVK79os1sn2lVUVnj7iQgP9qZ44OXOP\n3s8PfxzaWyaARAK9yQX05a4pCMeiHdcrvaByPQxdzndVxopHNQqCBw==\n-----END AGE ENCRYPTED FILE-----\n", | ||
| 7 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrYUYrcWRUQlVua283MTUx\nK3Y4K0VPd3p6Nzh6YXYzN21WTTV2bktzRFRFCjNjQmR1MDZIQ05vNTlkRkN5dDBX\nelM3bGtmWUNSVnVQb3Z6aWZyTjgrRDgKLS0tIENJcU5NZkIwZnFZck0vVmZ4bmp5\nTkpYRURrVGI5NCtJVWFFWjlXOStZR3cKJcqRnti3SnYLyC2/TKwkfGux8B7G1uta\nVmAMG8hf2tSJOaxM22/K/LGOXY8rinRYTCzCqvYX37HrBTRuGlcMOg==\n-----END AGE ENCRYPTED FILE-----\n", | ||
| 11 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2026-06-06T13:54:42Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:yVLQhcoaKrchMQq4A35GithgHCdl7v0hxQluVNWRPWNdHDNtFJB+qH1Otjcew+i+gqVJGZ5F6YBapU93tFQGSeUqEjnhelPwTglAld28rQvBqGm1uBK1FrltY3wMxhLkiVKuLAVNkbyi9hOHfNyuhca5bhA1pQaMN0OoiSykgLg=,iv:sx0G7th9PA874xfOLZMKAI5TGwkWZ83PCcxS/On0omw=,tag:WhmHJp31WVao59+vGuA7PA==,type:str]", | ||
| 16 | "version": "3.13.1" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/tls/tsig_keys/vikunja.yggdrasil.li b/hosts/surtr/tls/tsig_keys/vikunja.yggdrasil.li new file mode 100644 index 00000000..d5c19c2d --- /dev/null +++ b/hosts/surtr/tls/tsig_keys/vikunja.yggdrasil.li | |||
| @@ -0,0 +1,18 @@ | |||
| 1 | { | ||
| 2 | "data": "ENC[AES256_GCM,data:XfGp8x7wPhGf/Imo3m7/38mo5GD8zUODXEt1YZCVwWYDb6usiPMpGlNDTLzH,iv:mD0j48MKuU30h7llO575vKROOrojJzoA4Md9I6MR4Gg=,tag:h9EAJfViKUg3YQvU1I/ICQ==,type:str]", | ||
| 3 | "sops": { | ||
| 4 | "age": [ | ||
| 5 | { | ||
| 6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
| 7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZbHU3bDlwSS9VcnJNTzd6\ndFZyaC9CS2hQeWVSYVlDTzJLSlEvcEdJQlRFCmNoRzJpcUdycmx4T3dpREoxZTRL\neisxSGhlOXpUd0V2ZWgxdHc4empoRHcKLS0tIHhPNFFBUjNiaUMxWUx4NXNWeVNl\neHVib1Qwb2wyTWk3ZEtJQlNweHVhOUkK2kT2nmv9vwWGsMjW1RfLywGF/0yjLaNt\nb5M/v9jzYtV6S0PB1jegc4QxkGEKH4AxGsc/mqt6cXTG0em6hIIVDA==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 8 | }, | ||
| 9 | { | ||
| 10 | "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", | ||
| 11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSejM4cDZHTEtMdW5keUtk\naVV6Um4yOGd2anp0djduZ1pPMHg4bmNWTTBRCjZ2VE52Ym1YcDVNSEdPRUw5TFA3\nQnIwVjNwMzdUQWtjVUxndWozV2lnWUkKLS0tIGJSTTlEeE1sUysxUmVHVnNSaWRT\nRjJpOXFoUDgvMGxpaGNlV1ZVV0QvK3cKGDVfAudB5v201FOWFaTfCdT+io85Q14P\natzYgCAHbrpkicYL54gAdsgTPKfbnRU62DQlz7b2y69fU+kam4W0cw==\n-----END AGE ENCRYPTED FILE-----\n" | ||
| 12 | } | ||
| 13 | ], | ||
| 14 | "lastmodified": "2026-01-01T14:25:24Z", | ||
| 15 | "mac": "ENC[AES256_GCM,data:A/1ZIUhKxSZBiivvbuDykcZ5DaUzq7FBD74mkP0ZECev0oBrziYtTgqA4MBgukV/hSQohDl8rzxReiQ7vxUotr6UocnF4x43guhABBayWh9Sp9n5T4yMIYYAemEQ67jYbTdRbgm4xQ+jSofSDRNFILBpdxDbCITRWBbIXh92iIo=,iv:Y4wZAd0+rc3c4eTnNz1QMJGQN1c0FQEx4/CB3t5sEeY=,tag:ha91ZLhWBDDHSubXXDos3A==,type:str]", | ||
| 16 | "version": "3.11.0" | ||
| 17 | } | ||
| 18 | } | ||
diff --git a/hosts/surtr/vikunja.nix b/hosts/surtr/vikunja.nix new file mode 100644 index 00000000..50d8c00e --- /dev/null +++ b/hosts/surtr/vikunja.nix | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | { config, ... }: | ||
| 2 | |||
| 3 | { | ||
| 4 | config = { | ||
| 5 | security.acme.rfc2136Domains = { | ||
| 6 | "vikunja.yggdrasil.li" = { | ||
| 7 | restartUnits = ["nginx.service"]; | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | |||
| 11 | services.nginx = { | ||
| 12 | upstreams."vikunja" = { | ||
| 13 | servers = { | ||
| 14 | "[2a03:4000:52:ada:4:1::]:3456" = {}; | ||
| 15 | }; | ||
| 16 | extraConfig = '' | ||
| 17 | keepalive 8; | ||
| 18 | ''; | ||
| 19 | }; | ||
| 20 | virtualHosts = { | ||
| 21 | "vikunja.yggdrasil.li" = { | ||
| 22 | kTLS = true; | ||
| 23 | http3 = true; | ||
| 24 | forceSSL = true; | ||
| 25 | sslCertificate = "/run/credentials/nginx.service/vikunja.yggdrasil.li.pem"; | ||
| 26 | sslCertificateKey = "/run/credentials/nginx.service/vikunja.yggdrasil.li.key.pem"; | ||
| 27 | sslTrustedCertificate = "/run/credentials/nginx.service/vikunja.yggdrasil.li.chain.pem"; | ||
| 28 | extraConfig = '' | ||
| 29 | charset utf-8; | ||
| 30 | ''; | ||
| 31 | |||
| 32 | locations = { | ||
| 33 | "/".extraConfig = '' | ||
| 34 | proxy_pass http://vikunja; | ||
| 35 | |||
| 36 | proxy_http_version 1.1; | ||
| 37 | proxy_set_header Upgrade $http_upgrade; | ||
| 38 | proxy_set_header Connection "upgrade"; | ||
| 39 | |||
| 40 | proxy_redirect off; | ||
| 41 | proxy_set_header Host $host; | ||
| 42 | proxy_set_header X-Real-IP $remote_addr; | ||
| 43 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||
| 44 | proxy_set_header X-Forwarded-Host $server_name; | ||
| 45 | proxy_set_header X-Forwarded-Proto $scheme; | ||
| 46 | |||
| 47 | client_max_body_size 0; | ||
| 48 | proxy_request_buffering off; | ||
| 49 | proxy_buffering off; | ||
| 50 | ''; | ||
| 51 | }; | ||
| 52 | }; | ||
| 53 | }; | ||
| 54 | }; | ||
| 55 | |||
| 56 | systemd.services.nginx = { | ||
| 57 | serviceConfig = { | ||
| 58 | LoadCredential = [ | ||
| 59 | "vikunja.yggdrasil.li.key.pem:${config.security.acme.certs."vikunja.yggdrasil.li".directory}/key.pem" | ||
| 60 | "vikunja.yggdrasil.li.pem:${config.security.acme.certs."vikunja.yggdrasil.li".directory}/fullchain.pem" | ||
| 61 | "vikunja.yggdrasil.li.chain.pem:${config.security.acme.certs."vikunja.yggdrasil.li".directory}/chain.pem" | ||
| 62 | ]; | ||
| 63 | }; | ||
| 64 | }; | ||
| 65 | }; | ||
| 66 | } | ||
diff --git a/hosts/surtr/vpn/default.nix b/hosts/surtr/vpn/default.nix index 1bdcf74e..92223144 100644 --- a/hosts/surtr/vpn/default.nix +++ b/hosts/surtr/vpn/default.nix | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | { pkgs, config, lib, ... }: | 1 | { flake, pkgs, config, lib, ... }: |
| 2 | 2 | ||
| 3 | with lib; | 3 | with lib; |
| 4 | 4 | ||
| @@ -22,7 +22,11 @@ in { | |||
| 22 | "--load-credential=surtr.priv:/run/credentials/container@vpn.service/surtr.priv" | 22 | "--load-credential=surtr.priv:/run/credentials/container@vpn.service/surtr.priv" |
| 23 | "--network-ipvlan=ens3:upstream" | 23 | "--network-ipvlan=ens3:upstream" |
| 24 | ]; | 24 | ]; |
| 25 | config = { | 25 | config = let hostConfig = config; in { config, pkgs, ... }: { |
| 26 | system.stateVersion = lib.mkIf hostConfig.containers."vpn".ephemeral config.system.nixos.release; | ||
| 27 | system.configurationRevision = mkIf (flake ? rev) flake.rev; | ||
| 28 | nixpkgs.pkgs = hostConfig.nixpkgs.pkgs; | ||
| 29 | |||
| 26 | boot.kernel.sysctl = { | 30 | boot.kernel.sysctl = { |
| 27 | "net.core.rmem_max" = 4194304; | 31 | "net.core.rmem_max" = 4194304; |
| 28 | "net.core.wmem_max" = 4194304; | 32 | "net.core.wmem_max" = 4194304; |
diff --git a/hosts/surtr/vpn/geri.pub b/hosts/surtr/vpn/geri.pub index ed5de2b2..2cd9b24e 100644 --- a/hosts/surtr/vpn/geri.pub +++ b/hosts/surtr/vpn/geri.pub | |||
| @@ -1 +1 @@ | |||
| sYuQSNZHzfegv8HRz71jnZm2nFLGeRnaGwVonhKUj2k= | hhER05bvstOTGfiAG3IJsFkBNWCUZHokBXwaiC5d534= | ||
diff --git a/hosts/surtr/zfs.nix b/hosts/surtr/zfs.nix index 17c5cd32..3795956d 100644 --- a/hosts/surtr/zfs.nix +++ b/hosts/surtr/zfs.nix | |||
| @@ -49,7 +49,7 @@ | |||
| 49 | 49 | ||
| 50 | boot.postBootCommands = '' | 50 | boot.postBootCommands = '' |
| 51 | echo "=== STARTING ZPOOL IMPORT ===" | 51 | echo "=== STARTING ZPOOL IMPORT ===" |
| 52 | ${pkgs.zfs}/bin/zpool import -a -N -d /dev | 52 | ${pkgs.zfs}/bin/zpool import -a -f -N -d /dev |
| 53 | ${pkgs.zfs}/bin/zpool status | 53 | ${pkgs.zfs}/bin/zpool status |
| 54 | ${pkgs.zfs}/bin/zfs mount -a | 54 | ${pkgs.zfs}/bin/zfs mount -a |
| 55 | echo "=== ZPOOL IMPORT COMPLETE ===" | 55 | echo "=== ZPOOL IMPORT COMPLETE ===" |
