diff --git a/consul/configuration/.gitignore b/consul/configuration/.gitignore index dabb84d..056b4d2 100644 --- a/consul/configuration/.gitignore +++ b/consul/configuration/.gitignore @@ -29,3 +29,5 @@ !directory/*/* !traefik/traefik.toml + +!garage/config.toml diff --git a/consul/configuration/directory/bottin/config.json b/consul/configuration/directory/bottin/config.json index 27351f4..c30a4d5 100644 --- a/consul/configuration/directory/bottin/config.json +++ b/consul/configuration/directory/bottin/config.json @@ -22,6 +22,8 @@ "*,ou=invitations,dc=deuxfleurs,dc=fr::modifyAdd:cn=email,ou=groups,dc=deuxfleurs,dc=fr:*", "*:cn=asso_deuxfleurs,ou=groups,dc=deuxfleurs,dc=fr:modifyAdd:cn=seafile,ou=groups,dc=deuxfleurs,dc=fr:*", "*,ou=invitations,dc=deuxfleurs,dc=fr::modifyAdd:cn=seafile,ou=groups,dc=deuxfleurs,dc=fr:*", + "*:cn=asso_deuxfleurs,ou=groups,dc=deuxfleurs,dc=fr:modifyAdd:cn=nextcloud,ou=groups,dc=deuxfleurs,dc=fr:*", + "*,ou=invitations,dc=deuxfleurs,dc=fr::modifyAdd:cn=seafile,ou=nextcloud,dc=deuxfleurs,dc=fr:*", "cn=admin,dc=deuxfleurs,dc=fr::read add modify delete:*:*", "*:cn=admin,ou=groups,dc=deuxfleurs,dc=fr:read add modify delete:*:*" diff --git a/consul/configuration/directory/guichet/config.json.tpl b/consul/configuration/directory/guichet/config.json.tpl index ce34f98..98e2297 100644 --- a/consul/configuration/directory/guichet/config.json.tpl +++ b/consul/configuration/directory/guichet/config.json.tpl @@ -13,7 +13,8 @@ "invited_mail_format": "{}@deuxfleurs.fr", "invited_auto_groups": [ "cn=email,ou=groups,dc=deuxfleurs,dc=fr", - "cn=seafile,ou=groups,dc=deuxfleurs,dc=fr" + "cn=seafile,ou=groups,dc=deuxfleurs,dc=fr", + "cn=nextcloud,ou=groups,dc=deuxfleurs,dc=fr" ], "web_address": "https://guichet.deuxfleurs.fr", diff --git a/consul/configuration/nextcloud/config.php.tpl b/consul/configuration/nextcloud/config.php.tpl new file mode 100644 index 0000000..7dcfc6e --- /dev/null +++ b/consul/configuration/nextcloud/config.php.tpl @@ -0,0 +1,49 @@ + false, + 'instanceid' => '{{ key "secrets/nextcloud/instance_id" | trimSpace }}', + 'passwordsalt' => '{{ key "secrets/nextcloud/password_salt" | trimSpace }}', + 'secret' => '{{ key "secrets/nextcloud/secret" | trimSpace }}', + 'trusted_domains' => array ( + 0 => 'nextcloud.deuxfleurs.fr', + ), + 'memcache.local' => '\\OC\\Memcache\\APCu', + + 'objectstore' => array( + 'class' => '\\OC\\Files\\ObjectStore\\S3', + 'arguments' => array( + 'bucket' => 'nextcloud', + 'autocreate' => false, + 'key' => '{{ key "secrets/nextcloud/garage_access_key" | trimSpace }}', + 'secret' => '{{ key "secrets/nextcloud/garage_secret_key" | trimSpace }}', + 'hostname' => 'garage.deuxfleurs.fr', + 'port' => 443, + 'use_ssl' => true, + 'region' => 'garage', + // required for some non Amazon S3 implementations + 'use_path_style' => true + ), + ), + + 'dbtype' => 'pgsql', + 'dbhost' => 'psql-proxy.service.2.cluster.deuxfleurs.fr', + 'dbname' => 'nextcloud', + 'dbtableprefix' => 'nc_', + 'dbuser' => '{{ key "secrets/nextcloud/db_user" | trimSpace }}', + 'dbpassword' => '{{ key "secrets/nextcloud/db_pass" | trimSpace }}', + + 'default_language' => 'fr', + 'default_locale' => 'fr_FR', + + 'mail_domain' => 'deuxfleurs.fr', + 'mail_from_address' => 'nextcloud@deuxfleurs.fr', + // TODO SMTP CONFIG + + // TODO REDIS CACHE + + 'version' => '19.0.0.12', + 'overwrite.cli.url' => 'https://nextcloud.deuxfleurs.fr', + + 'installed' => true, +); + diff --git a/docker/nextcloud/Dockerfile b/docker/nextcloud/Dockerfile new file mode 100644 index 0000000..9f817f6 --- /dev/null +++ b/docker/nextcloud/Dockerfile @@ -0,0 +1,27 @@ +FROM debian:10 + +RUN apt-get update && \ + apt-get -qq -y full-upgrade + +RUN apt-get install -y apache2 php php-gd php-mbstring php-pgsql php-curl php-dom php-xml php-zip \ + php-intl php-ldap php-fileinfo php-exif php-apcu php-redis php-imagick unzip curl wget && \ + phpenmod gd && \ + phpenmod curl && \ + phpenmod mbstring && \ + phpenmod pgsql && \ + phpenmod dom && \ + phpenmod zip && \ + phpenmod intl && \ + phpenmod ldap && \ + phpenmod fileinfo && \ + phpenmod exif && \ + phpenmod apcu && \ + phpenmod redis && \ + phpenmod imagick && \ + phpenmod xml + +COPY container-setup.sh /tmp +RUN /tmp/container-setup.sh + +COPY entrypoint.sh / +CMD /entrypoint.sh diff --git a/docker/nextcloud/container-setup.sh b/docker/nextcloud/container-setup.sh new file mode 100755 index 0000000..8330291 --- /dev/null +++ b/docker/nextcloud/container-setup.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +set -ex + +curl https://download.nextcloud.com/server/releases/nextcloud-19.0.0.zip > /tmp/nextcloud.zip +cd /var/www +unzip /tmp/nextcloud.zip +rm /tmp/nextcloud.zip +mv html html.old +mv nextcloud html + +cd html +mkdir data + +cd apps +wget https://github.com/nextcloud/tasks/releases/download/v0.13.1/tasks.tar.gz +tar xf tasks.tar.gz +wget https://github.com/nextcloud/maps/releases/download/v0.1.6/maps-0.1.6.tar.gz +tar xf maps-0.1.6.tar.gz +wget https://github.com/nextcloud/calendar/releases/download/v2.0.3/calendar.tar.gz +tar xf calendar.tar.gz +wget https://github.com/nextcloud/news/releases/download/14.1.11/news.tar.gz +tar xf news.tar.gz +wget https://github.com/nextcloud/notes/releases/download/v3.6.0/notes.tar.gz +tar xf notes.tar.gz +wget https://github.com/nextcloud/contacts/releases/download/v3.3.0/contacts.tar.gz +tar xf contacts.tar.gz +wget https://github.com/nextcloud/mail/releases/download/v1.4.0/mail.tar.gz +tar xf mail.tar.gz +wget https://github.com/nextcloud/groupfolders/releases/download/v6.0.6/groupfolders.tar.gz +tar xf groupfolders.tar.gz +rm *.tar.gz + +chown -R www-data:www-data /var/www/html + +cd /var/www/html +php occ diff --git a/docker/nextcloud/entrypoint.sh b/docker/nextcloud/entrypoint.sh new file mode 100755 index 0000000..72b4f94 --- /dev/null +++ b/docker/nextcloud/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +set -xe + +chown www-data:www-data /var/www/html/config/config.php +touch /var/www/html/data/.ocdata + +exec apachectl -DFOREGROUND diff --git a/man/nextcloud/README.md b/man/nextcloud/README.md new file mode 100644 index 0000000..f68520b --- /dev/null +++ b/man/nextcloud/README.md @@ -0,0 +1,60 @@ +# How to setup NextCloud + +## First setup + +It's complicated. + +First, create a service user `nextcloud` and a database `nextcloud` it owns. Also create a Garage access key and bucket `nextcloud` it is allowed to use. + +Fill in the following Consul keys with actual values: + +``` +secrets/nextcloud/db_user +secrets/nextcloud/db_pass +secrets/nextcloud/garage_access_key +secrets/nextcloud/garage_secret_key +``` + +Create the following Consul keys with empty values: + +``` +secrets/nextcloud/instance_id +secrets/nextcloud/password_salt +secrets/nextcloud/secret +``` + +Start the nextcloud.hcl nomad service. Enter the container and call `occ maintenance:install` with the correct database parameters as user `www-data`. +A possibility: call the admin user `nextcloud` and give it the same password as the `nextcloud` service user. + +Cat the newly generated `config.php` file and copy the instance id, password salt, and secret from there to Consul +(they were generated by the install script and we want to keep them). + +Restart the Nextcloud Nomad server. + +You should now be able to log in to Nextcloud using the admin user (`nextcloud` if you called it that). + +Go to the apps settings and enable desired apps. + +## Configure LDAP login + +LDAP login has to be configured from the admin interface. First, enable the LDAP authentification application. + +Go to settings > LDAP/AD integration. Enter the following parameters: + +- ldap server: `bottin2.service.2.cluster.deuxfleurs.fr` +- bind user: `cn=nextcloud,ou=services,ou=users,dc=deuxfleurs,dc=fr` +- bind password: password of the nextcloud service user +- base DN for users: `ou=users,dc=deuxfleurs,dc=fr` +- check "manually enter LDAP filters" +- in the users tab, edit LDAP query and set it to `(&(|(objectclass=inetOrgPerson))(|(memberof=cn=nextcloud,ou=groups,dc=deuxfleurs,dc=fr)))` +- in the login attributes tab, edit LDAP query and set it to `(&(&(|(objectclass=inetOrgPerson))(|(memberof=cn=nextcloud,ou=groups,dc=deuxfleurs,dc=fr)))(|(|(mailPrimaryAddress=%uid)(mail=%uid))(|(cn=%uid))))` +- in the groups tab, edit the LDAP query and set it to `(|(objectclass=groupOfNames))` +- in the advanced tab, enter the "directory setting" section and check/modify the following: + - user display name field: `displayname` + - base user tree: `ou=users,dc=deuxfleurs,dc=fr` + - user search attribute: `cn` + - groupe display name field: `displayname` + - **base group tree**: `ou=groups,dc=deuxfleurs,dc=fr` + - group search attribute: `cn` + +That should be it. Go to the login attributes tab and enter a username (which should have been added to the nextcloud group) to check that nextcloud is able to find it and allows it for login. diff --git a/nomad/garage.hcl b/nomad/garage.hcl new file mode 100644 index 0000000..923d393 --- /dev/null +++ b/nomad/garage.hcl @@ -0,0 +1,99 @@ +job "garage" { + datacenters = ["dc1", "belair", "saturne"] + type = "system" + + constraint { + attribute = "${attr.cpu.arch}" + value = "amd64" + } + + group "garage" { + task "server" { + driver = "docker" + config { + image = "lxpz/garage_amd64:3" + port_map { + rpc_port = 3901 + api_port = 3900 + } + volumes = [ + "/mnt/storage/garage/data:/garage/data", + "/mnt/ssd/garage/meta:/garage/meta", + "secrets/garage.toml:/garage/config.toml", + "secrets/garage-ca.crt:/garage/garage-ca.crt", + "secrets/garage.crt:/garage/garage.crt", + "secrets/garage.key:/garage/garage.key", + ] + } + + template { + data = "{{ key \"configuration/garage/garage.toml\" }}" + destination = "secrets/garage.toml" + } + template { + data = "{{ key \"secrets/garage/garage-ca.crt\" }}" + destination = "secrets/garage-ca.crt" + } + template { + data = "{{ key \"secrets/garage/garage.crt\" }}" + destination = "secrets/garage.crt" + } + template { + data = "{{ key \"secrets/garage/garage.key\" }}" + destination = "secrets/garage.key" + } + + resources { + memory = 500 + cpu = 2000 + network { + port "rpc_port" { + static = "3901" + } + port "api_port" {} + } + } + + service { + tags = [ + "garage_api", + "traefik.enable=true", + "traefik.frontend.entryPoints=https,http", + "traefik.frontend.rule=Host:garage.deuxfleurs.fr" + ] + port = "api_port" + address_mode = "host" + name = "garage-api" + check { + type = "tcp" + port = "api_port" + interval = "60s" + timeout = "5s" + check_restart { + limit = 3 + grace = "90s" + ignore_warnings = false + } + } + } + + service { + tags = ["garage-rpc"] + port = "rpc_port" + address_mode = "host" + name = "garage-rpc" + check { + type = "tcp" + port = "rpc_port" + interval = "60s" + timeout = "5s" + check_restart { + limit = 3 + grace = "90s" + ignore_warnings = false + } + } + } + } + } +} diff --git a/nomad/nextcloud.hcl b/nomad/nextcloud.hcl new file mode 100644 index 0000000..2cc4f5f --- /dev/null +++ b/nomad/nextcloud.hcl @@ -0,0 +1,67 @@ +job "nextcloud" { + datacenters = ["dc1", "belair"] + type = "service" + + constraint { + attribute = "${attr.cpu.arch}" + value = "amd64" + } + + group "nextcloud" { + count = 1 + task "nextcloud" { + driver = "docker" + config { + image = "lxpz/deuxfleurs_nextcloud_amd64:8" + port_map { + web_port = 80 + } + volumes = [ + "secrets/config.php:/var/www/html/config/config.php" + ] + } + + artifact { + source = "http://127.0.0.1:8500/v1/kv/configuration/nextcloud/config.php.tpl?raw" + destination = "secrets/config.php.tpl" + mode = "file" + } + template { + source = "secrets/config.php.tpl" + destination = "secrets/config.php" + } + + resources { + memory = 1000 + cpu = 2000 + network { + port "web_port" {} + } + } + + service { + name = "nextcloud" + tags = [ + "nextcloud", + "traefik.enable=true", + "traefik.frontend.entryPoints=https,http", + "traefik.frontend.rule=Host:nextcloud.deuxfleurs.fr", + ] + port = "web_port" + address_mode = "host" + check { + type = "tcp" + port = "web_port" + interval = "60s" + timeout = "5s" + check_restart { + limit = 3 + grace = "90s" + ignore_warnings = false + } + } + } + } + } +} +