From d05fb68b774b7011197c1c229e61809f642fcdd2 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Wed, 19 Feb 2025 19:10:58 +0100 Subject: hledger --- hosts/surtr/default.nix | 2 +- hosts/surtr/dns/default.nix | 2 +- hosts/surtr/dns/keys/hledger.yggdrasil.li_acme | 24 ++++++++ hosts/surtr/dns/zones/li.yggdrasil.soa | 10 +++- hosts/surtr/hledger.nix | 66 ++++++++++++++++++++ hosts/surtr/tls/tsig_keys/hledger.yggdrasil.li | 24 ++++++++ hosts/vidhar/default.nix | 2 +- hosts/vidhar/hledger/default.nix | 83 ++++++++++++++++++++++++++ hosts/vidhar/hledger/htpasswd | 24 ++++++++ hosts/vidhar/network/ruleset.nft | 6 +- 10 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 hosts/surtr/dns/keys/hledger.yggdrasil.li_acme create mode 100644 hosts/surtr/hledger.nix create mode 100644 hosts/surtr/tls/tsig_keys/hledger.yggdrasil.li create mode 100644 hosts/vidhar/hledger/default.nix create mode 100644 hosts/vidhar/hledger/htpasswd (limited to 'hosts') diff --git a/hosts/surtr/default.nix b/hosts/surtr/default.nix index 06d3866f..c5ba718e 100644 --- a/hosts/surtr/default.nix +++ b/hosts/surtr/default.nix @@ -7,7 +7,7 @@ with lib; tmpfs-root qemu-guest openssh rebuild-machines zfs ./zfs.nix ./dns ./tls ./http ./bifrost ./matrix ./postgresql ./prometheus ./email ./vpn ./borg.nix ./etebase ./immich.nix - ./paperless.nix ./firefly.nix + ./paperless.nix ./firefly.nix ./hledger.nix ]; config = { diff --git a/hosts/surtr/dns/default.nix b/hosts/surtr/dns/default.nix index eb09e296..a23b789c 100644 --- a/hosts/surtr/dns/default.nix +++ b/hosts/surtr/dns/default.nix @@ -157,7 +157,7 @@ in { ${concatMapStringsSep "\n" mkZone [ { domain = "yggdrasil.li"; addACLs = { "yggdrasil.li" = ["ymir_acme_acl"]; }; - acmeDomains = ["surtr.yggdrasil.li" "yggdrasil.li" "etesync.yggdrasil.li" "immich.yggdrasil.li" "app.etesync.yggdrasil.li" "paperless.yggdrasil.li" "firefly.yggdrasil.li"]; + acmeDomains = ["surtr.yggdrasil.li" "yggdrasil.li" "etesync.yggdrasil.li" "immich.yggdrasil.li" "app.etesync.yggdrasil.li" "paperless.yggdrasil.li" "firefly.yggdrasil.li" "hledger.yggdrasil.li"]; } { domain = "nights.email"; addACLs = { "nights.email" = ["ymir_acme_acl"]; }; 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 @@ +{ + "data": "ENC[AES256_GCM,data:lCj8VYJL9z29FJ154XQtxKQLwwitCRGy4krJ6u8yw2FMzoHprEpFgm33+mFspxSKk/It2G8cfTGMZSeVkYJEHb66HNKHl0A2Fz3hwjpRjh1MZAw0wiZJlnS/LNqoGstQ2PJmTQTW3aJRMoT1GS7q/gSp/3rqySA5EOm0GgUiA3Vi7nGpkBenKDEbQbcIBXRdMOk66BCdiz5XGm/1VLQQLO9oVwY2KBnLaZSISohyGVhbIy7GT2ygoWHHxHn0c5CRVNvGNwesM1gO1NnTFrISLMWSrsDPaAtQ,iv:fa8LFjzqsf2ccfbEe5MOmerb7FzXb4xr24y1GWIMT1Q=,tag:7oQ54DKBb76Pbw1lmEHt+Q==,type:str]", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzcHJLRHh0VkpDNDU3cGZS\nMWFlVWpFemZ2RnpnSllDWU1EWGoyWUxyejNzClBGandzaFI5NXY1bG51Y3VxRk9r\nc29NbXBOaEZDblBuaVowemQydkxBdjgKLS0tICtVb2xkMmh4T0Q0cU4xQnBzZExI\namFRUnRYTWIyQ3RHNUVHWTFrUzhhK1UKqmATNmxlhkxM5PP1U6w7fSYVA8AgIRAt\nJ9WZrTffQfXMdw4RmjWcoVHFH39Fe4SteedxliCCcqjkjgSEB4Rgow==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjWlhpQWI4c0x0ZXRGYVE2\nR1dHZzZud0ZxQWsrREhJWUowWE1zem5FVFI0CkJBUnIwY1FGS3N2VnpuSkZjRllZ\ncVgyeVg4cTVjRitzL0RKb0ZQb3BsOEkKLS0tIGs3SDBkamVBNDhQUlh5dmVVZXJs\nM3VKdlFKc21GcFY0UUtiaHFvYWI4V0kKKuWYEncxe9NT2ZS3X3+l/gT4BQOrdCg8\nj2jGL+Yzy/356GO3PFTn2HHLam6KWDKaYB5TlK/zSohfUt5giQH2Lw==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-02-19T17:13:51Z", + "mac": "ENC[AES256_GCM,data:XsBdMCBjB+YuBMZQrjJ5uZtaYKSqsdWVvm+IEoJflCKPIhPk2rBZ3nY8KngXFbq2fWgsYyTM83kb2trEGIEHUPuERt+mgfCI3bSlylriwgsDWihCjyBecNE+BbdXE0+YcNl8pIwBU4M+3f2StQMH22YamToLJ9i9kfKcBrirDuU=,iv:VTIdBVY3kVBMYWhYUmrP2vZ9rpH90DzF68y1aDf2EAs=,tag:YkL+nw6LNXAceZtx9vgf6A==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.9.4" + } +} \ No newline at end of file diff --git a/hosts/surtr/dns/zones/li.yggdrasil.soa b/hosts/surtr/dns/zones/li.yggdrasil.soa index d77337c6..21d36652 100644 --- a/hosts/surtr/dns/zones/li.yggdrasil.soa +++ b/hosts/surtr/dns/zones/li.yggdrasil.soa @@ -1,7 +1,7 @@ $ORIGIN yggdrasil.li. $TTL 3600 @ IN SOA ns.yggdrasil.li. hostmaster.yggdrasil.li ( - 2025021800 ; serial + 2025021900 ; serial 10800 ; refresh 3600 ; retry 604800 ; expire @@ -93,6 +93,14 @@ _acme-challenge.firefly IN NS ns.yggdrasil.li. firefly IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" +hledger IN A 202.61.241.61 +hledger IN AAAA 2a03:4000:52:ada:: +hledger IN MX 0 surtr.yggdrasil.li +hledger IN TXT "v=spf1 redirect=surtr.yggdrasil.li" +_acme-challenge.hledger IN NS ns.yggdrasil.li. + +hledger IN HTTPS 1 . alpn="h2,h3" ipv4hint="202.61.241.61" ipv6hint="2a03:4000:52:ada::" + vidhar IN AAAA 2a03:4000:52:ada:4:1:: vidhar IN MX 0 ymir.yggdrasil.li vidhar IN TXT "v=spf1 redirect=yggdrasil.li" 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 @@ +{ config, ... }: + +{ + config = { + security.acme.rfc2136Domains = { + "hledger.yggdrasil.li" = { + restartUnits = ["nginx.service"]; + }; + }; + + services.nginx = { + upstreams."hledger" = { + servers = { + "[2a03:4000:52:ada:4:1::]:5000" = {}; + }; + extraConfig = '' + keepalive 8; + ''; + }; + virtualHosts = { + "hledger.yggdrasil.li" = { + kTLS = true; + http3 = true; + forceSSL = true; + sslCertificate = "/run/credentials/nginx.service/hledger.yggdrasil.li.pem"; + sslCertificateKey = "/run/credentials/nginx.service/hledger.yggdrasil.li.key.pem"; + sslTrustedCertificate = "/run/credentials/nginx.service/hledger.yggdrasil.li.chain.pem"; + extraConfig = '' + charset utf-8; + ''; + + locations = { + "/".extraConfig = '' + proxy_pass http://hledger; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_redirect off; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $server_name; + proxy_set_header X-Forwarded-Proto $scheme; + + client_max_body_size 0; + proxy_request_buffering off; + proxy_buffering off; + ''; + }; + }; + }; + }; + + systemd.services.nginx = { + serviceConfig = { + LoadCredential = [ + "hledger.yggdrasil.li.key.pem:${config.security.acme.certs."hledger.yggdrasil.li".directory}/key.pem" + "hledger.yggdrasil.li.pem:${config.security.acme.certs."hledger.yggdrasil.li".directory}/fullchain.pem" + "hledger.yggdrasil.li.chain.pem:${config.security.acme.certs."hledger.yggdrasil.li".directory}/chain.pem" + ]; + }; + }; + }; +} 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 @@ +{ + "data": "ENC[AES256_GCM,data:Yd70QIj9DE6a5IN+Mf2M5p95vkRMHRg9BXaM686W7BRtthOw9m54/5FK6JWr,iv:cIOIKinkqFFPgTZdewWVY0h6kM5hGfVzuA4iYNhwK5c=,tag:Ds/oI+TOERbIdcGbI4WoEg==,type:str]", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1NnJ4SmsvSlh3ZlliSm9C\nNG45clh3NEZWZ05jaHhVK0xqTVRFL2wxN1ZrCk5hL2p2ZjhtcDBjTEZscXFTNkY5\nemVZSUUwV2V5cFBTdWo4RWxsM2xROVEKLS0tIDBFSFlkUVJ0ajJEUENlelVFKzVk\ndnJhMURMU2o3WVBKZGNVRXBiNytqUFEKHivcSTYy5D770C0h7RsmLBmkIG9+MDoV\ngJHvfkGzXPKwmDTMKdHbIk+ctI+u0/1jMn/K2Q9OFnOIYxP3gHiFag==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age19a7j77w267z04zls7m28a8hj4a0g5af6ltye2d5wypg33c3l89csd4r9zq", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArYUNCQ1U2MXpQdmM4SHR0\nTnJWZlFGTUQ1NjVqZ3Z2MGt5NFpBVFp0b0YwCkdseitkbzI1RkZyL3V5Z1pNMG9R\nVnEzRUxrTDQrS3BiMXB1QUFPeUcxZUkKLS0tIGJFODkwNFY3c0tBLzFBNjFiYjJk\nZW82bTdia2F1NHpNSG1IYmhWb1ZCTHMK9ovFx3+x5PrV4y6+RH5XA5DK2wRPXlAt\ncxxpRZIlmnvhZXIeCYE9yhHFmz3uAn0Oib1RUDblca9FlnF9tyYD6g==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-02-19T17:13:51Z", + "mac": "ENC[AES256_GCM,data:ReRuK9qdZV8AbMzA9Yur0AZW+1RF3aRnfBvsKJkQtXsFdkmJQ4QkRGtL27RmjFdvQ3kXBIyhib7hYA60AJ0amduYrSScY0dtz8AurjyE4f2BGQ9/QeKRBfKXHxLvj4/xWNvS4+PVdGKkKbqIs8isz9n77WQQ3lTHop2K/TjaTuQ=,iv:gUhDK9oeUHdpQ2Fp8mFDIgPFo2JjHE0jjooL7FmvmrE=,tag:2lkwSl3j3oqamdLbM9wbow==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.9.4" + } +} \ No newline at end of file diff --git a/hosts/vidhar/default.nix b/hosts/vidhar/default.nix index 90e58b42..de661f4a 100644 --- a/hosts/vidhar/default.nix +++ b/hosts/vidhar/default.nix @@ -4,7 +4,7 @@ with lib; { imports = with flake.nixosModules.systemProfiles; [ - ./zfs.nix ./network ./samba.nix ./dns ./prometheus ./borg ./pgbackrest ./postgresql.nix ./immich.nix ./paperless ./firefly-iii + ./zfs.nix ./network ./samba.nix ./dns ./prometheus ./borg ./pgbackrest ./postgresql.nix ./immich.nix ./paperless ./firefly-iii ./hledger tmpfs-root zfs initrd-all-crypto-modules default-locale openssh rebuild-machines build-server diff --git a/hosts/vidhar/hledger/default.nix b/hosts/vidhar/hledger/default.nix new file mode 100644 index 00000000..ae080f66 --- /dev/null +++ b/hosts/vidhar/hledger/default.nix @@ -0,0 +1,83 @@ +{ config, lib, pkgs, ... }: +{ + config = { + services.hledger-web = { + enable = true; + allow = "view"; + stateDir = "/var/lib/hledger"; + journalFiles = lib.mkForce ["web.journal"]; + baseUrl = "https://hledger.yggdrasil.li"; + extraOptions = [ + "--socket=/run/hledger-web/http.sock" + ]; + }; + users = { + users.hledger.uid = 982; + groups.hledger.gid = 979; + }; + systemd.services.hledger-web = { + serviceConfig = { + UMask = "0002"; + ReadOnlyPaths = [ config.services.hledger-web.stateDir ]; + RuntimeDirectory = [ "hledger-web" ]; + PrivateDevices = true; + StateDirectory = "hledger"; + CapabilityBoundingSet = ""; + AmbientCapabilities = ""; + ProtectSystem = "strict"; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + ProtectClock = true; + ProtectHostname = true; + ProtectHome = "tmpfs"; + ProtectKernelLogs = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + PrivateNetwork = false; + RestrictAddressFamilies = "AF_INET AF_INET6 AF_UNIX"; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service @resources" + "~@obsolete @privileged" + ]; + RestrictSUIDSGID = true; + RemoveIPC = true; + NoNewPrivileges = true; + RestrictRealtime = true; + RestrictNamespaces = true; + LockPersonality = true; + PrivateUsers = true; + TemporaryFileSystem = [ "/var/lib/hledger/.cache:mode=0750,uid=${toString (config.users.users.hledger.uid)},gid=${toString (config.users.groups.hledger.gid)}" ]; + }; + }; + services.nginx = { + upstreams.hledger = { + servers = { "unix:/run/hledger-web/http.sock" = {}; }; + }; + virtualHosts."hledger.yggdrasil.li" = { + listen = [ + { addr = "[2a03:4000:52:ada:4:1::]"; port = 5000; } + ]; + extraConfig = '' + set_real_ip_from 2a03:4000:52:ada:4::; + auth_basic "hledger"; + auth_basic_user_file "/run/credentials/nginx.service/hledger_users"; + ''; + locations."/" = { + proxyPass = "http://hledger/"; + proxyWebsockets = true; + }; + }; + }; + systemd.services.nginx.serviceConfig = { + SupplementaryGroups = [ "hledger" ]; + LoadCredential = [ "hledger_users:${config.sops.secrets."hledger_users".path}" ]; + }; + sops.secrets."hledger_users" = { + format = "binary"; + sopsFile = ./htpasswd; + reloadUnits = [ "nginx.service" ]; + }; + }; +} diff --git a/hosts/vidhar/hledger/htpasswd b/hosts/vidhar/hledger/htpasswd new file mode 100644 index 00000000..016cb525 --- /dev/null +++ b/hosts/vidhar/hledger/htpasswd @@ -0,0 +1,24 @@ +{ + "data": "ENC[AES256_GCM,data:9MNDIAc7ePYk3xQDorX2pU8ybJkJb33RKiJxc2DYauXFNQYxtGwCYhZwod7p7fPh3KqZxBNMRoZXr+/RnV+trsqjAcOOjnXTWLbX6nubq/xm+q0BxEjOPn7FvJF9XOblBeupldo+byGh2CMH9qQv5Fov,iv:3Tym+Mfr48OJet3qDFZPg0XjYr4sNQdNdiu0vUxmzbY=,tag:E0sxRY/jeMVlqH6uAYvD/Q==,type:str]", + "sops": { + "kms": null, + "gcp_kms": null, + "azure_kv": null, + "hc_vault": null, + "age": [ + { + "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3eFBsOEM2ZUNVT2V3LytC\nTUJvUDdKc0VzMyt2cDFKYU03djBjZVFpeVY4CjByMXhPVXRJVjhKQWZvQ2xuOTE3\ncXdJV1lZaHR3cVl0Z0hQaG00M2dGbjQKLS0tIEIzenVxb3cwM3pXTUl1YUZlSlk2\nbDc3VmE5NkEyZ2tRd01OUGZibmhtUlEKxdesIdvzm8s0SmXU5R+tSbmS5Dj24jrb\nEiMERYy1g8GyHR3d2/mU5iOIdsBegSZReUVzomaMT9L7/TmubgOP3g==\n-----END AGE ENCRYPTED FILE-----\n" + }, + { + "recipient": "age1qffdqvy9arld9zd5a5cylt0n98xhcns5shxhrhwjq5g4qa844ejselaa4l", + "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPa2RDZzR6cEFYTFA1QkND\nbndVeHVrMVJ0MWZvRmw5VXRhOHlRYllIRWxRCjU4dks4R25LS1RZMHFnbmpQRVZz\nNXhubkJvZFc2amRwMDVtQlE0NnBKNzQKLS0tIHRyeDUxTEFPMEMzWUVkZURzODdm\nSHdqbUpvNmFTS1QveFRpRHdnWHpHb28KnvdUkMkKGiBVHQD7Yv7n6WZjihCGJAR2\nMKl2WAn4g4jzgcXPwwIAIjUrMGSIdGpwCTUDcDnlKWAbRYO2B6P17A==\n-----END AGE ENCRYPTED FILE-----\n" + } + ], + "lastmodified": "2025-02-19T17:11:17Z", + "mac": "ENC[AES256_GCM,data:yBIEqHhr4igoMlRcgg2SigKfejqeuNmuleYolsLJo+QOaW4BHITJTvLxRV1JHPpcMVQkF//zx4ZfUUrb8tTN0znGu3Jnpd0JVagbfCVyEuT6d1SB/GzyUVvoQ2GlcA9us+5gjI4oEJTQCfVqnLDBWsw+jXdr3nEIWo6Mvbqo3lI=,iv:I6Swk4wyd+96+tJKRY/FHlS7ZShMDROcbl+l+ZLRxhM=,tag:P1uQvB4NLdkPEKRMI6lLxw==,type:str]", + "pgp": null, + "unencrypted_suffix": "_unencrypted", + "version": "3.9.4" + } +} \ No newline at end of file diff --git a/hosts/vidhar/network/ruleset.nft b/hosts/vidhar/network/ruleset.nft index 5398cbee..8f8f24f1 100644 --- a/hosts/vidhar/network/ruleset.nft +++ b/hosts/vidhar/network/ruleset.nft @@ -94,6 +94,7 @@ table inet filter { counter immich-rx {} counter paperless-rx {} counter firefly-rx {} + counter hledger-rx {} counter established-rx {} @@ -125,6 +126,7 @@ table inet filter { counter immich-tx {} counter paperless-tx {} counter firefly-tx {} + counter hledger-tx {} counter tx {} @@ -203,6 +205,7 @@ table inet filter { iifname bifrost tcp dport 2283 ip6 saddr $bifrost_surtr counter name immich-rx accept iifname bifrost tcp dport 28981 ip6 saddr $bifrost_surtr counter name paperless-rx accept iifname bifrost tcp dport 9000 ip6 saddr $bifrost_surtr counter name firefly-rx accept + iifname bifrost tcp dport 5000 ip6 saddr $bifrost_surtr counter name hledger-rx accept ct state { established, related } counter name established-rx accept @@ -253,7 +256,8 @@ table inet filter { iifname bifrost tcp sport 2283 ip6 daddr $bifrost_surtr counter name immich-tx accept iifname bifrost tcp sport 28981 ip6 daddr $bifrost_surtr counter name paperless-tx accept - iifname bifrost tcp sport 28981 ip6 daddr $bifrost_surtr counter name firefly-tx accept + iifname bifrost tcp sport 9000 ip6 daddr $bifrost_surtr counter name firefly-tx accept + iifname bifrost tcp sport 5000 ip6 daddr $bifrost_surtr counter name hledger-tx accept counter name tx -- cgit v1.2.3