mirror of
https://github.com/Swarsel/.dotfiles.git
synced 2025-12-06 00:57:22 +01:00
feat[work,server,client]: add opkssh
Some checks failed
Flake check / Check flake (push) Has been cancelled
Some checks failed
Flake check / Check flake (push) Has been cancelled
This commit is contained in:
parent
3b368ec8de
commit
c9e7e493d8
14 changed files with 604 additions and 340 deletions
|
|
@ -437,8 +437,8 @@ A short overview over each input and what it does:
|
||||||
swarsel-modules.url = "github:Swarsel/swarsel-modules/main";
|
swarsel-modules.url = "github:Swarsel/swarsel-modules/main";
|
||||||
swarsel-nix.url = "github:Swarsel/swarsel-nix/main";
|
swarsel-nix.url = "github:Swarsel/swarsel-nix/main";
|
||||||
home-manager = {
|
home-manager = {
|
||||||
url = "github:nix-community/home-manager";
|
# url = "github:nix-community/home-manager";
|
||||||
# url = "github:Swarsel/home-manager/main";
|
url = "github:Swarsel/home-manager/main";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
swarsel.url = "github:Swarsel/.dotfiles";
|
swarsel.url = "github:Swarsel/.dotfiles";
|
||||||
|
|
@ -2472,6 +2472,7 @@ This is my main server that I run at home. It handles most tasks that require bi
|
||||||
ankisync = lib.mkDefault true;
|
ankisync = lib.mkDefault true;
|
||||||
# snipeit = lib.mkDefault false;
|
# snipeit = lib.mkDefault false;
|
||||||
homebox = lib.mkDefault true;
|
homebox = lib.mkDefault true;
|
||||||
|
opkssh = lib.mkDefault true;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -8788,317 +8789,335 @@ A stupid (but simple) way to get the =originUrl= is to simply set any URL there
|
||||||
To get other URLs (token, etc.), use https://<kanidmDomain>/oauth2/openid/<clientID>/.well-known/oauth-authorization-server, e.g. https://<kanidmDomain>/oauth2/openid/nextcloud/.well-known/oauth-authorization-server, with clienID being the client name as specified in kanidm.
|
To get other URLs (token, etc.), use https://<kanidmDomain>/oauth2/openid/<clientID>/.well-known/oauth-authorization-server, e.g. https://<kanidmDomain>/oauth2/openid/nextcloud/.well-known/oauth-authorization-server, with clienID being the client name as specified in kanidm.
|
||||||
|
|
||||||
#+begin_src nix-ts :tangle modules/nixos/server/kanidm.nix
|
#+begin_src nix-ts :tangle modules/nixos/server/kanidm.nix
|
||||||
{ self, lib, pkgs, config, globals, ... }:
|
{ self, lib, pkgs, config, globals, ... }:
|
||||||
let
|
let
|
||||||
certsSopsFile = self + /secrets/certs/secrets.yaml;
|
certsSopsFile = self + /secrets/certs/secrets.yaml;
|
||||||
inherit (config.swarselsystems) sopsFile;
|
inherit (config.swarselsystems) sopsFile;
|
||||||
|
|
||||||
servicePort = 8300;
|
servicePort = 8300;
|
||||||
serviceUser = "kanidm";
|
serviceUser = "kanidm";
|
||||||
serviceGroup = serviceUser;
|
serviceGroup = serviceUser;
|
||||||
serviceName = "kanidm";
|
serviceName = "kanidm";
|
||||||
serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
|
serviceDomain = config.repo.secrets.common.services.domains.${serviceName};
|
||||||
serviceAddress = globals.hosts.winters.ipv4;
|
serviceAddress = globals.hosts.winters.ipv4;
|
||||||
|
|
||||||
oauth2ProxyDomain = globals.services.oauth2Proxy.domain;
|
oauth2ProxyDomain = globals.services.oauth2Proxy.domain;
|
||||||
immichDomain = globals.services.immich.domain;
|
immichDomain = globals.services.immich.domain;
|
||||||
paperlessDomain = globals.services.paperless.domain;
|
paperlessDomain = globals.services.paperless.domain;
|
||||||
forgejoDomain = globals.services.forgejo.domain;
|
forgejoDomain = globals.services.forgejo.domain;
|
||||||
grafanaDomain = globals.services.grafana.domain;
|
grafanaDomain = globals.services.grafana.domain;
|
||||||
nextcloudDomain = globals.services.nextcloud.domain;
|
nextcloudDomain = globals.services.nextcloud.domain;
|
||||||
|
|
||||||
certBase = "/etc/ssl";
|
certBase = "/etc/ssl";
|
||||||
certsDir = "${certBase}/certs";
|
certsDir = "${certBase}/certs";
|
||||||
privateDir = "${certBase}/private";
|
privateDir = "${certBase}/private";
|
||||||
certPath = "${certsDir}/${serviceName}.crt";
|
certPath = "${certsDir}/${serviceName}.crt";
|
||||||
keyPath = "${privateDir}/${serviceName}.key";
|
keyPath = "${privateDir}/${serviceName}.key";
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
|
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
|
||||||
config = lib.mkIf config.swarselmodules.server.${serviceName} {
|
config = lib.mkIf config.swarselmodules.server.${serviceName} {
|
||||||
|
|
||||||
users.users.${serviceUser} = {
|
users.users.${serviceUser} = {
|
||||||
group = serviceGroup;
|
group = serviceGroup;
|
||||||
isSystemUser = true;
|
isSystemUser = true;
|
||||||
};
|
|
||||||
|
|
||||||
users.groups.${serviceGroup} = { };
|
|
||||||
|
|
||||||
sops = {
|
|
||||||
secrets = {
|
|
||||||
"kanidm-self-signed-crt" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-self-signed-key" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-idm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-immich" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-paperless" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-forgejo" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-grafana" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-nextcloud" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-freshrss" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
"kanidm-oauth2-proxy" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ servicePort ];
|
users.groups.${serviceGroup} = { };
|
||||||
|
|
||||||
globals.services.${serviceName}.domain = serviceDomain;
|
sops = {
|
||||||
|
secrets = {
|
||||||
|
"kanidm-self-signed-crt" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-self-signed-key" = { sopsFile = certsSopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-idm-admin-pw" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-immich" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-paperless" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-forgejo" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-grafana" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-nextcloud" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-freshrss" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
"kanidm-oauth2-proxy" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
system.activationScripts."generateSSLCert-${serviceName}" =
|
networking.firewall.allowedTCPPorts = [ servicePort ];
|
||||||
let
|
|
||||||
daysValid = 3650;
|
|
||||||
renewBeforeDays = 365;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
text = ''
|
|
||||||
set -eu
|
|
||||||
|
|
||||||
${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir}
|
globals.services.${serviceName}.domain = serviceDomain;
|
||||||
${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir}
|
|
||||||
|
|
||||||
need_gen=0
|
system.activationScripts."generateSSLCert-${serviceName}" =
|
||||||
if [ ! -f "${certPath}" ] || [ ! -f "${keyPath}" ]; then
|
let
|
||||||
need_gen=1
|
daysValid = 3650;
|
||||||
else
|
renewBeforeDays = 365;
|
||||||
enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPath}" | cut -d= -f2)"
|
in
|
||||||
end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)"
|
{
|
||||||
now_epoch="$(${pkgs.coreutils}/bin/date +%s)"
|
text = ''
|
||||||
seconds_left=$(( end_epoch - now_epoch ))
|
set -eu
|
||||||
days_left=$(( seconds_left / 86400 ))
|
|
||||||
if [ "$days_left" -lt ${toString renewBeforeDays} ]; then
|
${pkgs.coreutils}/bin/install -d -m 0755 ${certsDir}
|
||||||
|
${pkgs.coreutils}/bin/install -d -m 0750 ${privateDir}
|
||||||
|
|
||||||
|
need_gen=0
|
||||||
|
if [ ! -f "${certPath}" ] || [ ! -f "${keyPath}" ]; then
|
||||||
need_gen=1
|
need_gen=1
|
||||||
|
else
|
||||||
|
enddate="$(${pkgs.openssl}/bin/openssl x509 -noout -enddate -in "${certPath}" | cut -d= -f2)"
|
||||||
|
end_epoch="$(${pkgs.coreutils}/bin/date -d "$enddate" +%s)"
|
||||||
|
now_epoch="$(${pkgs.coreutils}/bin/date +%s)"
|
||||||
|
seconds_left=$(( end_epoch - now_epoch ))
|
||||||
|
days_left=$(( seconds_left / 86400 ))
|
||||||
|
if [ "$days_left" -lt ${toString renewBeforeDays} ]; then
|
||||||
|
need_gen=1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$need_gen" -eq 1 ]; then
|
if [ "$need_gen" -eq 1 ]; then
|
||||||
${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \
|
${pkgs.openssl}/bin/openssl req -x509 -nodes -days ${toString daysValid} -newkey rsa:4096 -sha256 \
|
||||||
-keyout "${keyPath}" \
|
-keyout "${keyPath}" \
|
||||||
-out "${certPath}" \
|
-out "${certPath}" \
|
||||||
-subj "/CN=${serviceDomain}" \
|
-subj "/CN=${serviceDomain}" \
|
||||||
-addext "subjectAltName=DNS:${serviceDomain}"
|
-addext "subjectAltName=DNS:${serviceDomain}"
|
||||||
|
|
||||||
chmod 0644 "${certPath}"
|
chmod 0644 "${certPath}"
|
||||||
chmod 0600 "${keyPath}"
|
chmod 0600 "${keyPath}"
|
||||||
chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}"
|
chown ${serviceUser}:${serviceGroup} "${certPath}" "${keyPath}"
|
||||||
fi
|
fi
|
||||||
'';
|
|
||||||
deps = [ "etc" ];
|
|
||||||
};
|
|
||||||
|
|
||||||
services = {
|
|
||||||
${serviceName} = {
|
|
||||||
package = pkgs.kanidmWithSecretProvisioning_1_7;
|
|
||||||
enableServer = true;
|
|
||||||
serverSettings = {
|
|
||||||
domain = serviceDomain;
|
|
||||||
origin = "https://${serviceDomain}";
|
|
||||||
# tls_chain = config.sops.secrets.kanidm-self-signed-crt.path;
|
|
||||||
tls_chain = certPath;
|
|
||||||
# tls_key = config.sops.secrets.kanidm-self-signed-key.path;
|
|
||||||
tls_key = keyPath;
|
|
||||||
bindaddress = "0.0.0.0:${toString servicePort}";
|
|
||||||
trust_x_forward_for = true;
|
|
||||||
};
|
|
||||||
enableClient = true;
|
|
||||||
clientSettings = {
|
|
||||||
uri = config.services.kanidm.serverSettings.origin;
|
|
||||||
verify_ca = true;
|
|
||||||
verify_hostnames = true;
|
|
||||||
};
|
|
||||||
provision = {
|
|
||||||
enable = true;
|
|
||||||
adminPasswordFile = config.sops.secrets.kanidm-admin-pw.path;
|
|
||||||
idmAdminPasswordFile = config.sops.secrets.kanidm-idm-admin-pw.path;
|
|
||||||
groups = {
|
|
||||||
"immich.access" = { };
|
|
||||||
"paperless.access" = { };
|
|
||||||
"forgejo.access" = { };
|
|
||||||
"forgejo.admins" = { };
|
|
||||||
"grafana.access" = { };
|
|
||||||
"grafana.editors" = { };
|
|
||||||
"grafana.admins" = { };
|
|
||||||
"grafana.server-admins" = { };
|
|
||||||
"nextcloud.access" = { };
|
|
||||||
"nextcloud.admins" = { };
|
|
||||||
"navidrome.access" = { };
|
|
||||||
"freshrss.access" = { };
|
|
||||||
"firefly.access" = { };
|
|
||||||
"radicale.access" = { };
|
|
||||||
"slink.access" = { };
|
|
||||||
};
|
|
||||||
|
|
||||||
inherit (config.repo.secrets.local) persons;
|
|
||||||
|
|
||||||
systems = {
|
|
||||||
oauth2 = {
|
|
||||||
immich = {
|
|
||||||
displayName = "Immich";
|
|
||||||
originUrl = [
|
|
||||||
"https://${immichDomain}/auth/login"
|
|
||||||
"https://${immichDomain}/user-settings"
|
|
||||||
"app.immich:///oauth-callback"
|
|
||||||
"https://${immichDomain}/api/oauth/mobile-redirect"
|
|
||||||
];
|
|
||||||
originLanding = "https://${immichDomain}/";
|
|
||||||
basicSecretFile = config.sops.secrets.kanidm-immich.path;
|
|
||||||
preferShortUsername = true;
|
|
||||||
enableLegacyCrypto = true; # can use RS256 / HS256, not ES256
|
|
||||||
scopeMaps."immich.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
paperless = {
|
|
||||||
displayName = "Paperless";
|
|
||||||
originUrl = "https://${paperlessDomain}/accounts/oidc/kanidm/login/callback/";
|
|
||||||
originLanding = "https://${paperlessDomain}/";
|
|
||||||
basicSecretFile = config.sops.secrets.kanidm-paperless.path;
|
|
||||||
preferShortUsername = true;
|
|
||||||
scopeMaps."paperless.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
forgejo = {
|
|
||||||
displayName = "Forgejo";
|
|
||||||
originUrl = "https://${forgejoDomain}/user/oauth2/kanidm/callback";
|
|
||||||
originLanding = "https://${forgejoDomain}/";
|
|
||||||
basicSecretFile = config.sops.secrets.kanidm-forgejo.path;
|
|
||||||
scopeMaps."forgejo.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
# XXX: PKCE is currently not supported by gitea/forgejo,
|
|
||||||
# see https://github.com/go-gitea/gitea/issues/21376.
|
|
||||||
allowInsecureClientDisablePkce = true;
|
|
||||||
preferShortUsername = true;
|
|
||||||
claimMaps.groups = {
|
|
||||||
joinType = "array";
|
|
||||||
valuesByGroup."forgejo.admins" = [ "admin" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
grafana = {
|
|
||||||
displayName = "Grafana";
|
|
||||||
originUrl = "https://${grafanaDomain}/login/generic_oauth";
|
|
||||||
originLanding = "https://${grafanaDomain}/";
|
|
||||||
basicSecretFile = config.sops.secrets.kanidm-grafana.path;
|
|
||||||
preferShortUsername = true;
|
|
||||||
scopeMaps."grafana.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
claimMaps.groups = {
|
|
||||||
joinType = "array";
|
|
||||||
valuesByGroup = {
|
|
||||||
"grafana.editors" = [ "editor" ];
|
|
||||||
"grafana.admins" = [ "admin" ];
|
|
||||||
"grafana.server-admins" = [ "server_admin" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
nextcloud = {
|
|
||||||
displayName = "Nextcloud";
|
|
||||||
originUrl = " https://${nextcloudDomain}/apps/sociallogin/custom_oidc/kanidm";
|
|
||||||
originLanding = "https://${nextcloudDomain}/";
|
|
||||||
basicSecretFile = config.sops.secrets.kanidm-nextcloud.path;
|
|
||||||
allowInsecureClientDisablePkce = true;
|
|
||||||
scopeMaps."nextcloud.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
preferShortUsername = true;
|
|
||||||
claimMaps.groups = {
|
|
||||||
joinType = "array";
|
|
||||||
valuesByGroup = {
|
|
||||||
"nextcloud.admins" = [ "admin" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
oauth2-proxy = {
|
|
||||||
displayName = "Oauth2-Proxy";
|
|
||||||
originUrl = "https://${oauth2ProxyDomain}/oauth2/callback";
|
|
||||||
originLanding = "https://${oauth2ProxyDomain}/";
|
|
||||||
basicSecretFile = config.sops.secrets.kanidm-oauth2-proxy.path;
|
|
||||||
scopeMaps = {
|
|
||||||
"freshrss.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
"navidrome.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
"firefly.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
"radicale.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
"slink.access" = [
|
|
||||||
"openid"
|
|
||||||
"email"
|
|
||||||
"profile"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
preferShortUsername = true;
|
|
||||||
claimMaps.groups = {
|
|
||||||
joinType = "array";
|
|
||||||
valuesByGroup = {
|
|
||||||
"freshrss.access" = [ "ttrss_access" ];
|
|
||||||
"navidrome.access" = [ "navidrome_access" ];
|
|
||||||
"firefly.access" = [ "firefly_access" ];
|
|
||||||
"radicale.access" = [ "radicale_access" ];
|
|
||||||
"slink.access" = [ "slink_access" ];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systemd.services = {
|
|
||||||
${serviceName}.serviceConfig.RestartSec = "30";
|
|
||||||
};
|
|
||||||
|
|
||||||
nodes.moonside.services.nginx = {
|
|
||||||
upstreams = {
|
|
||||||
${serviceName} = {
|
|
||||||
servers = {
|
|
||||||
"${serviceAddress}:${builtins.toString servicePort}" = { };
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
virtualHosts = {
|
|
||||||
"${serviceDomain}" = {
|
|
||||||
enableACME = true;
|
|
||||||
forceSSL = true;
|
|
||||||
acmeRoot = null;
|
|
||||||
locations = {
|
|
||||||
"/" = {
|
|
||||||
proxyPass = "https://${serviceName}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
extraConfig = ''
|
|
||||||
proxy_ssl_verify off;
|
|
||||||
'';
|
'';
|
||||||
|
deps = [ "etc" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services = {
|
||||||
|
${serviceName} = {
|
||||||
|
package = pkgs.kanidmWithSecretProvisioning_1_7;
|
||||||
|
enableServer = true;
|
||||||
|
serverSettings = {
|
||||||
|
domain = serviceDomain;
|
||||||
|
origin = "https://${serviceDomain}";
|
||||||
|
# tls_chain = config.sops.secrets.kanidm-self-signed-crt.path;
|
||||||
|
tls_chain = certPath;
|
||||||
|
# tls_key = config.sops.secrets.kanidm-self-signed-key.path;
|
||||||
|
tls_key = keyPath;
|
||||||
|
bindaddress = "0.0.0.0:${toString servicePort}";
|
||||||
|
trust_x_forward_for = true;
|
||||||
|
};
|
||||||
|
enableClient = true;
|
||||||
|
clientSettings = {
|
||||||
|
uri = config.services.kanidm.serverSettings.origin;
|
||||||
|
verify_ca = true;
|
||||||
|
verify_hostnames = true;
|
||||||
|
};
|
||||||
|
provision = {
|
||||||
|
enable = true;
|
||||||
|
adminPasswordFile = config.sops.secrets.kanidm-admin-pw.path;
|
||||||
|
idmAdminPasswordFile = config.sops.secrets.kanidm-idm-admin-pw.path;
|
||||||
|
groups = {
|
||||||
|
"immich.access" = { };
|
||||||
|
"paperless.access" = { };
|
||||||
|
"forgejo.access" = { };
|
||||||
|
"forgejo.admins" = { };
|
||||||
|
"grafana.access" = { };
|
||||||
|
"grafana.editors" = { };
|
||||||
|
"grafana.admins" = { };
|
||||||
|
"grafana.server-admins" = { };
|
||||||
|
"nextcloud.access" = { };
|
||||||
|
"nextcloud.admins" = { };
|
||||||
|
"navidrome.access" = { };
|
||||||
|
"freshrss.access" = { };
|
||||||
|
"firefly.access" = { };
|
||||||
|
"radicale.access" = { };
|
||||||
|
"slink.access" = { };
|
||||||
|
"opkssh.access" = { };
|
||||||
|
};
|
||||||
|
|
||||||
|
inherit (config.repo.secrets.local) persons;
|
||||||
|
|
||||||
|
systems = {
|
||||||
|
oauth2 = {
|
||||||
|
immich = {
|
||||||
|
displayName = "Immich";
|
||||||
|
originUrl = [
|
||||||
|
"https://${immichDomain}/auth/login"
|
||||||
|
"https://${immichDomain}/user-settings"
|
||||||
|
"app.immich:///oauth-callback"
|
||||||
|
"https://${immichDomain}/api/oauth/mobile-redirect"
|
||||||
|
];
|
||||||
|
originLanding = "https://${immichDomain}/";
|
||||||
|
basicSecretFile = config.sops.secrets.kanidm-immich.path;
|
||||||
|
preferShortUsername = true;
|
||||||
|
enableLegacyCrypto = true; # can use RS256 / HS256, not ES256
|
||||||
|
scopeMaps."immich.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
paperless = {
|
||||||
|
displayName = "Paperless";
|
||||||
|
originUrl = "https://${paperlessDomain}/accounts/oidc/kanidm/login/callback/";
|
||||||
|
originLanding = "https://${paperlessDomain}/";
|
||||||
|
basicSecretFile = config.sops.secrets.kanidm-paperless.path;
|
||||||
|
preferShortUsername = true;
|
||||||
|
scopeMaps."paperless.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
forgejo = {
|
||||||
|
displayName = "Forgejo";
|
||||||
|
originUrl = "https://${forgejoDomain}/user/oauth2/kanidm/callback";
|
||||||
|
originLanding = "https://${forgejoDomain}/";
|
||||||
|
basicSecretFile = config.sops.secrets.kanidm-forgejo.path;
|
||||||
|
scopeMaps."forgejo.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
# XXX: PKCE is currently not supported by gitea/forgejo,
|
||||||
|
# see https://github.com/go-gitea/gitea/issues/21376.
|
||||||
|
allowInsecureClientDisablePkce = true;
|
||||||
|
preferShortUsername = true;
|
||||||
|
claimMaps.groups = {
|
||||||
|
joinType = "array";
|
||||||
|
valuesByGroup."forgejo.admins" = [ "admin" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
grafana = {
|
||||||
|
displayName = "Grafana";
|
||||||
|
originUrl = "https://${grafanaDomain}/login/generic_oauth";
|
||||||
|
originLanding = "https://${grafanaDomain}/";
|
||||||
|
basicSecretFile = config.sops.secrets.kanidm-grafana.path;
|
||||||
|
preferShortUsername = true;
|
||||||
|
scopeMaps."grafana.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
claimMaps.groups = {
|
||||||
|
joinType = "array";
|
||||||
|
valuesByGroup = {
|
||||||
|
"grafana.editors" = [ "editor" ];
|
||||||
|
"grafana.admins" = [ "admin" ];
|
||||||
|
"grafana.server-admins" = [ "server_admin" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
nextcloud = {
|
||||||
|
displayName = "Nextcloud";
|
||||||
|
originUrl = " https://${nextcloudDomain}/apps/sociallogin/custom_oidc/kanidm";
|
||||||
|
originLanding = "https://${nextcloudDomain}/";
|
||||||
|
basicSecretFile = config.sops.secrets.kanidm-nextcloud.path;
|
||||||
|
allowInsecureClientDisablePkce = true;
|
||||||
|
scopeMaps."nextcloud.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
preferShortUsername = true;
|
||||||
|
claimMaps.groups = {
|
||||||
|
joinType = "array";
|
||||||
|
valuesByGroup = {
|
||||||
|
"nextcloud.admins" = [ "admin" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
opkssh = {
|
||||||
|
displayName = "OPKSSH";
|
||||||
|
originUrl = [
|
||||||
|
"http://localhost:3000"
|
||||||
|
"http://localhost:3000/login-callback"
|
||||||
|
"http://localhost:10001/login-callback"
|
||||||
|
"http://localhost:11110/login-callback"
|
||||||
|
];
|
||||||
|
originLanding = "http://localhost:3000";
|
||||||
|
public = true;
|
||||||
|
enableLocalhostRedirects = true;
|
||||||
|
scopeMaps."opkssh.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
oauth2-proxy = {
|
||||||
|
displayName = "Oauth2-Proxy";
|
||||||
|
originUrl = "https://${oauth2ProxyDomain}/oauth2/callback";
|
||||||
|
originLanding = "https://${oauth2ProxyDomain}/";
|
||||||
|
basicSecretFile = config.sops.secrets.kanidm-oauth2-proxy.path;
|
||||||
|
scopeMaps = {
|
||||||
|
"freshrss.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
"navidrome.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
"firefly.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
"radicale.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
"slink.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
preferShortUsername = true;
|
||||||
|
claimMaps.groups = {
|
||||||
|
joinType = "array";
|
||||||
|
valuesByGroup = {
|
||||||
|
"freshrss.access" = [ "ttrss_access" ];
|
||||||
|
"navidrome.access" = [ "navidrome_access" ];
|
||||||
|
"firefly.access" = [ "firefly_access" ];
|
||||||
|
"radicale.access" = [ "radicale_access" ];
|
||||||
|
"slink.access" = [ "slink_access" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services = {
|
||||||
|
${serviceName}.serviceConfig.RestartSec = "30";
|
||||||
|
};
|
||||||
|
|
||||||
|
nodes.moonside.services.nginx = {
|
||||||
|
upstreams = {
|
||||||
|
${serviceName} = {
|
||||||
|
servers = {
|
||||||
|
"${serviceAddress}:${builtins.toString servicePort}" = { };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
virtualHosts = {
|
||||||
|
"${serviceDomain}" = {
|
||||||
|
enableACME = true;
|
||||||
|
forceSSL = true;
|
||||||
|
acmeRoot = null;
|
||||||
|
locations = {
|
||||||
|
"/" = {
|
||||||
|
proxyPass = "https://${serviceName}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_ssl_verify off;
|
||||||
|
'';
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
}
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
**** oauth2-proxy
|
**** oauth2-proxy
|
||||||
|
|
@ -9738,9 +9757,15 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.settings."10-radicale" = {
|
||||||
"d ${cfg.settings.storage.filesystem_folder} 0750 ${serviceUser} ${serviceGroup} - -"
|
"${cfg.settings.storage.filesystem_folder}" = {
|
||||||
];
|
d = {
|
||||||
|
group = serviceGroup;
|
||||||
|
user = serviceUser;
|
||||||
|
mode = "0750";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ servicePort ];
|
networking.firewall.allowedTCPPorts = [ servicePort ];
|
||||||
|
|
||||||
|
|
@ -10048,13 +10073,25 @@ in
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.settings."11-shlink" = builtins.listToAttrs (
|
||||||
"d ${serviceDir}/data 0750 1001 root - -"
|
map
|
||||||
"d ${serviceDir}/data/cache 0750 1001 root - -"
|
(path: {
|
||||||
"d ${serviceDir}/data/locks 0750 1001 root - -"
|
name = "${serviceDir}/${path}";
|
||||||
"d ${serviceDir}/data/log 0750 1001 root - -"
|
value = {
|
||||||
"d ${serviceDir}/data/proxies 0750 1001 root - -"
|
d = {
|
||||||
];
|
group = "root";
|
||||||
|
user = "1001";
|
||||||
|
mode = "0750";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) [
|
||||||
|
"${serviceDir}/data"
|
||||||
|
"${serviceDir}/data/cache"
|
||||||
|
"${serviceDir}/data/locks"
|
||||||
|
"${serviceDir}/data/log"
|
||||||
|
"${serviceDir}/data/proxies"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ servicePort ];
|
networking.firewall.allowedTCPPorts = [ servicePort ];
|
||||||
|
|
||||||
|
|
@ -10137,10 +10174,22 @@ Deployment notes:
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.settings."12-slink" = builtins.listToAttrs (
|
||||||
"d ${serviceDir}/var/data 0750 root root - -"
|
map
|
||||||
"d ${serviceDir}/images 0750 root root - -"
|
(path: {
|
||||||
];
|
name = "${serviceDir}/${path}";
|
||||||
|
value = {
|
||||||
|
d = {
|
||||||
|
group = "root";
|
||||||
|
user = "root";
|
||||||
|
mode = "0750";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) [
|
||||||
|
"${serviceDir}/var/data"
|
||||||
|
"${serviceDir}/images"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ servicePort ];
|
networking.firewall.allowedTCPPorts = [ servicePort ];
|
||||||
|
|
||||||
|
|
@ -10326,6 +10375,48 @@ Deployment notes:
|
||||||
|
|
||||||
}
|
}
|
||||||
#+end_src
|
#+end_src
|
||||||
|
**** OPKSSH
|
||||||
|
|
||||||
|
#+begin_src nix-ts :tangle modules/nixos/server/opkssh.nix
|
||||||
|
{ lib, config, globals, ... }:
|
||||||
|
let
|
||||||
|
serviceName = "opkssh";
|
||||||
|
serviceUser = "opksshuser";
|
||||||
|
serviceGroup = serviceUser;
|
||||||
|
|
||||||
|
kanidmDomain = globals.services.kanidm.domain;
|
||||||
|
|
||||||
|
inherit (config.swarselsystems) mainUser;
|
||||||
|
inherit (config.repo.secrets.local) persons;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
|
||||||
|
config = lib.mkIf config.swarselmodules.server.${serviceName} {
|
||||||
|
|
||||||
|
services.${serviceName} = {
|
||||||
|
enable = true;
|
||||||
|
user = serviceUser;
|
||||||
|
group = serviceGroup;
|
||||||
|
providers = {
|
||||||
|
kanidm = {
|
||||||
|
lifetime = "oidc";
|
||||||
|
issuer = "https://${kanidmDomain}/oauth2/openid/${serviceName}";
|
||||||
|
clientId = serviceName;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
authorizations = [
|
||||||
|
{
|
||||||
|
user = mainUser;
|
||||||
|
principal = builtins.head persons.${mainUser}.mailAddresses;
|
||||||
|
inherit (config.services.opkssh.providers.kanidm) issuer;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
*** Darwin
|
*** Darwin
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: h:ac0cd8b3-06cf-4dca-ba73-6100c8fedb47
|
:CUSTOM_ID: h:ac0cd8b3-06cf-4dca-ba73-6100c8fedb47
|
||||||
|
|
@ -11286,6 +11377,9 @@ This holds packages that I can use as provided, or with small modifications (as
|
||||||
simple-scan
|
simple-scan
|
||||||
cura-appimage
|
cura-appimage
|
||||||
|
|
||||||
|
# ssh login using idm
|
||||||
|
opkssh
|
||||||
|
|
||||||
# dict
|
# dict
|
||||||
(aspellWithDicts (dicts: with dicts; [ de en en-computers en-science ]))
|
(aspellWithDicts (dicts: with dicts; [ de en en-computers en-science ]))
|
||||||
|
|
||||||
|
|
@ -14651,9 +14745,15 @@ When setting up a new machine:
|
||||||
};
|
};
|
||||||
|
|
||||||
# assure correct permissions
|
# assure correct permissions
|
||||||
systemd.user.tmpfiles.rules = [
|
systemd.user.tmpfiles.settings."30-gpgagent".rules = {
|
||||||
"d ${homeDir}/.gnupg 700 ${mainUser} users"
|
"${homeDir}/.gnupg" = {
|
||||||
];
|
d = {
|
||||||
|
group = "users";
|
||||||
|
user = mainUser;
|
||||||
|
mode = "0700";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -15239,6 +15339,41 @@ This service changes the screen hue at night. I am not sure if that really does
|
||||||
}
|
}
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
**** opkssh
|
||||||
|
|
||||||
|
#+begin_src nix-ts :tangle modules/home/common/opkssh.nix
|
||||||
|
{ lib, config, ... }:
|
||||||
|
let
|
||||||
|
moduleName = "opkssh";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings";
|
||||||
|
config = lib.mkIf config.swarselmodules.${moduleName} {
|
||||||
|
programs.${moduleName} = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
default_provider = "kanidm";
|
||||||
|
|
||||||
|
providers = [
|
||||||
|
{
|
||||||
|
alias = "kanidm";
|
||||||
|
issuer = "https://sso.swarsel.win/oauth2/openid/opkssh";
|
||||||
|
client_id = "opkssh";
|
||||||
|
scopes = "openid email profile";
|
||||||
|
redirect_uris = [
|
||||||
|
"http://localhost:3000/login-callback"
|
||||||
|
"http://localhost:10001/login-callback"
|
||||||
|
"http://localhost:11110/login-callback"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
*** Server
|
*** Server
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
:CUSTOM_ID: h:b1a00339-6e9b-4ae4-b5dc-6fd5669a2ddb
|
:CUSTOM_ID: h:b1a00339-6e9b-4ae4-b5dc-6fd5669a2ddb
|
||||||
|
|
@ -18826,6 +18961,7 @@ This holds modules that are to be used on most hosts. These are also the most im
|
||||||
obs-studio = lib.mkDefault true;
|
obs-studio = lib.mkDefault true;
|
||||||
obsidian = lib.mkDefault true;
|
obsidian = lib.mkDefault true;
|
||||||
obsidian-tray = lib.mkDefault true;
|
obsidian-tray = lib.mkDefault true;
|
||||||
|
opkssh = lib.mkDefault true;
|
||||||
ownpackages = lib.mkDefault true;
|
ownpackages = lib.mkDefault true;
|
||||||
packages = lib.mkDefault true;
|
packages = lib.mkDefault true;
|
||||||
passwordstore = lib.mkDefault true;
|
passwordstore = lib.mkDefault true;
|
||||||
|
|
|
||||||
11
flake.lock
generated
11
flake.lock
generated
|
|
@ -4666,15 +4666,16 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1762025346,
|
"lastModified": 1762257324,
|
||||||
"narHash": "sha256-6KR4dsNfA3Pqm6uT8j7aKjWydP/KXFqZUhOfMlfP+1E=",
|
"narHash": "sha256-05SxDx82j23zd1/EMDFZTPYFgvzxviBiByUBVs+860w=",
|
||||||
"owner": "nix-community",
|
"owner": "Swarsel",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "87044c57222fb485974062e2dd557e7b8abd8fff",
|
"rev": "d27fabec395885790e7ab666c72522e18e534117",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "Swarsel",
|
||||||
|
"ref": "main",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@
|
||||||
swarsel-modules.url = "github:Swarsel/swarsel-modules/main";
|
swarsel-modules.url = "github:Swarsel/swarsel-modules/main";
|
||||||
swarsel-nix.url = "github:Swarsel/swarsel-nix/main";
|
swarsel-nix.url = "github:Swarsel/swarsel-nix/main";
|
||||||
home-manager = {
|
home-manager = {
|
||||||
url = "github:nix-community/home-manager";
|
# url = "github:nix-community/home-manager";
|
||||||
# url = "github:Swarsel/home-manager/main";
|
url = "github:Swarsel/home-manager/main";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
swarsel.url = "github:Swarsel/.dotfiles";
|
swarsel.url = "github:Swarsel/.dotfiles";
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@
|
||||||
ankisync = lib.mkDefault true;
|
ankisync = lib.mkDefault true;
|
||||||
# snipeit = lib.mkDefault false;
|
# snipeit = lib.mkDefault false;
|
||||||
homebox = lib.mkDefault true;
|
homebox = lib.mkDefault true;
|
||||||
|
opkssh = lib.mkDefault true;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"data": "ENC[AES256_GCM,data:lDbxvTQBbWAyHGx1a0TPXA6nIJ4crJICZaG/VYdeRl09NbJeF1dO2/UEquQxulE0IR+VkzIbfRiLPJ74kRcEsuFEBQ9LrF+gMEgwocQGCPGRTaWTfl84HfcX4qo+elOB5/W5lx1moOdYKFNFkxKbAj6wN0A8n0YBFqPDW/zeMO0DU6+MLW1XEb8zjG0hERocHb8svHVv2Xhu6sP2AX844vtN9u2xKil/kAR8XLPyuVCutsO+8GNfGkZh4hYdn5H+TYmWcWzzLujBt2H8+7UfdYsU4Q2PYcJ/Uokol8PAqMmPQDt9fF2S/IBbWZBmJY+ZmcxGHgYGY1+FeXZviIR37i8t9DS6isasDmGexDn4WyBq45XI/xo96qy0+GNHbeUoirAWWa+2YhLeqekG8q1luTbMh1uLw1n+ZmT3SexA20ens2sYmwjWdhyCR0cY3lcLhP/NVXgnbmOP61RUl7/RCPq0F3PCZ29LJG7oeDjD3JbJypRhTKnRMF+heEPrvmacWrkCMpEAkR8eB2WQmDxUTFyFTk/tv55GtHDuw5uA77pSmPIqVPppH2CupzDf+nBKyVIqON1jbpyxjlE8bBHtrEWEd0SioiTuC/CcoytzB8IiiEDgNjgoqNHfHYRyxGq0EKFtVcdqvkm3mbD0XyGG0UR3Arl8QSdHhIBSqedN7Y6rZJxef6VfLuxE13FWrZnSVGopAjMb/RTZbXLxjDNeHg6HwdBlrXMT7rps7jxbg39v5sOhGYhphF/L7KdCKVfmi8ubAfDVFZ3XRSuBzcHCW8FkxBWG+7Gnl3mMoNVw8loQwUjT+PbL1VHNQCr2fqS4wrv6ehQZIqOsqqlUF9JH9A3TgmHb4ioQ+jAEyOymTmrMzeaUBzcB9w54epkU+okDTO1LOvwC6gvEOQMoHv6fI2YCsQRCH3Mk3rhNBaotD3lQfuz1Pc3XL8t/9KGrCVwHLAoA+lt9g6o1KZoiBfcp3pFCWsPX3lrmUsJnKZHIVO+S9jOz+aJdOgaX/h5+cHp607bL8Zb296N4yK9yt5U+3mYONKn/hzGAmSghjfb/GTlMRJa5f6J9SerUvKqrjUVXJ2CmMAYojBt30Z1QRXIADRLLeyJglMZy9TwtoNsVr7iD2+rylU5TLJmPpxDbnQFriN0X4yhp1wYYBgjVkXV4SNGElDxjm0HFsBJkBaOpXeijCrcOJ5vmnuGLIhBTw+3qG4dEx/foUYRV1oJFrwH1U/f4oL9cOfdC0B9fv9yXJ/GORywOIlVb4FNLewSbu+PIAiZJLVQcBeBWNKQfoIb892ao2RXXJN6XZxp7IfEIBRBM/sfcfgtDk5ud+nuYPWYf09533t/ZjgbZ1en24MAwsit060IPROVwW3pIh2TSx/j1iMWbJ9ljaabBhivmGVo8CLVErGeSLwLL8eXLQ02D9i+LgY1oQavx3675Z7RDwQbdQxjLCKB5Fq77nPGuf2mzTLE/6NL7l6INCcuyg+Vp2zaxX87NMgh+0q9ZFW/ECL/+QzNeBaUmFJ2tXwMiVJAcm2vGiUvI,iv:emlV4hFKBALvzUiaDtu3CDX0Y8fd8TTQmPaR9WyqN4I=,tag:aFPEYachc1H0F+/q3FbuGA==,type:str]",
|
"data": "ENC[AES256_GCM,data:i8kqmycc80NLcOirK7D20hxsWWFGNMx5d1SDueaSTmymvTb0rNMFiRoLf44c9Bc5yBySg9zRNCJ8lyc1SZH5YAqIYGN8y4nzOTxyPxT1R+Igtzm49sBdp1dK6MVCW1/xIsjDE/niV19l9LTptN7neCIEuDjB22bSMRhfVOxOiSwd2FKBeH61XACFLAz3AuVC4a+FhqsBkmLOAg7SIG0xdsyi2tjuTOCiMci9eQk8q9XkmLQC3z6vBaIBxPErkIG/fyhNBYt0Hv+37b/TFVbBL9qnGK369Ln9EUm0IarInaq9haxE18DkI5bzlJH5hw4JNjMGFz8av6rOJT5oW52yPor1RBodwUtP6YDQCQsdINIbjmAM9C0HGBY31nyy07fVT+QDcNydjT1fEXLSJTseO5E/MrRCVBioorBpG+5kBBQhRMihGeT8htVGVQpiJC7peARRfSQTUqjNH/esWTPCk0xPOXgApgPIbXBIJFj4RiH2erzN1PKPpuGZfuqbEr63VXCp6t0jttZKDEEjob1ZJMKfiqRubaz+ycg/sxFb1p+l9O21ihW8jM9huiBpVTc+mHU0ENTSstC4uB5LG6HMqV9vmqrKP4OM13vifggpQ6K9VRXebpI/t4tdRETcwWIMo/LRCmhGO4o0+1tNG+ayVDVmY/ORJu/Nrl61TtmUXxGc74Vd1sea+60LuqDHdIEs06thxFLSCVXaxa70gTlQIlVSEJBz9yaAMm7Iw4CSvLbYTXrRg6P/jIZx7rGSyC7I/kFMAPsa2KYxUUkBNd8zSoHyf8paxbgocb3yNcMtHIyNYiOXaLgr56DasJKsXTdjnuic6PLBCd9+U9o9R4wdBw4CGHZ3+3P+LexImkK9InVTm3QD9gyWtgDe66jrQMJxicixtx6hKvP0P0nmjhE6UjhfMMYV2Qu7vx1APhE62KF9y+axIlKju4kYkRhC9BHi2FuZUCFkPiPd/RRWzBTuChnKud9TWTixBtzpBI39/5e3i8f55hcG0XkUT+rMolq/hCObIczq7M2TVrZK4vUGByHXi1Vljk+K2tUZLVGq+Vpa7JUfmyp/qdUBG5FFXBBLUmAA0yjR+XxTtuZ4+M7JdgoYlzXEN8AbyBTEfVps4HJVPfwWMZaXEWqc7fwSVNlkRpIGSkbF8+tzBd0M66FtjbC9hs1P/SwwUr/ZTwJW0D8EXDUOJo2VCGpGtzHZpg5wd7qPTKL20fLVrpdfKIMeBrPtpCkv2YAzSXClAMQqMJ1DtrFr9WNeTAv0ROwkfnGIYwFpDnK3Xy3Z9V1HlZY3K/UYybzb43Dvtl0qWcSmXxKWLK0rqe3r4sWKA/gpOi8UIyCssAv5At0JO2e0yBJv7tXi+WGNZIBEy559EYdnfHty2KZTR5M/PiP5t1PMbuzUkee3voybnAioCZfGsh5Ln04ZihUHbtbxocM4yieaqBd7nryO81b1ZARoZKbASaGMc7y65pgsA1MiNnbtGIZUwlNyg1q3iZxdtkG6qgG2vCY9Z6JNXXl6RoBmbDbCaIzvid8OXvK8z0z4t0BpYQCFVb3/sEAqweUnQffstEFB,iv:+cS1MmSlZWLdRt5Ey31y6WrDAudgjHxsUbfCBUK0/Sg=,tag:byOqNWWPQmlrDWQO1tRRJQ==,type:str]",
|
||||||
"sops": {
|
"sops": {
|
||||||
"age": [
|
"age": [
|
||||||
{
|
{
|
||||||
|
|
@ -11,8 +11,8 @@
|
||||||
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGtTZ0ZSV0trWlQrS2dV\nSFo0dytGYXhRTjl6cDZrUU0wZ1IybDVRaFZrCmZmRmxJNmdwS0xodHdEOGU4bldU\nR1JScHAvZHhlVTBJbWExb0VpR0h2MXMKLS0tIDYwQmZpMjdYRmpBeXFNOXArN0h5\nVGN1THljeCtVV0hXenMyRVJkMjlHNEEKm+yZTT48nYr3H0Bd1OKw/CYk1kwnrBzk\nTgSQHsGXhmOyDag9cSZ4wAOmqtqSjA9bouFBuhl2lSbgpjnarvFaXQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNeGtTZ0ZSV0trWlQrS2dV\nSFo0dytGYXhRTjl6cDZrUU0wZ1IybDVRaFZrCmZmRmxJNmdwS0xodHdEOGU4bldU\nR1JScHAvZHhlVTBJbWExb0VpR0h2MXMKLS0tIDYwQmZpMjdYRmpBeXFNOXArN0h5\nVGN1THljeCtVV0hXenMyRVJkMjlHNEEKm+yZTT48nYr3H0Bd1OKw/CYk1kwnrBzk\nTgSQHsGXhmOyDag9cSZ4wAOmqtqSjA9bouFBuhl2lSbgpjnarvFaXQ==\n-----END AGE ENCRYPTED FILE-----\n"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"lastmodified": "2025-09-16T11:26:37Z",
|
"lastmodified": "2025-11-04T09:26:35Z",
|
||||||
"mac": "ENC[AES256_GCM,data:T87Y33N0Tu8IySeUgrV7lgMzG+8Cl0ezJkjZFHzmeXy7+TJ2JKrnTfy0nY2oXjVCRLC2CBRh6e9n6ITnAnQJxyS3ZDF/FaY1h5LSm4e6bklFxBZRTQhssVJHbRE4dm8VZL+NLli32VM5YG+E8Kn640YE0oUgBlxqS4qmH4/fLl4=,iv:37xHtgBX6nmgGUGhwSpLIItN8OMto5yLL+Xr+KA4h9E=,tag:Y4FU6/HYmu1IgLG4ChutZw==,type:str]",
|
"mac": "ENC[AES256_GCM,data:T8GqsMxfFB9s1EOeLHNzxoz23FCOnlNsBsbvMxiLq7a78xt5Xw3dVN/IWfkyiCDwfSjo+fVx2yEd5tP/B3fSN7S8WJNSe5ZywLpal/RlsCzv7ARvbVCaBx22S4az97JsR1qQUcGSvoiTH5e/0t2tBtimGJ1witbvbiGkTBp8taw=,iv:Qs26cjeMLtRhTDO91yfBo93wUKJ9zVfUbJ8o6myHGUo=,tag:FbT8emz6q1QnXdxoX6hsYQ==,type:str]",
|
||||||
"pgp": [
|
"pgp": [
|
||||||
{
|
{
|
||||||
"created_at": "2025-08-24T23:36:17Z",
|
"created_at": "2025-08-24T23:36:17Z",
|
||||||
|
|
@ -21,6 +21,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"unencrypted_suffix": "_unencrypted",
|
"unencrypted_suffix": "_unencrypted",
|
||||||
"version": "3.10.2"
|
"version": "3.11.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,9 +37,15 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
# assure correct permissions
|
# assure correct permissions
|
||||||
systemd.user.tmpfiles.rules = [
|
systemd.user.tmpfiles.settings."30-gpgagent".rules = {
|
||||||
"d ${homeDir}/.gnupg 700 ${mainUser} users"
|
"${homeDir}/.gnupg" = {
|
||||||
];
|
d = {
|
||||||
|
group = "users";
|
||||||
|
user = mainUser;
|
||||||
|
mode = "0700";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
30
modules/home/common/opkssh.nix
Normal file
30
modules/home/common/opkssh.nix
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{ lib, config, ... }:
|
||||||
|
let
|
||||||
|
moduleName = "opkssh";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.swarselmodules.${moduleName} = lib.mkEnableOption "enable ${moduleName} and settings";
|
||||||
|
config = lib.mkIf config.swarselmodules.${moduleName} {
|
||||||
|
programs.${moduleName} = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
default_provider = "kanidm";
|
||||||
|
|
||||||
|
providers = [
|
||||||
|
{
|
||||||
|
alias = "kanidm";
|
||||||
|
issuer = "https://sso.swarsel.win/oauth2/openid/opkssh";
|
||||||
|
client_id = "opkssh";
|
||||||
|
scopes = "openid email profile";
|
||||||
|
redirect_uris = [
|
||||||
|
"http://localhost:3000/login-callback"
|
||||||
|
"http://localhost:10001/login-callback"
|
||||||
|
"http://localhost:11110/login-callback"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -22,6 +22,9 @@
|
||||||
simple-scan
|
simple-scan
|
||||||
cura-appimage
|
cura-appimage
|
||||||
|
|
||||||
|
# ssh login using idm
|
||||||
|
opkssh
|
||||||
|
|
||||||
# dict
|
# dict
|
||||||
(aspellWithDicts (dicts: with dicts; [ de en en-computers en-science ]))
|
(aspellWithDicts (dicts: with dicts; [ de en en-computers en-science ]))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,7 @@ in
|
||||||
"firefly.access" = { };
|
"firefly.access" = { };
|
||||||
"radicale.access" = { };
|
"radicale.access" = { };
|
||||||
"slink.access" = { };
|
"slink.access" = { };
|
||||||
|
"opkssh.access" = { };
|
||||||
};
|
};
|
||||||
|
|
||||||
inherit (config.repo.secrets.local) persons;
|
inherit (config.repo.secrets.local) persons;
|
||||||
|
|
@ -229,6 +230,23 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
opkssh = {
|
||||||
|
displayName = "OPKSSH";
|
||||||
|
originUrl = [
|
||||||
|
"http://localhost:3000"
|
||||||
|
"http://localhost:3000/login-callback"
|
||||||
|
"http://localhost:10001/login-callback"
|
||||||
|
"http://localhost:11110/login-callback"
|
||||||
|
];
|
||||||
|
originLanding = "http://localhost:3000";
|
||||||
|
public = true;
|
||||||
|
enableLocalhostRedirects = true;
|
||||||
|
scopeMaps."opkssh.access" = [
|
||||||
|
"openid"
|
||||||
|
"email"
|
||||||
|
"profile"
|
||||||
|
];
|
||||||
|
};
|
||||||
oauth2-proxy = {
|
oauth2-proxy = {
|
||||||
displayName = "Oauth2-Proxy";
|
displayName = "Oauth2-Proxy";
|
||||||
originUrl = "https://${oauth2ProxyDomain}/oauth2/callback";
|
originUrl = "https://${oauth2ProxyDomain}/oauth2/callback";
|
||||||
|
|
|
||||||
38
modules/nixos/server/opkssh.nix
Normal file
38
modules/nixos/server/opkssh.nix
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
{ lib, config, globals, ... }:
|
||||||
|
let
|
||||||
|
serviceName = "opkssh";
|
||||||
|
serviceUser = "opksshuser";
|
||||||
|
serviceGroup = serviceUser;
|
||||||
|
|
||||||
|
kanidmDomain = globals.services.kanidm.domain;
|
||||||
|
|
||||||
|
inherit (config.swarselsystems) mainUser;
|
||||||
|
inherit (config.repo.secrets.local) persons;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
|
||||||
|
config = lib.mkIf config.swarselmodules.server.${serviceName} {
|
||||||
|
|
||||||
|
services.${serviceName} = {
|
||||||
|
enable = true;
|
||||||
|
user = serviceUser;
|
||||||
|
group = serviceGroup;
|
||||||
|
providers = {
|
||||||
|
kanidm = {
|
||||||
|
lifetime = "oidc";
|
||||||
|
issuer = "https://${kanidmDomain}/oauth2/openid/${serviceName}";
|
||||||
|
clientId = serviceName;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
authorizations = [
|
||||||
|
{
|
||||||
|
user = mainUser;
|
||||||
|
principal = builtins.head persons.${mainUser}.mailAddresses;
|
||||||
|
inherit (config.services.opkssh.providers.kanidm) issuer;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -76,9 +76,15 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.settings."10-radicale" = {
|
||||||
"d ${cfg.settings.storage.filesystem_folder} 0750 ${serviceUser} ${serviceGroup} - -"
|
"${cfg.settings.storage.filesystem_folder}" = {
|
||||||
];
|
d = {
|
||||||
|
group = serviceGroup;
|
||||||
|
user = serviceUser;
|
||||||
|
mode = "0750";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ servicePort ];
|
networking.firewall.allowedTCPPorts = [ servicePort ];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,13 +48,25 @@ in
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.settings."11-shlink" = builtins.listToAttrs (
|
||||||
"d ${serviceDir}/data 0750 1001 root - -"
|
map
|
||||||
"d ${serviceDir}/data/cache 0750 1001 root - -"
|
(path: {
|
||||||
"d ${serviceDir}/data/locks 0750 1001 root - -"
|
name = "${serviceDir}/${path}";
|
||||||
"d ${serviceDir}/data/log 0750 1001 root - -"
|
value = {
|
||||||
"d ${serviceDir}/data/proxies 0750 1001 root - -"
|
d = {
|
||||||
];
|
group = "root";
|
||||||
|
user = "1001";
|
||||||
|
mode = "0750";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) [
|
||||||
|
"${serviceDir}/data"
|
||||||
|
"${serviceDir}/data/cache"
|
||||||
|
"${serviceDir}/data/locks"
|
||||||
|
"${serviceDir}/data/log"
|
||||||
|
"${serviceDir}/data/proxies"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ servicePort ];
|
networking.firewall.allowedTCPPorts = [ servicePort ];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,22 @@ in
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.settings."12-slink" = builtins.listToAttrs (
|
||||||
"d ${serviceDir}/var/data 0750 root root - -"
|
map
|
||||||
"d ${serviceDir}/images 0750 root root - -"
|
(path: {
|
||||||
];
|
name = "${serviceDir}/${path}";
|
||||||
|
value = {
|
||||||
|
d = {
|
||||||
|
group = "root";
|
||||||
|
user = "root";
|
||||||
|
mode = "0750";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}) [
|
||||||
|
"${serviceDir}/var/data"
|
||||||
|
"${serviceDir}/images"
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
networking.firewall.allowedTCPPorts = [ servicePort ];
|
networking.firewall.allowedTCPPorts = [ servicePort ];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
obs-studio = lib.mkDefault true;
|
obs-studio = lib.mkDefault true;
|
||||||
obsidian = lib.mkDefault true;
|
obsidian = lib.mkDefault true;
|
||||||
obsidian-tray = lib.mkDefault true;
|
obsidian-tray = lib.mkDefault true;
|
||||||
|
opkssh = lib.mkDefault true;
|
||||||
ownpackages = lib.mkDefault true;
|
ownpackages = lib.mkDefault true;
|
||||||
packages = lib.mkDefault true;
|
packages = lib.mkDefault true;
|
||||||
passwordstore = lib.mkDefault true;
|
passwordstore = lib.mkDefault true;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue