Nextcloud

Überblick

Es spielt eine Rolle, welchem Anbieter man seine Daten (Dateien aller Art, Kalender-Einträge etc.) anvertraut: Unternehmen mit Sitz in den USA müssen laut US CLOUD Act nach Aufforderung der Behörden jederzeit Daten von ihren Servern liefern, auch wenn sie ausserhalb der USA stehen. Die National Security Letters verbieten ihnen unter Strafandrohung, ihre Kunden darüber zu informieren. Das kollidiert mit den Schweizer- und EU-Datenschutzregeln und/oder nationalem Recht. Der Einsatz solcher Lösungen kann daher beispielsweise in Deutschland zu massiven DSGVO-Strafen führen.

Nextcloud ist Open Source und bietet Cloud-Dienste und Datensynchronisation auf eigenen Servern, die zu 100% unter eigener Kontrolle stehen - also ganz im Gegensatz zu AWS, Azure und Office 365, Dropbox oder GCP. Nextcloud ging Mitte 2016 aus Owncloud hervor. Der Unternehmensgründer Frank Karlitschek selbst gab den Fork bekannt.

Kern-Feature ist die verteilte Zusammenarbeit an Dateien, die per Web-GUI, WebDAV oder dem Nextcloud-Client verwaltet und synchronisiert werden können.

Apps erweitern das System in beliebige Richtungen:

  • Kalender und Adressbuch (Standard)

  • Videokonferenz

  • Social-Media-Funktionen

  • Kartenintegration

  • alternative Benutzerdatenbanken (LDAP, OAuth)

  • etc.

Installation und der Betrieb sind komplex. Anbieter wie die Linuxfabrik nehmen einem per as-a-Service-Angebot für Einzelnutzer als auch für Teams diesen Aufwand ab. Leistungsmerkmale für die „Nextcloud für Teams“-Server sind u.a.:

  • Die Nextcloud-Instanz steht dem Kunden exklusiv zur Verfügung.

  • Der Kunde besitzt einen Admin-Zugang und kann damit sämtliche Sicherheitsfunktionen wie beispielsweise Two-Factor-Authentication (2FA) oder End-to-End-Encryption unabhängig von der Linuxfabrik selbst einrichten.

  • Weitere Leistungsmerkmale.

Details siehe auch https://nextcloud.com/hub/.

Installation

Siehe https://docs.nextcloud.com/server/latest/admin_manual/installation/example_centos.html. Download von https://download.nextcloud.com/server/releases/ (neueste Datei: https://download.nextcloud.com/server/releases/latest.tar.bz2).

Tipp

Wer eine Shared Instance betreibt, auf der sich die Benutzer untereinander nicht kennen, sollte die App „User status“ abschalten - sie ermöglicht im Nextcloud-Dashboard die Anzeige der „Recent statuses“, eine Liste der letzten Anmeldevorgänge der Benutzer (inkl. E-Mail-Adresse).

Update/Upgrade durchführen

per OCC (bevorzugt)
update-nextcloud
#!/usr/bin/env bash

sudo -u apache php /var/www/html/nextcloud/occ user:list > /tmp/nextcloud-user-list-before-update
sudo -u apache php /var/www/html/nextcloud/occ config:list > /tmp/nextcloud-config-list-before-update
sudo -u apache php /var/www/html/nextcloud/occ app:list > /tmp/nextcloud-app-list-before-update

cd /var/www/html/nextcloud/updater/
sudo -u apache php updater.phar  --no-interaction

cd ..
sudo -u apache ./occ upgrade
sudo -u apache ./occ db:add-missing-indices
sudo -u apache ./occ db:add-missing-columns
sudo -u apache ./occ db:convert-filecache-bigint --no-interaction

sudo -u apache php /var/www/html/nextcloud/occ user:list > /tmp/nextcloud-user-list-after-update
sudo -u apache php /var/www/html/nextcloud/occ config:list > /tmp/nextcloud-config-list-after-update
sudo -u apache php /var/www/html/nextcloud/occ app:list > /tmp/nextcloud-app-list-after-update

echo " "
echo " "
echo " "
echo "Diff after update"
echo "-----------------"

echo " "
echo 'diff /tmp/nextcloud-user-list-before-update /tmp/nextcloud-user-list-after-update'
diff /tmp/nextcloud-user-list-before-update /tmp/nextcloud-user-list-after-update

echo " "
echo 'diff /tmp/nextcloud-config-list-before-update /tmp/nextcloud-config-list-after-update'
diff /tmp/nextcloud-config-list-before-update /tmp/nextcloud-config-list-after-update

echo " "
echo 'diff /tmp/nextcloud-app-list-before-update /tmp/nextcloud-app-list-after-update'
diff /tmp/nextcloud-app-list-before-update /tmp/nextcloud-app-list-after-update
per Web-Interface
setsebool httpd_unified on
setsebool httpd_can_network_connect on

Jetzt das Update über das Webinterface durchführen. Anschliessend:

setsebool -P httpd_unified off
# if we don't need any network connections
setsebool -P httpd_can_network_connect off

Nextcloud Loglevel

  • 0: DEBUG: All activity; the most detailed logging.

  • 1: INFO: Activity such as user logins and file activities, plus warnings, errors, and fatal errors.

  • 2: WARN: Operations succeed, but with warnings of potential problems, plus errors and fatal errors.

  • 3: ERROR: An operation fails, but other services and operations continue, plus fatal errors.

  • 4: FATAL: The server stops.

OCC Cheat Sheet

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
      --no-warnings     Skip global warnings, show command output only
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  check                                  check dependencies of the server environment
  help                                   Display help for a command
  list                                   List commands
  status                                 show some status information
  upgrade                                run upgrade routines after installation of a new release. The release has to be installed before.
 activity
  activity:send-mails                    Sends the activity notification mails
 app
  app:check-code                         check code to be compliant
  app:disable                            disable an app
  app:enable                             enable an app
  app:getpath                            Get an absolute path to the app directory
  app:install                            install an app
  app:list                               List all available apps
  app:remove                             remove an app
  app:update                             update an app or all apps
 background
  background:ajax                        Use ajax to run background jobs
  background:cron                        Use cron to run background jobs
  background:webcron                     Use webcron to run background jobs
 background-job
  background-job:execute                 Execute a single background job manually
 broadcast
  broadcast:test                         test the SSE broadcaster
 circles
  circles:check                          Checking your configuration
  circles:maintenance                    Clean stuff, keeps the app running
  circles:manage:config                  edit config/type of a Circle
  circles:manage:create                  create a new circle
  circles:manage:destroy                 destroy a circle by its ID
  circles:manage:details                 get details about a circle by its ID
  circles:manage:edit                    edit displayName or description of a Circle
  circles:manage:join                    emulate a user joining a Circle
  circles:manage:leave                   simulate a user joining a Circle
  circles:manage:list                    listing current circles
  circles:manage:setting                 edit setting for a Circle
  circles:members:add                    Add a member to a Circle
  circles:members:details                get details about a member by its ID
  circles:members:level                  Change the level of a member from a Circle
  circles:members:list                   listing Members from a Circle
  circles:members:remove                 remove a member from a circle
  circles:members:search                 Change the level of a member from a Circle
  circles:memberships                    index and display memberships for local and federated users
  circles:remote                         remote features
  circles:shares:files                   listing shares files
  circles:sync                           Sync Circles and Members
  circles:test                           testing some features
 config
  config:app:delete                      Delete an app config value
  config:app:get                         Get an app config value
  config:app:set                         Set an app config value
  config:import                          Import a list of configs
  config:list                            List all configs
  config:system:delete                   Delete a system config value
  config:system:get                      Get a system config value
  config:system:set                      Set a system config value
 dav
  dav:create-addressbook                 Create a dav addressbook
  dav:create-calendar                    Create a dav calendar
  dav:delete-calendar                    Delete a dav calendar
  dav:list-calendars                     List all calendars of a user
  dav:move-calendar                      Move a calendar from an user to another
  dav:remove-invalid-shares              Remove invalid dav shares
  dav:retention:clean-up
  dav:send-event-reminders               Sends event reminders
  dav:sync-birthday-calendar             Synchronizes the birthday calendar
  dav:sync-system-addressbook            Synchronizes users to the system addressbook
 db
  db:add-missing-columns                 Add missing optional columns to the database tables
  db:add-missing-indices                 Add missing indices to the database tables
  db:add-missing-primary-keys            Add missing primary keys to the database tables
  db:convert-filecache-bigint            Convert the ID columns of the filecache to BigInt
  db:convert-mysql-charset               Convert charset of MySQL/MariaDB to use utf8mb4
  db:convert-type                        Convert the Nextcloud database to the newly configured one
 deck
  deck:export                            Export a JSON dump of user data
 encryption
  encryption:change-key-storage-root     Change key storage root
  encryption:decrypt-all                 Disable server-side encryption and decrypt all files
  encryption:disable                     Disable encryption
  encryption:disable-master-key          Disable the master key and use per-user keys instead. Only available for fresh installations with no existing encrypted data! There is no way to enable it again.
  encryption:enable                      Enable encryption
  encryption:enable-master-key           Enable the master key. Only available for fresh installations with no existing encrypted data! There is also no way to disable it again.
  encryption:encrypt-all                 Encrypt all files for all users
  encryption:fix-encrypted-version       Fix the encrypted version if the encrypted file(s) are not downloadable.
  encryption:list-modules                List all available encryption modules
  encryption:migrate-key-storage-format  Migrate the format of the keystorage to a newer format
  encryption:recover-user                Recover user data in case of password lost. This only works if the user enabled the recovery key.
  encryption:scan:legacy-format          Scan the files for the legacy format
  encryption:set-default-module          Set the encryption default module
  encryption:show-key-storage-root       Show current key storage root
  encryption:status                      Lists the current status of encryption
 files
  files:cleanup                          cleanup filecache
  files:recommendations:recommend
  files:repair-tree                      Try and repair malformed filesystem tree structures
  files:scan                             rescan filesystem
  files:scan-app-data                    rescan the AppData folder
  files:transfer-ownership               All files and folders are moved to another user - outgoing shares and incoming user file shares (optionally) are moved as well.
 group
  group:add                              Add a group
  group:adduser                          add a user to a group
  group:delete                           Remove a group
  group:info                             Show information about a group
  group:list                             list configured groups
  group:removeuser                       remove a user from a group
 integrity
  integrity:check-app                    Check integrity of an app using a signature.
  integrity:check-core                   Check integrity of core code using a signature.
  integrity:sign-app                     Signs an app using a private key.
  integrity:sign-core                    Sign core using a private key.
 l10n
  l10n:createjs                          Create javascript translation files for a given app
 log
  log:file                               manipulate logging backend
  log:manage                             manage logging configuration
  log:tail                               Tail the nextcloud logfile
  log:watch                              Watch the nextcloud logfile
 mail
  mail:account:create                    creates IMAP account
  mail:account:delete                    Delete an IMAP account
  mail:account:diagnose                  Diagnose a user's IMAP connection
  mail:account:export                    Exports a user's IMAP account(s)
  mail:account:export-threads            Exports a user's account threads
  mail:account:sync                      Synchronize an IMAP account
  mail:account:train                     Train the classifier of new messages
  mail:clean-up                          clean up all orphaned data
  mail:repair:tags                       Create default tags for account. If no account ID given, all tag entries will be repaired
  mail:tags:migration-jobs               Creates a background job entry in the cron table for every user to migrate important labels to IMAP
  mail:thread                            Build threads from the exported data of an account
 maintenance
  maintenance:data-fingerprint           update the systems data-fingerprint after a backup is restored
  maintenance:mimetype:update-db         Update database mimetypes and update filecache
  maintenance:mimetype:update-js         Update mimetypelist.js
  maintenance:mode                       set maintenance mode
  maintenance:repair                     repair this installation
  maintenance:theme:update               Apply custom theme changes
  maintenance:update:htaccess            Updates the .htaccess file
 news
  news:feed:add                          Add a feed
  news:feed:delete                       Remove a feed
  news:feed:list                         List all feeds
  news:feed:read                         Read feed
  news:folder:add                        Add a folder
  news:folder:delete                     Remove a folder
  news:folder:list                       List all folders
  news:folder:read                       Read folder
  news:generate-explore                  Prints a JSON string which represents the given feed URL and votes, e.g.: {"title":"Feed - Title","favicon":"www.web.com\/favicon.ico","url":"www.web.com","feed":"www.web.com\/rss.xml","description":"description is here","votes":100}
  news:item:list                         List all items
  news:item:list-feed                    List all items in a feed
  news:item:list-folder                  List all items in a folder
  news:item:read                         Read item
  news:opml:export                       Print OPML file
  news:show-feed                         Prints a JSON string which represents the given feed as it would be in the DB.
  news:updater:after-update              removes old read articles which are not starred
  news:updater:before-update             This is used to clean up the database. It deletes folders and feeds that are marked for deletion
  news:updater:update-feed               Console API for updating a single user's feed
  news:updater:update-user               Console API for updating a single user's feed
 notification
  notification:generate                  Generate a notification for the given user
  notification:test-push                 Generate a notification for the given user
 preview
  preview:repair                         distributes the existing previews into subfolders
  preview:reset-rendered-texts           Deletes all generated avatars and previews of text and md files
 richdocuments
  richdocuments:activate-config          Activate config changes
  richdocuments:convert-bigint           Convert the ID columns of the richdocuments tables to BigInt
  richdocuments:update-empty-templates   Update empty template files
 security
  security:bruteforce:reset              resets bruteforce attemps for given IP address
  security:certificates                  list trusted certificates
  security:certificates:import           import trusted certificate in PEM format
  security:certificates:remove           remove trusted certificate
 serverinfo
  serverinfo:update-storage-statistics   Triggers an update of the counts related to storages used in serverinfo
 sharing
  sharing:cleanup-remote-storages        Cleanup shared storage entries that have no matching entry in the shares_external table
  sharing:expiration-notification        Notify share initiators when a share will expire the next day.
 tag
  tag:add                                Add new tag
  tag:delete                             delete a tag
  tag:edit                               edit tag attributes
  tag:list                               list tags
 text
  text:reset                             Reset a text document
 theming
  theming:config                         Set theming app config values
 trashbin
  trashbin:cleanup                       Remove deleted files
  trashbin:expire                        Expires the users trashbin
  trashbin:size                          Configure the target trashbin size
 twofactorauth
  twofactorauth:cleanup                  Clean up the two-factor user-provider association of an uninstalled/removed provider
  twofactorauth:disable                  Disable two-factor authentication for a user
  twofactorauth:enable                   Enable two-factor authentication for a user
  twofactorauth:enforce                  Enabled/disable enforced two-factor authentication
  twofactorauth:state                    Get the two-factor authentication (2FA) state of a user
 update
  update:check                           Check for server and app updates
 user
  user:add                               adds a user
  user:add-app-password                  Add app password for the named user
  user:delete                            deletes the specified user
  user:disable                           disables the specified user
  user:enable                            enables the specified user
  user:info                              show user info
  user:lastseen                          shows when the user was logged in last time
  user:list                              list configured users
  user:report                            shows how many users have access
  user:resetpassword                     Resets the password of the named user
  user:setting                           Read and modify user settings
 versions
  versions:cleanup                       Delete versions
  versions:expire                        Expires the users file versions
 workflows
  workflows:list                         Lists configured workflows

Storage: S3 Object Storage als Backend

So wird ein Block-basierter Nextcloud-Storage auf ein S3-Backend migriert.

Hier wird von folgenden Voraussetzungen ausgegangen:

  • Der Nextcloud-Server heisst „servername“.

  • Die MariaDB heisst „nextcloud“.

  • Der lokalen Nextcloud-Storage liegt auf /var/www/html/nextcloud/data/.

  • Der S3-Storage läuft im Beispiel bei Exoscale im Zürcher Datacenter.

  • S3-Bucket namens „bucket-name“ ist angelegt, Credentials für S3 liegen vor.

  • Credentials für MariaDB liegen vor.

S3-Storage einrichten und Credentials vorhalten:

  • URL: https://sos-ch-dk-2.exo.io

  • Bucket-Name: bucket-name (es empfiehlt sich, hier den Hostnamen zu verwenden)

  • Key: EXOmylittlekey

  • Secret: mysupersecret

  • Region: ch-dk-2

Alle Zeitangaben beziehen sich auf ein System mit 80 Benutzern und etwas mehr als 2 Millionen Dateien mit einer Gesamtgrösse von rund 3.7 TB.

Vorbereitende Massnahmen:

export OC_PASS="mypassword"

# 30 minutes
chown -R apache:apache /var/www/html/nextcloud/data/
# 30 minutes
sudo -u apache /var/www/html/nextcloud/occ files:scan --all

Maintenance-Mode aktivieren (Benutzer für die Zeit der Migration aus Konsistenzgründen aussperren):

sudo -u apache php /var/www/html/nextcloud/occ maintenance:mode --on

Datenbank abfragen, um eine Liste der Dateien aller Benutzer inkl. Metadaten zu erhalten. Die beiden resultierenden SQL-Dumps belegen auf dem beschriebenen System zusammengenommen 500 MB.

# get the user files
mysql --user root --password --batch --disable-column-names --database nextcloud << EOF > /tmp/user_file_list
    select concat('urn:oid:', fileid, ' ', '/var/www/html/nextcloud/data/', substring(id from 7), '/', path)
    from oc_filecache join oc_storages on storage = numeric_id
    where id like 'home::%'
    order by id;
EOF

# get the meta files
# 2 minutes
mysql --user root --password --batch --disable-column-names --database nextcloud << EOF > /tmp/meta_file_list
    select concat('urn:oid:', fileid, ' ', substring(id from 8), path)
    from oc_filecache join oc_storages on storage = numeric_id
    where id like 'local::%'
    order by id;
EOF

Symbolischen Link für Block-Storage-Datei auf zukünftige Datei im S3-Bucket anlegen:

mkdir -p /var/www/html/nextcloud/data/s3files
cd /var/www/html/nextcloud/data/s3files

# count the files that have to be processed
find /var/www/html/nextcloud/data/ -type f | wc -l

# 40 minutes
while read target source ; do
    if [ -f "$source" ] ; then
        ln -s "$source" "$target"
    fi
done < /tmp/user_file_list

# 20 minutes
while read target source ; do
    if [ -f "$source" ] ; then
        ln -s "$source" "$target"
    fi
done < /tmp/meta_file_list

Am Ende ergibt dies ein Verzeichnis mit (im Beispiel etwas über 2.3 Millionen) urn:oid:<nnnnn>-Dateien.

Das Python-Programm AWS CLI per Download installieren und konfigurieren (die Version in den Repos ist hoffnungslos veraltet):

dnf -y install unzip
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
./aws/install --bin-dir /usr/bin

aws configure --endpoint-url https://sos-ch-dk-2.exo.io

Dateien der Nextcloud-Benutzer hin zu S3 syncen:

cd /var/www/html/nextcloud/data/s3files

# 12.5 hours, ~ 5 GB/min
aws configure set s3.max_concurrent_requests 50
aws s3 sync . s3://bucket-name --endpoint-url https://sos-ch-dk-2.exo.io --color auto
rm -rf /var/www/html/nextcloud/data/s3files

Ging es bisher nur um den Sync, wird es ab hier ernst und die bestehende Nextcloud-Instanz tatsächlich geändert. Die einzelnen Schritte sollten vor der Ausführung unbedingt genau geprüft werden.

Datenbank-Backup bereithalten.

Datenbank aktualisieren und die Storage-Einträge auf den S3 zeigen lassen (im Beispiel auf den Bucket „bucket-name“):

mysql --user root --password --database nextcloud << EOF > use nextcloud;
    update oc_storages
    set id = concat('object::user:', substring(id from 7))
    where id like 'home::%';
    update oc_storages
    set id = 'object::store:amazon::bucket-name'
    where id like 'local::%';
EOF

Nextcloud-Konfiguration im Storage-Bereich auf S3 umkonfigurieren:

'objectstore' => array(
    'class' => 'OC\\Files\\ObjectStore\\S3',
        'arguments' => array(
        'autocreate' => true,
        'bucket' => 'bucket-name', // your bucket name
        'hostname' => 'sos-ch-dk-2.exo.io',
        'key'    => 'EXOmylittlekey', // your key
        'region' => 'ch-dk-2', // your region
        'secret' => 'mysupersecret', // your secret
        'use_ssl' => true,
    ),
),

Fertig. Testen.

Benutzer wieder ins System lassen:

sudo -u apache /var/www/html/nextcloud/occ maintenance:repair
sudo -u apache php /var/www/html/nextcloud/occ maintenance:mode --off

Inspiration dafür war https://pedal.me.uk/migrating-a-nextcloud-instance-to-amazon-s3/

Storage: External SMB/CIFS Storage

Ein optimales Setup braucht sowohl smbclient und libsmbclient-php. smbclient wird von occ external_storage:notify benötigt, libsmbclient-php wird von Nextcloud direkt verwendet. Unter CentOS:

yum install cifs-utils php-smbclient -y

Pro External Storage muss ein occ external_storage:notify gestartet werden. Dazu verwenden wir die nc-external-files-notify Skripte.

nc-external-files-notify.timer und nc-external-files-notify.service sollten falls möglich in das Monitoring aufgenommen werden.

nc-external-files-notify.timer
activestate: active
loadstate: loaded
substate: running, waiting
unitfilestate: enabled
nc-external-files-notify.service
activestate: active, inactive
loadstate: loaded
substate: running, dead
unitfilestate: disabled

LDAP

App LDAP user and group backend verwenden.

Tipp

Issue seit mind. 2017: wird ein LDAP-Zugang konfiguriert, werden wie erwartet die passenden Benutzer aus dem LDAP in der Nextcloud-Benutzerliste angezeigt. Später im AD/LDAP hinzugefügte Benutzer tauchen dann aber dort nicht mehr auf, obwohl sie bekannt sind und ein Login problemlos funktioniert. Möchte man jetzt die Eigenschaften der unauffindbaren/nicht gelisteten LDAP-Benutzer in Nextcloud anpassen, ruft man die Benutzerliste auf und nutzt die Nextcloud-Suche. Dabei erscheinen die bisher unsichtbaren Benutzer, und man kann wie gewohnt deren Eigenschaften wie beispielsweise deren Gruppenzugehörigkeit anpassen.

LDAP gegen FreeIPA konfigurieren

Server:

User DN: uid=freeipa-reader,cn=sysaccounts,cn=etc,dc=myorg,dc=tld Password: xxx Base DN: dc=myorg,dc=tld

Users - nur Benutzer aus der FreeIPA-Gruppe „nextcloud“ zulassen:

LDAP-Query: (&(objectclass=inetorgperson)(memberof=cn=nextcloud,cn=groups,cn=accounts,dc=myorg,dc=tld)) Advanced > Directory Settings > User Display Name Field: uid

Login Attributes:

LDAP / AD Username: yes LDAP / AD Email Address: yes

Test einer LDAP-Query mit ldapsearch:

dnf -y install openldap-clients
ldapsearch -v \
    -H ldap://freeipa \
    -D "uid=freeipa-reader,cn=sysaccounts,cn=etc,dc=myorg,dc=tld" \
    -W -x \
    --batch 'DC=myorg,DC=tld' \
    '(&(objectClass=inetorgperson)(memberOf=cn=nextcloud,cn=groups,cn=accounts,dc=myorg,dc=tld))'

Umgang mit OCC und LDAP auf der Kommandozeile:

ldap:check-user          checks whether a user exists on LDAP.
ldap:create-empty-config creates an empty LDAP configuration
ldap:delete-config       deletes an existing LDAP configuration
ldap:search              executes a user or group search
ldap:set-config          modifies an LDAP configuration
ldap:show-config         shows the LDAP configuration
ldap:show-remnants       shows which users are not available on LDAP anymore, but have remnants in Nextcloud.
ldap:test-config         tests an LDAP configuration
sudo -u apache /var/www/html/nextcloud/occ ldap:check-user "Markus Frei"
# user exists? then:
sudo -u apache /var/www/html/nextcloud/occ ldap:search "Markus Frei"

Um „remnant“-Benutzer zu löschen, regelmässig sudo -u apache php /var/www/html/nextcloud/occ user:delete <nextcloud name> (erste Spalte aus show-remnants) verwenden. Achtung: Man muss vor dem Löschen die Dateien einem anderen Benutzer zuweisen, sonst werden die Dateien des LDAP-Benutzers gelöscht.

Keycloak (oAuth, SAML)

Nextcloud-Seite

Es gibt drei Möglichkeiten - in unseren Tests hat Stand 2021-03 keine davon funktioniert:

  1. Nextcloud und Keycloak per SAML über die App SSO & SAML authentication verbinden (schon wegen SAML und dem Zertifikatshandling nicht zu empfehlen)

  2. Nextcloud und Keycloak per OpenID-Connect über die App Social Login verbinden. Unterstützt Roles, aber keine benutzerspezifischen Attribute.

  3. Nextcloud und Keycloak per OpenID-Connect über die App OpenID Connect Login verbinden. Unterstützt eigene User-Attribute wie „Quota“, aber keine Roles. Ist zudem nur über die config.php administrierbar.

Für die Nextcloud-App Social Login:

Damit sich Nextcloud über Keycloak authentifizieren kann, wird im Keycloak-Realm ein Client (hier „nextcloud“) und in Nextcloud die App „Social Login“ benötigt, womit OpenID-Connect/OAuth verwendet wird. Wer SAML bevorzugt, muss die App „SSO & SAML authentication“ installieren.

Konfiguration der „Social Login“-App:

  • [x] Prevent creating an account if the email address exists in another account

  • [x] Update user profile every login

  • [x] Restrict login for users without mapped groups

  • > Save

„Custom OpenID Connect“-Button klicken.

„Add group mapping“ anklicken.

  • users / users

Save.

Benutzer wählen > Role Mappings > Client Roles: nextcloud > Rolle zuweisen.

Siehe auch

Für die Nextcloud-App OpenID Connect Login

Siehe

Keycloak-Seite

Die Keycloak-Konfiguration hängt von der verwendeten Nextcloud-App ab.

Für die Nextcloud-App Social Login:

Neuer Client „nextcloud“ mit „openid-connect“ und Root URL „https://nextcloud.example.com“.

  • Clients > „nextcloud“ > Settings

    • Client ID: nextcloud

    • Client Protocol: openid-connect

    • Access Type: confidential

  • Clients > „nextcloud“ > Roles > Add Role

    • Role name: users

  • Clients > „nextcloud“ > Mappers > Add Builtin

    • „client roles“ auswählen > Add selected

  • Clients > „nextcloud“ > Mappers > „client roles“

    • Client ID: nextcloud

    • Token Claim Name: roles

    • Add to userinfo: ON

  • Clients > „nextcloud“ > Scope

    • Full Scope Allowed: OFF (This will ensure that only the client roles are stored in the token)

Sollen keine kryptische Benutzernamen in der Form „04f21d18-6176-11eb-a904-525400b49b22“ erzeugt werden, muss das sub-Property der userinfo per Mapper überschrieben werden:

  • Clients > „nextcloud“ > Mappers > Create

    • Name: sub

    • Mapper Type: User Prooperty

    • Property: username

    • Token Claim Name: sub

Siehe auch https://janikvonrotz.ch/2020/10/20/openid-connect-with-nextcloud-and-keycloak/.

Encryption in Nextcloud

Nextcloud bietet mehrere Verschlüsselungsebenen.

Transportverschlüsselung (TLS)

Schützt vor Lauschangriffen. Schützt nicht vor kompromittierten Geräten oder Servern.

Server Side Encryption (SSE) - Daten beim Speichern verschlüsseln

Optional. Jede Datei wird vor dem Speichern mit einem eindeutigen Schlüssel verschlüsselt - entweder serverweit (aus Funktions- und Leistungsgründen der Standard), oder einem Schlüssel pro Benutzer. SSE verschlüsselt nur den Inhalt der Dateien, nicht aber deren Namen oder Ordnerstruktur.

Server Side Encryption wurde ursprünglich eingeführt, um External Storage wie Dropbox und dergleichen sicher anbinden zu können: Nextcloud sorgt dann dafür, dass alle Daten ausserhalb des eigenen Standorts verschlüsselt gespeichert werden.

Der serverweite Schlüssel (technisch ein Passwort zum Entschlüsseln der Dateien) wird mit Hilfe des Secrets in der config.php verschlüsselt im Nextcloud-Datenverzeichnis abgelegt (und lässt sich im Desaster-Fall wiederherstellen).

Benutzerschlüssel liegen in den Datenverzeichnissen der einzelnen Benutzer und werden mit deren Benutzerkennwort verschlüsselt. Wird dieses Feature aktiviert, ist der Einsatz eines Online-Office (Collabora, OnlyOffice) nicht mehr möglich.

SSE schützt Dateien, solange die Dateiablage nicht auf dem gleichen System wie Nextcloud selbst liegt - eine auf ein lokales Datenverzeichnis angwendete SSE bietet wenn überhaupt nur geringen Schutz, schliesslich wird hier der Schlüssel zusammen mit den Daten gespeichert.

Stand 2021-04 „lügt“ die Web-Oberfläche noch: ist „Serverseitige Verschlüsselung“ aktiviert, meldet das eigene Benutzerprofil unter „Datenschutz“ ein „Deine Dateien sind mittels der serverseitigen Verschlüsselung verschlüsselt“ - egal ob „Benutzerverzeichnis verschlüsseln“ aktiviert wurde.

Fazit:

  • SSE macht Sinn, wenn die App External Storage angeboten wird, oder das Datenverzeichnis nicht auf dem gleichen System wie die Nextcloud-Installation selbst liegt.

  • Die Anwendung von SSE auf ein lokales Datenverzeichnis bringt keinen Sicherheitsvorteil (trügerische Sicherheit, die durch Meldungen unter „Datenschutz“ noch verstärkt werden).

  • Sollen Dateiinhalte vor dem Serverbetreiber verborgen werden, muss End-to-End-Encryption (E2E) zum Einsatz kommen.

End-to-End-Encryption (E2E, E2EE - Client-basierte Verschlüsselung)

Der ultimative Schutz der Benutzerdaten wird durch die Ende-zu-Ende-Verschlüsselung gewährleistet. Nur hier hat der Server niemals Zugriff auf Schlüssel oder unverschlüsselte Dateien. Der Sync-Client verschlüsselt die Daten vor dem Senden innerhalb des E2E-fähigen Ordners (jedoch nicht in darunterliegenden Ordnern).

Das geht nicht ohne Funktionsverlust: die Nextcloud-Weboberfläche kann die verschlüsselten Dateien nicht einsehen, der Sync-Client ist damit Pflicht. Eine öffentliche Freigabe oder Freigabe an Gruppen ist nicht möglich, die Suchmaschine kennt deren Inhalte nicht, und Collaboration per Online-Office funktioniert nicht.

E2E lässt sich für einen oder mehrere Ordner aktivieren. Der Inhalt jedes dieser Ordner wird vollständig vom Server ausgeblendet, einschließlich Dateinamen und Verzeichnisstruktur. Um die Daten mit anderen Geräten zu synchronisieren, müssen Benutzer eine vom ersten Gerät erstellte Mnemonic-Passphrase nutzen. Sobald dies erledigt ist, werden durchgängig verschlüsselte Ordner nahtlos zwischen Geräten synchronisiert. Nextcloud kann beispielsweise auch so konfiguriert werden, dass alle von der Finanzabteilung erstellten Dateien automatisch verschlüsselt werden.

Tipp

Die „Mnemonic-Passphrase“ ist ein aus 12 zufälligen, englischen Wörtern bestehendes Passwort. Die Mnemonic-Passphrase wird zur Verschlüsselung der Dateien verwendet - daher diese UNBEDINGT notieren und in einem Passwort-Manager speichern. Sollte man mehrere Nextcloud-Clients nutzen, wird man nach dieser Passphrase gefragt. Man kann sich die Passphrase im Client unter „Account > Show E2E mnemonic“ nochmals anzeigen lassen. Es wird ein Client >= v2.5.0 benötigt.

Kein Admin dieser Welt kann helfen, falls man die Passphrase vergessen oder nicht notiert hat.

So erhält man die Mnemonic-Passphrase:

  1. Nextcloud-Client in der neuesten Version installieren oder updaten (>= 2.5.0).

  2. Nextcloud-Client (erneut) mit dem Server verbinden. Es erscheint ein Popup mit der „Mnemonic Passphrase“. Passphrase notieren.

So verschlüsselt man einen Ordner:

  1. Einen neuen, leeren Ordner im lokalen Nextcloud-Verzeichnis anlegen.

  2. Nextcloud-Client öffnen, rechte Maustaste auf den Ordner und „Encrypt“ auswählen.

Das war’s. Dateien, die in diesen Ordnern landen, werden nur noch verschlüsselt auf einen Nextcloud-Server hochgeladen - uneinsehbar für den Rest der Welt. Es können beliebig viele Ordner verschlüsselt werden.

Das ist mit verschlüsselten Ordnern nicht mehr möglich:

  • Zugriff per Web-Interface

  • Freigabe an eine Gruppe

  • Freigabe auf Dateiebene

  • Serverseitige Suche oder Vorschau

  • Serverseitiger Papierkorb und Versionierung

E2E ist seit 2020-08 (NC19+) produktiv einsetzbar, davor galt E2E lange Jahre als „experimental“.

Die End-to-End-Verschlüsselung in Nextcloud schützt Benutzerdaten vor jedem Angriffsszenario, selbst im Falle einer unentdeckten Sicherheitslücke oder vor (nicht vertrauenswürdigen) Serverbetreibern.

Die Daten auf den Benutzergeräten selbst werden nicht geschützt, und der Diebstahl eines unverschlüsselten, entsperrten Benutzergeräts würde es einem Angreifer ermöglichen, auf private Schlüssel zuzugreifen.

Fazit:

  • E2E hat einen sehr spezifischen Anwendungsfall, die Einschränkungen sind nur bei sensiblen Daten sinnvoll.

  • Verliert ein Benutzer seine Mnemonic-Passphrase, sind auch die damit verschlüsselten Daten unweigerlich verloren.

Der gleichzeitige Betrieb von SSE mit lokal verschlüsseltem Benutzerverzeichnis und E2E ist zwar möglich, wird aber nicht unterstützt - beides zusammen wird zu technischen Problemen führen. Und egal welche der beiden Methoden zum Einsatz kommt: verschlüsselt werden nur Dateien. Kalender, ToDo-Listen und andere Daten werden nicht verschlüsselt, da es beispielsweise im Bereich CalDAV dafür an Clients fehlt, die dies unterstützen.

Hier finden sich noch einige Details: https://nextcloud.com/blog/encryption-in-nextcloud/.

Collabora und ODF vs OnlyOffice und OOXML

ODF vs OOXML

ODF ist das leichgewichtigere, offenere und von LibreOffice präferierte Format für Dokumente aller Art. Die Spezifikation für ODF 1.2 umfasst ca. 1’000 Seiten (ISO 26300). ODF-Spreadsheets werden beispielsweise als .ods gespeichert, Textdokumente als .odt. Einige Microsoft-Office-Funktionen lassen sich mit ODF nicht umsetzen, weshalb es durch die Redmonder nicht unterstützt wird.

Wenn die Microsoft-eigenen, mit Binärcode gespickten, XML-basierten Office-Formate .docx & Co. nicht zum Einsatz kommen, ist Office Open XML (OOXML) das von Microsoft Office präferierte Dokumentenformat, welches 2008 als ISO-Norm 29500 verabschiedet wurde und einen Umfang von ca. 6’000 Seiten aufweist. Es ist daher nicht vollständig implementiert; der Umfang ist hauptsächlich der MS-Office Rückwärtskompatibilität geschuldet.

Collabora vs OnlyOffice

Collabora ist quasi eine auf dem Server ausgeführte LibreOffice-Installation, für die der Browser mehr oder weniger nur das GUI anzeigt. Collabora orientiert sich bei Look & Feel also an LibreOffice und verarbeitet die Dokumente auf dem Server.

OnlyOffice hat den gegenteiligen Ansatz - es orientiert sich vom Aussehen her an MS-Office und verlagert das Document Processing auf den Client. Deren Document-Server stellt den Speicherplatz zur Verfügung und ist hier mehr für die kollaborative Kommunikation zuständig, der Grossteil der Applikation läuft dagegen im Browser.

In Collabora lässt sich bei der Erstellung einer Datei das Dateiformat frei wählen (ODF vs. OOXML), ODF wird aber wie bei LibreOffice klar präferiert. OnlyOffice bevorzugt dagegen Dokumente im OOXML-Format. Siehe https://www.onlyoffice.com/blog/2018/09/onlyffice-makes-it-easier-to-work-with-odf-in-integrated-solutions/.

OnlyOffice beherrscht das Freezing von Zeilen und Spalten, was für Collabora erst ab v6 angekündigt ist.

In einer Nextcloud-Instanz lassen sich beide Office-Suiten parallel nutzen. In diesem Fall werden Dokumente On-Click sofort in Collabora geöffnet; im Web-GUI ist OnlyOffice per Kontext-Menu (3 Punkte) verfügbar. In der Smartphone-App von Nextcloud ist das nicht der Fall, das Dokument kann nur mit OnlyOffice geöffnet werden.

Kommt in Nextcloud ausschliesslich Collabora zum Einsatz, wird es als Standard-Editor für sämtliche durch Collabora unterstützen Dateiformate benutzt. Bei OnlyOffice lässt sich in den Einstellung anpassen, welche Formate damit geöffnet werden sollen; per Kontext-Menu lassen sich damit trotzdem abgewählte Formate öffnen.

Ab Nextcloud Hub v18 wird zum ersten Mal OnlyOffice während der Nextcloud-Installation on demand installiert und integriert. OnlyOffice findet sich nicht im Nextcloud tarball/zip. Collabora wird (wie bis dato auch) per separater App angeboten oder dediziert und losgelöst von Nextcloud installiert. Ein klares Bekenntnis der Nextcloud-Macher zu OnlyOffice also. Für Verwirrung sorgte dann die Pressemitteilung von Collabora auf https://www.collaboraoffice.com/press-releases/collabora-online-as-default-in-nextcloud-hub/, dass ab Nextcloud Hub v19 Collabora das neue Default Web-Office-Paket ist.

Wohl auch durch die neu gewonnene Popularität hat OnlyOffice im Nextcloud-Umfeld recht schnell mit einigen „Known Issues“ auf sich aufmerksam gemacht, die einen negativen Einfluss auf die Funktion haben, siehe zum Beispiel https://github.com/nextcloud/documentserver_community/issues/100 und https://api.onlyoffice.com/editors/nextcloud#issue.

Die Features in der Übersicht:

Produkt

Preis

Edit auf Mobile

max. gleichz. geöffnete Dokumente

max. gleichz. Verbindungen

max. Benutzer

Collabora CODE

kostenlos

ja

10

20

k.A.

Collabora for SMBs

17€/User/Jahr

ja

k.A.

k.A.

99

Collabora for Enterprises

k.A.

ja

k.A.

k.A.

k.A.

OnlyOffice CE

kostenlos

view only

k.A.

20

bis 20

OnlyOffice Integration Edition Start

35€ pro Server-Lifetime, 1 Jahr Support & Updates

ja

k.A.

50

bis 50

OnlyOffice Integration Edition Standard

1870€ pro Server-Lifetime, 1 Jahr Support & Updates

ja

k.A.

100

bis 100

OnlyOffice Integration Edition Standard+

3740€ pro Server-Lifetime, 1 Jahr Support & Updates

ja

k.A.

200

bis 400

Siehe auch:

DB: Informationen zu Benutzern auslesen

Liste der E-Mail-Adressen aller Benutzer erhalten:

select json_extract(data, '$.email.value')
from oc_accounts;

Alle deaktivierten Benutzer auflisten (gilt nicht für LDAP):

select userid
from oc_preferences as p
left join oc_users as u on p.userid = u.uid
where p.appid = "core"
and p.configkey = "enabled"
and p.configvalue = "false"

E-Mail-Adressen aller aktivierten Benutzer auflisten (gilt nicht für LDAP):

select json_extract(data, '$.email.value')
from oc_accounts
where uid not in (
    select userid
    from oc_preferences as p
    left join oc_users as u on p.userid = u.uid
    where p.appid = "core"
    and p.configkey = "enabled"
    and p.configvalue = "false"
)

Wieviel Storage hat der Benutzer beansprucht, inkl. versionierten Dateien und Trash?

select s.id, size
from `oc_filecache` as f
inner join `oc_storages` as s on f.storage = s.numeric_id
where s.id = 'object::user:admin'
and f.parent = -1

Wieviel Storage hat der Benutzer ohne versionierte Dateien und ohne Trash beansprucht?

select s.id, size
from `oc_filecache` as f
inner join `oc_storages` as s on f.storage = s.numeric_id
where s.id = 'object::user:admin'
and path = 'files'

DB: Informationen zum Server auslesen

# databaseVersion
SELECT VERSION() AS version;

# databasePerfData
SHOW variables;
SHOW global status;

# databaseSize
SHOW databases;
SHOW TABLE STATUS FROM `databaseName`;
USE `databaseName`;

# getNumberOfActiveUsers in the last 5 minutes
SELECT count(*) as num_entries FROM oc_authtoken WHERE last_activity > UNIX_TIMESTAMP() - 300;

# countUserEntries
SELECT COUNT(*) as num_entries FROM oc_preferences WHERE configkey= "lastLogin";

# countHomeStorages
SELECT COUNT(*) as num_entries FROM oc_storages WHERE id like 'home::%';

# countLocalStorages
SELECT COUNT(*) as num_entries FROM oc_storages WHERE id like 'local::%';

# countOtherStorages
SELECT COUNT(*) as num_entries FROM oc_storages WHERE id not like 'home::%' and id not like 'local::%';

# getShareStatistics
SELECT COUNT(*) as num_entries, permissions, share_type FROM oc_share WHERE 1 GROUP BY permissions, share_type;

Nextcloud API

Das API verlangt, dass User-Credentials Base64-encoded werden. In python beispielsweise so:

credentials = base64.b64encode('api-user:api-password')
header = {
    'Authorization' : "Basic %s" % credentials,
    'OCS-APIRequest': 'true',
}

Grundlegende Statistiken ermitteln:

curl \
    -H 'Authorization: Basic bmV4dGNsbp3d0NIVQ==' \
    -H 'OCS-APIRequest: true' \
    http://localhost/nextcloud/ocs/v2.php/apps/serverinfo/api/v1/info?format=json

Security Scan

https://scan.nextcloud.com sucht nach folgenden PHP-Skripts, um die Daten zur gewünschten Instanz abzurufen:

  • /nextcloud/status.php

  • /status.php

  • /oc-shib/status.php (sollte im Idealfall nicht gefunden werden)

  • /oc/status.php (sollte im Idealfall nicht gefunden werden)

  • /owncloud/status.php (sollte im Idealfall nicht gefunden werden)

Auf der Kommandozeile geht das ganze so:

# in "data", set what to scan
curl --silent --request POST \
    --header 'Content-type: application/x-www-form-urlencoded' \
    --header 'X-CSRF: true' \
    --data 'url: cloud3.linuxfabrik.ch' \
    https://scan.nextcloud.com/api/queue | jq

# search for the returned Nextcloud UUID
# e.g. 558eccce-8aba-4717-850b-28d47cb84a16

curl --silent https://scan.nextcloud.com/api/result/558eccce-8aba-4717-850b-28d47cb84a16 | jq

Der Nextcloud-Client

Was fragt der Nextcloud-Client (User-Agent „mirall“, nutzt HTTP/1.1) in welcher Reihenfolge mit welcher Methode ab?

# first contact - if this fails, the client won't work at all
GET /status.php

# after that and round about every 30 seconds at least this:
PROPFIND /remote.php/dav/files/username/
GET /ocs/v1.php/cloud/user?format=json
GET /remote.php/dav/avatars/username/128.png

Built on 2022-06-03