gerd.forgejo: now uses authelia for authentication + patches for signin

This commit is contained in:
eyjhb 2024-08-12 13:56:34 +02:00
parent d459fa895e
commit 5d94967c48
No known key found for this signature in database
GPG key ID: 609F508E3239F920
11 changed files with 243 additions and 118 deletions

View file

@ -7,9 +7,9 @@
./../shared/applications/state/ssh.nix
./gerd/services/lldap.nix
# ./gerd/services/authelia.nix
./gerd/services/authelia.nix
./gerd/services/fricloud-website.nix
./gerd/services/forgejo.nix
./gerd/services/forgejo
./gerd/services/teeworlds.nix
./gerd/services/murmur.nix
./gerd/services/hedgedoc.nix

View file

@ -8,7 +8,7 @@ in {
services.authelia.instances.main = {
enable = true;
environmentVariables.AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE = config.age.secrets.authelia-lldap-bind-user-pass.path;
environmentVariables.AUTHELIA_AUTHENTICATION_BACKEND_LDAP_PASSWORD_FILE = config.age.secrets.lldap-bind-user-pass.path;
secrets = {
jwtSecretFile = config.age.secrets.authelia-jwt.path;
storageEncryptionKeyFile = config.age.secrets.authelia-storage.path;
@ -17,9 +17,13 @@ in {
};
settings = {
access_control.default_policy = "one_factor";
session.domain = config.mine.settings.domain;
# totp - disable for now, as it requires email server
access_control.default_policy = "one_factor";
default_2fa_method = "totp";
totp.issuer = "auth.fricloud.dk";
storage.local.path = "${autheliaStateDir}/authelia.sqlite3";
notifier.filesystem.filename = "${autheliaStateDir}/authelia_notifier.txt";
@ -53,29 +57,6 @@ in {
};
};
# example configuration for forgejo. Should live in forgejo.nix if needed
# services.authelia.instances.main.settings.identity_providers.oidc.clients = [{
# id = "forgejo";
# description = "Forgejo";
# # authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986
# secret = "$pbkdf2-sha512$310000$cOGtLwMHyfugAJCIiUUjfQ$ao7zC8QB1m8aTGNf1dxYbRAPivZ0G1eaJ4bNFVfJiTFZX06U5baBjT0emvoaeFHXMFbYHzorb2/8vxnY/D0b5Q";
# public = false;
# authorization_policy = "one_factor";
# redirect_uris = [ "https://git.fricloud.dk/user/oauth2/authelia/callback" ];
# scopes = [
# "openid"
# "email"
# "profile"
# ];
# userinfo_signing_algorithm = "none";
# # userinfo_signed_response_alg = "none";
# # token_endpoint_auth_method = "client_secret_basic";
# }];
services.nginx.virtualHosts."${svc_domain}" = {
forceSSL = true;
enableACME = true;
@ -96,4 +77,7 @@ in {
};
users.groups."${config.age.secrets.lldap-bind-user-pass.group}".members = [ config.users.users.authelia-main.name ];
# settings
mine.settings.authelia.domain = svc_domain;
}

View file

@ -1,91 +0,0 @@
{ config, lib, pkgs, ... }:
let
svc_domain = "git.${config.mine.settings.domain}";
scriptAddLDAPAuth = pkgs.writeShellScript "forgejo-add-update-ldap-auth.sh" ''
#!/usr/bin/env sh
FORGEJO_WORK_PATH="${config.services.forgejo.stateDir}"
FORGEJO_AUTH_LDAP_NAME="lldap"
# get lldap id if any
FORGEJO_AUTH_ID=$(gitea --work-path "$FORGEJO_WORK_PATH" admin auth list | grep "$FORGEJO_AUTH_LDAP_NAME" | cut -d$'\t' -f1)
ACTION=""
EXTRA_ARG=""
if [ -n "''${FORGEJO_AUTH_ID}" ]; then
echo "PRERUN-LDAP: Authentication source exists, updating..."
ACTION="update-ldap"
EXTRA_ARG="--id $FORGEJO_AUTH_ID"
else
echo "PRERUN-LDAP: Authentication source does not exists, adding..."
ACTION="add-ldap"
fi
BIND_USERPASS="$(cat $CREDENTIALS_DIRECTORY/lldap-bind-user-pass)"
gitea \
--work-path /srv/forgejo/ \
admin auth "$ACTION" $EXTRA_ARG \
--name "$FORGEJO_AUTH_LDAP_NAME" \
--active \
--security-protocol unencrypted \
--skip-tls-verify \
--host ${config.mine.settings.ldap.host} \
--port ${builtins.toString config.mine.settings.ldap.port} \
--bind-dn "${config.mine.settings.ldap.bind_dn}" \
--bind-password "$BIND_USERPASS" \
--user-filter '(&${config.mine.settings.ldap.user_filter}(|(${config.mine.settings.ldap.attr.uid}=%[1]s)(${config.mine.settings.ldap.attr.email}=%[1]s)))' \
--admin-filter '${config.mine.settings.ldap.admin_filter}' \
--username-attribute ${config.mine.settings.ldap.attr.uid} \
--firstname-attribute ${config.mine.settings.ldap.attr.firstname} \
--surname-attribute ${config.mine.settings.ldap.attr.lastname} \
--email-attribute ${config.mine.settings.ldap.attr.email} \
--avatar-attribute ${config.mine.settings.ldap.attr.avatar} \
--synchronize-users \
--user-search-base '${config.mine.settings.ldap.search_base}' \
echo "PRERUN-LDAP: Finished adding/updating..."
'';
in {
services.forgejo = {
enable = true;
stateDir = config.mine.zfsMounts."rpool/safe/svcs/forgejo";
settings = {
server = {
DOMAIN = svc_domain;
ROOT_URL = "https://${svc_domain}";
HTTPPORT = 3000;
};
# sync ldap and forgejo
"cron.sync_external_users" = {
RUN_AT_START = true;
SCHEDULE = "@every 15m";
UPDATE_EXISTING = true;
};
service.DISABLE_REGISTRATION = true;
};
};
# add script to add/update ldap source (+ place credential into the service)
systemd.services.forgejo.preStart = lib.mkAfter (builtins.toString scriptAddLDAPAuth);
systemd.services.forgejo.serviceConfig.LoadCredential = "lldap-bind-user-pass:${config.age.secrets.lldap-bind-user-pass.path}";
# TODO(eyJhb): remove after our ban expires (and nginx config)
# already issued for this exact set of domains in the last 168 hours: git.fricloud.dk, retry after 2024-08-10T01:34:44Z
security.acme.certs."git.fricloud.dk".extraDomainNames = [ "git2.fricloud.dk" ];
services.nginx.virtualHosts."${svc_domain}" = {
forceSSL = true;
enableACME = true;
extraConfig = ''
client_max_body_size 512M;
'';
locations."/".proxyPass = "http://localhost:${builtins.toString config.services.forgejo.settings.server.HTTPPORT}";
};
}

View file

@ -0,0 +1,119 @@
{ config, lib, pkgs, ... }:
let
AUTHELIA_AUTH_NAME = "authelia";
scriptAddLDAPAuth = pkgs.writeShellScript "forgejo-add-update-ldap-auth.sh" ''
#!/usr/bin/env sh
FORGEJO_WORK_PATH="${config.services.forgejo.stateDir}"
FORGEJO_AUTH_NAME="lldap"
# get auth id if any
FORGEJO_AUTH_ID=$(gitea --work-path "$FORGEJO_WORK_PATH" admin auth list | grep "$FORGEJO_AUTH_NAME" | cut -d$'\t' -f1)
ACTION=""
EXTRA_ARG=""
if [ -n "''${FORGEJO_AUTH_ID}" ]; then
echo "PRERUN-LDAP: Authentication source exists, updating..."
ACTION="update-ldap"
EXTRA_ARG="--id $FORGEJO_AUTH_ID"
else
echo "PRERUN-LDAP: Authentication source does not exists, adding..."
ACTION="add-ldap"
fi
BIND_USERPASS="$(cat $CREDENTIALS_DIRECTORY/lldap-bind-user-pass)"
${pkgs.forgejo}/bin/gitea \
--work-path '${config.mine.zfsMounts."rpool/safe/svcs/forgejo"}' \
admin auth "$ACTION" $EXTRA_ARG \
--name "$FORGEJO_AUTH_NAME" \
--active \
--security-protocol unencrypted \
--skip-tls-verify \
--host ${config.mine.settings.ldap.host} \
--port ${builtins.toString config.mine.settings.ldap.port} \
--bind-dn "${config.mine.settings.ldap.bind_dn}" \
--bind-password "$BIND_USERPASS" \
--user-filter '(&${config.mine.settings.ldap.user_filter}(|(${config.mine.settings.ldap.attr.uid}=%[1]s)(${config.mine.settings.ldap.attr.email}=%[1]s)))' \
--admin-filter '${config.mine.settings.ldap.admin_filter}' \
--username-attribute ${config.mine.settings.ldap.attr.uid} \
--firstname-attribute ${config.mine.settings.ldap.attr.firstname} \
--surname-attribute ${config.mine.settings.ldap.attr.lastname} \
--email-attribute ${config.mine.settings.ldap.attr.email} \
--avatar-attribute ${config.mine.settings.ldap.attr.avatar} \
--synchronize-users \
--user-search-base '${config.mine.settings.ldap.search_base}' \
echo "PRERUN-LDAP: Finished adding/updating..."
'';
scriptAddOAuth = pkgs.writeShellScript "forgejo-add-update-oauth.sh" ''
#!/usr/bin/env sh
FORGEJO_WORK_PATH="${config.services.forgejo.stateDir}"
FORGEJO_AUTH_NAME="${AUTHELIA_AUTH_NAME}"
# get auth id if any
FORGEJO_AUTH_ID=$(gitea --work-path "$FORGEJO_WORK_PATH" admin auth list | grep "$FORGEJO_AUTH_NAME" | cut -d$'\t' -f1)
ACTION=""
EXTRA_ARG=""
if [ -n "''${FORGEJO_AUTH_ID}" ]; then
echo "PRERUN-AUTH: Authentication source exists, updating..."
ACTION="update-oauth"
EXTRA_ARG="--id $FORGEJO_AUTH_ID"
else
echo "PRERUN-AUTH: Authentication source does not exists, adding..."
ACTION="add-oauth"
fi
SECRET="$(cat $CREDENTIALS_DIRECTORY/authelia-secret)"
${pkgs.forgejo}/bin/gitea \
--work-path '${config.mine.zfsMounts."rpool/safe/svcs/forgejo"}' \
admin auth "$ACTION" $EXTRA_ARG \
--name "$FORGEJO_AUTH_NAME" \
--provider openidConnect \
--key forgejo \
--secret "$SECRET" \
--auto-discover-url "https://${config.mine.settings.authelia.domain}/.well-known/openid-configuration" \
--skip-local-2fa true \
--scopes "email" \
--scopes "profile" \
echo "PRERUN-AUTH: Finished adding/updating..."
'';
in {
systemd.services.forgejo.preStart = lib.mkAfter ''
${scriptAddLDAPAuth}
${scriptAddOAuth}
'';
systemd.services.forgejo.serviceConfig.LoadCredential = [
"authelia-secret:${config.age.secrets.forgejo-authelia-secret.path}"
"lldap-bind-user-pass:${config.age.secrets.lldap-bind-user-pass.path}"
];
# example configuration for forgejo. Should live in forgejo.nix if needed
services.authelia.instances.main.settings.identity_providers.oidc.clients = [{
id = "forgejo";
description = "Forgejo";
# authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986
secret = "$pbkdf2-sha512$310000$cOGtLwMHyfugAJCIiUUjfQ$ao7zC8QB1m8aTGNf1dxYbRAPivZ0G1eaJ4bNFVfJiTFZX06U5baBjT0emvoaeFHXMFbYHzorb2/8vxnY/D0b5Q";
public = false;
# authorization_policy = "one_factor";
redirect_uris = [ "https://${config.mine.settings.forgejo.domain}/user/oauth2/${AUTHELIA_AUTH_NAME}/callback" ];
scopes = [
"openid"
"email"
"profile"
];
userinfo_signing_algorithm = "none";
}];
}

View file

@ -0,0 +1,6 @@
{
imports = [
./forgejo.nix
./auth_sources.nix
];
}

View file

@ -0,0 +1,53 @@
{ config, lib, pkgs, ... }:
let
svc_domain = "git.${config.mine.settings.domain}";
in {
services.forgejo = {
enable = true;
package = pkgs.forgejo.overrideAttrs (old: {
patches = old.patches ++ [
./patches/signin-template.patch
./patches/link-accounts-template.patch
];
});
stateDir = config.mine.zfsMounts."rpool/safe/svcs/forgejo";
settings = {
server = {
DOMAIN = svc_domain;
ROOT_URL = "https://${svc_domain}";
HTTPPORT = 3000;
};
# sync ldap and forgejo
"cron.sync_external_users" = {
RUN_AT_START = true;
SCHEDULE = "@every 15m";
UPDATE_EXISTING = true;
};
# disable registration, only account linking is possible
service.DISABLE_REGISTRATION = true;
};
};
# TODO(eyJhb): remove after our ban expires (and nginx config)
# already issued for this exact set of domains in the last 168 hours: git.fricloud.dk, retry after 2024-08-10T01:34:44Z
security.acme.certs."git.fricloud.dk".extraDomainNames = [ "git2.fricloud.dk" ];
services.nginx.virtualHosts."${svc_domain}" = {
forceSSL = true;
enableACME = true;
extraConfig = ''
client_max_body_size 512M;
'';
locations."/".proxyPass = "http://localhost:${builtins.toString config.services.forgejo.settings.server.HTTPPORT}";
};
# settings
mine.settings.forgejo.domain = svc_domain;
}

View file

@ -0,0 +1,18 @@
diff --git a/templates/user/auth/link_account.tmpl b/templates/user/auth/link_account.tmpl
index 8dd49ccd60..8cdce5e1ad 100644
--- a/templates/user/auth/link_account.tmpl
+++ b/templates/user/auth/link_account.tmpl
@@ -17,11 +17,11 @@
</overflow-menu>
<div class="ui middle very relaxed page grid">
<div class="column">
- <div class="ui tab {{if not .user_exists}}active{{end}}"
+ <div class="ui tab"
data-tab="auth-link-signup-tab">
{{template "user/auth/signup_inner" .}}
</div>
- <div class="ui tab {{if .user_exists}}active{{end}}"
+ <div class="ui tab active"
data-tab="auth-link-signin-tab">
<div class="ui user signin container icon">
{{template "user/auth/signin_inner" .}}

View file

@ -0,0 +1,20 @@
diff --git a/templates/user/auth/signin_inner.tmpl b/templates/user/auth/signin_inner.tmpl
index 9872096fbc..1076f90326 100644
--- a/templates/user/auth/signin_inner.tmpl
+++ b/templates/user/auth/signin_inner.tmpl
@@ -10,6 +10,7 @@
</h4>
<div class="ui attached segment">
<form class="ui form tw-max-w-2xl tw-m-auto" action="{{.SignInLink}}" method="post">
+ <div {{if not .LinkAccountMode}}style="display:none;"{{end}}>
{{.CsrfTokenHtml}}
<div class="required field {{if and (.Err_UserName) (or (not .LinkAccountMode) (and .LinkAccountMode .LinkAccountModeSignIn))}}error{{end}}">
<label for="user_name">{{ctx.Locale.Tr "home.uname_holder"}}</label>
@@ -53,6 +54,7 @@
<div class="divider divider-text">
{{ctx.Locale.Tr "sign_in_or"}}
</div>
+ </div>
<div id="oauth2-login-navigator" class="tw-py-1">
<div class="tw-flex tw-flex-col tw-justify-center">
<div id="oauth2-login-navigator-inner" class="tw-flex tw-flex-col tw-flex-wrap tw-items-center tw-gap-2">

View file

@ -21,6 +21,9 @@
# mumble
murmur-env.file = ./murmur/env.age;
murmur-superpassword.file = ./murmur/superpassword.age;
# forgejo
forgejo-authelia-secret.file = ./forgejo/authelia-secret.age;
};
users.groups.secrets-lldap-bind-user-pass = {};

View file

@ -0,0 +1,10 @@
age-encryption.org/v1
-> ssh-ed25519 QSDXqg 6QDsf2ACEhUdb2IUxDaILcvoPLPdpXupn7DDTQCREWA
8VYqwj6UoIee6DHG+bF3lHnY+NxLP8KkjjxynSiEUEk
-> ssh-ed25519 n8n9DQ wAIhE1M0sMi+0tdc2fZDFzLJLlaZkhZOXIEkB2lm3UE
iG5tvWLkYfv/klmc0LjUn+96RuYTRUrLbMpPicpVchc
-> ssh-ed25519 BTp6UA GSOxjXyCvjwg/jS3pG3gegh9jcYbVHy3y4v/dUM7plQ
ItU5OQJswLZ3nCpfUcLMhkdEVF6Iu+lPP0qGj9MU7h0
--- ONOkuJRp+quOeMUJ6kf+j4Bweks4FAGurAE3xgk3wIw
ðà7‡h#p<>·ŒØ˜ÿ,ŒÙîúàSV|^8"‰)¢š§†‡è]ýbiàڡܶġTWêi Aÿ
¹\›ò¾%X¨ v « 4Fè”9{<7B>FY<59>"Ä5`wZ¬¼¸MÓ$eý='€a

View file

@ -25,4 +25,7 @@ in
# mumble
"murmur/env.age".publicKeys = defaultAccess;
"murmur/superpassword.age".publicKeys = defaultAccess;
# forgejo
"forgejo/authelia-secret.age".publicKeys = defaultAccess;
}