From 8f55ef31938850a272f698e76da93da3c3955306 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Sun, 4 Jun 2023 01:59:35 +0200 Subject: [PATCH] Bekkalokk: Configure Gitea, clean web services Update bekkalokk secrets format Update gitea keys and firewall rules Create gitea-user-import script Fix SSH host key verification Gitea-import-users bug squashification Fix Gitea-import SSH problems --- hosts/bekkalokk/configuration.nix | 8 +- hosts/bekkalokk/services/gitea/default.nix | 86 +++++++++++++++++++ .../services/gitea/gitea-import-users.py | 82 ++++++++++++++++++ .../services/{website => }/mediawiki.nix | 2 +- hosts/bekkalokk/services/nginx.nix | 44 ++++++++++ .../services/{website => }/website.nix | 0 hosts/bekkalokk/services/website/gitea.nix | 26 ------ hosts/bekkalokk/services/website/nginx.nix | 42 --------- secrets/bekkalokk/bekkalokk.yaml | 16 ++-- 9 files changed, 226 insertions(+), 80 deletions(-) create mode 100644 hosts/bekkalokk/services/gitea/default.nix create mode 100644 hosts/bekkalokk/services/gitea/gitea-import-users.py rename hosts/bekkalokk/services/{website => }/mediawiki.nix (99%) create mode 100644 hosts/bekkalokk/services/nginx.nix rename hosts/bekkalokk/services/{website => }/website.nix (100%) delete mode 100644 hosts/bekkalokk/services/website/gitea.nix delete mode 100644 hosts/bekkalokk/services/website/nginx.nix diff --git a/hosts/bekkalokk/configuration.nix b/hosts/bekkalokk/configuration.nix index 84e54dc..33b1564 100644 --- a/hosts/bekkalokk/configuration.nix +++ b/hosts/bekkalokk/configuration.nix @@ -9,10 +9,10 @@ #./services/keycloak.nix # TODO: set up authentication for the following: - # ./services/website/website.nix - ./services/website/nginx.nix - # ./services/website/gitea.nix - ./services/website/mediawiki.nix + # ./services/website.nix + ./services/nginx.nix + ./services/gitea/default.nix + # ./services/mediawiki.nix ]; sops.defaultSopsFile = ../../secrets/bekkalokk/bekkalokk.yaml; diff --git a/hosts/bekkalokk/services/gitea/default.nix b/hosts/bekkalokk/services/gitea/default.nix new file mode 100644 index 0000000..9ce79d2 --- /dev/null +++ b/hosts/bekkalokk/services/gitea/default.nix @@ -0,0 +1,86 @@ +{ config, values, pkgs, ... }: +let + cfg = config.services.gitea; + domain = "git2.pvv.ntnu.no"; + sshPort = 2222; +in { + sops.secrets = { + "gitea/database" = { + owner = "gitea"; + group = "gitea"; + }; + "gitea/passwd-ssh-key" = { }; + "gitea/ssh-known-hosts" = { }; + "gitea/import-user-env" = { }; + }; + + services.gitea = { + enable = true; + stateDir = "/data/gitea"; + appName = "PVV Git"; + + database = { + type = "postgres"; + host = "postgres.pvv.ntnu.no"; + port = config.services.postgresql.port; + passwordFile = config.sops.secrets."gitea/database".path; + createDatabase = false; + }; + + settings = { + server = { + DOMAIN = domain; + ROOT_URL = "https://${domain}/"; + PROTOCOL = "http+unix"; + SSH_PORT = sshPort; + }; + service.DISABLE_REGISTRATION = true; + session.COOKIE_SECURE = true; + database.LOG_SQL = false; + picture = { + DISABLE_GRAVATAR = true; + ENABLE_FEDERATED_AVATAR = false; + }; + }; + }; + + services.nginx.virtualHosts."${domain}" = { + forceSSL = true; + enableACME = true; + locations."/" = { + proxyPass = "http://unix:${cfg.settings.server.HTTP_ADDR}"; + recommendedProxySettings = true; + extraConfig = '' + client_max_body_size 512M; + ''; + }; + }; + + networking.firewall.allowedTCPPorts = [ sshPort ]; + + # Automatically import users + systemd.services.gitea-import-users = { + enable = true; + preStart=''${pkgs.rsync}/bin/rsync -e "${pkgs.openssh}/bin/ssh -o UserKnownHostsFile=$CREDENTIALS_DIRECTORY/ssh-known-hosts -i $CREDENTIALS_DIRECTORY/sshkey" -a pvv@smtp.pvv.ntnu.no:/etc/passwd /tmp/passwd-import''; + serviceConfig = { + ExecStart = pkgs.writers.writePython3 "gitea-import-users" { libraries = [ pkgs.python3Packages.requests ]; } (builtins.readFile ./gitea-import-users.py); + LoadCredential=[ + "sshkey:${config.sops.secrets."gitea/passwd-ssh-key".path}" + "ssh-known-hosts:${config.sops.secrets."gitea/ssh-known-hosts".path}" + ]; + DynamicUser="yes"; + EnvironmentFile=config.sops.secrets."gitea/import-user-env".path; + }; + }; + + systemd.timers.gitea-import-users = { + enable = true; + requires = [ "gitea.service" ]; + after = [ "gitea.service" ]; + timerConfig = { + OnCalendar = "*-*-* 02:00:00"; + Persistent = true; + Unit = "gitea-import-users.service"; + }; + }; +} diff --git a/hosts/bekkalokk/services/gitea/gitea-import-users.py b/hosts/bekkalokk/services/gitea/gitea-import-users.py new file mode 100644 index 0000000..1a1cbea --- /dev/null +++ b/hosts/bekkalokk/services/gitea/gitea-import-users.py @@ -0,0 +1,82 @@ +import requests +import secrets +import os + +EMAIL_DOMAIN = os.getenv('EMAIL_DOMAIN') +if EMAIL_DOMAIN is None: + EMAIL_DOMAIN = 'pvv.ntnu.no' + +API_TOKEN = os.getenv('API_TOKEN') +if API_TOKEN is None: + raise Exception('API_TOKEN not set') + +GITEA_API_URL = os.getenv('GITEA_API_URL') +if GITEA_API_URL is None: + GITEA_API_URL = 'https://git2.pvv.ntnu.no/api/v1' + +BANNED_SHELLS = [ + "/usr/bin/nologin", + "/usr/sbin/nologin", + "/sbin/nologin", + "/bin/false", + "/bin/msgsh", +] + +existing_users = [] + + +def add_user(username, name): + if username in existing_users: + return + + user = { + "email": username + '@' + EMAIL_DOMAIN, + "full_name": name, + "login_name": username, + "password": secrets.token_urlsafe(32), + "source_id": 1, # 1 = SMTP + "username": username, + "must_change_password": False, + "visibility": "private", + } + + r = requests.post(GITEA_API_URL + '/admin/users', json=user, + headers={'Authorization': 'token ' + API_TOKEN}) + if r.status_code != 201: + print('ERR: Failed to create user ' + username + ': ' + r.text) + return + + print('Created user ' + username) + existing_users.append(username) + + +def main(): + + # Fetch existing users + r = requests.get(GITEA_API_URL + '/admin/users', + headers={'Authorization': 'token ' + API_TOKEN}) + if r.status_code != 200: + raise Exception('Failed to get users: ' + r.text) + + for user in r.json(): + existing_users.append(user['login']) + + # Read the file, add each user + with open("/tmp/passwd-import", 'r') as f: + for line in f.readlines(): + uid = int(line.split(':')[2]) + if uid < 1000: + continue + + shell = line.split(':')[-1] + if shell in BANNED_SHELLS: + continue + + username = line.split(':')[0] + name = line.split(':')[4] + + add_user(username, name) + + +if __name__ == '__main__': + main() diff --git a/hosts/bekkalokk/services/website/mediawiki.nix b/hosts/bekkalokk/services/mediawiki.nix similarity index 99% rename from hosts/bekkalokk/services/website/mediawiki.nix rename to hosts/bekkalokk/services/mediawiki.nix index 94036f9..1caea97 100644 --- a/hosts/bekkalokk/services/website/mediawiki.nix +++ b/hosts/bekkalokk/services/mediawiki.nix @@ -28,7 +28,7 @@ in { database = { type = "postgres"; - host = values.hosts.postgres.ipv4; + host = "postgres.pvv.ntnu.no"; port = config.services.postgresql.port; passwordFile = config.sops.secrets."keys/postgres/mediawiki".path; createLocally = false; diff --git a/hosts/bekkalokk/services/nginx.nix b/hosts/bekkalokk/services/nginx.nix new file mode 100644 index 0000000..ff3138a --- /dev/null +++ b/hosts/bekkalokk/services/nginx.nix @@ -0,0 +1,44 @@ +{ pkgs, config, ... }: +{ + security.acme = { + acceptTerms = true; + defaults.email = "drift@pvv.ntnu.no"; + }; + + services.nginx = { + enable = true; + + recommendedTlsSettings = true; + recommendedProxySettings = true; + recommendedOptimisation = true; + recommendedGzipSettings = true; + + #virtualHosts = { + # "bekkalokk.pvv.ntnu.no" = { + # forceSSL = true; + # enableACME = true; + # root = "${config.services.mediawiki.finalPackage}/share/mediawiki"; + # locations = { + # "/" = { + # extraConfig = '' + # fastcgi_split_path_info ^(.+\.php)(/.+)$; + # fastcgi_index index.php; + # fastcgi_pass unix:${config.services.phpfpm.pools.mediawiki.socket}; + # include ${pkgs.nginx}/conf/fastcgi_params; + # include ${pkgs.nginx}/conf/fastcgi.conf; + # ''; + # }; +# +# "/images".root = config.services.mediawiki.uploadsDir; +# +# # "/git" = { +# # proxyPass = "http://unix:${config.services.gitea.settings.server.HTTP_ADDR}"; +# # proxyWebsockets = true; +# # }; +# }; +# }; +# }; + }; + + networking.firewall.allowedTCPPorts = [ 80 443 ]; +} diff --git a/hosts/bekkalokk/services/website/website.nix b/hosts/bekkalokk/services/website.nix similarity index 100% rename from hosts/bekkalokk/services/website/website.nix rename to hosts/bekkalokk/services/website.nix diff --git a/hosts/bekkalokk/services/website/gitea.nix b/hosts/bekkalokk/services/website/gitea.nix deleted file mode 100644 index 908bc22..0000000 --- a/hosts/bekkalokk/services/website/gitea.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ config, values, ... }: -{ - sops.secrets."postgres/gitea/password" = { }; - - services.gitea = { - enable = true; - rootUrl = "https://git2.pvv.ntnu.no/"; - stateDir = "/data/gitea"; - appName = "PVV Git"; - - enableUnixSocket = true; - - database = { - type = "postgres"; - host = values.bicep.ipv4; - port = config.services.postgresql.port; - passwordFile = config.sops.secrets."postgres/gitea/password".path; - createDatabase = false; - }; - - settings = { - service.DISABLE_REGISTRATION = true; - session.COOKIE_SECURE = true; - }; - }; -} diff --git a/hosts/bekkalokk/services/website/nginx.nix b/hosts/bekkalokk/services/website/nginx.nix deleted file mode 100644 index c2ecbac..0000000 --- a/hosts/bekkalokk/services/website/nginx.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ pkgs, config, ... }: -{ - security.acme = { - acceptTerms = true; - defaults.email = "drift@pvv.ntnu.no"; - }; - - services.nginx = { - enable = true; - - recommendedTlsSettings = true; - recommendedProxySettings = true; - recommendedOptimisation = true; - recommendedGzipSettings = true; - - virtualHosts = { - "bekkalokk.pvv.ntnu.no" = { - forceSSL = true; - enableACME = true; - root = "${config.services.mediawiki.finalPackage}/share/mediawiki"; - locations = { - "/" = { - extraConfig = '' - fastcgi_split_path_info ^(.+\.php)(/.+)$; - fastcgi_index index.php; - fastcgi_pass unix:${config.services.phpfpm.pools.mediawiki.socket}; - include ${pkgs.nginx}/conf/fastcgi_params; - include ${pkgs.nginx}/conf/fastcgi.conf; - ''; - }; - - "/images".root = config.services.mediawiki.uploadsDir; - - # "/git" = { - # proxyPass = "http://unix:${config.services.gitea.settings.server.HTTP_ADDR}"; - # proxyWebsockets = true; - # }; - }; - }; - }; - }; -} diff --git a/secrets/bekkalokk/bekkalokk.yaml b/secrets/bekkalokk/bekkalokk.yaml index 7ae1ed6..73be2bf 100644 --- a/secrets/bekkalokk/bekkalokk.yaml +++ b/secrets/bekkalokk/bekkalokk.yaml @@ -1,12 +1,14 @@ gitea: password: ENC[AES256_GCM,data:hlNzdU1ope0t50/3aztyLeXjMHd2vFPpwURX+Iu8f49DOqgSnEMtV+KtLA==,iv:qljRnSnchL5cFmaUAfCH9GQYQxcy5cyWejgk1x6bFgI=,tag:tIhboFU5kZsj5oAQR3hLbw==,type:str] + database: ENC[AES256_GCM,data:UlS33IdCEyeSvT6ngpmnkBWHuSEqsB//DT+3b7C+UwbD8UXWJlsLf1X8/w==,iv:mPRW5ldyZaHP+y/0vC2JGSLZmlkhgmkvXPk4LazkSDs=,tag:gGk6Z/nbPvzE1zG+tJC8Sw==,type:str] + passwd-ssh-key: ENC[AES256_GCM,data:L0lF0wvpayss1NU9m3A45cH0bCMQzODTFVrq6EPd1JHx54wIcoaRBYLmxXKXASzBlCg9zlwXMUIk3OQcS3kdzMKL0iqcSL2iicAcKjFIHyrWLqXgwV5pRSP/tRPcVw8KW8gz0bh33EgESs5ReddZ3VZ0Cy1s2YupMRQvBXr89k1+Hv70OWB6P06hvxhv/zKcMGI1N/dWLroMgrQuT9imw4+/Q1RqwzTYeEU+eUn24AM9GjcBg4qf3OI+6g0nXUat/upIYE28iF5J3lbUSmDSmirBLc8xgHLdOyyJPTObWYWYxlSL78T7IqiMm9lI3rtBlpJDDcn/YxZpVqN5bg2154GISNK+uR0TVSLdJ+drdGHIfIX3G78XSxf2L9rbJyRn8MQlgStfdBIQicLavQKVMrmj+XQfvEMez23WbPLjH4oViBQFI+GrOHOGy/f16cz8Sn4n+69OcsOeTxs3tKYdfq6r1XLYSJ/fe/zvxBpaZiyGXljsuyEdIyBL2A8D6uSXe3Nd3/DAdBtceFfIdN1olCdutixzVWgxaJnrel161z5A/4w=,iv:Uy46yY3jFYSvpxrgCHxRMUksnWfhf5DViLMvCXVMMl4=,tag:wFEJ5+icFrOKkc56gY0A5g==,type:str] + ssh-known-hosts: ENC[AES256_GCM,data:zlRLoelQeumMxGqPmgMTB69X1RVWXIs2jWwc67lk0wrdNOHUs5UzV5TUA1JnQ43RslBU92+js7DkyvE5enGzw7zZE5F1ZYdGv/eCgvkTMC9BoLfzHzP6OzayPLYEt3xJ5PRocN8JUAD55cuu4LgsuebuydHPi2oWOfpbSUBKSeCh6dvk5Pp1XRDprPS5SzGLW8Xjq98QlzmfGv50meI9CDJZVF9Wq/72gkyfgtb3YVdr,iv:AF06TBitHegfWk6w07CdkHklh4ripQCmA45vswDQgss=,tag:zKh7WVXMJN2o9ZIwIkby3Q==,type:str] + import-user-env: ENC[AES256_GCM,data:LNzlIOwN7pWMmq+2+OqDqt17/QFW6UB7gguB8FIKPa/AqE6P8M5LaUFRRd06u8KVWSU=,iv:epWfPmvpqHYnqUr0nlHqg6Hshtno+i2wiY4Z1LdDAQM=,tag:H0xwTcgIa48aycpllV1XEQ==,type:str] mediawiki: password: ENC[AES256_GCM,data:HsBuA1E7187roGnKuFPfPDYxA16GFjAUucgUtrdUFmcOzmTNiFH+NWY2ZQ==,iv:vDYUmmZftcrkDtJxNYKAJSx9j+AQcmQarC62QRHR4IM=,tag:3TKjNrGRivFWoK3djC748g==,type:str] -keys: - postgres: - gitea: ENC[AES256_GCM,data:lG4P8kzp7Zq94WftN7p1RJqM65esPuTFZ2JJWkFFXTzlid2DRZPsG2FGIA==,iv:JvHQUgwwb7wJTNMxjLjOUw5sKKWlyMJafVaUOLUu9Sk=,tag:qE0+gDFU/YtghqCv/d2Qgw==,type:str] - mediawiki: ENC[AES256_GCM,data:p+s/uQ3ywQY9RpImFWTxjt1orzl905i9kTQPzsAIs6hAK5t3B00XVzKZgQ==,iv:xp3PRrjCGFxCsRZOlJGIonBOKWJ+3/1CByc4q7O3vDw=,tag:bfKlU2Pcoq0cQjbhp+UXag==,type:str] - keycloak: ENC[AES256_GCM,data:A3cbJTfP97yT35ov/yuWaD+b3wD2I8H+2GkW1ONp3YiNEsmKFjROx2rpwA==,iv:kMbuPtvy/49soEH9jxdY/X0BFDoiK7EyZ56xMkwjMUg=,tag:Ttp8BbJqfPWaeH5iaOwcQQ==,type:str] + database: ENC[AES256_GCM,data:EvVK3Mo6cZiIZS+gTxixU4r9SXN41VqwaWOtortZRNH+WPJ4xcYvzYMJNg==,iv:JtFTRLn3fzKIfgAPRqRgQjct7EdkEHtiyQKPy8/sZ2Q=,tag:nqzseG6BC0X5UNI/3kZZ3A==,type:str] +keycloak: + database: ENC[AES256_GCM,data:76+AZnNR5EiturTP7BdOCKE90bFFkfGlRtviSP5NHxPbb3RfFPJEMlwtzA==,iv:nS7VTossHdlrHjPeethhX+Ysp9ukrb5JD7kjG28OFpY=,tag:OMpiEv9nQA7v6lWJfNxEEw==,type:str] sops: kms: [] gcp_kms: [] @@ -40,8 +42,8 @@ sops: akVjeTNTeGorZjJQOVlMeCtPRUVYL3MK+VMvGxrbzGz4Q3sdaDDWjal+OiK+JYKX GHiMXVHQJZu/RrlxMjHKN6V3iaqxZpuvLAEJ2Lzy5EOHPtuiiRyeHQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2023-05-06T21:36:22Z" - mac: ENC[AES256_GCM,data:F9XujlDa5o0N07UfA4QTjApiJQyaT/l6jVSmekwx8exLWGKfMIVs3KKt8ZIT8MmmCg1+GPYHV1MzC+OCImj1q0uYDkqG/Of5KAKYrizz2GwmVa8pSyV/b+tFdBNKxlVjH+YWwxkMltCoZNzaYJDALAfUv07Xp8mnKaXdkS7SQBQ=,iv:LAmhmXDui8gkYKjL8gk9HPRFlcKAviQ9g9prp7yDptQ=,tag:GNffyDqt+mm3umUtnTU9hw==,type:str] + lastmodified: "2023-06-04T03:40:15Z" + mac: ENC[AES256_GCM,data:b0/75mHIRm+rBpzaOEWVoN2v2WTNfLMUpiHqQY7xPehuMFHycGZZaqPXr+bxDXYDm940ufQHGy0KDN8IuG/ENbFby8AnG8PGPe0rM5Nf8zux/5jlyUQB+tjIvRNy/cg9eiqlYJPp2yOclBCFUmTmAjOU+Je1bV2VCgFCINMoSec=,iv:5Ejw1WLpiDbuiS6KQudbka7HYV9fDSM1vnghtjNjXzY=,tag:7eKPDmU+eG7c/3qj6tgb0Q==,type:str] pgp: - created_at: "2023-05-21T00:28:40Z" enc: |