first build
This commit is contained in:
39 files changed
+2522
No files matched your search
@@ -0,0 +1,98 @@
|
||||
# Setup
|
||||
|
||||
The portal runs on Linux (bare metal, VM, or container). It needs outbound HTTPS to the IdP, LDAPS to a domain controller, and HTTPS to AD CS Web Enrollment.
|
||||
|
||||
## 1. Configuration
|
||||
|
||||
Copy [`.env.example`](../.env.example) to `.env`. Every variable is commented there. Minimum:
|
||||
|
||||
- `SESSION_SECRET` — long random string
|
||||
- `PUBLIC_BASE_URL` — the URL browsers use (the reverse-proxy origin)
|
||||
- `OIDC_*` — issuer, client id/secret, redirect `https://<portal>/auth/callback`
|
||||
- `LDAP_*` — `ldaps://` URL, bind DN/password, base DN
|
||||
- `CERTSRV_*` — `https://ca.example.com/certsrv`, NTLM user, template common name
|
||||
- `PROFILE_SIGNING_P12_PATH` / `PROFILE_SIGNING_P12_PASSWORD`
|
||||
|
||||
Set `SESSION_HTTPS_ONLY=true` behind HTTPS. For a local `http://127.0.0.1:8000` lab only, set it false and use matching `OIDC_REDIRECT_URI`.
|
||||
|
||||
## 2. OpenID Connect client
|
||||
|
||||
Register a confidential web app at your IdP:
|
||||
|
||||
- Redirect URI: `{PUBLIC_BASE_URL}/auth/callback`
|
||||
- Scopes: `openid email profile` (override with `OIDC_SCOPES`)
|
||||
- PKCE: S256 (the portal always sends a code challenge)
|
||||
|
||||
`OIDC_ISSUER` must be the discovery origin (no trailing slash). The portal loads `{issuer}/.well-known/openid-configuration`.
|
||||
|
||||
`OIDC_USERNAME_CLAIM` (default `email`) is what LDAP searches for. If your IdP puts the AD UPN in `preferred_username` or `upn`, set the claim accordingly and keep `LDAP_USER_FILTER` in sync.
|
||||
|
||||
## 3. LDAP
|
||||
|
||||
Use **LDAPS** (`ldaps://dc:636`) in production. The bind account only needs to read users (and, if `LDAP_REQUIRED_GROUP` is set, group membership).
|
||||
|
||||
Default filter:
|
||||
|
||||
```
|
||||
(&(objectClass=user)(|(userPrincipalName={username})(mail={username})))
|
||||
```
|
||||
|
||||
`LDAP_REQUIRED_GROUP` may be a full DN or a CN. Nested members are included (`LDAP_MATCHING_RULE_IN_CHAIN`).
|
||||
|
||||
If the DC uses a private CA, set `LDAP_CA_CERTS_FILE` to a PEM bundle. `LDAP_VERIFY_TLS=false` is lab-only.
|
||||
|
||||
## 4. AD CS Web Enrollment
|
||||
|
||||
See [adcs.md](adcs.md). From the Linux host you should be able to reach `CERTSRV_URL` over HTTPS. The portal uses NTLM (`CERTSRV_DOMAIN` + `CERTSRV_USERNAME`). If `CERTSRV_USERNAME` is already `DOMAIN\user` or `user@upn`, the domain field is ignored.
|
||||
|
||||
Install the issuing CA TLS cert into `CERTSRV_CA_CERTS_FILE` (or the system trust store). Do not disable `CERTSRV_VERIFY_TLS` except in a lab.
|
||||
|
||||
## 5. Profile signing material
|
||||
|
||||
Place a PKCS#12 on the host (for Docker, bind-mount it) and point `PROFILE_SIGNING_P12_PATH` at it. See [profile-signing.md](profile-signing.md).
|
||||
|
||||
Optional: `PROFILE_CA_CERT_PATH` PEM/DER of the issuing CA to embed so devices that do not already trust it still accept the user cert.
|
||||
|
||||
## 6. Reverse proxy / TLS
|
||||
|
||||
Terminate TLS at Caddy, nginx, or another proxy. Forward `Host`, `X-Forwarded-For`, and `X-Forwarded-Proto`. The app is started with `proxy_headers=True`.
|
||||
|
||||
Example Caddy:
|
||||
|
||||
```
|
||||
certs.example.com {
|
||||
reverse_proxy 127.0.0.1:8000
|
||||
}
|
||||
```
|
||||
|
||||
## 7. Run
|
||||
|
||||
**Local**
|
||||
|
||||
```bash
|
||||
python3.12 -m venv .venv
|
||||
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||
pip install -e ".[dev]"
|
||||
python -m cert_portal
|
||||
```
|
||||
|
||||
Listens on `HOST`/`PORT` (default `0.0.0.0:8000`).
|
||||
|
||||
**Docker**
|
||||
|
||||
```bash
|
||||
docker build -t cert-portal .
|
||||
docker run --rm -p 8000:8000 --env-file .env \
|
||||
-v /etc/cert-portal:/etc/cert-portal:ro \
|
||||
cert-portal
|
||||
```
|
||||
|
||||
The image runs as UID 1000. The signing P12 path inside the container must match `PROFILE_SIGNING_P12_PATH`.
|
||||
|
||||
## 8. OpenAPI
|
||||
|
||||
`/docs`, `/redoc`, and `/openapi.json` are **off** when `ENVIRONMENT=production` unless you set `DOCS_ENABLED=true`. They are on in `development`. Do not expose Swagger to the internet without additional access control.
|
||||
|
||||
## Health
|
||||
|
||||
`GET /health` returns `{"status":"ok","version":"..."}` and does not require a session. Point your load balancer at it.
|
||||
Reference in new issue
Block a user