Files
ouranos/docs/searxng-auth.md
Robert Helewka b4d60f2f38 docs: rewrite README with structured overview and quick start guide
Replaces the minimal project description with a comprehensive README
including a component overview table, quick start instructions, common
Ansible operations, and links to detailed documentation. Aligns with
Red Panda Approval™ standards.
2026-03-03 12:49:06 +00:00

9.5 KiB
Raw Blame History

SearXNG Authentication Design Document

Red Panda Approved

Overview

This document describes the design for adding Casdoor-based authentication to SearXNG, which doesn't natively support SSO/OIDC authentication.

Architecture

┌──────────────┐     ┌───────────────┐     ┌─────────────────────────────────────┐
│   Browser    │────▶│    HAProxy    │────▶│             Oberon                  │
│              │     │   (titania)   │     │  ┌────────────────┐  ┌───────────┐  │
└──────────────┘     └───────┬───────┘     │  │  OAuth2-Proxy  │─▶│  SearXNG  │  │
                             │             │  │  (port 22073)  │  │  (22083)  │  │
                             │             │  └───────┬────────┘  └───────────┘  │
                             │             └──────────┼─────────────────────────┘
                             │                        │ OIDC
                             │     ┌──────────────────▼────────────────┐
                             └────▶│            Casdoor                │
                                   │    (OIDC Provider - titania)      │
                                   └───────────────────────────────────┘

The OAuth2-Proxy runs as a native binary sidecar on Oberon alongside SearXNG, following the same pattern used for JupyterLab on Puck. The upstream connection is localhost — eliminating the cross-host hop from the previous Docker-based deployment on Titania.

Each host supports at most one OAuth2-Proxy sidecar instance. The binary is shared at /usr/local/bin/oauth2-proxy; each service gets a unique config directory and systemd unit name.

Components

1. OAuth2-Proxy (Sidecar on Oberon)

  • Purpose: Acts as authentication gateway for SearXNG
  • Port: 22073 (exposed to HAProxy)
  • Binary: Native oauth2-proxy v7.6.0 (systemd service oauth2-proxy-searxng)
  • Config: /etc/oauth2-proxy-searxng/oauth2-proxy.cfg
  • Upstream: http://127.0.0.1:22083 (localhost sidecar to SearXNG)
  • Logging: systemd journal (SyslogIdentifier=oauth2-proxy-searxng)

2. Casdoor (Existing on Titania)

  • Purpose: OIDC Identity Provider
  • Port: 22081
  • URL: https://id.ouranos.helu.ca/ (via HAProxy)
  • Required Setup:
    • Create Application for SearXNG
    • Configure redirect URI
    • Generate client credentials

3. HAProxy Updates (Titania)

  • Route searxng.ouranos.helu.ca to OAuth2-Proxy on Oberon (oberon.incus:22073)
  • OAuth2-Proxy handles authentication before proxying to SearXNG on localhost

4. SearXNG (Existing on Oberon)

  • No changes required - remains unaware of authentication
  • Receives pre-authenticated requests from OAuth2-Proxy

Authentication Flow

  1. User navigates to https://searxng.ouranos.helu.ca/
  2. HAProxy routes to OAuth2-Proxy on oberon:22073
  3. OAuth2-Proxy checks for valid session cookie (_oauth2_proxy_searxng)
  4. If no valid session:
    • Redirect to Casdoor login: https://id.ouranos.helu.ca/login/oauth/authorize
    • User authenticates with Casdoor (username/password, social login, etc.)
    • Casdoor redirects back with authorization code
    • OAuth2-Proxy exchanges code for tokens
    • OAuth2-Proxy sets session cookie
  5. If valid session:
    • OAuth2-Proxy adds X-Forwarded-User header
    • Request proxied to SearXNG at 127.0.0.1:22083 (localhost sidecar)

Casdoor Configuration

Application Setup (Manual via Casdoor UI)

  1. Login to Casdoor at https://id.ouranos.helu.ca/
  2. Navigate to Applications → Add
  3. Configure:
    • Name: searxng
    • Display Name: SearXNG Search
    • Organization: built-in (or your organization)
    • Redirect URLs:
      • https://searxng.ouranos.helu.ca/oauth2/callback
    • Grant Types: authorization_code, refresh_token
    • Response Types: code
  4. Save and note the Client ID and Client Secret

Generate a 32-byte random secret for OAuth2-Proxy cookies:

openssl rand -base64 32

Environment Variables

Development (Sandbox)

# In inventory/host_vars/oberon.incus.yml
searxng_oauth2_proxy_dir: /etc/oauth2-proxy-searxng
searxng_oauth2_proxy_version: "7.6.0"
searxng_proxy_port: 22073
searxng_domain: "ouranos.helu.ca"
searxng_oauth2_oidc_issuer_url: "https://id.ouranos.helu.ca"
searxng_oauth2_redirect_url: "https://searxng.ouranos.helu.ca/oauth2/callback"

# OAuth2 Credentials (from vault)
searxng_oauth2_client_id: "{{ vault_searxng_oauth2_client_id }}"
searxng_oauth2_client_secret: "{{ vault_searxng_oauth2_client_secret }}"
searxng_oauth2_cookie_secret: "{{ vault_searxng_oauth2_cookie_secret }}"

Variables use the searxng_ prefix, following the same naming pattern as jupyterlab_oauth2_* variables on Puck. The upstream URL (http://127.0.0.1:22083) is derived from searxng_port in the config template — no cross-host URL needed.

Deployment Steps

1. Add Vault Secrets

ansible-vault edit inventory/group_vars/all/vault.yml

Add:

vault_searxng_oauth2_client_id: "<from-casdoor>"
vault_searxng_oauth2_client_secret: "<from-casdoor>"
vault_searxng_oauth2_cookie_secret: "<generated-32-byte-secret>"

Note: The searxng_ prefix allows service-specific credentials. The Oberon host_vars maps these directly to searxng_oauth2_* variables used by the sidecar config template.

2. Update Host Variables

OAuth2-Proxy variables are defined in inventory/host_vars/oberon.incus.yml alongside the existing SearXNG configuration. No separate service entry is needed — the OAuth2-Proxy sidecar is deployed as part of the searxng service.

# SearXNG OAuth2-Proxy Sidecar (in oberon.incus.yml)
searxng_oauth2_proxy_dir: /etc/oauth2-proxy-searxng
searxng_oauth2_proxy_version: "7.6.0"
searxng_proxy_port: 22073
searxng_domain: "ouranos.helu.ca"
searxng_oauth2_oidc_issuer_url: "https://id.ouranos.helu.ca"
searxng_oauth2_redirect_url: "https://searxng.ouranos.helu.ca/oauth2/callback"

3. Update HAProxy Backend

Route SearXNG traffic through OAuth2-Proxy on Oberon:

# In inventory/host_vars/titania.incus.yml
haproxy_backends:
  - subdomain: "searxng"
    backend_host: "oberon.incus"   # Same host as SearXNG
    backend_port: 22073            # OAuth2-Proxy port
    health_path: "/ping"           # OAuth2-Proxy health endpoint

4. Deploy

cd ansible

# Deploy SearXNG + OAuth2-Proxy sidecar
ansible-playbook searxng/deploy.yml

# Update HAProxy configuration
ansible-playbook haproxy/deploy.yml

Monitoring

Logs

OAuth2-Proxy logs to systemd journal on Oberon. Alloy's default systemd_logs source captures these logs automatically, filterable by SyslogIdentifier=oauth2-proxy-searxng.

# View logs on Oberon
ssh oberon.incus
journalctl -u oauth2-proxy-searxng -f

Metrics

OAuth2-Proxy exposes Prometheus metrics at /metrics on port 22073:

  • oauth2_proxy_requests_total - Total requests
  • oauth2_proxy_errors_total - Error count
  • oauth2_proxy_upstream_latency_seconds - Upstream latency

Security Considerations

  1. Cookie Security:

    • cookie_secure = true enforces HTTPS-only cookies
    • cookie_httponly = true prevents JavaScript access
    • cookie_samesite = "lax" provides CSRF protection
  2. Email Domain Restriction:

    • Configure oauth2_proxy_email_domains to limit who can access
    • Example: ["yourdomain.com"] or ["*"] for any
  3. Group-Based Access:

    • Optional: Configure oauth2_proxy_allowed_groups in Casdoor
    • Only users in specified groups can access SearXNG

Troubleshooting

Check OAuth2-Proxy Status

ssh oberon.incus
systemctl status oauth2-proxy-searxng
journalctl -u oauth2-proxy-searxng --no-pager -n 50

Test OIDC Discovery

curl https://id.ouranos.helu.ca/.well-known/openid-configuration

Test Health Endpoint

curl http://oberon.incus:22073/ping

Ensure the cookie domain (.ouranos.helu.ca) matches your HAProxy domain. Cookies won't work across different domains.

Files

File Purpose
ansible/searxng/deploy.yml SearXNG + OAuth2-Proxy sidecar deployment
ansible/searxng/oauth2-proxy-searxng.cfg.j2 OAuth2-Proxy OIDC configuration
ansible/searxng/oauth2-proxy-searxng.service.j2 Systemd unit for OAuth2-Proxy
ansible/inventory/host_vars/oberon.incus.yml Host variables (searxng_oauth2_*)
docs/searxng-auth.md This design document

Generic OAuth2-Proxy Module (Retained)

The standalone ansible/oauth2_proxy/ directory is retained as a generic, reusable Docker-based OAuth2-Proxy module for future services:

File Purpose
ansible/oauth2_proxy/deploy.yml Generic Docker Compose deployment
ansible/oauth2_proxy/docker-compose.yml.j2 Docker Compose template
ansible/oauth2_proxy/oauth2-proxy.cfg.j2 Generic OIDC configuration template
ansible/oauth2_proxy/stage.yml Validation / dry-run playbook