Skip to content

Docker

A single-host setup with Docker Compose: PostgreSQL, lakefs-authz, lakefs-authn, lakeFS, and nginx in front, so that lakeFS and the /oidc/ prefix share one host name. The files live in examples/docker in the repository.

1. Settings

Copy .env.example to .env and fill it in. LAKEFS_URL is the address users open; with TLS on the proxy it starts with https.

.env.example
# Release versions. Pin lakefs-auth to a release from https://github.com/ion-elgreco/lakefs-auth/releases.
LAKEFS_AUTH_VERSION=latest
LAKEFS_VERSION=1.86.0

# The address users open. With TLS on the proxy, use the https address.
LAKEFS_URL=http://lakefs.example.com

# One random string for lakeFS, lakefs-authz, and lakefs-authn: openssl rand -hex 32
SHARED_SECRET=change-me

# PostgreSQL password of lakefs-authz.
AUTHZ_DB_PASSWORD=change-me

# The OIDC client registered with the redirect URI <LAKEFS_URL>/oidc/callback.
OIDC_ISSUER=https://idp.example.com/realms/lakefs
OIDC_CLIENT_ID=lakefs
OIDC_CLIENT_SECRET=change-me

2. Compose file

The two servers run from the release images as a non-root user, with a read-only root filesystem and no capabilities. lakeFS keeps its metadata and its data in a volume; see the lakeFS documentation for a database and an object store.

docker-compose.yml
# lakeFS with lakefs-authz and lakefs-authn on one host. Settings come from .env; see .env.example.
services:
  postgres:
    image: postgres:17-alpine
    environment:
      POSTGRES_USER: authz
      POSTGRES_PASSWORD: ${AUTHZ_DB_PASSWORD}
      POSTGRES_DB: authz
    volumes:
      - authz-db:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U authz"]
      interval: 5s
      timeout: 5s
      retries: 10
    restart: unless-stopped

  authz:
    image: ghcr.io/ion-elgreco/lakefs-authz:${LAKEFS_AUTH_VERSION}
    read_only: true
    cap_drop: [ALL]
    security_opt: [no-new-privileges:true]
    environment:
      LAKEFS_AUTHZ_DATABASE_URL: postgres://authz:${AUTHZ_DB_PASSWORD}@postgres:5432/authz
      LAKEFS_AUTHZ_SECRET_KEY: ${SHARED_SECRET}
      LAKEFS_AUTHZ_LOG_FORMAT: json
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

  authn:
    image: ghcr.io/ion-elgreco/lakefs-authn:${LAKEFS_AUTH_VERSION}
    read_only: true
    cap_drop: [ALL]
    security_opt: [no-new-privileges:true]
    environment:
      LAKEFS_AUTHN_SECRET_KEY: ${SHARED_SECRET}
      LAKEFS_AUTHN_PUBLIC_URL: ${LAKEFS_URL}
      LAKEFS_AUTHN_OIDC_ISSUER: ${OIDC_ISSUER}
      LAKEFS_AUTHN_OIDC_CLIENT_ID: ${OIDC_CLIENT_ID}
      LAKEFS_AUTHN_OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET}
      LAKEFS_AUTHN_AUTHZ_URL: http://authz:8002/api/v1
      LAKEFS_AUTHN_POST_LOGIN_REDIRECT_URL: ${LAKEFS_URL}/
      LAKEFS_AUTHN_LOG_FORMAT: json
    ports:
      - "127.0.0.1:8001:8001"   # health checks from the host only
    depends_on:
      - authz
    restart: unless-stopped

  lakefs:
    image: treeverse/lakefs:${LAKEFS_VERSION}
    command: ["run"]
    environment:
      LAKEFS_DATABASE_TYPE: local
      LAKEFS_DATABASE_LOCAL_PATH: /home/lakefs/metadata
      LAKEFS_BLOCKSTORE_TYPE: local
      LAKEFS_BLOCKSTORE_LOCAL_PATH: /home/lakefs/data
      LAKEFS_AUTH_ENCRYPT_SECRET_KEY: ${SHARED_SECRET}
      LAKEFS_AUTH_API_ENDPOINT: http://authz:8002/api/v1
      LAKEFS_AUTH_API_HEALTH_CHECK_TIMEOUT: 120s
      LAKEFS_AUTH_AUTHENTICATION_API_ENDPOINT: http://authn:8001/api/v1
      LAKEFS_AUTH_UI_CONFIG_RBAC: internal
      LAKEFS_AUTH_UI_CONFIG_FALLBACK_LOGIN_URL: /oidc/login
      LAKEFS_AUTH_UI_CONFIG_FALLBACK_LOGIN_LABEL: Sign in with SSO
      LAKEFS_AUTH_UI_CONFIG_LOGOUT_URL: /oidc/logout
      LAKEFS_AUTH_UI_CONFIG_LOGIN_COOKIE_NAMES: internal_auth_session
      # No telemetry, and no welcome page that asks for an email address and a country.
      LAKEFS_STATS_ENABLED: "false"
      LAKEFS_USAGE_REPORT_ENABLED: "false"
      LAKEFS_EMAIL_SUBSCRIPTION_ENABLED: "false"
    volumes:
      - lakefs-data:/home/lakefs
    depends_on:
      - authz
    restart: unless-stopped

  proxy:
    image: nginx:1.27-alpine
    ports:
      - "${PROXY_PORT:-80}:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro
    depends_on:
      - lakefs
      - authn
    restart: unless-stopped

volumes:
  authz-db:
  lakefs-data:

3. Reverse proxy

nginx sends /oidc/ to lakefs-authn and everything else to lakeFS, and passes Set-Cookie through, which the login callback needs. To serve TLS, terminate it here and set LAKEFS_URL to the https address.

nginx.conf
events {}

http {
  # Docker's DNS, so that nginx resolves the service names at request time.
  resolver 127.0.0.11 valid=10s;

  server {
    listen 80;
    # lakeFS uploads pass through here.
    client_max_body_size 0;

    # lakefs-authn owns the /oidc/ prefix.
    location /oidc/ {
      set $authn http://authn:8001;
      proxy_pass $authn;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    # Everything else is lakeFS.
    location / {
      set $lakefs http://lakefs:8000;
      proxy_pass $lakefs;
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  }
}

4. Start

docker compose up -d
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/api/v1/healthcheck   # 204: lakeFS through the proxy
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8001/readyz          # 200: lakefs-authn reached the provider

Then continue with After the install.