Files
gh-christianlouis-docuelevate/docs/CredentialRotationGuide.md
T
copilot-swe-agent[bot] a08b103271 fix: merge main into feature branch - resolve all merge conflicts cleanly
Merges origin/main (v0.156.0) into the classification feature branch,
properly resolving all 23 merge conflicts:

- Auto-generated files (BUILD_DATE, VERSION, etc.): accept main's version
- Non-classification files (SharePoint, QR auth, session mgmt, mobile): accept main's version
- Classification files (api/__init__.py, models.py, migrations/env.py, conftest.py):
  keep classification additions alongside main's content

Previously the branch was incorrectly removing files from main (SharePoint
integration, QR scanner, session management). This merge properly preserves
all main branch content while maintaining the classification feature additions.

Migration chain validated: 038_add_classification_rules chains from
037_add_user_sessions_and_qr_challenges.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-17 16:14:45 +00:00

270 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Credential Rotation Guide
This guide documents how to rotate API keys and credentials used by DocuElevate, along with onboarding and offboarding procedures for team members and service accounts.
## Overview
DocuElevate integrates with several external services that require API keys, tokens, or passwords. Regularly rotating these credentials limits the blast radius of a potential leak and is a security best practice.
Credentials fall into two categories:
| Category | Examples |
|---|---|
| **API keys** | OpenAI API key, Azure AI key, Paperless-ngx API token, AWS access keys |
| **OAuth tokens / secrets** | Dropbox, Google Drive, OneDrive, SharePoint, Authentik client secrets and refresh tokens |
| **Passwords** | Admin password, Nextcloud, Email (SMTP), IMAP, FTP, SFTP, WebDAV |
| **Private keys** | SFTP private key and passphrase |
All credentials are stored either in environment variables or, when set via the Settings UI, encrypted in the database using Fernet symmetric encryption (keyed from `SESSION_SECRET`).
---
## Recommended Rotation Schedule
| Credential Type | Recommended Rotation Interval |
|---|---|
| API keys (OpenAI, Azure, AWS, Paperless) | Every 90 days |
| OAuth client secrets | Every 180 days |
| OAuth refresh tokens | Rotate on revocation / after each re-authorization |
| Passwords (SMTP, IMAP, FTP, SFTP, Nextcloud, WebDAV) | Every 90 days or on personnel change |
| Admin password | Every 90 days or on personnel change |
| `SESSION_SECRET` | On suspected compromise; note all active sessions will be invalidated |
---
## How to Rotate a Credential
DocuElevate supports two rotation methods:
### Method 1 — Settings API (recommended, zero-downtime)
Use the Settings REST API to update individual credentials while the application is running. No restart is needed for most credentials (check `restart_required` in the response).
```bash
# Rotate the OpenAI API key
curl -X POST https://<your-host>/api/settings/openai_api_key \
-H "Content-Type: application/json" \
-b "session=<admin-session-cookie>" \
-d '{"key": "openai_api_key", "value": "sk-new-key-here"}'
```
The endpoint returns `"restart_required": true` for settings that require an application restart to take effect (e.g., database URL, session secret). All AI-service and storage-provider credentials take effect immediately without a restart.
### Method 2 — Environment variable / `.env` file
1. Update the relevant variable in your `.env` file (or your container/Kubernetes secret).
2. Restart the application so the new value is loaded:
```bash
docker compose restart api worker
```
> **Note:** Settings stored in the database take precedence over environment variables. If you previously set a credential via the Settings UI, you must also update or delete it from the database (via the Settings API) to have the environment variable take effect.
---
## Per-Credential Rotation Procedures
### OpenAI API Key
1. Log in to [platform.openai.com](https://platform.openai.com) → **API keys**.
2. Create a new secret key and copy it.
3. Update in DocuElevate:
```
POST /api/settings/openai_api_key {"key": "openai_api_key", "value": "<new-key>"}
```
4. Verify document processing still works (upload a test file).
5. Delete the old key in the OpenAI dashboard.
### Azure Document Intelligence Key
1. Open [portal.azure.com](https://portal.azure.com) → your Document Intelligence resource → **Keys and Endpoint**.
2. Regenerate **Key 2** while **Key 1** is still live (avoids downtime).
3. Update `azure_ai_key` in DocuElevate with the new key.
4. Verify connectivity, then regenerate **Key 1** and optionally update again.
### AWS S3 Access Keys
1. In the **IAM Console**, create a new access key for the service user.
2. Update both `aws_access_key_id` and `aws_secret_access_key` in DocuElevate together (use the bulk-update endpoint or update both settings in sequence before verifying).
3. Test an S3 upload from DocuElevate.
4. Deactivate the old IAM access key, then delete it after 24 hours.
### Dropbox App Credentials & Refresh Token
Dropbox refresh tokens are long-lived; rotate them by re-authorizing the application:
1. In [dropbox.com/developers](https://www.dropbox.com/developers), revoke the existing token.
2. Follow the Dropbox OAuth flow documented in `docs/DropboxSetup.md` to obtain a new refresh token.
3. Update `dropbox_refresh_token` (and `dropbox_app_key` / `dropbox_app_secret` if also rotating those).
### Google Drive OAuth Credentials
1. In the [Google Cloud Console](https://console.cloud.google.com), navigate to **APIs & Services → Credentials**.
2. Rotate the OAuth client secret: delete the old secret and create a new one.
3. Update `google_drive_client_secret` in DocuElevate.
4. Re-authorize to obtain a fresh refresh token and update `google_drive_refresh_token`.
For service-account credentials (`google_drive_credentials_json`):
1. Create a new service-account key in the Google Cloud Console.
2. Update `google_drive_credentials_json` with the new JSON.
3. Verify access, then delete the old key.
### OneDrive (Microsoft OAuth)
1. In **Azure App Registrations**, navigate to **Certificates & secrets** for your app.
2. Add a new client secret.
3. Update `onedrive_client_secret` in DocuElevate.
4. Re-authorize via the OAuth flow to get a fresh `onedrive_refresh_token`.
5. Delete the old client secret in Azure.
### SharePoint (Microsoft OAuth)
1. SharePoint uses the same Azure AD app registration as OneDrive.
2. In **Azure App Registrations**, navigate to **Certificates & secrets** for your app.
3. Add a new client secret.
4. Update `sharepoint_client_secret` in DocuElevate.
5. Re-authorize via the OAuth flow to get a fresh `sharepoint_refresh_token`.
6. Delete the old client secret in Azure.
### Authentik (OIDC)
1. In your Authentik admin panel, navigate to the DocuElevate application and regenerate the client secret.
2. Update `authentik_client_secret` in DocuElevate.
3. Restart the application (this setting requires a restart: `restart_required: true`).
### Paperless-ngx API Token
1. Log in to your Paperless-ngx instance → **Settings → API Tokens**.
2. Create a new token.
3. Update `paperless_ngx_api_token` in DocuElevate.
4. Verify document routing works, then revoke the old token.
### SMTP / Email Password
1. Rotate the password in your mail server or email provider.
2. Update `email_password` in DocuElevate.
### IMAP Passwords
Update `imap1_password` and/or `imap2_password` after rotating the credentials with your email provider.
### Nextcloud Password / App Password
1. In Nextcloud → **Settings → Security**, revoke the existing app password and create a new one.
2. Update `nextcloud_password` in DocuElevate.
### FTP / SFTP / WebDAV Passwords
1. Rotate the credential on the respective server.
2. Update `ftp_password`, `sftp_password`, or `webdav_password` in DocuElevate.
### SFTP Private Key
1. Generate a new key pair:
```bash
ssh-keygen -t ed25519 -f ~/.ssh/docuelevate_sftp -C "docuelevate-sftp"
```
2. Install the new public key on the SFTP server.
3. Update `sftp_private_key` (and `sftp_private_key_passphrase` if encrypted) in DocuElevate.
4. Verify connectivity, then remove the old public key from the SFTP server.
### Admin Password
1. Update `admin_password` in DocuElevate (via the Settings UI or API).
2. Communicate the new password to any users who share it (discouraged; prefer individual accounts via OAuth).
3. Requires application restart.
### `SESSION_SECRET`
> **Warning:** Rotating `SESSION_SECRET` invalidates all active user sessions. All logged-in users will be signed out immediately.
1. Generate a new secret (minimum 32 characters):
```bash
python -c "import secrets; print(secrets.token_hex(32))"
```
2. Update the environment variable or `.env` file.
3. Restart the application.
4. Existing encrypted settings stored in the database **will no longer be readable** because the encryption key is derived from `SESSION_SECRET`. You must re-enter all sensitive settings that were stored via the UI after rotating this value.
---
## Bulk Credential Audit
Use the dedicated endpoint to list all credential settings and their configured/unconfigured status:
```bash
GET /api/settings/credentials
```
Example response:
```json
{
"credentials": [
{
"key": "openai_api_key",
"category": "AI Services",
"description": "OpenAI API key for metadata extraction",
"configured": true,
"source": "env"
},
{
"key": "azure_ai_key",
"category": "AI Services",
"description": "Azure AI key for document intelligence",
"configured": true,
"source": "db"
},
...
],
"total": 24,
"configured_count": 8,
"unconfigured_count": 16
}
```
The `source` field indicates whether the value comes from the **database** (`db`) or an **environment variable** (`env`).
---
## Onboarding a New Team Member or Service Account
1. **Identify required credentials** Use `GET /api/settings/credentials` to see which credentials are active in the deployment.
2. **Create service-specific credentials** For each external service (OpenAI, AWS, etc.) create a new API key or sub-account rather than sharing the existing one. This enables individual revocation without disrupting others.
3. **Set credentials via the Settings API** Provide the new credential via `POST /api/settings/{key}`. The value is encrypted at rest.
4. **Restrict access** Ensure the new service account has only the minimum permissions needed (e.g., an S3 IAM user with write access to the specific bucket only).
5. **Document the credential** Record *which* system generated the credential and *when* it was created, so it can be identified during offboarding.
---
## Offboarding a Team Member or Decommissioning a Service Account
1. **Identify credentials tied to the departing user** Review all third-party services for keys or OAuth authorizations issued under their account.
2. **Revoke credentials** Delete or disable the API key/token in each third-party service immediately.
3. **Rotate shared credentials** If any credential was shared (e.g., a team-wide admin password), rotate it now using the procedures above.
4. **Update DocuElevate** Set the new credential via `POST /api/settings/{key}` or delete the old entry via `DELETE /api/settings/{key}` if the service is no longer used.
5. **Verify operations** Trigger a test document processing run to confirm all integrations still work.
6. **Audit logs** Review audit logs for any anomalous activity by the departing user before revoking access.
---
## Emergency Credential Revocation
If a credential is believed to be compromised:
1. **Revoke immediately** in the external service (do not wait to have a replacement ready).
2. **Review audit logs** for unauthorized usage.
3. **Generate and deploy a replacement** credential as soon as possible.
4. **Notify stakeholders** per your incident response plan (see [SECURITY.md](../SECURITY.md)).
---
## Related Documentation
- [Configuration Guide](ConfigurationGuide.md) — Full list of environment variables
- [Deployment Guide](DeploymentGuide.md) — Deployment and restart procedures
- [SECURITY_AUDIT.md](../SECURITY_AUDIT.md) — Security audit findings and status
- [SECURITY.md](../SECURITY.md) — Security contact and disclosure policy