#100 Immich service
- Declarative SSO setup via json config file - roleClaim via LDAP groups to automatically set admin privileges - SSO tested manually, but not yet in playwright test - Storage quota claim not yet implemented - Authelia rule prevents access by non-members of userGroup/adminUserGroup
This commit is contained in:
parent
4621a02dff
commit
2f785919d9
3 changed files with 710 additions and 0 deletions
|
|
@ -78,6 +78,7 @@
|
|||
self.nixosModules.${system}.forgejo
|
||||
self.nixosModules.${system}.grocy
|
||||
self.nixosModules.${system}.hledger
|
||||
self.nixosModules.${system}.immich
|
||||
self.nixosModules.${system}.assistant
|
||||
self.nixosModules.${system}.jellyfin
|
||||
self.nixosModules.${system}.nextcloud-server
|
||||
|
|
@ -112,6 +113,7 @@
|
|||
nixosModules.forgejo = modules/services/forgejo.nix;
|
||||
nixosModules.grocy = modules/services/grocy.nix;
|
||||
nixosModules.hledger = modules/services/hledger.nix;
|
||||
nixosModules.immich = modules/services/immich.nix;
|
||||
nixosModules.assistant = modules/services/home-assistant.nix;
|
||||
nixosModules.jellyfin = modules/services/jellyfin.nix;
|
||||
nixosModules.nextcloud-server = modules/services/nextcloud-server.nix;
|
||||
|
|
@ -256,6 +258,7 @@
|
|||
// (vm_test "forgejo" ./test/services/forgejo.nix)
|
||||
// (vm_test "grocy" ./test/services/grocy.nix)
|
||||
// (vm_test "hledger" ./test/services/hledger.nix)
|
||||
// (vm_test "immich" ./test/services/immich.nix)
|
||||
// (vm_test "homeassistant" ./test/services/home-assistant.nix)
|
||||
// (vm_test "jellyfin" ./test/services/jellyfin.nix)
|
||||
// (vm_test "monitoring" ./test/services/monitoring.nix)
|
||||
|
|
|
|||
560
modules/services/immich.nix
Normal file
560
modules/services/immich.nix
Normal file
|
|
@ -0,0 +1,560 @@
|
|||
{ config, pkgs, lib, ... }:
|
||||
|
||||
let
|
||||
cfg = config.shb.immich;
|
||||
|
||||
contracts = pkgs.callPackage ../contracts {};
|
||||
shblib = pkgs.callPackage ../../lib {};
|
||||
|
||||
fqdn = "${cfg.subdomain}.${cfg.domain}";
|
||||
protocol = if !(isNull cfg.ssl) then "https" else "http";
|
||||
|
||||
roleClaim = "immich_user";
|
||||
|
||||
# TODO: Quota management, see https://github.com/ibizaman/selfhostblocks/pull/523#discussion_r2309421694
|
||||
#quotaClaim = "immich_quota";
|
||||
scopes = [ "openid" "email" "profile" "groups" "immich_scope"];
|
||||
|
||||
dataFolder = cfg.mediaLocation;
|
||||
ssoFqdnWithPort = if isNull cfg.sso.port
|
||||
then cfg.sso.endpoint
|
||||
else "${cfg.sso.endpoint}:${toString cfg.sso.port}";
|
||||
# Generate Immich configuration file only for SHB-managed settings
|
||||
shbManagedSettings = lib.optionalAttrs (cfg.settings != {}) cfg.settings
|
||||
// lib.optionalAttrs (cfg.sso.enable) {
|
||||
oauth = {
|
||||
enabled = true;
|
||||
issuerUrl = "${ssoFqdnWithPort}";
|
||||
clientId = cfg.sso.clientID;
|
||||
roleClaim = roleClaim;
|
||||
clientSecret = { source = cfg.sso.sharedSecret.result.path; };
|
||||
scope = builtins.concatStringsSep " " scopes;
|
||||
storageLabelClaim = cfg.sso.storageLabelClaim;
|
||||
#storageQuotaClaim = quotaClaim; # TODO (commented out, otherwise defaults to 0 bytes!)
|
||||
defaultStorageQuota = 0;
|
||||
buttonText = cfg.sso.buttonText;
|
||||
autoRegister = cfg.sso.autoRegister;
|
||||
autoLaunch = cfg.sso.autoLaunch;
|
||||
passwordLogin = cfg.sso.passwordLogin;
|
||||
mobileOverrideEnabled = false;
|
||||
mobileRedirectUri = "";
|
||||
};
|
||||
}
|
||||
// lib.optionalAttrs (cfg.smtp != null) {
|
||||
notifications = {
|
||||
smtp = {
|
||||
enabled = true;
|
||||
from = cfg.smtp.from;
|
||||
replyTo = cfg.smtp.replyTo;
|
||||
transport = {
|
||||
host = cfg.smtp.host;
|
||||
port = cfg.smtp.port;
|
||||
username = cfg.smtp.username;
|
||||
password = { source = cfg.smtp.password.result.path; };
|
||||
ignoreTLS = cfg.smtp.ignoreTLS;
|
||||
secure = cfg.smtp.secure;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
configFile = "/var/lib/immich/config.json";
|
||||
|
||||
# Use SHB's replaceSecrets function for loading secrets at runtime
|
||||
configSetupScript = lib.optionalString (cfg.sso.enable || cfg.smtp != null) (
|
||||
shblib.replaceSecrets {
|
||||
userConfig = shbManagedSettings;
|
||||
resultPath = configFile;
|
||||
generator = shblib.replaceSecretsFormatAdapter (pkgs.formats.json {});
|
||||
user = "immich";
|
||||
permissions = "u=r,g=,o=";
|
||||
}
|
||||
);
|
||||
inherit (lib) mkEnableOption mkIf lists mkOption optionals;
|
||||
inherit (lib.types) attrs attrsOf bool enum listOf nullOr port submodule str path;
|
||||
in
|
||||
{
|
||||
options.shb.immich = {
|
||||
enable = mkEnableOption "selfhostblocks.immich";
|
||||
|
||||
subdomain = mkOption {
|
||||
type = str;
|
||||
description = ''
|
||||
Subdomain under which Immich will be served.
|
||||
|
||||
```
|
||||
<subdomain>.<domain>
|
||||
```
|
||||
'';
|
||||
example = "photos";
|
||||
};
|
||||
|
||||
domain = mkOption {
|
||||
description = ''
|
||||
Domain under which Immich is served.
|
||||
|
||||
```
|
||||
<subdomain>.<domain>
|
||||
```
|
||||
'';
|
||||
type = str;
|
||||
example = "example.com";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
description = ''
|
||||
Port under which Immich will listen.
|
||||
'';
|
||||
type = port;
|
||||
default = 2283;
|
||||
};
|
||||
|
||||
ssl = mkOption {
|
||||
description = "Path to SSL files";
|
||||
type = nullOr contracts.ssl.certs;
|
||||
default = null;
|
||||
};
|
||||
|
||||
mediaLocation = mkOption {
|
||||
description = "Directory where Immich will store media files.";
|
||||
type = str;
|
||||
default = "/var/lib/immich";
|
||||
};
|
||||
|
||||
jwtSecretFile = mkOption {
|
||||
description = ''
|
||||
File containing Immich's JWT secret key for sessions.
|
||||
This is required for secure session management.
|
||||
'';
|
||||
type = nullOr (submodule {
|
||||
options = contracts.secret.mkRequester {
|
||||
mode = "0400";
|
||||
owner = "immich";
|
||||
restartUnits = [ "immich-server.service" ];
|
||||
};
|
||||
});
|
||||
default = null;
|
||||
};
|
||||
|
||||
mount = mkOption {
|
||||
type = contracts.mount;
|
||||
description = ''
|
||||
Mount configuration. This is an output option.
|
||||
|
||||
Use it to initialize a block implementing the "mount" contract.
|
||||
For example, with a zfs dataset:
|
||||
|
||||
```
|
||||
shb.zfs.datasets."immich" = {
|
||||
poolName = "root";
|
||||
} // config.shb.immich.mount;
|
||||
```
|
||||
'';
|
||||
readOnly = true;
|
||||
default = { path = dataFolder; };
|
||||
};
|
||||
|
||||
backup = mkOption {
|
||||
description = ''
|
||||
Backup configuration for Immich media files and database.
|
||||
'';
|
||||
default = {};
|
||||
type = submodule {
|
||||
options = contracts.backup.mkRequester {
|
||||
user = "immich";
|
||||
sourceDirectories = [
|
||||
dataFolder
|
||||
];
|
||||
excludePatterns = [
|
||||
"*.tmp"
|
||||
"cache/*"
|
||||
"encoded-video/*"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
accelerationDevices = mkOption {
|
||||
description = ''
|
||||
Hardware acceleration devices for Immich.
|
||||
Set to null to allow access to all devices.
|
||||
Set to empty list to disable hardware acceleration.
|
||||
'';
|
||||
type = nullOr (listOf path);
|
||||
default = null;
|
||||
example = [ "/dev/dri" ];
|
||||
};
|
||||
|
||||
machineLearning = mkOption {
|
||||
description = "Machine learning configuration.";
|
||||
default = {};
|
||||
type = submodule {
|
||||
options = {
|
||||
enable = mkOption {
|
||||
description = "Enable machine learning features.";
|
||||
type = bool;
|
||||
default = true;
|
||||
};
|
||||
|
||||
environment = mkOption {
|
||||
description = "Extra environment variables for machine learning service.";
|
||||
type = attrsOf str;
|
||||
default = {};
|
||||
example = {
|
||||
MACHINE_LEARNING_WORKERS = "2";
|
||||
MACHINE_LEARNING_WORKER_TIMEOUT = "180";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sso = mkOption {
|
||||
description = ''
|
||||
Setup SSO integration.
|
||||
'';
|
||||
default = {};
|
||||
type = submodule {
|
||||
options = {
|
||||
enable = mkEnableOption "SSO integration.";
|
||||
|
||||
provider = mkOption {
|
||||
type = enum [ "Authelia" "Keycloak" "Generic" ];
|
||||
description = "OIDC provider name, used for display.";
|
||||
default = "Authelia";
|
||||
};
|
||||
|
||||
endpoint = mkOption {
|
||||
type = str;
|
||||
description = "OIDC endpoint for SSO.";
|
||||
example = "https://authelia.example.com";
|
||||
};
|
||||
|
||||
clientID = mkOption {
|
||||
type = str;
|
||||
description = "Client ID for the OIDC endpoint.";
|
||||
default = "immich";
|
||||
};
|
||||
|
||||
adminUserGroup = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "OIDC admin group";
|
||||
default = "immich_admin";
|
||||
};
|
||||
|
||||
userGroup = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
description = "OIDC user group";
|
||||
default = "immich_user";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
description = "If given, adds a port to the endpoint.";
|
||||
type = nullOr port;
|
||||
default = null;
|
||||
};
|
||||
|
||||
storageLabelClaim = mkOption {
|
||||
type = str;
|
||||
description = "Claim to use for user storage label.";
|
||||
default = "preferred_username";
|
||||
};
|
||||
|
||||
buttonText = mkOption {
|
||||
type = str;
|
||||
description = "Text to display on the SSO login button.";
|
||||
default = "Login with SSO";
|
||||
};
|
||||
|
||||
autoRegister = mkOption {
|
||||
type = bool;
|
||||
description = "Automatically register new users from SSO provider.";
|
||||
default = true;
|
||||
};
|
||||
|
||||
autoLaunch = mkOption {
|
||||
type = bool;
|
||||
description = "Automatically redirect to SSO provider.";
|
||||
default = true;
|
||||
};
|
||||
|
||||
passwordLogin = mkOption {
|
||||
type = bool;
|
||||
description = "Enable password login.";
|
||||
default = true;
|
||||
};
|
||||
|
||||
sharedSecret = mkOption {
|
||||
description = "OIDC shared secret for Immich.";
|
||||
type = submodule {
|
||||
options = contracts.secret.mkRequester {
|
||||
mode = "0400";
|
||||
owner = "immich";
|
||||
group = "immich";
|
||||
restartUnits = [ "immich-server.service" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
sharedSecretForAuthelia = mkOption {
|
||||
description = "OIDC shared secret for Authelia. Content must be the same as `sharedSecret` option.";
|
||||
type = submodule {
|
||||
options = contracts.secret.mkRequester {
|
||||
mode = "0400";
|
||||
owner = "authelia";
|
||||
};
|
||||
};
|
||||
default = null;
|
||||
};
|
||||
|
||||
authorization_policy = mkOption {
|
||||
type = enum [ "one_factor" "two_factor" ];
|
||||
description = "Require one factor (password) or two factor (device) authentication.";
|
||||
default = "one_factor";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
type = attrs;
|
||||
description = ''
|
||||
Immich configuration settings.
|
||||
Only specify settings that you want SHB to manage declaratively.
|
||||
Other settings can be configured through Immich's admin UI.
|
||||
|
||||
See https://immich.app/docs/install/config-file/ for available options.
|
||||
'';
|
||||
default = {};
|
||||
example = {
|
||||
ffmpeg.crf = 23;
|
||||
job.backgroundTask.concurrency = 5;
|
||||
storageTemplate = {
|
||||
enabled = true;
|
||||
template = "{{y}}/{{y}}-{{MM}}-{{dd}}/{{filename}}";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
smtp = mkOption {
|
||||
description = ''
|
||||
SMTP configuration for sending notifications.
|
||||
'';
|
||||
default = null;
|
||||
type = nullOr (submodule {
|
||||
options = {
|
||||
from = mkOption {
|
||||
type = str;
|
||||
description = "SMTP address from which the emails originate.";
|
||||
example = "noreply@example.com";
|
||||
};
|
||||
|
||||
replyTo = mkOption {
|
||||
type = str;
|
||||
description = "Reply-to address for emails.";
|
||||
example = "support@example.com";
|
||||
};
|
||||
|
||||
host = mkOption {
|
||||
type = str;
|
||||
description = "SMTP host to send the emails to.";
|
||||
example = "smtp.example.com";
|
||||
};
|
||||
|
||||
port = mkOption {
|
||||
type = port;
|
||||
description = "SMTP port to send the emails to.";
|
||||
default = 587;
|
||||
};
|
||||
|
||||
username = mkOption {
|
||||
type = str;
|
||||
description = "Username to connect to the SMTP host.";
|
||||
example = "smtp-user";
|
||||
};
|
||||
|
||||
password = mkOption {
|
||||
description = "File containing the password to connect to the SMTP host.";
|
||||
type = submodule {
|
||||
options = contracts.secret.mkRequester {
|
||||
mode = "0400";
|
||||
owner = "immich";
|
||||
restartUnits = [ "immich-server.service" ];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
ignoreTLS = mkOption {
|
||||
type = bool;
|
||||
description = "Ignore TLS certificate errors.";
|
||||
default = false;
|
||||
};
|
||||
|
||||
secure = mkOption {
|
||||
type = bool;
|
||||
description = "Use secure connection (SSL/TLS).";
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
debug = mkOption {
|
||||
type = bool;
|
||||
description = "Set to true to enable debug logging.";
|
||||
default = false;
|
||||
example = true;
|
||||
};
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion = !(isNull cfg.ssl) -> !(isNull cfg.ssl.paths.cert) && !(isNull cfg.ssl.paths.key);
|
||||
message = "SSL is enabled for Immich but no cert or key is provided.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.sso.enable -> cfg.ssl != null;
|
||||
message = "To integrate SSO, SSL must be enabled, set the shb.immich.ssl option.";
|
||||
}
|
||||
];
|
||||
|
||||
# Configure Immich service
|
||||
services.immich = {
|
||||
enable = true;
|
||||
host = "127.0.0.1";
|
||||
port = cfg.port;
|
||||
mediaLocation = cfg.mediaLocation;
|
||||
|
||||
# Hardware acceleration configuration
|
||||
accelerationDevices = cfg.accelerationDevices;
|
||||
|
||||
# Database configuration defaults to Unix socket /run/postgresql
|
||||
|
||||
# Database configuration
|
||||
database = {
|
||||
# Disable pgvecto.rs, as it was deprecated before SHB integration
|
||||
enableVectors = false;
|
||||
};
|
||||
|
||||
# Machine learning configuration
|
||||
machine-learning = mkIf cfg.machineLearning.enable {
|
||||
enable = true;
|
||||
environment = cfg.machineLearning.environment;
|
||||
};
|
||||
|
||||
# Environment configuration
|
||||
environment = {
|
||||
IMMICH_LOG_LEVEL = if cfg.debug then "debug" else "log";
|
||||
REDIS_HOSTNAME = "127.0.0.1";
|
||||
REDIS_PORT = "6379";
|
||||
REDIS_DBINDEX = "0";
|
||||
} // lib.optionalAttrs (cfg.jwtSecretFile != null) {
|
||||
JWT_SECRET_FILE = cfg.jwtSecretFile.result.path;
|
||||
} // lib.optionalAttrs (cfg.settings != {} || cfg.sso.enable || cfg.smtp != null) {
|
||||
IMMICH_CONFIG_FILE = configFile;
|
||||
};
|
||||
};
|
||||
|
||||
# Create basic directories for Immich
|
||||
systemd.tmpfiles.rules = [
|
||||
"d /var/lib/immich 0700 immich immich"
|
||||
];
|
||||
|
||||
# Configuration setup service - generates config only for SHB-managed settings
|
||||
systemd.services.immich-setup-config = mkIf (cfg.enable && (cfg.settings != {} || cfg.sso.enable || cfg.smtp != null)) {
|
||||
description = "Setup Immich configuration for SHB-managed settings";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
before = [ "immich-server.service" ];
|
||||
after = [ "network.target" ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
User = "immich";
|
||||
Group = "immich";
|
||||
};
|
||||
script = ''
|
||||
mkdir -p ${dataFolder}
|
||||
|
||||
# Generate config file with only SHB-managed settings
|
||||
${configSetupScript}
|
||||
'';
|
||||
};
|
||||
|
||||
# Add immich user to video and render groups for hardware acceleration
|
||||
users.users.immich.extraGroups = optionals (cfg.accelerationDevices != []) [ "video" "render" ];
|
||||
|
||||
# PostgreSQL extensions are automatically handled by the Immich service
|
||||
|
||||
# Redis is automatically configured by the Immich service
|
||||
|
||||
# Configure Nginx reverse proxy
|
||||
shb.nginx.vhosts = [
|
||||
{
|
||||
inherit (cfg) subdomain domain ssl;
|
||||
upstream = "http://127.0.0.1:${toString cfg.port}";
|
||||
autheliaRules = lib.mkIf (cfg.sso.enable) [
|
||||
{
|
||||
domain = fqdn;
|
||||
policy = cfg.sso.authorization_policy;
|
||||
subject = ["group:immich_user" "group:immich_admin"];
|
||||
}
|
||||
];
|
||||
authEndpoint = lib.mkIf (cfg.sso.enable) cfg.sso.endpoint;
|
||||
extraConfig = ''
|
||||
client_max_body_size 50000M;
|
||||
proxy_read_timeout 600s;
|
||||
proxy_send_timeout 600s;
|
||||
send_timeout 600s;
|
||||
proxy_buffering off;
|
||||
'';
|
||||
}
|
||||
];
|
||||
|
||||
# Ensure services start in correct order
|
||||
systemd.services.immich-server = {
|
||||
after = [ "postgresql.service" "redis-immich.service" ]
|
||||
++ optionals (cfg.settings != {} || cfg.sso.enable || cfg.smtp != null) [ "immich-setup-config.service" ];
|
||||
requires = [ "postgresql.service" "redis-immich.service" ]
|
||||
++ optionals (cfg.settings != {} || cfg.sso.enable || cfg.smtp != null) [ "immich-setup-config.service" ];
|
||||
};
|
||||
|
||||
systemd.services.immich-machine-learning = mkIf cfg.machineLearning.enable {
|
||||
after = [ "immich-server.service" ];
|
||||
};
|
||||
|
||||
# Authelia integration for SSO
|
||||
shb.authelia.extraDefinitions = {
|
||||
# Immich expects all users that get a token to be granted access. So users can either be part of the
|
||||
# "admin" group or the "user" group. Users that are not part of either should be blocked by
|
||||
# the ID provider (Authelia).
|
||||
user_attributes.${roleClaim}.expression = ''"${cfg.sso.adminUserGroup}" in groups ? "admin" : "user"'';
|
||||
};
|
||||
shb.authelia.extraOidcClaimsPolicies.immich_policy = {
|
||||
custom_claims = {
|
||||
${roleClaim} = {};
|
||||
};
|
||||
};
|
||||
shb.authelia.extraOidcScopes.immich_scope = {
|
||||
claims = [ roleClaim ];
|
||||
};
|
||||
|
||||
|
||||
shb.authelia.oidcClients = lists.optionals (cfg.sso.enable && cfg.sso.provider == "Authelia") [
|
||||
{
|
||||
client_id = cfg.sso.clientID;
|
||||
client_name = "Immich";
|
||||
client_secret.source = cfg.sso.sharedSecretForAuthelia.result.path;
|
||||
public = false;
|
||||
authorization_policy = cfg.sso.authorization_policy;
|
||||
claims_policy = "immich_policy";
|
||||
token_endpoint_auth_method = "client_secret_post";
|
||||
redirect_uris = [
|
||||
"${protocol}://${fqdn}/auth/login"
|
||||
"${protocol}://${fqdn}/user-settings"
|
||||
"app.immich:///oauth-callback"
|
||||
];
|
||||
inherit scopes;
|
||||
}
|
||||
];
|
||||
};
|
||||
}
|
||||
147
test/services/immich.nix
Normal file
147
test/services/immich.nix
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
{ pkgs, lib }:
|
||||
let
|
||||
testLib = pkgs.callPackage ../common.nix {};
|
||||
|
||||
subdomain = "i";
|
||||
domain = "example.com";
|
||||
|
||||
commonTestScript = testLib.accessScript {
|
||||
hasSSL = { node, ... }: !(isNull node.config.shb.immich.ssl);
|
||||
waitForServices = { ... }: [ "immich-server.service" "postgresql.service" "nginx.service" ];
|
||||
waitForPorts = { ... }: [ 2283 80 ];
|
||||
waitForUrls = { proto_fqdn, ... }: [ "${proto_fqdn}" ];
|
||||
};
|
||||
|
||||
base = { config, ... }: {
|
||||
imports = [
|
||||
testLib.baseModule
|
||||
../../modules/services/immich.nix
|
||||
];
|
||||
|
||||
virtualisation.memorySize = 4096;
|
||||
virtualisation.cores = 2;
|
||||
|
||||
test = {
|
||||
inherit subdomain domain;
|
||||
};
|
||||
|
||||
shb.immich = {
|
||||
enable = true;
|
||||
inherit subdomain domain;
|
||||
|
||||
debug = true;
|
||||
};
|
||||
|
||||
# Required for tests
|
||||
environment.systemPackages = [ pkgs.curl ];
|
||||
};
|
||||
|
||||
basic = { config, ... }: {
|
||||
imports = [ base ];
|
||||
|
||||
test.hasSSL = false;
|
||||
};
|
||||
|
||||
https = { config, ... }: {
|
||||
imports = [
|
||||
base
|
||||
testLib.certs
|
||||
];
|
||||
|
||||
test.hasSSL = true;
|
||||
shb.immich.ssl = config.shb.certs.certs.selfsigned.n;
|
||||
};
|
||||
|
||||
backup = { config, ... }: {
|
||||
imports = [
|
||||
https
|
||||
(testLib.backup config.shb.immich.backup)
|
||||
];
|
||||
};
|
||||
|
||||
sso = { config, ... }: {
|
||||
imports = [
|
||||
https
|
||||
testLib.ldap
|
||||
(testLib.sso config.shb.certs.certs.selfsigned.n)
|
||||
];
|
||||
|
||||
shb.immich.sso = {
|
||||
enable = true;
|
||||
provider = "Authelia";
|
||||
endpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
|
||||
clientID = "immich";
|
||||
autoLaunch = true;
|
||||
sharedSecret.result = config.shb.hardcodedsecret.immichSSOSecret.result;
|
||||
sharedSecretForAuthelia.result = config.shb.hardcodedsecret.immichSSOSecretAuthelia.result;
|
||||
};
|
||||
|
||||
shb.hardcodedsecret.immichSSOSecret = {
|
||||
request = config.shb.immich.sso.sharedSecret.request;
|
||||
settings.content = "immichSSOSecret";
|
||||
};
|
||||
|
||||
shb.hardcodedsecret.immichSSOSecretAuthelia = {
|
||||
request = config.shb.immich.sso.sharedSecretForAuthelia.request;
|
||||
settings.content = "immichSSOSecret";
|
||||
};
|
||||
|
||||
# Configure LDAP groups for group-based access control
|
||||
shb.lldap.ensureGroups.immich_user = {};
|
||||
|
||||
shb.lldap.ensureUsers.immich_test_user = {
|
||||
email = "immich_user@example.com";
|
||||
groups = [ "immich_user" ];
|
||||
password.result = config.shb.hardcodedsecret.ldapImmichUserPassword.result;
|
||||
};
|
||||
|
||||
shb.lldap.ensureUsers.regular_test_user = {
|
||||
email = "regular_user@example.com";
|
||||
groups = [ ];
|
||||
password.result = config.shb.hardcodedsecret.ldapRegularUserPassword.result;
|
||||
};
|
||||
|
||||
shb.hardcodedsecret.ldapImmichUserPassword = {
|
||||
request = config.shb.lldap.ensureUsers.immich_test_user.password.request;
|
||||
settings.content = "immich_user_password";
|
||||
};
|
||||
|
||||
shb.hardcodedsecret.ldapRegularUserPassword = {
|
||||
request = config.shb.lldap.ensureUsers.regular_test_user.password.request;
|
||||
settings.content = "regular_user_password";
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
basic = pkgs.nixosTest {
|
||||
name = "immich-basic";
|
||||
|
||||
nodes.server = basic;
|
||||
nodes.client = {};
|
||||
|
||||
testScript = commonTestScript;
|
||||
};
|
||||
|
||||
https = pkgs.nixosTest {
|
||||
name = "immich-https";
|
||||
|
||||
nodes.server = https;
|
||||
nodes.client = {};
|
||||
|
||||
testScript = commonTestScript;
|
||||
};
|
||||
|
||||
backup = pkgs.nixosTest {
|
||||
name = "immich-backup";
|
||||
|
||||
nodes.server = backup;
|
||||
nodes.client = {};
|
||||
|
||||
testScript = (testLib.mkScripts {
|
||||
hasSSL = args: !(isNull args.node.config.shb.immich.ssl);
|
||||
waitForServices = args: [ "immich-server.service" "postgresql.service" "nginx.service" ];
|
||||
waitForPorts = args: [ 2283 80 ];
|
||||
waitForUrls = args: [ "${args.proto_fqdn}" ];
|
||||
}).backup;
|
||||
};
|
||||
}
|
||||
Loading…
Reference in a new issue