Installation
Warning
Both provided installation options serve as templates for productive use only. Even though they can run out of the box, they will need proper configuration for the requirements of the environment they will be installed in. This includes additional hardening and security measures.
Docker Compose
SecObserve provides 2 Docker Compose files as templates for productive use: docker-compose-prod-mysql.yml and docker-compose-prod-postgres.yml. Both start Traefik as an edge router as well as the SecObserve frontend and backend plus a database (either MySQL or PostgreSQL).
Without any changes to the Docker Compose file, 3 URL's are available:
- Frontend: http://secobserve.localhost
- Backend: http://secobserve-backend.localhost (base URL)
- Traefik: http://traefik.localhost (dashboard)
name: "secobserve_prod"
volumes:
prod_postgres_data:
networks:
traefik:
database:
services:
traefik:
image: "traefik:v3.6.1"
container_name: "prod_traefik"
command:
- "--log.level=INFO"
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=secobserve_prod_traefik"
- "--entrypoints.web.address=:80"
labels:
- "traefik.enable=true"
# - "traefik.http.middlewares.traefik-ipallowlist.ipallowlist.sourcerange=172.18.0.1/24"
# - "traefik.http.routers.api.middlewares=traefik-ipallowlist@docker"
- "traefik.http.routers.api.entrypoints=web"
- "traefik.http.routers.api.rule=Host(`traefik.localhost`)"
- "traefik.http.routers.api.service=api@internal"
ports:
- "80:80"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock:ro"
networks:
- default
- traefik
frontend:
image: ghcr.io/secobserve/secobserve-frontend:1.42.0
container_name: "prod_secobserve_frontend"
labels:
- "traefik.enable=true"
- "traefik.http.routers.frontend.rule=Host(`secobserve.localhost`)"
- "traefik.http.routers.frontend.entrypoints=web"
- "traefik.http.services.frontend.loadbalancer.server.port=3000"
environment:
API_BASE_URL: ${SO_API_BASE_URL:-http://secobserve-backend.localhost/api}
OIDC_ENABLE: ${SO_OIDC_ENABLE:-false}
OIDC_AUTHORITY: ${SO_OIDC_AUTHORITY:-dummy}
OIDC_CLIENT_ID: ${SO_OIDC_CLIENT_ID:-dummy}
OIDC_REDIRECT_URI: ${SO_OIDC_REDIRECT_URI:-http://secobserve.localhost}
OIDC_POST_LOGOUT_REDIRECT_URI: ${SO_OIDC_POST_LOGOUT_REDIRECT_URI:-http://secobserve.localhost}
OIDC_SCOPE: ${SO_OIDC_SCOPE:-openid profile email}
networks:
- traefik
backend:
image: ghcr.io/secobserve/secobserve-backend:1.42.0
container_name: "prod_secobserve_backend"
labels:
- "traefik.enable=true"
- "traefik.http.routers.backend.rule=Host(`secobserve-backend.localhost`)"
- "traefik.http.routers.backend.entrypoints=web"
depends_on:
- postgres
environment:
# --- Admin user ---
ADMIN_USER: ${SO_ADMIN_USER:-admin}
ADMIN_PASSWORD: ${SO_ADMIN_PASSWORD:-admin}
ADMIN_EMAIL: ${SO_ADMIN_EMAIL:-admin@example.com}
# --- Gunicorn ---
GUNICORN_WORKERS: ${SO_GUNICORN_WORKERS:-3}
GUNICORN_THREADS: ${SO_GUNICORN_THREADS:-10}
GUNICORN_LIMIT_REQUEST_FIELD_SIZE: ${SO_GUNICORN_LIMIT_REQUEST_FIELD_SIZE:-16380}
# --- Database ---
DATABASE_ENGINE: ${SO_DATABASE_ENGINE:-django.db.backends.postgresql}
DATABASE_HOST: ${SO_DATABASE_HOST:-postgres}
DATABASE_PORT: ${SO_DATABASE_PORT:-5432}
DATABASE_DB: ${SO_DATABASE_DB:-secobserve}
DATABASE_USER: ${SO_DATABASE_USER:-secobserve}
DATABASE_PASSWORD: ${SO_DATABASE_PASSWORD:-secobserve}
# --- Security ---
ALLOWED_HOSTS: ${SO_ALLOWED_HOSTS:-secobserve-backend.localhost}
CORS_ALLOWED_ORIGINS: ${SO_CORS_ALLOWED_ORIGINS:-http://secobserve.localhost}
DJANGO_SECRET_KEY: ${SO_DJANGO_SECRET_KEY:-NxYPEF5lNGgk3yonndjSbwP77uNJxOvfKTjF5aVBqsHktNlf1wfJHHvJ8iifk32r}
FIELD_ENCRYPTION_KEY: ${SO_FIELD_ENCRYPTION_KEY:-DtlkqVb3wlaVdJK_BU-3mB4wwuuf8xx8YNInajiJ7GU=}
# --- OpenID Connect ---
OIDC_AUTHORITY: ${SO_OIDC_AUTHORITY:-}
OIDC_CLIENT_ID: ${SO_OIDC_CLIENT_ID:-}
OIDC_USERNAME: ${SO_OIDC_USERNAME:-}
OIDC_FIRST_NAME: ${SO_OIDC_FIRST_NAME:-}
OIDC_LAST_NAME: ${SO_OIDC_LAST_NAME:-}
OIDC_FULL_NAME: ${SO_OIDC_FULL_NAME:-}
OIDC_EMAIL: ${SO_OIDC_EMAIL:-}
OIDC_GROUPS: ${SO_OIDC_GROUPS:-}
networks:
- traefik
- database
postgres:
image: postgres:15.15-alpine
container_name: "prod_postgres"
environment:
POSTGRES_DB: ${SO_POSTGRES_DB:-secobserve}
POSTGRES_USER: ${SO_POSTGRES_USER:-secobserve}
POSTGRES_PASSWORD: ${SO_POSTGRES_PASSWORD:-secobserve}
volumes:
- prod_postgres_data:/var/lib/postgresql/data
networks:
- database
Configuration for Traefik
- The Traefik dashboard should either be configured with authentication or disabled, see The Dashboard.
- Encrypted communiction should be configured for frontend and backend. Traefik supports given certificates and automatic configuration with Let's Encrypt, see HTTPS & TLS.
Configuration for SecObserve
The Docker Compose file sets default values for the SecObserve configuration, so that the containers can run out of the box. All default values can be overriden, by setting respective environment variables in the shell before starting Docker Compose. To avoid name collisions, the environment variables in the shell need to have a SO_ prefix in front of the name as it is stated in Configuration.
Some values should be changed for productive use, to avoid using the default values for secrets:
SO_ADMIN_PASSWORDSO_DATABASE_PASSWORDSO_DJANGO_SECRET_KEYSO_FIELD_ENCRYPTION_KEY
Startup
- The database structure is initialized with the first start of the backend container.
- The URLs for frontend and backend are available after approximately 30 seconds, after the healthcheck of the containers has been running for the first time.
Kubernetes
SecObserve provides a Helm chart as a template for productive use. The default values will work if the release name is secobserve and the frontend will be accessible with https://secobserve.dev/.
Database
The PostgreSQL database is provided by Bitnami's Helm chart. Bitnami doesn't provide updates for their free tier anymore, see Upcoming changes to the Bitnami Catalog and the Docker image is pulled from the bitnamilegacy repository.
This is ok to test the Kubernetes installation, but not suitable for production use. A productive environment has to use an update-to-date database, e.g. installed as an operator like CloudNativePG or a managed service of a cloud provider.
If the provided database is used and the chart is installed with a release name different from secobserve, all occurrences of secobserve-postgresql in the chart have to be changed to <release_name>-postgresql.
Secrets
Three values are read from a secret, which has to be set up manually before installing the chart:
ADMIN_PASSWORDDJANGO_SECRET_KEYFIELD_ENCRYPTION_KEY
The command to setup the secret can look like this:
kubectl create secret generic secobserve-secrets \
--namespace ... \
--from-literal=password='...' \
--from-literal=django_secret_key='...' \
--from-literal=field_encryption_key='...'
See Configuration for more information how to set these values.