server-configs/machines/gerd/services/nextcloud.nix
eyjhb 8e5f22a87e
authelia: update stopped providing claims in response
This adds the default claim policy, which can be used to provide the
past behaviour for this. Services that require this still needs to be identified.
2025-05-29 16:22:28 +02:00

263 lines
9.2 KiB
Nix

{ config, lib, pkgs, ... }:
let
svc_domain = "nextcloud.${config.mine.shared.settings.domain}";
default_storage_quota = "1mb";
# place data into own zfs dataset
stateDir = config.mine.zfsMounts."rpool/safe/svcs/nextcloud";
# helper variables
nextcloud_user = config.users.users.nextcloud.name;
nextcloud_group = config.users.groups.nextcloud.name;
AUTHELIA_AUTH_NAME = "nextcloud";
# occ bin
occ = config.services.nextcloud.occ + "/bin/nextcloud-occ";
# script for setting up ldap for nextcloud
# - ensure user_ldap app is intalled
# - ensure user_ldap app is enabled
# - delete all ldap configurations
# - add new configuration with our settings
nextcloudSetupLdap = let
ldap_settings = {
ldapHost = "localhost";
ldapPort = 3890;
ldapAgentName = config.mine.shared.settings.ldap.bind_dn;
# ldapAgentPassword = "<insert-from-secret-env>";
ldapBase = config.mine.shared.settings.ldap.dc;
ldapBaseUsers = config.mine.shared.settings.ldap.dc;
ldapBaseGroups = config.mine.shared.settings.ldap.dc;
ldapLoginFilter = config.mine.shared.lib.ldap.mkFilter (lconfig: llib:
llib.mkAnd [
(llib.mkOC lconfig.oc.person)
(llib.mkSearch lconfig.attr.uid "%uid")
]
);
# EDIT: nextcloud_users group, contains the users who can login to Nextcloud
ldapUserFilter = config.mine.shared.lib.ldap.mkFilter (lconfig: llib:
llib.mkAnd [
(llib.mkOC lconfig.oc.person)
(llib.mkGroup lconfig.groups.member)
]
);
ldapUserFilterObjectclass = config.mine.shared.settings.ldap.oc.person;
ldapGroupFilter = config.mine.shared.lib.ldap.mkFilter (lconfig: llib:
llib.mkAnd [
(llib.mkOC lconfig.oc.groupOfUniqueNames)
(llib.mkOr [ "cn=${lconfig.groups.nextcloud_admin}" "cn=${lconfig.groups.member}"])
]
);
ldapGroupFilterGroups = "admin;user";
ldapGroupFilterObjectclass = config.mine.shared.settings.ldap.oc.groupOfUniqueNames;
ldapGroupMemberAssocAttr = "uniqueMember";
ldapEmailAttribute = config.mine.shared.settings.ldap.attr.email;
ldapUserFilterMode = 1;
ldapExpertUsernameAttr = config.mine.shared.settings.ldap.attr.uid;
ldapConfigurationActive = 1;
ldapQuotaDefault = 1;
ldapQuotaAttribute = config.mine.shared.settings.ldap.attr.nextcloudquota;
};
ldap_commands = lib.mapAttrsToList (n: v: "${occ} ldap:set-config $NEW_CONFIG_ID ${n} '${builtins.toString v}'") ldap_settings;
in pkgs.writeShellScript "nextcloud-add-ldap.sh" ''
# enable ldap service, remove config and create new empty one
${occ} app:install user_ldap
${occ} app:enable user_ldap
# create new empty config
NEW_CONFIG_ID="$(${occ} ldap:create-empty-config -p)"
# setup ldap password
BIND_USERPASS="$(cat $CREDENTIALS_DIRECTORY/lldap-bind-user-pass)"
${occ} ldap:set-config $NEW_CONFIG_ID ldapAgentPassword "$BIND_USERPASS"
# set settings
${builtins.concatStringsSep "\n" ldap_commands}
# delete all other configurations
CONFIGS=$(${occ} ldap:show-config --output=json | ${pkgs.jq}/bin/jq -r '. | keys | .[]')
echo "$CONFIGS" | while read CONFIG_ID; do
if [[ "$NEW_CONFIG_ID" != "$CONFIG_ID" ]]; then
${occ} ldap:delete-config "$CONFIG_ID"
fi
done
# promote ldap admin group to admins
${occ} ldap:promote-group ${config.mine.shared.settings.ldap.groups.nextcloud_admin} --yes -n
'';
# script for resetting nextcloud admin password on each startup
nextcloudSetupAdmin = pkgs.writeShellScript "nextcloud-setup-admin.sh" ''
# reset admin password on each start
export OC_PASS="$(cat $CREDENTIALS_DIRECTORY/nextcloud-admin-pass)"
${occ} user:resetpassword --password-from-env -- ${config.services.nextcloud.config.adminuser}
'';
# script for setting encryption for nextcloud
# - ensure encryption app is intalled
# - ensure encryption app is enabled
# - enable encryption
# - ensure all files are encrypted
nextcloudSetupEncryption = pkgs.writeShellScript "nextcloud-setup-encryption.sh" ''
# enable encryption
${occ} app:install encryption
${occ} app:enable encryption
${occ} encryption:enable
echo "Ensuring everything is encrypted!"
if [[ ! -e ${stateDir}/.encrypt-setup ]]; then
echo "Running encrypt-all!"
printf "y\n" | ${occ} encryption:encrypt-all
touch ${stateDir}/.encrypt-setup
else
echo "Encrypt all has already ran, not running again."
fi
'';
# script for setting up tho storage quota
# possible to set based on groups
# https://github.com/nextcloud/groupquota
nextcloudSetupStorageQuota = pkgs.writeShellScript "nextcloud-setup-storage-quota.sh" ''
# set default quota
${occ} config:app:set files default_quota --value '${default_storage_quota}'
'';
in {
services.nextcloud = {
enable = true;
package = pkgs.nextcloud30;
datadir = stateDir;
config.adminpassFile = config.age.secrets.nextcloud-admin-pass.path;
hostName = svc_domain;
https = true;
configureRedis = true;
# apps
extraAppsEnable = true;
extraApps = {
inherit (config.services.nextcloud.package.packages.apps) contacts calendar tasks gpoddersync;
oidc_login = let
version = "3.2.2";
# TODO(eyJhb): add to niv
in pkgs.fetchNextcloudApp {
sha256 = "sha256-RLYquOE83xquzv+s38bahOixQ+y4UI6OxP9HfO26faI=";
url = "https://github.com/pulsejet/nextcloud-oidc-login/releases/download/v${version}/oidc_login.tar.gz";
license = "agpl3Only";
};
};
# secrets
secretFile = config.age.secrets.nextcloud-secrets.path;
# use postgresql for database
# createLocally will enable postgresql, add database and user
database.createLocally = true;
config.dbtype = "pgsql";
# settings
settings = rec {
# open connect/oidc
oidc_login_provider_url = "https://${config.mine.shared.settings.authelia.domain}";
oidc_login_client_id = AUTHELIA_AUTH_NAME;
# oidc_login_client_secret = "<set-using-secrets-file>";
oidc_login_proxy_ldap = true; # SUPER IMPORTANT!
oidc_login_auto_redirect = true;
oidc_login_button_text = "Log in with Authelia";
oidc_login_use_id_token = true;
oidc_login_attributes = {
id = "preferred_username";
ldap_uid = "preferred_username";
name = "name";
mail = "email";
groups = "groups";
};
oidc_login_scope = "openid profile email groups";
oidc_login_code_challenge_method = "S256";
# mail
mail_from_address = "nextcloud";
mail_smtpmode = "smtp";
mail_sendmailmode = "smtp";
mail_domain = "${config.mine.shared.settings.domain}";
mail_smtphost = "${config.mine.shared.settings.mail.domain_smtp}";
mail_smtpport = config.mine.shared.settings.mail.ports.submissions;
mail_smtpsecure = "ssl";
mail_smtpname = mail_from_address;
# mail_smtppassword = "defined-in-the-secrets-file-and-in-a-separate-file-for-lldap";
};
};
# setup lldap user for nextcloud that can send emails
services.lldap.provision.users = config.mine.shared.lib.ldap.mkScope (lconfig: llib: {
nextcloud = llib.mkProvisionUserSystem "nextcloud" config.age.secrets.nextcloud-smtp-pass.path;
});
systemd.services.nextcloud-setup = {
# runs this after all the main nextcloud-setup stuff
script = lib.mkAfter ''
${nextcloudSetupLdap}
${nextcloudSetupAdmin}
${nextcloudSetupEncryption}
${nextcloudSetupStorageQuota}
'';
# setup credentials for service
serviceConfig.LoadCredential = [
"lldap-bind-user-pass:${config.age.secrets.lldap-bind-user-pass.path}"
"nextcloud-admin-pass:${config.age.secrets.nextcloud-admin-pass.path}"
];
# do not run on each nixos rebuild switch!!!!!!!!!!!
serviceConfig.RemainAfterExit = true;
};
# setup authelia for nextcloud
services.authelia.instances.main.settings.identity_providers.oidc.clients = [{
client_id = AUTHELIA_AUTH_NAME;
client_name = "Nextcloud";
client_secret = "$pbkdf2-sha512$310000$kLNQ/1A.uasSN4g8q94jUQ$8OKNUNNumHCh8dVG5/QWys7u.y1guqFXlrL.bMm7/HKTsWhpib/W.8qlU6VU7V1Be/h14Y.fJi3RLvbkEdo2kA";
consent_mode = "implicit";
redirect_uris = [ "https://${svc_domain}/apps/oidc_login/oidc" ];
claims_policy = "default";
scopes = [
"openid"
"profile"
"email"
"groups"
];
}];
services.nginx.virtualHosts."${svc_domain}" = {
forceSSL = true;
enableACME = true;
};
# ensure that nextcloud can access stateDir
systemd.tmpfiles.rules = [
"Z ${stateDir} 6770 ${nextcloud_user} ${nextcloud_group} -"
];
age.secrets = {
nextcloud-admin-pass.owner = nextcloud_user;
nextcloud-secrets.owner = nextcloud_user;
};
mine.shared.meta.nextcloud = {
name = "Nextcloud";
description = "We host our own Nextcloud for having a central place for personal files, etc. (all files are encrypted using the standard encryption module)! Login using your credentials.";
url = "https://${svc_domain}";
package = let
pkg = config.services.nextcloud.package;
in {
name = pkg.pname;
version = pkg.version;
meta = pkg.meta;
};
};
}