karakeep: configure meilisearch with master key and auto update

This commit is contained in:
ibizaman 2025-10-23 23:55:09 +02:00 committed by Pierre Penninckx
parent 3f1aeaa64a
commit 6b7a6c6748
4 changed files with 117 additions and 61 deletions

View file

@ -2978,6 +2978,54 @@
"services-karakeep-options-shb.karakeep.ldap.userGroup": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.ldap.userGroup"
],
"services-karakeep-options-shb.karakeep.meilisearchMasterKey": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.meilisearchMasterKey"
],
"services-karakeep-options-shb.karakeep.meilisearchMasterKey.request": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.meilisearchMasterKey.request"
],
"services-karakeep-options-shb.karakeep.meilisearchMasterKey.request.group": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.meilisearchMasterKey.request.group"
],
"services-karakeep-options-shb.karakeep.meilisearchMasterKey.request.mode": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.meilisearchMasterKey.request.mode"
],
"services-karakeep-options-shb.karakeep.meilisearchMasterKey.request.owner": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.meilisearchMasterKey.request.owner"
],
"services-karakeep-options-shb.karakeep.meilisearchMasterKey.request.restartUnits": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.meilisearchMasterKey.request.restartUnits"
],
"services-karakeep-options-shb.karakeep.meilisearchMasterKey.result": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.meilisearchMasterKey.result"
],
"services-karakeep-options-shb.karakeep.meilisearchMasterKey.result.path": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.meilisearchMasterKey.result.path"
],
"services-karakeep-options-shb.karakeep.nextauthSecret": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.nextauthSecret"
],
"services-karakeep-options-shb.karakeep.nextauthSecret.request": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.nextauthSecret.request"
],
"services-karakeep-options-shb.karakeep.nextauthSecret.request.group": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.nextauthSecret.request.group"
],
"services-karakeep-options-shb.karakeep.nextauthSecret.request.mode": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.nextauthSecret.request.mode"
],
"services-karakeep-options-shb.karakeep.nextauthSecret.request.owner": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.nextauthSecret.request.owner"
],
"services-karakeep-options-shb.karakeep.nextauthSecret.request.restartUnits": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.nextauthSecret.request.restartUnits"
],
"services-karakeep-options-shb.karakeep.nextauthSecret.result": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.nextauthSecret.result"
],
"services-karakeep-options-shb.karakeep.nextauthSecret.result.path": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.nextauthSecret.result.path"
],
"services-karakeep-options-shb.karakeep.port": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.port"
],
@ -3011,30 +3059,6 @@
"services-karakeep-options-shb.karakeep.sso.enable": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.enable"
],
"services-karakeep-options-shb.karakeep.sso.nextauthSecret": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.nextauthSecret"
],
"services-karakeep-options-shb.karakeep.sso.nextauthSecret.request": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.nextauthSecret.request"
],
"services-karakeep-options-shb.karakeep.sso.nextauthSecret.request.group": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.nextauthSecret.request.group"
],
"services-karakeep-options-shb.karakeep.sso.nextauthSecret.request.mode": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.nextauthSecret.request.mode"
],
"services-karakeep-options-shb.karakeep.sso.nextauthSecret.request.owner": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.nextauthSecret.request.owner"
],
"services-karakeep-options-shb.karakeep.sso.nextauthSecret.request.restartUnits": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.nextauthSecret.request.restartUnits"
],
"services-karakeep-options-shb.karakeep.sso.nextauthSecret.result": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.nextauthSecret.result"
],
"services-karakeep-options-shb.karakeep.sso.nextauthSecret.result.path": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.nextauthSecret.result.path"
],
"services-karakeep-options-shb.karakeep.sso.sharedSecret": [
"services-karakeep.html#services-karakeep-options-shb.karakeep.sso.sharedSecret"
],

View file

@ -96,22 +96,13 @@ in
default = "one_factor";
};
nextauthSecret = lib.mkOption {
description = "NextAuth secret.";
type = lib.types.submodule {
options = contracts.secret.mkRequester {
owner = "karakeep";
restartUnits = [ "karakeep.service" ];
};
};
};
sharedSecret = lib.mkOption {
description = "OIDC shared secret for Karakeep.";
type = lib.types.submodule {
options = contracts.secret.mkRequester {
owner = "karakeep";
restartUnits = [ "karakeep.service" ];
# These services are the ones relying on the environment file containing the secrets.
restartUnits = [ "karakeep-init.service" "karakeep-workers.service" "karakeep-workers.service" ];
};
};
};
@ -144,12 +135,35 @@ in
};
};
};
nextauthSecret = lib.mkOption {
description = "NextAuth secret.";
type = lib.types.submodule {
options = contracts.secret.mkRequester {
owner = "karakeep";
# These services are the ones relying on the environment file containing the secrets.
restartUnits = [ "karakeep-init.service" "karakeep-workers.service" "karakeep-workers.service" ];
};
};
};
meilisearchMasterKey = lib.mkOption {
description = "Master key used to secure communication with Meilisearch.";
type = lib.types.submodule {
options = contracts.secret.mkRequester {
owner = "karakeep";
# These services are the ones relying on the environment file containing the secrets.
restartUnits = [ "karakeep-init.service" "karakeep-workers.service" "karakeep-workers.service" ];
};
};
};
};
config = (lib.mkMerge [
(lib.mkIf cfg.enable {
services.karakeep = {
enable = true;
meilisearch.enable = true;
extraEnvironment = {
PORT = toString cfg.port;
@ -163,6 +177,32 @@ in
upstream = "http://127.0.0.1:${toString cfg.port}/";
}
];
# Piggybacking onto the upstream karakeep-init and replacing its script by ours.
# This is needed otherwise the MEILI_MASTER_KEY is generated randomly on first start
# instead of using the value from the cfg.meilisearchMasterKey option.
systemd.services.karakeep-init = {
script = lib.mkForce ((lib.shb.replaceSecrets {
userConfig = {
MEILI_MASTER_KEY = cfg.meilisearchMasterKey.result.path;
NEXTAUTH_SECRET.source = cfg.nextauthSecret.result.path;
} // lib.optionalAttrs cfg.sso.enable {
OAUTH_CLIENT_SECRET.source = cfg.sso.sharedSecret.result.path;
};
resultPath = "/var/lib/karakeep/settings.env";
generator = lib.shb.toEnvVar;
}) + ''
export DATA_DIR="$STATE_DIRECTORY"
exec ${config.services.karakeep.package}/lib/karakeep/migrate
'');
};
})
(lib.mkIf cfg.enable {
services.meilisearch = {
dumplessUpgrade = true;
environment = "production";
masterKeyFile = cfg.meilisearchMasterKey.result.path;
};
})
(lib.mkIf (cfg.enable && cfg.sso.enable) {
shb.lldap.ensureGroups = {
@ -199,25 +239,6 @@ in
OAUTH_CLIENT_ID = cfg.sso.clientID;
OAUTH_SCOPE = "openid email profile";
};
environmentFile = "/run/karakeep/secrets.env";
};
systemd.tmpfiles.rules = [
"d '/run/karakeep' 0750 root root - -"
];
systemd.services.karakeep-pre = {
script = lib.shb.replaceSecrets {
userConfig = {
NEXTAUTH_SECRET.source = cfg.sso.nextauthSecret.result.path;
OAUTH_CLIENT_SECRET.source = cfg.sso.sharedSecret.result.path;
};
resultPath = "/run/karakeep/secrets.env";
generator = lib.shb.toEnvVar;
};
serviceConfig.Type = "oneshot";
wantedBy = [ "multi-user.target" ];
before = [ "karakeep-web.service" "karakeep-workers.service" ];
requiredBy = [ "karakeep-web.service" "karakeep-workers.service" ];
};
})
]);

View file

@ -17,6 +17,7 @@ It integrates well with [Ollama][].
- Declarative [SSO](#services-karakeep-options-shb.karakeep.sso) Configuration.
- When SSO is enabled, login with user and password is disabled.
- Registration is enabled through SSO.
- Meilisearch configured with production environment and master key.
- Access through [subdomain](#services-karakeep-options-shb.karakeep.subdomain) using reverse proxy.
- Access through [HTTPS](#services-karakeep-options-shb.karakeep.ssl) using reverse proxy.
- [Backup](#services-karakeep-options-shb.karakeep.sso) through the [backup block](./blocks-backup.html).
@ -39,17 +40,18 @@ The following snippet assumes a few blocks have been setup already:
ssl = config.shb.certs.certs.letsencrypt.${domain};
nextauthSecret.result = config.shb.sops.secret.nextauthSecret.result;
sso = {
enable = true;
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
nextauthSecret.result = config.shb.sops.secret.nextauthSecret.result;
sharedSecret.result = config.shb.sops.secret.oidcSecret.result;
sharedSecretForAuthelia.result = config.shb.sops.secret.oidcAutheliaSecret.result;
};
};
shb.sops.secret.nextauthSecret.request = config.shb.karakeep.sso.sharedSecret.request;
shb.sops.secret.nextauthSecret.request = config.shb.karakeep.nextauthSecret.request;
shb.sops.secret.oidcSecret.request = config.shb.karakeep.sso.sharedSecret.request;
shb.sops.secret.oidcAutheliaSecret = {
request = config.shb.karakeep.sso.sharedSecretForAuthelia.request;

View file

@ -8,6 +8,8 @@ let
commonTestScript = testLib.mkScripts {
hasSSL = { node, ... }: !(isNull node.config.shb.karakeep.ssl);
waitForServices = { ... }: [
"karakeep-init.service"
"karakeep-browser.service"
"karakeep-web.service"
"karakeep-workers.service"
"nginx.service"
@ -32,6 +34,18 @@ let
shb.karakeep = {
enable = true;
inherit (config.test) subdomain domain;
nextauthSecret.result = config.shb.hardcodedsecret.nextauthSecret.result;
meilisearchMasterKey.result = config.shb.hardcodedsecret.meilisearchMasterKey.result;
};
shb.hardcodedsecret.nextauthSecret = {
request = config.shb.karakeep.nextauthSecret.request;
settings.content = nextauthSecret;
};
shb.hardcodedsecret.meilisearchMasterKey = {
request = config.shb.karakeep.meilisearchMasterKey.request;
settings.content = "meilisearch-master-key";
};
networking.hosts = {
@ -107,16 +121,11 @@ let
authEndpoint = "https://${config.shb.authelia.subdomain}.${config.shb.authelia.domain}";
clientID = "karakeep";
nextauthSecret.result = config.shb.hardcodedsecret.nextauthSecret.result;
sharedSecret.result = config.shb.hardcodedsecret.oidcSecret.result;
sharedSecretForAuthelia.result = config.shb.hardcodedsecret.oidcAutheliaSecret.result;
};
};
shb.hardcodedsecret.nextauthSecret = {
request = config.shb.karakeep.sso.nextauthSecret.request;
settings.content = nextauthSecret;
};
shb.hardcodedsecret.oidcSecret = {
request = config.shb.karakeep.sso.sharedSecret.request;
settings.content = oidcSecret;