diff --git a/hosts/c3d2-web/default.nix b/hosts/c3d2-web/default.nix index 127ed4cc..bf6b4c37 100644 --- a/hosts/c3d2-web/default.nix +++ b/hosts/c3d2-web/default.nix @@ -1,7 +1,6 @@ { config, hostRegistry, pkgs, ... }: let webroot = "/var/www"; - deployCommand = "${pkgs.systemd}/bin/systemctl start deploy-c3d2-web.service"; in { microvm = { @@ -22,7 +21,7 @@ in ]; security.acme.certs = { - # agate cannot load "ec256" keys + # agate cannot load modern crypto like "ec256" keys "www.c3d2.de".keyType = "rsa4096"; }; @@ -103,14 +102,6 @@ in return 301 https://datenspuren.de; ''; }; - - # hooks, logs - "c3d2-web.flpk.zentralwerk.org" = { - enableACME = true; - forceSSL = true; - root = webroot; - locations."/hooks/".proxyPass = "http://localhost:9000/hooks/"; - }; }; }; # Gemini server @@ -125,45 +116,44 @@ in language = "de"; }; - systemd.packages = with pkgs; [ telme10 ]; - - systemd.services.telme10 = { - serviceConfig = { - AmbientCapabilities="CAP_NET_BIND_SERVICE"; + systemd.services = { + # lets agate access the tls certs + agate = { + requires = [ "agate-keys.service" ]; + after = [ "agate-keys.service" ]; + serviceConfig = { + Group = "keys"; + }; + }; + agate-keys = { + path = with pkgs; [ openssl ]; + script = + let + stateDir = "/var/lib/agate/certificates"; + in + '' + mkdir -p ${stateDir} + openssl x509 \ + -in /var/lib/acme/www.c3d2.de/cert.pem \ + -out ${stateDir}/cert.der \ + -outform DER + openssl rsa \ + -in /var/lib/acme/www.c3d2.de/key.pem \ + -out ${stateDir}/key.der \ + -outform DER + chown root:keys ${stateDir}/* + chmod 0640 ${stateDir}/* + ''; + serviceConfig = { + Type = "oneshot"; + }; + }; + telm10 = { + path = with pkgs; [ telme10 ]; + serviceConfig.AmbientCapabilities = "CAP_NET_BIND_SERVICE"; }; }; - # let agate access the tls certs - systemd.services.agate = { - requires = [ "agate-keys.service" ]; - after = [ "agate-keys.service" ]; - serviceConfig = { - Group = "keys"; - }; - }; - systemd.services.agate-keys = { - path = with pkgs; [ openssl ]; - script = let - stateDir = "/var/lib/agate/certificates"; - in '' - mkdir -p ${stateDir} - openssl x509 \ - -in /var/lib/acme/www.c3d2.de/cert.pem \ - -out ${stateDir}/cert.der \ - -outform DER - openssl rsa \ - -in /var/lib/acme/www.c3d2.de/key.pem \ - -out ${stateDir}/key.der \ - -outform DER - chown root:keys ${stateDir}/* - chmod 0640 ${stateDir}/* - ''; - serviceConfig = { - Type = "oneshot"; - }; - }; - - # Build user users = { groups = { c3d2-web = { }; @@ -171,9 +161,28 @@ in }; users = { c3d2-web = { - isSystemUser = true; group = "c3d2-web"; home = "/var/lib/c3d2-web"; + isSystemUser = true; + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILARLBE2MrSaOPJ+PwXeujas9j5t989nzd2HZo7IaXLm drone@c3d2-web" + ]; + packages = with pkgs; [ + git + # nix + curl + libxslt + # (libxslt.override { + # cryptoSupport = true; + # }) + libxml2 + wget + rsync + gnumake + # bash + ]; + # otherwise the the drone ssh runner cannot log in + useDefaultShell = true; }; telme10 = { isSystemUser = true; @@ -184,130 +193,12 @@ in systemd.tmpfiles.rules = with config.users.users.c3d2-web; [ "d ${webroot}/c3d2 0755 c3d2-web ${group} -" - "d ${webroot}/log 0755 c3d2-web ${group} -" "d ${config.services.agate.contentDir} 0755 c3d2-web ${group} -" "d ${home} 0700 c3d2-web ${group} -" ]; - # Build script - systemd.services.deploy-c3d2-web = { - wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" ]; - path = with pkgs; [ - git nix curl - (libxslt.override { - cryptoSupport = true; - }) libxml2 wget rsync gnumake bash - ]; - script = '' - # Build at least once - touch ${config.users.users.c3d2-web.home}/deploy-pending - - status() { - curl -X POST \ - "https://gitea.c3d2.de/api/v1/repos/c3d2/c3d2-web/statuses/$REV?token=$(cat ${config.sops.secrets."c3d2-web/gitea-token".path})" \ - -H "Accept: application/json" \ - -H "Content-Type: application/json" \ - -d "$1" - } - - if [ ! -d c3d2-web ]; then - git clone --depth=1 https://gitea.c3d2.de/c3d2/c3d2-web.git - cd c3d2-web - else - cd c3d2-web - git fetch origin - git reset --hard origin/master - - # `make export` may have created read-only files, - # fix that before cleaning up - chmod -R u+w . - git clean -d -f -x - fi - - # Loop in case the webhook was called while we were building - while [ -e ${config.users.users.c3d2-web.home}/deploy-pending ]; do - rm ${config.users.users.c3d2-web.home}/deploy-pending - git pull - REV=$(git rev-parse HEAD) - - # web - set +e - status "{ \"context\": \"c3d2-web\", \"description\": \"building...\", \"state\": \"pending\", \"target_url\": \"https://c3d2-web.flpk.zentralwerk.org/log/build-$REV.txt\"}" - - make -j$(nproc) export DESTDIR=${webroot}/c3d2 \ - &> ${webroot}/log/build-$REV.txt - - if [ $? = 0 ]; then - status "{ \"context\": \"c3d2-web\", \"description\": \"deployed\", \"state\": \"success\", \"target_url\": \"https://c3d2-web.flpk.zentralwerk.org/log/build-$REV.txt\"}" - else - status "{ \"context\": \"c3d2-web\", \"description\": \"build failure\", \"state\": \"failure\", \"target_url\": \"https://c3d2-web.flpk.zentralwerk.org/log/build-$REV.txt\"}" - fi - - git clean -fx - # gemini - status "{ \"context\": \"c3d2-gemini\", \"description\": \"building...\", \"state\": \"pending\", \"target_url\": \"https://c3d2-web.flpk.zentralwerk.org/log/build-gemini-$REV.txt\"}" - - make -f Makefile.gemini -j$(nproc) export DESTDIR=${config.services.agate.contentDir} \ - &> ${webroot}/log/build-gemini-$REV.txt - - if [ $? = 0 ]; then - status "{ \"context\": \"c3d2-gemini\", \"description\": \"deployed\", \"state\": \"success\", \"target_url\": \"https://c3d2-web.flpk.zentralwerk.org/log/build-gemini-$REV.txt\"}" - else - status "{ \"context\": \"c3d2-gemini\", \"description\": \"build failure\", \"state\": \"failure\", \"target_url\": \"https://c3d2-web.flpk.zentralwerk.org/log/build-gemini-$REV.txt\"}" - fi - set -e - done - ''; - serviceConfig = { - User = "c3d2-web"; - Group = config.users.users.c3d2-web.group; - PrivateTmp = true; - ProtectSystem = "full"; - WorkingDirectory = config.users.users.c3d2-web.home; - ReadWritePaths = [ webroot config.users.users.c3d2-web.home ]; - }; - }; - - systemd.timers.deploy-c3d2-web = { - partOf = [ "deploy-c3d2-web.service" ]; - wantedBy = [ "timers.target" ]; - timerConfig.OnCalendar = "hourly"; - }; - - security.sudo.extraRules = [ { - users = [ "c3d2-web" ]; - commands = [ { - command = deployCommand; - options = [ "NOPASSWD" ]; - } ]; - } ]; - sops = { defaultSopsFile = ./secrets.yaml; secrets."c3d2-web/gitea-token".owner = "c3d2-web"; }; - - systemd.services.webhook = - let - hooksJson = pkgs.writeText "hooks.json" (builtins.toJSON [ { - id = "deploy-c3d2-web"; - execute-command = pkgs.writeShellScript "deploy-c3d2-web" '' - # Request (re-)deployment - touch ${config.users.users.c3d2-web.home}/deploy-pending - - # Start deploy-c3d2-web.service if not already running - exec /run/wrappers/bin/sudo ${deployCommand} - ''; - } ]); - in { - wantedBy = [ "multi-user.target" ]; - serviceConfig = { - ExecStart = "${pkgs.webhook}/bin/webhook -hooks ${hooksJson} -verbose -ip 127.0.0.1"; - User = "c3d2-web"; - Group = config.users.users.c3d2-web.group; - PrivateTmp = true; - ProtectSystem = "full"; - }; - }; } diff --git a/hosts/c3d2-web/secrets.yaml b/hosts/c3d2-web/secrets.yaml index 86648b57..cc6559a7 100644 --- a/hosts/c3d2-web/secrets.yaml +++ b/hosts/c3d2-web/secrets.yaml @@ -1,4 +1,7 @@ c3d2-web: + ssh-key: + private: ENC[AES256_GCM,data:TAHMP1U76t+HiPrtV5UnXzJAHy3ZqWfTja62IVSyMSlTFgI+bPaEPK0kyb+120GQWyLZvviAdeQyJ4b/8LgY1jm4W28OAC4fOZcgqUQ9AEvnsnxKzp+/lTGEpWk1ZZq4K+Kns+EHAR1R4huaN+tlpb38ws5pW+VWzqmwHqhrrfeWr0pMqTQ01tmvdf1MEZvmSHWaMzBgUeNEYbVtujJp8fKocTrAxDvVSFl2PbSsXnH6kethOepX6kHQJdPx9ziw09uSeAXV7wTtRh5ISEbpePs4tOJoYQ7Z5UPsiKm+43ux5f3y0vOs1NQDowtPDXjryE6J31jHINa/wCRvNsPYlon/mbYAntP9t+Asex7/PwYQvAW4+P9vzvGWUVpgxTIGPrUUkLz97MVIsZ2P3CV616X/jeZQmKLkiScQggoKqvXOgxH415GqPZ6oOhw+q76t+XFJsYfB/0ENhBOXX3hQz4+FR+/8O4zAobGavsWH8B1ovCW8TWPndmSSlzf1R4uLHOEpuTDJvRfYn7lHZybLao+bipjKE1wr+0Ze,iv:LyMZ+tuxvv/ReTjNoyjs99e3MRnOR36EhazcJ4a7xlw=,tag:yPnQ7QZA35o+acZFK0C1tA==,type:str] + public: ENC[AES256_GCM,data:l7lpD0oiR3o2GKLGisTGnXWHBdExy8f7Rhqu42GWS1BKut+DqGxQSVGH+ap6tysCCSVHpDShBoZQD4AWgnGe2S1zZ4p9JUtqzD55Qd1qjOvJ+xI7pwhRiFgODgfrnrU=,iv:0kSxCoKU0es6aU1HEVe+SliwCidySMmwsWXeiMCJ4SE=,tag:XjesvswMhRibEWFRzl4oyQ==,type:str] gitea-token: ENC[AES256_GCM,data:W5NC7+7F2HSwRRyFdqkxwZVdW14PfG8PTJ4RI6UWyv262GMqgLbA1Q==,iv:mW5ahfvdzIng0dqphtZtZwOgF5W5s3rbP0AF0GxmcjQ=,tag:sYyMsqrKerxHcDRM4OkEMQ==,type:str] sops: kms: [] @@ -24,8 +27,8 @@ sops: OWtJZ2pzSXpTVnNrYTY1bGJCQ2lYZFkKerY4F/HPsr9vrMxu68FRVNVEKysE1M+q zOY/n3CNAdlVjnWt6D60BpEHIpDhO5dvBvvqLwsOizI7fgfmwFnGDw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2022-12-26T22:08:37Z" - mac: ENC[AES256_GCM,data:v1goHC28SBz5G2FtCl/Iwbc3t6piDbNXYsUmXzuXcZrS4wr4e7KpXIXwYnNwMTrEBJ4O3ML734i8qx5BHDTS6FiTgvYSQnDR/cWXmiaVFoPAZDP4Cdx+eUYtmnZ2g8gUmpa2Swpp4gDlm3Rdab+R6mkAfDVcjCcgnxB6eSIk28g=,iv:Ao4+gCGNOOKiFLATBygGvf2E7GfPCyt/fJ1R+nuYsU8=,tag:NBZzrWzpm/fyahzE/27Q0Q==,type:str] + lastmodified: "2023-01-29T21:44:24Z" + mac: ENC[AES256_GCM,data:EmRAkfgdmQ1SWERxQa9B4rMAkoJITvIjuBKNNNC2c6uV0q5IIDB/d7TDRbxnzXPfOUft8lTFCuuCvRN1XRf+yjoRJBIKU6kgJS0YP6RBS5oS/mHkJXGGRI5qvWsm4xxptT6YvR/3ZzJSld/X7QHeHx0JISRGfayvJIqCVKjSThA=,iv:UosrjZe7CPWBeND46Q0dW+zdf5FgPIUkXvVqouTMkIE=,tag:KsHUAkYNMPo+XQwAjM93cA==,type:str] pgp: - created_at: "2022-12-26T22:07:00Z" enc: |