From 239cb6f9b2c1e737ff70d98973a6ee2f26859b78 Mon Sep 17 00:00:00 2001 From: eyjhb Date: Wed, 14 Aug 2024 21:29:57 +0200 Subject: [PATCH] gerd.nextcloud: added nextcloud! ldap, authelia, encryption! --- machines/gerd.nix | 2 + machines/gerd/services/nextcloud.nix | 209 +++++++++++++++++++++++++++ secrets/default.nix | 4 + secrets/nextcloud/admin-pass.age | Bin 0 -> 465 bytes secrets/nextcloud/secrets.age | Bin 0 -> 536 bytes secrets/secrets.nix | 4 + 6 files changed, 219 insertions(+) create mode 100644 machines/gerd/services/nextcloud.nix create mode 100644 secrets/nextcloud/admin-pass.age create mode 100644 secrets/nextcloud/secrets.age 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 0000000000000000000000000000000000000000..50709e162ede2dcc52e1d69b64f04237689165f9 GIT binary patch literal 465 zcmZ9`J&V&|003a;%yNT*W7&1W0L={9i@9S_9m zs5m&eh<`v3gd5cH#sddIa1(F7U+_Fm6kx%|%lBEigqstXM|e#l*dw$kVl40}h9P+r zOr+U1Lgxh8%eBCUN)a7vKs0(So?E#X*8JYqOy6Z!-ikDg)E*%58h1n1nNR!}e}a=e z5h_kaFGnhsR7pGc%$=-B5$sq{zO8Mz4KD$dle(a**Kty}r5PKNYbz6B+Dv5llIlLS%pgXy;)&%m~Wb0(~br%~Ff3VMa}uMZ_@WLgQ#{=-|n1tvAhBOF%=) zHSL?c+B7W_`r$Ymy9EqMI*o};9j95$XCe{cWjjQ=Wu7Ur!e@BLn|UG6Lme!vO0I#n z*XOd=`2DD0*Q^O{Gz>$Tbzdfh2%JB>!zE!H8@*PY$_kCi=^y;SP@NvKq+Mb^nizs#`JX(VN9E~$aH*2@imFY6vk-h#;6s^ ztQ&X{FIi^U5@*$h{&ejmU&lnM;xq>N zBUW|7JG>Qc*qB7bhN-mg33;d9hhZmV;+&2$ZkUz4BxSHFk89>wY_Jqy`&5MQaNUs+ z)RYP(iM681cd2UCE_nk=4>hGgc#h0+dUB}5=}01xh)IK>*S5I8#>y$aDO;AJ1{k8` zyG>Va!U6$WN(rfB{xAa~4}XxtlbVB^ncsQN?CkQeA+m8`ybCv!At-E literal 0 HcmV?d00001 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; }