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.
This commit is contained in:
2026-03-03 12:49:06 +00:00
parent c7be03a743
commit b4d60f2f38
219 changed files with 34586 additions and 2 deletions

253
docs/searxng-auth.md Normal file
View File

@@ -0,0 +1,253 @@
# 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 |