1
0
Fork 0

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
This commit is contained in:
Felix Albrigtsen 2023-06-04 01:59:35 +02:00 committed by Felix Albrigtsen
parent db44bcf4bc
commit 8f55ef3193
9 changed files with 226 additions and 80 deletions

View File

@ -9,10 +9,10 @@
#./services/keycloak.nix #./services/keycloak.nix
# TODO: set up authentication for the following: # TODO: set up authentication for the following:
# ./services/website/website.nix # ./services/website.nix
./services/website/nginx.nix ./services/nginx.nix
# ./services/website/gitea.nix ./services/gitea/default.nix
./services/website/mediawiki.nix # ./services/mediawiki.nix
]; ];
sops.defaultSopsFile = ../../secrets/bekkalokk/bekkalokk.yaml; sops.defaultSopsFile = ../../secrets/bekkalokk/bekkalokk.yaml;

View File

@ -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";
};
};
}

View File

@ -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()

View File

@ -28,7 +28,7 @@ in {
database = { database = {
type = "postgres"; type = "postgres";
host = values.hosts.postgres.ipv4; host = "postgres.pvv.ntnu.no";
port = config.services.postgresql.port; port = config.services.postgresql.port;
passwordFile = config.sops.secrets."keys/postgres/mediawiki".path; passwordFile = config.sops.secrets."keys/postgres/mediawiki".path;
createLocally = false; createLocally = false;

View File

@ -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 ];
}

View File

@ -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;
};
};
}

View File

@ -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;
# };
};
};
};
};
}

View File

@ -1,12 +1,14 @@
gitea: gitea:
password: ENC[AES256_GCM,data:hlNzdU1ope0t50/3aztyLeXjMHd2vFPpwURX+Iu8f49DOqgSnEMtV+KtLA==,iv:qljRnSnchL5cFmaUAfCH9GQYQxcy5cyWejgk1x6bFgI=,tag:tIhboFU5kZsj5oAQR3hLbw==,type:str] 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: mediawiki:
password: ENC[AES256_GCM,data:HsBuA1E7187roGnKuFPfPDYxA16GFjAUucgUtrdUFmcOzmTNiFH+NWY2ZQ==,iv:vDYUmmZftcrkDtJxNYKAJSx9j+AQcmQarC62QRHR4IM=,tag:3TKjNrGRivFWoK3djC748g==,type:str] password: ENC[AES256_GCM,data:HsBuA1E7187roGnKuFPfPDYxA16GFjAUucgUtrdUFmcOzmTNiFH+NWY2ZQ==,iv:vDYUmmZftcrkDtJxNYKAJSx9j+AQcmQarC62QRHR4IM=,tag:3TKjNrGRivFWoK3djC748g==,type:str]
keys: database: ENC[AES256_GCM,data:EvVK3Mo6cZiIZS+gTxixU4r9SXN41VqwaWOtortZRNH+WPJ4xcYvzYMJNg==,iv:JtFTRLn3fzKIfgAPRqRgQjct7EdkEHtiyQKPy8/sZ2Q=,tag:nqzseG6BC0X5UNI/3kZZ3A==,type:str]
postgres: keycloak:
gitea: ENC[AES256_GCM,data:lG4P8kzp7Zq94WftN7p1RJqM65esPuTFZ2JJWkFFXTzlid2DRZPsG2FGIA==,iv:JvHQUgwwb7wJTNMxjLjOUw5sKKWlyMJafVaUOLUu9Sk=,tag:qE0+gDFU/YtghqCv/d2Qgw==,type:str] database: ENC[AES256_GCM,data:76+AZnNR5EiturTP7BdOCKE90bFFkfGlRtviSP5NHxPbb3RfFPJEMlwtzA==,iv:nS7VTossHdlrHjPeethhX+Ysp9ukrb5JD7kjG28OFpY=,tag:OMpiEv9nQA7v6lWJfNxEEw==,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]
sops: sops:
kms: [] kms: []
gcp_kms: [] gcp_kms: []
@ -40,8 +42,8 @@ sops:
akVjeTNTeGorZjJQOVlMeCtPRUVYL3MK+VMvGxrbzGz4Q3sdaDDWjal+OiK+JYKX akVjeTNTeGorZjJQOVlMeCtPRUVYL3MK+VMvGxrbzGz4Q3sdaDDWjal+OiK+JYKX
GHiMXVHQJZu/RrlxMjHKN6V3iaqxZpuvLAEJ2Lzy5EOHPtuiiRyeHQ== GHiMXVHQJZu/RrlxMjHKN6V3iaqxZpuvLAEJ2Lzy5EOHPtuiiRyeHQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2023-05-06T21:36:22Z" lastmodified: "2023-06-04T03:40:15Z"
mac: ENC[AES256_GCM,data:F9XujlDa5o0N07UfA4QTjApiJQyaT/l6jVSmekwx8exLWGKfMIVs3KKt8ZIT8MmmCg1+GPYHV1MzC+OCImj1q0uYDkqG/Of5KAKYrizz2GwmVa8pSyV/b+tFdBNKxlVjH+YWwxkMltCoZNzaYJDALAfUv07Xp8mnKaXdkS7SQBQ=,iv:LAmhmXDui8gkYKjL8gk9HPRFlcKAviQ9g9prp7yDptQ=,tag:GNffyDqt+mm3umUtnTU9hw==,type:str] mac: ENC[AES256_GCM,data:b0/75mHIRm+rBpzaOEWVoN2v2WTNfLMUpiHqQY7xPehuMFHycGZZaqPXr+bxDXYDm940ufQHGy0KDN8IuG/ENbFby8AnG8PGPe0rM5Nf8zux/5jlyUQB+tjIvRNy/cg9eiqlYJPp2yOclBCFUmTmAjOU+Je1bV2VCgFCINMoSec=,iv:5Ejw1WLpiDbuiS6KQudbka7HYV9fDSM1vnghtjNjXzY=,tag:7eKPDmU+eG7c/3qj6tgb0Q==,type:str]
pgp: pgp:
- created_at: "2023-05-21T00:28:40Z" - created_at: "2023-05-21T00:28:40Z"
enc: | enc: |