9-course Dutch e-learning platform fused onto atlasacademy.nl via Caddy reverse proxy. Odoo 19 Community as course engine (website_slides), static HTML for marketing front. Single Odoo account system. - static/: 8 marketing pages (index, pricing, coaching, leerpad, over, shop, bisl, esf) - backend/odoo_relay.py: lead relay Flask service (POST /academy-lead → Odoo CRM) - caddy/academy.caddyfile: full Caddy config with Odoo proxy + auth rewrites - docs/: ARCHITECTURE, USERFLOW, COURSES, DEPLOYMENT, SECURITY, ODOO Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
108 lines
3.6 KiB
Markdown
108 lines
3.6 KiB
Markdown
# Security Model — Atlas Academy
|
|
|
|
## Dreigingsmodel
|
|
|
|
| Dreiging | Maatregel | Status |
|
|
|----------|-----------|--------|
|
|
| Hardcoded secrets in source | Env-bestanden (`/etc/atlas/*.env`, root 600) | ✅ Opgelost |
|
|
| Zwakke wachtwoord-hashing | bcrypt via `academy_auth_v2.py` (nu retired; Odoo native auth) | ✅ Opgelost |
|
|
| PII in publieke admin-panel | `academy_admin.py` verwijderd uit docroot | ✅ Opgelost |
|
|
| Odoo backend publiek bereikbaar | `/web` niet geproxied via academy-domein | ✅ Opgelost |
|
|
| Open signup op corp-website | `website 1.auth_signup_uninvited = 'b2b'` | ✅ Opgelost |
|
|
| Clickjacking | `X-Frame-Options: DENY` via Caddy | ✅ Actief |
|
|
| MIME-sniffing | `X-Content-Type-Options: nosniff` | ✅ Actief |
|
|
| HTTPS downgrade | `Strict-Transport-Security: max-age=31536000` | ✅ Actief |
|
|
| ESF-tracker indexeerbaar | `X-Robots-Tag: noindex, nofollow` + `robots.txt` | ✅ Actief |
|
|
| Stale SMTP app-wachtwoord | Handmatige rotatie vereist (Google Account UI) | ⚠️ Openstaand |
|
|
| XML-RPC relay-wachtwoord | In env, maar waarde mogelijk stale | ⚠️ Controleren |
|
|
|
|
---
|
|
|
|
## Secrets locaties
|
|
|
|
Alle secrets zijn **buiten source** gehouden. Alleen locaties zijn gedocumenteerd.
|
|
|
|
| Bestand | Inhoud | Rechten |
|
|
|---------|--------|---------|
|
|
| `/etc/atlas/academy-relay.env` | `ODOO_RELAY_LOGIN`, `ODOO_RELAY_PASS`, `ACADEMY_ADMIN_PASS`, `LEAD_SMTP_PASS` | `root:root 600` |
|
|
| `/etc/atlas/academy-auth.env` | `AA_SECRET` (retired Flask JWT secret) | `root:root 600` |
|
|
|
|
---
|
|
|
|
## Toegangsarchitectuur
|
|
|
|
```
|
|
Internet
|
|
│
|
|
▼
|
|
atlasacademy.nl (Caddy)
|
|
│
|
|
├── /slides, /web/login, /web/signup → Odoo (public eLearning)
|
|
│
|
|
├── /academy-lead → odoo_relay.py (localhost only)
|
|
│
|
|
├── /var/www/atlasacademy.nl/* → Static files
|
|
│
|
|
└── /web (NIET geproxied) → ❌ Geblokkeerd voor publiek
|
|
(Odoo backend enkel via tailnet)
|
|
|
|
odoo.atlascorporation.nl (Caddy)
|
|
│
|
|
└── Authentik forward_auth → Alleen via SSO bereikbaar
|
|
```
|
|
|
|
---
|
|
|
|
## Odoo signup-beveiliging
|
|
|
|
```
|
|
Website 1 (Atlas Corporation) → auth_signup_uninvited = 'b2b' → GESLOTEN
|
|
Website 3 (Atlas Academy) → auth_signup_uninvited = 'b2c' → OPEN (gewenst)
|
|
```
|
|
|
|
Verificatie:
|
|
```bash
|
|
ssh atlas-01 "docker exec -i atlas-odoo odoo shell -d atlas --no-http" <<'EOF'
|
|
for w in env['website'].sudo().search([]):
|
|
print(f"Website {w.id} ({w.name}): signup={w.auth_signup_uninvited}")
|
|
EOF
|
|
```
|
|
|
|
---
|
|
|
|
## Headers (Caddy)
|
|
|
|
```caddyfile
|
|
header {
|
|
X-Frame-Options DENY
|
|
X-Content-Type-Options nosniff
|
|
Referrer-Policy strict-origin-when-cross-origin
|
|
Strict-Transport-Security max-age=31536000
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Secrets roteren
|
|
|
|
### SMTP app-wachtwoord (`LEAD_SMTP_PASS`)
|
|
1. Ga naar [myaccount.google.com/apppasswords](https://myaccount.google.com/apppasswords)
|
|
2. Verwijder het oude wachtwoord, maak een nieuw aan
|
|
3. Update op atlas-01: `sudo nano /etc/atlas/academy-relay.env`
|
|
4. Herstart: `sudo systemctl restart atlas-academy-relay`
|
|
|
|
### Odoo relay-wachtwoord (`ODOO_RELAY_PASS`)
|
|
1. Log in op Odoo backend (tailnet)
|
|
2. Wijzig wachtwoord van de relay-gebruiker
|
|
3. Update `/etc/atlas/academy-relay.env`
|
|
4. `sudo systemctl restart atlas-academy-relay`
|
|
|
|
---
|
|
|
|
## Wat NIET te doen
|
|
|
|
- ❌ Nooit secrets committen in git
|
|
- ❌ Nooit `/web` proxien via het publieke academy-domein
|
|
- ❌ Nooit wachtwoorden automatisch roteren (operator handelt dit af)
|
|
- ❌ Nooit `--send` gebruiken in `atlas_client_email.py` zonder goedkeuring
|
|
- ❌ Nooit studentgegevens publiceren (geen nep-reviews, nep-studentaantallen)
|