server-configs/machines/gerd/services/nextcloud.nix

235 lines
8 KiB
Nix

{ config, lib, pkgs, ... }:
let
svc_domain = "nextcloud.${config.mine.shared.settings.domain}";
default_storage_quota = "100MB";
# 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.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;
};
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.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.nextcloud29;
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;
oidc_login = let
version = "3.1.1";
# TODO(eyJhb): add to niv
in pkgs.fetchNextcloudApp {
sha256 = "sha256-b/tKk+y+ZypCHGNDtunDua2msYD6/TzA0haoC0k85F4=";
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;
# settings
settings = {
# open connect/oidc
oidc_login_provider_url = "https://auth.fricloud.dk";
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";
};
};
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}"
];
};
# ensure that nextcloud can access stateDir
systemd.tmpfiles.rules = [
"Z ${stateDir} 6770 ${nextcloud_user} ${nextcloud_group} -"
];
# 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";
redirect_uris = [ "https://${svc_domain}/apps/oidc_login/oidc" ];
scopes = [
"openid"
"profile"
"email"
"groups"
];
}];
services.nginx.virtualHosts."${svc_domain}" = {
forceSSL = true;
enableACME = true;
};
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;
};
};
}