Last Updated: March 18, 2026 Purpose: Compact overview of the security controls implemented in the current PKI application.
This application manages certificate issuance, renewal, revocation, CRL generation, and certificate artifact downloads. It protects sensitive operations with layered controls:
- JWT-based session authentication
- role-based authorization
- dual protection for Root CA private key use
- encryption at rest for certificate material
- request middleware for CSRF and security headers
- audit logging for certificate lifecycle actions
The application is security-sensitive, but deployment hardening is still the operator's responsibility.
The Root CA private key is the highest-value secret in the system. Access requires two independent inputs:
- A filesystem password generated by the system and stored encrypted in
.pwd.enc - A user-provided root password supplied at Root CA creation time and again for Root CA operations
The effective decryption key is derived with HMAC-SHA256 using the filesystem password and the user password. The root password is never stored on disk and must be re-entered when the Root CA private key is needed.
Used for:
- Root CA creation
- Intermediate CA creation signed by the Root CA
- Revocation flows that require the Root CA private key for CRL regeneration
Security properties:
- possession of disk artifacts alone is not enough
- knowledge of the user password alone is not enough
- wrong passwords fail at the cryptographic layer
- user password stays in memory only
Intermediate CA private keys do not use the same dual-password model. They are encrypted with their own filesystem password only.
Sensitive certificate artifacts are stored encrypted on disk.
- Algorithm: AES-256-GCM
- Key derivation: PBKDF2-HMAC-SHA256
- Salt:
PKI_ENCRYPTION_SALT(installation-specific) - Nonce: random 12-byte nonce per file
Protected artifacts include:
- encrypted PEM files
- encrypted private keys
- encrypted password files such as
.pwd.enc
This provides confidentiality and integrity for stored certificate material. Operators must still protect filesystem access and backups.
Authentication is session-based and uses JWTs issued after API key validation.
- JWT algorithm: HS256
- Token stored in HTTPOnly cookie
SecureandSameSitecookie behavior controlled by deployment settings- Token includes session identity and role claims
- Expired or invalid tokens are rejected and redirected to login flows
Important deployment note:
PKI_JWT_SECRETis required- operators should use a strong random secret of at least 32 characters
The FastAPI app applies middleware-based protections to all requests.
Authentication/session middleware:
- validates public route exemptions from
rbac.json(marked with["public"]sentinel) - validates signed JWT session cookies for protected routes
- loads session role and enforces RBAC checks for protected endpoints
CSRF protection:
- state-changing requests (POST, PUT, DELETE, PATCH) require either:
- A valid session cookie (SameSite=Lax primary defense), OR
X-Requested-With: xmlhttprequestheader (for AJAX requests)
- public endpoints (marked with
["public"]) are exempt from CSRF checks - intended to reduce forged browser-origin requests
Security headers:
X-Frame-Options: DENYX-Content-Type-Options: nosniffReferrer-Policy: strict-origin-when-cross-originContent-Security-PolicyStrict-Transport-Securityon HTTPS deployments
These controls reduce exposure to clickjacking, MIME sniffing, weak cross-origin behavior, and basic browser-side attack classes.
Authorization is enforced per route using roles from the JWT. All route access policies are configuration-driven via backend/config/rbac.json without requiring code changes.
Supported roles:
admin: full management operationsmanager: limited certificate-management operationsuser: read-only access
Configuration example (backend/config/rbac.json):
{
"GET /toolbox": ["admin"],
"POST /create-organization": ["admin"],
"GET /organizations": ["admin", "manager", "user"],
"GET /auth/login": ["public"]
}Access rules:
- Public routes (sentinel:
["public"]) require no authentication - Protected routes with explicit role list enforce role checks
- Routes without explicit role list allow any authenticated user
Examples of protected behavior:
- organization creation is admin-only
- revocation is restricted to admin
- lower roles cannot use privileged management routes
- unauthenticated requests to protected routes redirect to login
Configuration validation at startup:
- Format validation: all routes are
"METHOD /path"with valid roles - Role validation: all roles are
admin,manager,user, orpublicsentinel - Public route coverage: all expected public routes (login, health, CRL, static files) are configured
- Private route coverage: all expected protected routes are configured and not accidentally marked public
- Permission changes require editing
rbac.jsonand restarting (no Python code deployments) - Comprehensive error messages identify exactly which routes are misconfigured
RBAC is one of the main protections against accidental or malicious privilege escalation.
The app validates inputs at the application boundary and uses parameterized SQL access through SQLAlchemy-based database code.
This is intended to reduce risk from:
- malformed certificate requests
- invalid revocation reasons
- certificate chain misuse
- SQL injection
- cross-organization access attempts
Database constraints also reinforce uniqueness and relationship integrity for organizations, certificates, issuer links, and certificate identifiers.
The application avoids exposing internal stack traces and implementation details to end users.
- user-facing errors are generic
- server logs retain diagnostic detail
- cryptographic failures do not intentionally disclose password correctness
This limits reconnaissance value for attackers while preserving enough telemetry for operators.
Security-relevant certificate operations are logged with session identity and timestamps.
Typical events include:
- certificate creation
- certificate renewal
- certificate revocation
- artifact downloads
- PKCS#12 password view actions
This supports traceability, forensic review, and operational accountability.
Certificate revocation updates both certificate state and CRL-related records.
- revoked certificates are tracked in the database
- CRL metadata is tracked relationally
- revocation flows regenerate CRLs for affected issuers
- CA hierarchy checks help prevent invalid revocation sequences
For Root CA operations, revocation security is tied to the dual-protection model because Root CA private key access is required.
Certificate generation and related cryptographic operations can invoke subprocesses. Timeouts are enforced to reduce denial-of-service risk from hung child processes.
Operators are responsible for:
- enabling HTTPS in front of the app
- setting
PKI_COOKIE_SECURE=truein production - choosing strong values for
PKI_JWT_SECRET, API keys, andPKI_ENCRYPTION_KEY - generating a unique
PKI_ENCRYPTION_SALT - protecting
.env, database files, encrypted certificate storage, and backups - validating reverse proxy behavior for cookies, headers, and TLS termination
- backing up the database and encrypted certificate storage regularly
Built-in Backup Feature:
- Admin users can export a full backup via the Toolbox page (
GET /admin/backup/database) - The export creates a consistent ZIP archive containing:
pki.db— SQLite database snapshot (created using WAL-safe online backup API)data/— Complete encrypted certificate storage directory tree
- The backup can be safely downloaded while the application is live (no database locks)
- Filename format:
pki-backup-YYYY-MM-DD.zip
Built-in Restore Feature:
- Admin users can restore a previously exported backup via the Toolbox page (
POST /admin/restore/database) - The restore process:
- Validates ZIP integrity and structure (rejects path traversal attempts, unexpected content)
- Verifies SQLite database integrity (
PRAGMA integrity_check) - Confirms schema version compatibility (must match current application version)
- Rewrites paths if restoring from a different data directory (e.g., Windows → Linux, or different environment)
- Performs atomic swap of database and data directory (maintains consistency)
- Preserves recovery backups during the operation
- Cross-platform restore supported: backups can be restored to a different operating system or directory layout (e.g., Windows backup → Linux deployment) as long as encryption keys match
- Can be safely run while the application is live (no manual restart required)
- Upload limits: 5 GB max file size, 10 GB max uncompressed size
- Error recovery:
- All validations occur before touching live data
- If any check fails before the swap point, live state is untouched
- If the swap fails, automatic recovery restores from backup
- Old database and data backups are preserved during recovery but cleaned up after successful restore
Backup Storage Security:
- Backup files contain encrypted certificate material (
*.pem.enc,*.p12.enc) with AES-256-GCM encryption - Full backups should be stored in a secure location with restricted filesystem access
- If storing backups off-site or in cloud storage, ensure encryption in transit and at rest
- Critical requirement: The encryption key (
PKI_ENCRYPTION_KEY) and salt (PKI_ENCRYPTION_SALT) must be identical between backup and restore environments; without matching keys, certificate material cannot be decrypted during restore - Test restore procedures regularly to ensure backup integrity, especially for cross-platform or cross-environment restores
- Backup operations are audit-logged with the requesting user's identity
Manual Backup Alternative:
- Operators can manually archive both
database/pki.dband thedata/directory - Ensure backups are taken consistently and stored securely
Recommended production posture:
- TLS 1.2+
- strong random secrets
- restricted filesystem permissions
- encrypted backups
- log monitoring for auth failures and server errors
- The app requires strong operator-managed secrets; it does not fully enforce secret strength by itself.
- Rate limiting on
POST /auth/session(accepted risk): The authentication endpoint accepts API key credentials with no application-level rate limiting or lockout. Brute-force enumeration of API keys is theoretically possible for any client with network access. This is an accepted risk: rate limiting is treated as a deployment-layer responsibility. Operators should enforce it via reverse proxy rate limiting (e.g., nginxlimit_req_zone, Caddyrate_limit), WAF rules targeting the/auth/sessionpath, or network policy restricting client access to the endpoint. - CSP: no
unsafe-inline:script-srcandstyle-srcare restricted to'self'. All inline scripts and styles have been extracted to static files under/static/. Server-side Jinja2 values are passed to JS via<script type="application/json">data islands. Inline event handlers have been replaced withaddEventListenerbindings, withdata-*attributes carrying per-element server-rendered values. Future template changes must not reintroduce inline scripts, inline styles, oron*HTML attributes. - Security posture depends on correct environment configuration, HTTPS, and access control around the host filesystem.