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:
253
docs/searxng-auth.md
Normal file
253
docs/searxng-auth.md
Normal 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 |
|
||||
Reference in New Issue
Block a user