diff --git a/machines/gerd.nix b/machines/gerd.nix index 329592a..872a504 100644 --- a/machines/gerd.nix +++ b/machines/gerd.nix @@ -14,6 +14,7 @@ ./gerd/services/murmur.nix ./gerd/services/hedgedoc.nix ./gerd/services/cyberchef.nix + ./gerd/services/nextcloud.nix ./gerd/services/member-website @@ -30,6 +31,7 @@ pools.rpool.datasets = { "safe/svcs/forgejo" = { mountpoint = "/srv/forgejo"; extra.options.quota = "5G"; }; "safe/svcs/hedgedoc" = { mountpoint = "/srv/hedgedoc"; extra.options.quota = "5G"; }; + "safe/svcs/nextcloud" = { mountpoint = "/srv/nextcloud"; extra.options.quota = "5G"; }; }; }; diff --git a/machines/gerd/services/nextcloud.nix b/machines/gerd/services/nextcloud.nix new file mode 100644 index 0000000..71aa0fe --- /dev/null +++ b/machines/gerd/services/nextcloud.nix @@ -0,0 +1,209 @@ +{ config, lib, pkgs, ... }: + +let + svc_domain = "nextcloud.${config.mine.shared.settings.domain}"; + + # 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 = "n$dYTi7@!3v#sTbF2AV7mW7szS2Z$oFV"; + + # EDIT: Base DN + ldapBase = config.mine.shared.settings.ldap.dc; + ldapBaseUsers = config.mine.shared.settings.ldap.dc; + ldapBaseGroups = config.mine.shared.settings.ldap.dc; + ldapConfigurationActive = 1; + ldapLoginFilter = "(&(objectclass=person)(${config.mine.shared.settings.ldap.attr.uid}=%uid))"; + + # EDIT: nextcloud_users group, contains the users who can login to Nextcloud + ldapUserFilter = "(&(objectclass=person)${config.mine.shared.settings.ldap.user_filter})"; + ldapUserFilterObjectclass = "person"; + ldapGroupFilter = "(&(objectclass=groupOfUniqueNames)(cn=${config.mine.shared.settings.ldap.groups.member}))"; + ldapGroupFilterGroups = config.mine.shared.settings.ldap.groups.member; + ldapGroupFilterObjectclass = "groupOfUniqueNames"; + ldapGroupMemberAssocAttr = "uniqueMember"; + ldapEmailAttribute = config.mine.shared.settings.ldap.attr.email; + ldapUserFilterMode = 1; + ldapExpertUsernameAttr = config.mine.shared.settings.ldap.attr.uid; + }; + ldap_commands = lib.mapAttrsToList (n: v: "${occ} ldap:set-config s01 ${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 + + # ensure previous configs are deleted + CONFIGS=$(${occ} ldap:show-config --output=json | ${pkgs.jq}/bin/jq -r '. | keys | .[]') + echo "$CONFIGS" | while read configId; do + ${occ} ldap:delete-config "$configId" + done + + # create new empty config + ${occ} ldap:create-empty-config + + # setup password + BIND_USERPASS="$(cat $CREDENTIALS_DIRECTORY/lldap-bind-user-pass)" + ${occ} ldap:set-config s01 ldapAgentPassword "$BIND_USERPASS" + + # set settings + ${builtins.concatStringsSep "\n" ldap_commands} + ''; + + # 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!" + printf "y\n" | ${occ} encryption:encrypt-all + ''; +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-EVHDDFtz92lZviuTqr+St7agfBWok83HpfuL6DFCoTE="; + 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 = ""; + 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 + postStop = lib.mkAfter '' + ${nextcloudSetupLdap} + ${nextcloudSetupAdmin} + ${nextcloudSetupEncryption} + ''; + + # 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 = [{ + id = AUTHELIA_AUTH_NAME; + description = "Nextcloud"; + + # authelia crypto hash generate pbkdf2 --variant sha512 --random --random.length 72 --random.charset rfc3986 + secret = "$pbkdf2-sha512$310000$kLNQ/1A.uasSN4g8q94jUQ$8OKNUNNumHCh8dVG5/QWys7u.y1guqFXlrL.bMm7/HKTsWhpib/W.8qlU6VU7V1Be/h14Y.fJi3RLvbkEdo2kA"; + + public = false; + authorization_policy = "one_factor"; + # require_pkce = true; + # pkce_challenge_method = "S256"; + redirect_uris = [ "https://${svc_domain}/apps/oidc_login/oidc" ]; + scopes = [ + "openid" + "profile" + "email" + "groups" + ]; + + userinfo_signing_algorithm = "none"; + }]; + + 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; + }; + }; +} diff --git a/secrets/default.nix b/secrets/default.nix index 6ab8521..54804ed 100644 --- a/secrets/default.nix +++ b/secrets/default.nix @@ -27,6 +27,10 @@ # teeworlds teeworlds-env.file = ./teeworlds/env.age; + + # nextcloud + nextcloud-admin-pass.file = ./nextcloud/admin-pass.age; + nextcloud-secrets.file = ./nextcloud/secrets.age; }; users.groups.secrets-lldap-bind-user-pass = {}; diff --git a/secrets/nextcloud/admin-pass.age b/secrets/nextcloud/admin-pass.age new file mode 100644 index 0000000..50709e1 Binary files /dev/null and b/secrets/nextcloud/admin-pass.age differ diff --git a/secrets/nextcloud/secrets.age b/secrets/nextcloud/secrets.age new file mode 100644 index 0000000..19d4b58 Binary files /dev/null and b/secrets/nextcloud/secrets.age differ diff --git a/secrets/secrets.nix b/secrets/secrets.nix index f2ca33d..78c782c 100644 --- a/secrets/secrets.nix +++ b/secrets/secrets.nix @@ -31,4 +31,8 @@ in # teeworlds "teeworlds/env.age".publicKeys = defaultAccess; + + # nextcloud + "nextcloud/admin-pass.age".publicKeys = defaultAccess; + "nextcloud/secrets.age".publicKeys = defaultAccess; }