201 lines
7.4 KiB
Markdown
201 lines
7.4 KiB
Markdown
# Auth LXC – Shared Portal Auth Database
|
||
|
||
## Purpose
|
||
|
||
The **Auth LXC** is a dedicated container that runs PostgreSQL and hosts the **shared auth database** (`portal_auth`). It allows multiple portal applications (e.g. FreePBX Portal, future billing or other portals) to use the **same user accounts** without duplicating users or maintaining separate credentials per portal.
|
||
|
||
- **One set of users:** Create an account once; it works for every portal that points to this DB.
|
||
- **Central auth data:** Users, sessions, auth logs, and API tokens live here.
|
||
- **Portal-specific data stays elsewhere:** Each portal keeps its own database (e.g. extensions, companies, assignments) on its own host or on this LXC; only auth is shared.
|
||
|
||
---
|
||
|
||
## Host Details
|
||
|
||
| Item | Value |
|
||
|------|--------|
|
||
| **Host / LXC** | Auth (DB) LXC |
|
||
| **IP address** | `10.110.60.210` |
|
||
| **SSH access** | `ssh root@10.110.60.210` |
|
||
| **OS** | Debian GNU/Linux 13 (trixie) |
|
||
| **PostgreSQL** | 17 (Debian package) |
|
||
| **Listen** | All interfaces, port `5432` |
|
||
|
||
---
|
||
|
||
## What This LXC Hosts
|
||
|
||
### Database: `portal_auth`
|
||
|
||
This is the **only database** used for shared authentication. It contains four tables:
|
||
|
||
| Table | Purpose |
|
||
|-------|--------|
|
||
| `users` | User accounts (username, password hash, role, active flag) |
|
||
| `sessions` | Active login sessions (session_id, username, expires_at) |
|
||
| `auth_logs` | Auth events (login, logout, failed login, account_locked, deactivated) |
|
||
| `api_tokens` | API tokens for programmatic access (token hash, username, expiry, active) |
|
||
|
||
No other application data (extensions, companies, trunks, activity logs, etc.) is stored here; that remains in each portal’s own database.
|
||
|
||
---
|
||
|
||
## Database Structure (`portal_auth`)
|
||
|
||
### 1. `users`
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| `id` | SERIAL | PRIMARY KEY | Auto-incrementing user ID |
|
||
| `username` | VARCHAR(255) | UNIQUE, NOT NULL | Login username |
|
||
| `password_hash` | TEXT | NOT NULL | Bcrypt or legacy salt:hash |
|
||
| `role` | VARCHAR(50) | NOT NULL, DEFAULT 'support' | `admin` or `support` |
|
||
| `created_at` | TIMESTAMP | NOT NULL | Account creation (UTC) |
|
||
| `created_by` | VARCHAR(255) | NULL | Creator username |
|
||
| `is_active` | BOOLEAN | DEFAULT TRUE | Whether the account can log in |
|
||
|
||
### 2. `sessions`
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| `session_id` | VARCHAR(255) | PRIMARY KEY | Session identifier (cookie value) |
|
||
| `username` | VARCHAR(255) | NOT NULL, FK → users(username) | Owner of the session |
|
||
| `created_at` | TIMESTAMP | NOT NULL | Session start (UTC) |
|
||
| `expires_at` | TIMESTAMP | NOT NULL | Session end (UTC) |
|
||
|
||
Sessions are validated on each request; expired rows can be purged by the app (e.g. on startup).
|
||
|
||
### 3. `auth_logs`
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| `id` | SERIAL | PRIMARY KEY | Log entry ID |
|
||
| `username` | VARCHAR(255) | NOT NULL | User involved |
|
||
| `event_type` | VARCHAR(50) | NOT NULL | `login`, `logout`, `login_failed`, `deactivated`, `account_locked` |
|
||
| `timestamp` | TIMESTAMP | NOT NULL | Event time (UTC) |
|
||
| `ip_address` | VARCHAR(45) | NULL | Client IP (IPv4/IPv6) |
|
||
| `user_agent` | TEXT | NULL | Browser/client string |
|
||
| `details` | TEXT | NULL | Extra info |
|
||
|
||
**Indexes:** `idx_auth_logs_username`, `idx_auth_logs_timestamp`, `idx_auth_logs_event_type`
|
||
|
||
### 4. `api_tokens`
|
||
|
||
| Column | Type | Constraints | Description |
|
||
|--------|------|-------------|-------------|
|
||
| `id` | SERIAL | PRIMARY KEY | Token ID |
|
||
| `token_hash` | VARCHAR(255) | UNIQUE, NOT NULL | SHA-256 hash of the token |
|
||
| `token_prefix` | VARCHAR(20) | NOT NULL | First 20 chars (for display only) |
|
||
| `username` | VARCHAR(255) | NOT NULL, FK → users(username) | Token owner |
|
||
| `description` | TEXT | NULL | Optional label |
|
||
| `created_at` | TIMESTAMP | NOT NULL | Creation time (UTC) |
|
||
| `created_by` | VARCHAR(255) | NULL | Creator username |
|
||
| `last_used_at` | TIMESTAMP | NULL | Last validation time |
|
||
| `expires_at` | TIMESTAMP | NULL | Optional expiry |
|
||
| `is_active` | BOOLEAN | DEFAULT TRUE | Whether the token is valid |
|
||
|
||
**Indexes:** `idx_api_tokens_token_hash`, `idx_api_tokens_username`, `idx_api_tokens_is_active`
|
||
|
||
### Relationships
|
||
|
||
```
|
||
users (username)
|
||
├── sessions.username → users(username)
|
||
└── api_tokens.username → users(username) ON DELETE CASCADE
|
||
```
|
||
|
||
`auth_logs` references users only by `username` (no FK); it is an append-only log.
|
||
|
||
---
|
||
|
||
## Access and Security
|
||
|
||
- **DB user:** `portal_user` (password set on the server; same as used in portal `.env` for `DB_AUTH_PASSWORD`).
|
||
- **Allowed clients (pg_hba.conf):**
|
||
- `10.110.60.0/24` – portal LXCs on the same subnet
|
||
- `192.168.200.0/24` – gateway/subnet used by the production portal host to reach this LXC
|
||
- **Authentication:** `scram-sha-256`.
|
||
- **Timezone:** Connections use UTC.
|
||
|
||
Adding another portal: ensure its host IP (or subnet) is allowed in `/etc/postgresql/17/main/pg_hba.conf` for database `portal_auth` and user `portal_user`, then reload PostgreSQL.
|
||
|
||
---
|
||
|
||
## How Portals Use This LXC
|
||
|
||
Each portal (e.g. FreePBX Portal) is configured with two DB targets:
|
||
|
||
1. **Auth DB (this LXC):** `DB_AUTH_HOST=10.110.60.210`, `DB_AUTH_NAME=portal_auth`, etc.
|
||
Used for: login, sessions, auth logs, user management, API tokens.
|
||
|
||
2. **Portal DB (local or elsewhere):** `DB_HOST`, `DB_NAME=freepbx_portal`, etc.
|
||
Used for: extensions, companies, assignments, activity logs, and all other app data.
|
||
|
||
In the portal `.env`:
|
||
|
||
```ini
|
||
# Shared auth (this LXC)
|
||
DB_AUTH_HOST=10.110.60.210
|
||
DB_AUTH_PORT=5432
|
||
DB_AUTH_NAME=portal_auth
|
||
DB_AUTH_USER=portal_user
|
||
DB_AUTH_PASSWORD=<same password as on Auth LXC>
|
||
|
||
# Portal’s own data (e.g. same host or another DB server)
|
||
DB_HOST=localhost
|
||
DB_NAME=freepbx_portal
|
||
DB_USER=portal_user
|
||
DB_PASSWORD=<password>
|
||
```
|
||
|
||
If `DB_AUTH_HOST` is not set, the portal runs in single-DB mode and uses only its own database for everything (no use of this LXC).
|
||
|
||
---
|
||
|
||
## Verification
|
||
|
||
- **Connections from a portal:** On the Auth LXC, as `postgres`:
|
||
```sql
|
||
SELECT count(*), client_addr
|
||
FROM pg_stat_activity
|
||
WHERE datname = 'portal_auth'
|
||
GROUP BY client_addr;
|
||
```
|
||
You should see connections from the portal host(s).
|
||
|
||
- **Recent logins:** After logging in via a portal:
|
||
```sql
|
||
SELECT username, event_type, timestamp, ip_address
|
||
FROM auth_logs
|
||
ORDER BY timestamp DESC
|
||
LIMIT 10;
|
||
```
|
||
|
||
- **Active sessions:**
|
||
```sql
|
||
SELECT session_id, username, created_at, expires_at
|
||
FROM sessions;
|
||
```
|
||
|
||
---
|
||
|
||
## Maintenance
|
||
|
||
- **Backups:** Backup the `portal_auth` database (e.g. `pg_dump -U postgres -d portal_auth`) regularly; it holds all shared identities and sessions.
|
||
- **Log retention:** The portal app can purge old `auth_logs` rows (e.g. via `AUTH_LOG_RETENTION_DAYS`); expired `sessions` are removed on app startup or by scheduled jobs.
|
||
- **PostgreSQL:** Managed with systemd (`postgresql.service`); config under `/etc/postgresql/17/main/` (`postgresql.conf`, `pg_hba.conf`).
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
| What | Where |
|
||
|------|--------|
|
||
| **LXC** | 10.110.60.210 (Auth / DB LXC) |
|
||
| **Use** | Shared user accounts and auth for multiple portals |
|
||
| **Database** | `portal_auth` |
|
||
| **Tables** | `users`, `sessions`, `auth_logs`, `api_tokens` |
|
||
| **Portal config** | Set `DB_AUTH_HOST=10.110.60.210` (and related `DB_AUTH_*`) in each portal’s `.env` |
|
||
|
||
For full schema details of auth and portal tables, see [DATABASE_SCHEMA.md](DATABASE_SCHEMA.md).
|