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

254 lines
9.5 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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`
### Cookie Secret Generation
Generate a 32-byte random secret for OAuth2-Proxy cookies:
```bash
openssl rand -base64 32
```
## Environment Variables
### Development (Sandbox)
```yaml
# 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
```bash
ansible-vault edit inventory/group_vars/all/vault.yml
```
Add:
```yaml
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.
```yaml
# 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:
```yaml
# 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
```bash
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`.
```bash
# 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
```bash
ssh oberon.incus
systemctl status oauth2-proxy-searxng
journalctl -u oauth2-proxy-searxng --no-pager -n 50
```
### Test OIDC Discovery
```bash
curl https://id.ouranos.helu.ca/.well-known/openid-configuration
```
### Test Health Endpoint
```bash
curl http://oberon.incus:22073/ping
```
### Verify Cookie Domain
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 |