59 lines
2.1 KiB
Markdown
59 lines
2.1 KiB
Markdown
# Security
|
||
|
||
## Private key on the server
|
||
|
||
Design B generates the user private key in the portal:
|
||
|
||
- Created in RAM on POST `/download`
|
||
- Exported into an identity PKCS#12 (still RAM)
|
||
- Embedded in the plist, which is then CMS-signed
|
||
- Returned in the HTTP response
|
||
- Not written to disk; no cache of keys or P12 passwords
|
||
|
||
Anyone who can download a profile for a user obtains that user’s private key. Protect the app like an RA:
|
||
|
||
- OIDC on every download
|
||
- Optional `LDAP_REQUIRED_GROUP`
|
||
- HTTPS only in production (`SESSION_HTTPS_ONLY`, reverse-proxy TLS)
|
||
- Restrict who can reach the portal (VPN, SSO group, IP allow list)
|
||
|
||
Do not use this design for keys that must be device-bound.
|
||
|
||
## Logging
|
||
|
||
The portal logs UPN and SID at info when a profile is issued. It does **not** log:
|
||
|
||
- Identity P12 bytes or passwords
|
||
- Profile-signing P12 passwords
|
||
- OIDC client secrets, LDAP bind passwords, certsrv passwords
|
||
- Raw CSR PEM at info (avoid debug logging in production)
|
||
|
||
Session cookie: `HttpOnly`, `SameSite=lax`, `Secure` when `SESSION_HTTPS_ONLY` is true.
|
||
|
||
## Who can enroll
|
||
|
||
1. Must complete OIDC (valid session).
|
||
2. Must match exactly one LDAP user.
|
||
3. If `LDAP_REQUIRED_GROUP` is set, must be a member (nested groups allowed).
|
||
4. The **service account**, not the user, must have Enroll on the template. A signed-in user cannot enroll a template the portal account cannot enroll.
|
||
|
||
There is no Enrollment Agent. A caller cannot request a cert for a different SID than LDAP returned for their username.
|
||
|
||
## CA trust
|
||
|
||
Prefer `CERTSRV_VERIFY_TLS=true` and `LDAP_VERIFY_TLS=true`. Disabling TLS verification allows credential theft on the path to certsrv (NTLM) and LDAP.
|
||
|
||
## OpenAPI
|
||
|
||
Leave `DOCS_ENABLED=false` in production so `/docs` is not public.
|
||
|
||
## Threat notes
|
||
|
||
| Issue | Mitigation |
|
||
| --- | --- |
|
||
| Stolen session cookie | Short IdP session, HTTPS, `Secure` cookies |
|
||
| Stolen signing P12 | Filesystem permissions / secret store; rotate |
|
||
| Template too powerful | Dedicated Wi-Fi user template, not a smartcard/admin template |
|
||
| certsrv HTML change | Parser fails closed (unknown page = error), fixtures in tests |
|
||
| SSRF-ish CA URL | `CERTSRV_URL` is config, not user input |
|