Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ INSECURE=true
#COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:traefik/opencloud.yml:traefik/collabora.yml:idm/ldap-keycloak.yml:traefik/ldap-keycloak.yml
# External IDP
#COMPOSE_FILE=docker-compose.yml:weboffice/collabora.yml:traefik/opencloud.yml:traefik/collabora.yml:idm/external-idp.yml
# Authelia + LLDAP Shared User Directory
#COMPOSE_FILE=docker-compose.yml:traefik/opencloud.yml:idm/authelia-lldap.yml:traefik/authelia-lldap.yml
# External Authelia
#COMPOSE_FILE=docker-compose.yml:traefik/opencloud.yml:idm/external-authelia.yml

## Traefik Settings ##
# Note: Traefik is always enabled and can't be disabled.
Expand Down Expand Up @@ -330,6 +334,40 @@ KC_DB_USERNAME=
# Keycloak Database password. Defaults to "keycloak".
KC_DB_PASSWORD=

## Authelia + LLDAP ##
# Use together with idm/authelia-lldap.yml and traefik/authelia-lldap.yml
# Domain for the Authelia authentication portal. Defaults to "auth.opencloud.test".
AUTHELIA_DOMAIN=
# Domain for the LLDAP web admin interface. Defaults to "lldap.opencloud.test".
LLDAP_DOMAIN=
# Admin password for LLDAP (and used by Authelia to query LDAP).
# NOTE: This variable needs to be set before the first start. Changes after first start will be IGNORED.
LLDAP_ADMIN_PASSWORD=
# JWT secret used by LLDAP to sign session tokens.
# Generate with: openssl rand -hex 32
LLDAP_JWT_SECRET=
# Secret used by Authelia for JWT-based password reset tokens.
# Generate with: openssl rand -hex 32
AUTHELIA_JWT_SECRET=
# Secret used by Authelia to encrypt the session cookie.
# Generate with: openssl rand -hex 32
AUTHELIA_SESSION_SECRET=
# Secret used by Authelia to encrypt the SQLite database.
# Generate with: openssl rand -hex 32
AUTHELIA_STORAGE_ENCRYPTION_KEY=
# HMAC secret used by Authelia to sign OIDC tokens.
# Generate with: openssl rand -hex 32
AUTHELIA_OIDC_HMAC_SECRET=

## External Authelia ##
# Use together with idm/external-authelia.yml when you already have a running Authelia instance.
# Domain of your external Authelia instance (without https://).
# Example: "auth.example.com"
#IDP_DOMAIN=
# Full Authelia base URL used as the OIDC issuer.
# Example: "https://auth.example.com"
#IDP_ISSUER_URL=

## Demo Users ##
# Enable demo users and groups in the shared LDAP directory.
# To enable, create custom/ldap-keycloak-demo-users.yml with:
Expand Down
72 changes: 72 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,78 @@ This setup includes:
- Shared LDAP server as a user directory with demo users and groups
- Integration with Keycloak using OpenCloud clients (`web`, `OpenCloudDesktop`, `OpenCloudAndroid`, `OpenCloudIOS`)

### With Authelia and LLDAP

OpenCloud can be deployed with [Authelia](https://www.authelia.com/) as the authentication portal and [LLDAP](https://github.com/lldap/lldap) as a lightweight LDAP user directory:

> **DNS Requirements**: This setup requires DNS entries for the OpenCloud domain, the Authelia domain, and the LLDAP admin domain. Configure DNS A/AAAA records (e.g., `cloud.example.com`, `auth.example.com`, `lldap.example.com`) or use a wildcard DNS entry (`*.example.com`).

Using `-f` flags:
```bash
docker compose -f docker-compose.yml -f idm/authelia-lldap.yml -f traefik/opencloud.yml -f traefik/authelia-lldap.yml up -d
```

Or by setting in `.env`:
```
COMPOSE_FILE=docker-compose.yml:idm/authelia-lldap.yml:traefik/opencloud.yml:traefik/authelia-lldap.yml
```

Configure the required secrets in your `.env` file (generate each with `openssl rand -hex 32`):
```ini
AUTHELIA_DOMAIN=auth.example.com
LLDAP_DOMAIN=lldap.example.com
LLDAP_ADMIN_PASSWORD=your_lldap_admin_password
LLDAP_JWT_SECRET=
AUTHELIA_JWT_SECRET=
AUTHELIA_SESSION_SECRET=
AUTHELIA_STORAGE_ENCRYPTION_KEY=
AUTHELIA_OIDC_HMAC_SECRET=
```

> **For local development only**: Add to `/etc/hosts`:
> ```
> 127.0.0.1 auth.opencloud.test
> 127.0.0.1 lldap.opencloud.test
> ```

This setup includes:
- Authelia as a self-hosted authentication portal with 2FA (TOTP and WebAuthn)
- LLDAP as a lightweight LDAP server for managing users and groups
- Redis session persistence
- OIDC integration with OpenCloud web, desktop, iOS, and Android clients

**First-time admin setup:**

Before starting, you must create at least one user in LLDAP. After the stack is up, navigate to `https://lldap.example.com` (or `http://localhost:17170` if using the external proxy variant) and:

1. Log in with `admin` and the `LLDAP_ADMIN_PASSWORD` you set
2. Create a group named `opencloud-admin`
3. Create your admin user and add them to the `opencloud-admin` group

Then follow the role-assignment bootstrap steps described in `idm/authelia-lldap.yml` to enable the OIDC role mapping: uncomment and adjust the block at the top of `config/opencloud/proxy.yaml`, setting `claim_value` to your admin group name.

**OIDC JWKS key**: The RSA private key used to sign OIDC tokens is automatically generated on first startup and persisted in the `authelia-config` Docker volume. No manual key generation is required.

### With External Authelia

If you already have a running Authelia instance, use the external variant. Configure your Authelia instance with the OIDC clients from `config/authelia/configuration.dist.yml` and point OpenCloud at it:

Using `-f` flags:
```bash
docker compose -f docker-compose.yml -f idm/external-authelia.yml -f traefik/opencloud.yml up -d
```

Or by setting in `.env`:
```
COMPOSE_FILE=docker-compose.yml:idm/external-authelia.yml:traefik/opencloud.yml
```

Set in `.env`:
```ini
IDP_DOMAIN=auth.example.com
IDP_ISSUER_URL=https://auth.example.com
```

### With Collabora Online

Include Collabora for document editing using either method:
Expand Down
181 changes: 181 additions & 0 deletions config/authelia/configuration.dist.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
---
# Authelia configuration template for OpenCloud + LLDAP integration.
# This file is processed by Authelia's Go template engine (X_AUTHELIA_CONFIG_FILTERS=template).
# Environment variables referenced here are passed into the authelia container.

theme: auto
default_2fa_method: totp

server:
address: tcp://0.0.0.0:9091/

log:
level: warn

totp:
disable: false
issuer: '{{ env "AUTHELIA_DOMAIN" }}'

webauthn:
disable: false
timeout: 60s
attestation_conveyance_preference: indirect
user_verification: preferred

authentication_backend:
ldap:
implementation: lldap
address: 'ldap://lldap:3890'
base_dn: 'dc=opencloud,dc=eu'
user: 'uid=admin,ou=people,dc=opencloud,dc=eu'
password: '{{ env "LLDAP_ADMIN_PASSWORD" }}'

access_control:
default_policy: two_factor

session:
name: authelia_session
cookies:
- domain: '{{ env "AUTHELIA_DOMAIN" }}'
authelia_url: 'https://{{ env "AUTHELIA_DOMAIN" }}'
expiration: 24h
inactivity: 24h
remember_me_duration: 30d
redis:
host: redis
port: 6379

regulation:
max_retries: 3
find_time: 2m
ban_time: 5m

storage:
local:
path: /config/db.sqlite3

notifier:
filesystem:
filename: /config/notifications.txt

identity_providers:
oidc:
lifespans:
access_token: 1d
refresh_token: 30d
jwks:
- key_id: opencloud
algorithm: RS256
use: sig
key: |
{{ secret "/config/secrets/oidc_jwks.pem" | mindent 10 "|" | msquote }}
cors:
endpoints:
- authorization
- token
- revocation
- introspection
- userinfo
allowed_origins:
- 'https://{{ env "OC_DOMAIN" }}'
allowed_origins_from_client_redirect_uris: false
clients:
- client_id: web
client_name: OpenCloud Web
public: true
authorization_policy: two_factor
consent_mode: auto
pre_configured_consent_duration: 1w
scopes:
- openid
- email
- profile
- groups
- offline_access
redirect_uris:
- 'https://{{ env "OC_DOMAIN" }}/'
- 'https://{{ env "OC_DOMAIN" }}/oidc-callback.html'
- 'https://{{ env "OC_DOMAIN" }}/oidc-silent-redirect.html'
grant_types:
- refresh_token
- authorization_code
response_types:
- code
response_modes:
- form_post
- query
- fragment
userinfo_signed_response_alg: none

- client_id: OpenCloudDesktop
client_name: OpenCloud Desktop Client
public: true
authorization_policy: one_factor
consent_mode: auto
pre_configured_consent_duration: 1w
scopes:
- openid
- groups
- profile
- email
- offline_access
redirect_uris:
- http://127.0.0.1
grant_types:
- refresh_token
- authorization_code
response_types:
- code
response_modes:
- form_post
userinfo_signed_response_alg: none

- client_id: OpenCloudIOS
client_name: OpenCloud iOS Client
public: true
authorization_policy: one_factor
consent_mode: auto
pre_configured_consent_duration: 1w
allow_multiple_auth_methods: true
scopes:
- openid
- groups
- profile
- email
- offline_access
redirect_uris:
- oc://ios.opencloud.eu
grant_types:
- refresh_token
- authorization_code
response_types:
- code
response_modes:
- form_post
- query
userinfo_signed_response_alg: none

- client_id: OpenCloudAndroid
client_name: OpenCloud Android Client
public: true
authorization_policy: one_factor
consent_mode: auto
pre_configured_consent_duration: 1w
allow_multiple_auth_methods: true
scopes:
- openid
- groups
- profile
- email
- offline_access
redirect_uris:
- oc://android.opencloud.eu
grant_types:
- refresh_token
- authorization_code
response_types:
- code
response_modes:
- form_post
- query
userinfo_signed_response_alg: none
18 changes: 18 additions & 0 deletions config/authelia/docker-entrypoint-override.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#!/bin/sh
set -e

SECRETS_DIR=/config/secrets
JWKS_KEY="${SECRETS_DIR}/oidc_jwks.pem"

mkdir -p "${SECRETS_DIR}"

# Auto-generate the OIDC JWKS RSA private key on first startup if not present.
# Authelia uses this key to sign OIDC identity tokens.
if [ ! -f "${JWKS_KEY}" ]; then
echo "Generating OIDC JWKS RSA private key..."
openssl genrsa -out "${JWKS_KEY}" 4096
echo "OIDC JWKS RSA key generated at ${JWKS_KEY}"
fi

# Hand off to the default Authelia entrypoint
exec authelia "$@"
14 changes: 14 additions & 0 deletions config/opencloud/proxy.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
# Role assignment via OIDC groups (Authelia / external IdP)
# Uncomment and configure the section below to map a group from your IdP to an OpenCloud role.
# This is needed when using idm/authelia-lldap.yml or idm/external-authelia.yml.
# See the bootstrap instructions in idm/authelia-lldap.yml for the full setup procedure.
#
# proxy:
# role_assignment:
# driver: oidc
# oidc_role_mapper:
# role_claim: groups
# role_mapping:
# - role_name: admin # OpenCloud role name
# claim_value: opencloud-admin # group name in LLDAP / your IdP

# This adds four additional routes to the proxy. Forwarding
# request on '/carddav/', '/caldav/' and the respective '/.well-knwown'
# endpoints to the radicale container and setting the required headers.
Expand Down
11 changes: 11 additions & 0 deletions external-proxy/authelia-exposed.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
# only expose the ports when you know what you are doing!
services:
authelia:
ports:
# expose the authelia portal on all interfaces
- "0.0.0.0:9091:9091"
lldap:
ports:
# expose the LLDAP web UI on all interfaces
- "0.0.0.0:17170:17170"
10 changes: 10 additions & 0 deletions external-proxy/authelia.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
services:
authelia:
ports:
# expose the authelia portal on localhost
- "127.0.0.1:9091:9091"
lldap:
ports:
# expose the LLDAP web UI on localhost
- "127.0.0.1:17170:17170"
Loading