-
-
Notifications
You must be signed in to change notification settings - Fork 101
Architecture
This document covers the complete CertMate architecture — both the main server certificate system and the client certificate subsystem.
- Main System Architecture
- High-Level Diagram
- Manager Classes
- Certificate Creation Flow
- Storage Architecture
- Configuration Structure
- API Endpoints
- Technology Stack
- Client Certificates Architecture
CertMate is a modular, pluggable SSL/TLS certificate management system built with Python/Flask. It supports multiple CA providers, two dozen+ DNS providers, and pluggable storage backends.
Key Facts:
- Language: Python 3.9+ (Flask, Flask-RESTX)
- Storage: Local filesystem default + 4 cloud backends (Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, Infisical)
- CA Providers: Let's Encrypt, DigiCert ACME, Private CA
- DNS Providers: two dozen+ supported (Cloudflare, AWS Route53, Azure, Google, and more — see DNS Providers for the full list)
- API: REST with Swagger/OpenAPI via Flask-RESTX
- Current Certificate Types: Server-side TLS (DV, OV, EV)
┌─────────────────────────────────────────────────────┐
│ CertMate Application │
│ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Web Layer (Flask) │ │
│ │ Dashboard Settings Help Client Certs │ │
│ └────────────────────┬──────────────────────────┘ │
│ ↓ │
│ ┌──────────────────┐ ┌────────────────────────┐ │
│ │ REST API │ │ Web Routes │ │
│ │ /api/certificates│ │ /api/web/certificates │ │
│ │ /api/client-certs│ │ /client-certificates │ │
│ └────────┬─────────┘ └────────┬───────────────┘ │
│ └──────────┬───────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Manager Layer (Business Logic) │ │
│ │ │ │
│ │ CertificateManager CAManager │ │
│ │ DNSManager StorageManager │ │
│ │ AuthManager SettingsManager │ │
│ │ CacheManager FileOperations │ │
│ │ ClientCertManager OCSPResponder │ │
│ │ CRLManager AuditLogger │ │
│ └────────────────────┬──────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Execution Layer │ │
│ │ Certbot (server certs via DNS-01 ACME) │ │
│ │ PrivateCA (client certs via direct signing) │ │
│ └────────────────────┬──────────────────────────┘ │
│ ↓ │
│ ┌───────────────────────────────────────────────┐ │
│ │ Storage Layer (Pluggable Backends) │ │
│ │ Local FS │ Azure KV │ AWS SM │ Vault │ Infis │ │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
CertMateApp (main application)
├── FileOperations # File I/O, backups
├── SettingsManager # Load/save settings.json
├── AuthManager # Token validation
├── CertificateManager # Create/renew/info (server certs)
├── CAManager # CA provider config, Certbot building
├── DNSManager # DNS provider accounts
├── CacheManager # Deployment cache
├── StorageManager # Backend abstraction
├── ClientCertificateManager # Client cert lifecycle
├── PrivateCAGenerator # Self-signed CA management
├── OCSPResponder # Certificate status queries
├── CRLManager # Revocation list generation
└── AuditLogger # Operation tracking
1. User submits: domain, email, DNS provider, CA provider
2. Validate inputs (domain format, email, provider existence)
3. Get CA config (ACME URL, EAB credentials if DigiCert)
4. Get DNS config (account credentials from settings)
5. Create directory: certificates/{domain}/
6. Build certbot command:
certbot certonly --non-interactive --agree-tos
--server {acme_url}
--email {email}
--{dns_plugin} --{dns_plugin}-credentials {cred_file}
--{dns_plugin}-propagation-seconds {timeout}
--eab-kid/--eab-hmac-key (if required)
-d {domain}
7. Create temporary DNS credentials file (600 permissions)
8. Execute certbot (30-minute timeout)
9. Resolve symlinks, copy cert files to domain root
10. Store via configured backend + create metadata.json
11. Clean up credentials file
1. User submits: common_name, email, organization, cert_usage
2. Initialize or load existing CA (4096-bit RSA)
3. Generate CSR (or accept provided CSR)
4. Sign CSR with private CA
5. Store cert/key/csr files + metadata.json
6. Log in audit trail
certificates/
example.com/
cert.pem # Server certificate
chain.pem # Intermediate CA chain
fullchain.pem # cert + chain
privkey.pem # Private key (600 permissions)
metadata.json # Certificate metadata
data/certs/
ca/
ca.crt # CA certificate
ca.key # CA private key (600 permissions)
ca_metadata.json # CA metadata
crl.pem # Certificate Revocation List
client/
api-mtls/ # Certificates by usage type
cert-001/
cert.crt
cert.key
cert.csr
metadata.json
vpn/
cert-002/
...
All backends implement CertificateStorageBackend:
| Backend | Storage Location |
|---|---|
| Local Filesystem |
certificates/{domain}/ (default) |
| Azure Key Vault | Azure Key Vault secrets |
| AWS Secrets Manager | AWS Secrets Manager |
| HashiCorp Vault | Vault KV v1/v2 |
| Infisical | Infisical secrets |
All settings are stored in data/settings.json:
{
"email": "admin@example.com",
"domains": ["example.com", "*.example.com"],
"auto_renew": true,
"renewal_threshold_days": 30,
"api_bearer_token": "secure-token",
"dns_provider": "cloudflare",
"dns_providers": {
"cloudflare": {
"accounts": {
"production": {"api_token": "token-prod"},
"staging": {"api_token": "token-staging"}
}
}
},
"default_accounts": {
"cloudflare": "production"
},
"ca_providers": {
"letsencrypt": {
"accounts": {
"default": {"email": "admin@example.com"}
}
}
},
"certificate_storage": {
"backend": "local_filesystem",
"cert_dir": "certificates"
}
}| Method | Endpoint | Purpose |
|---|---|---|
| GET | /api/health |
Health check |
| GET | /api/certificates |
List all certificates |
| POST | /api/certificates |
Create new certificate |
| GET | /api/certificates/{domain} |
Get certificate info |
| POST | /api/certificates/{domain}/renew |
Renew certificate |
| GET | /api/certificates/{domain}/download |
Download as ZIP |
| GET | /{domain}/tls |
Direct fullchain download |
| Method | Endpoint | Purpose |
|---|---|---|
| POST | /api/client-certs/create |
Create certificate |
| GET | /api/client-certs |
List with filters |
| GET | /api/client-certs/{id} |
Get metadata |
| GET | /api/client-certs/{id}/download/{type} |
Download cert/key/csr |
| POST | /api/client-certs/{id}/revoke |
Revoke certificate |
| POST | /api/client-certs/{id}/renew |
Renew certificate |
| GET | /api/client-certs/stats |
Statistics |
| POST | /api/client-certs/batch |
Batch CSV import |
| GET | /api/ocsp/status/{serial} |
OCSP status |
| GET | /api/crl/download/{format} |
Download CRL |
| Layer | Technologies |
|---|---|
| Backend | Python 3.9+, Flask, Flask-RESTX, APScheduler, Certbot |
| Frontend | HTML5, Tailwind CSS, Vanilla JavaScript, Font Awesome |
| Cloud SDKs | Azure SDK, boto3, hvac, infisical-python |
| Crypto | cryptography (OpenSSL), certbot plugins |
| Deployment | Docker, Docker Compose, Gunicorn, systemd |
- Certbot-only for server certs: DNS-01 ACME challenges only
- Domain-centric server storage: One cert per domain directory
- No DB: Single JSON file for configuration
- Server cert key usage: No control over keyUsage/extendedKeyUsage extensions
Web UI Layer
(/client-certificates web dashboard)
API Layer
(/api/client-certs, /api/ocsp, /api/crl)
(REST endpoints with Flask-RESTX)
Managers Layer
ClientCertificateManager (lifecycle + metadata)
OCSPResponder (certificate status queries)
CRLManager (revocation list generation)
AuditLogger (operation tracking)
SimpleRateLimiter (request throttling)
Core Modules Layer
PrivateCAGenerator (CA management)
CSRHandler (CSR validation & creation)
ClientCertificateManager (cert operations)
OCSPResponder (status responses)
CRLManager (revocation lists)
AuditLogger (logging)
RateLimitConfig/SimpleRateLimiter (limiting)
Cryptography & Storage Layer
Cryptography Library (OpenSSL)
File System Storage (data/certs/)
Storage Backends (Azure, AWS, Vault, etc)
Purpose: Generate and manage the self-signed Certificate Authority
Key Features:
- Generates 4096-bit RSA keys for CA
- 10-year validity period
- Self-signed certificates with proper extensions
- CA backup and restore functionality
- CRL signing capability
Files Created:
-
data/certs/ca/ca.crt- CA certificate (PEM) -
data/certs/ca/ca.key- CA private key (PEM, 0600 permissions) -
data/certs/ca/ca_metadata.json- CA metadata -
data/certs/ca/crl.pem- Certificate Revocation List
Key Methods:
initialize() # Initialize or load existing CA
sign_certificate_request() # Sign a CSR
generate_crl() # Generate CRL from revoked serials
get_crl_pem() # Get CRL in PEM formatPurpose: Validate, parse, and create Certificate Signing Requests
Key Features:
- Create new CSRs with private keys (2048 or 4096-bit)
- Validate PEM-encoded CSRs
- Extract CSR information (CN, Org, Email, SAN, etc.)
- Support for Subject Alternative Names (SANs)
- Save CSR and key pairs to disk
Key Methods:
create_csr() # Create new CSR with private key
validate_csr_pem() # Validate and load CSR from PEM
get_csr_info() # Extract information from CSR
save_csr_and_key() # Save CSR and key to filesPurpose: Complete lifecycle management of client certificates
Key Features:
- Create certificates (with CA-signed or CSR)
- List/filter certificates (by usage, status, search)
- Revoke certificates with audit trail
- Renew certificates (same CN, new serial)
- Auto-renewal scheduling
- Metadata storage (JSON per certificate)
- Support for 30k+ concurrent certificates
Storage Structure:
data/certs/client/
api-mtls/ # Certificates for API mTLS
cert-001/
cert.crt
cert.key
cert.csr
metadata.json
vpn/ # Certificates for VPN
cert-002/
...
other/ # Other usage types
...
Metadata Structure (JSON):
{
"type": "client_certificate",
"identifier": "cert-001",
"common_name": "user@example.com",
"email": "user@example.com",
"organization": "ACME Corp",
"organizational_unit": "Engineering",
"country": "US",
"state": "California",
"locality": "San Francisco",
"serial_number": "12345678901234567890",
"key_usage": ["digitalSignature", "keyEncipherment"],
"extended_key_usage": ["serverAuth", "clientAuth"],
"created_at": "2024-10-30T18:00:00Z",
"expires_at": "2025-10-30T18:00:00Z",
"cert_usage": "api-mtls",
"notes": "Production certificate",
"revocation": {
"revoked": false,
"revoked_at": null,
"reason_revoked": null
},
"renewal": {
"renewal_enabled": true,
"renewal_threshold_days": 30,
"last_renewed_at": null
}
}Key Methods:
create_client_certificate() # Create new certificate
list_client_certificates() # List with optional filters
get_certificate_metadata() # Get cert metadata
get_certificate_file() # Get cert/key/csr file
revoke_certificate() # Revoke with reason
renew_certificate() # Renew certificate
check_renewals() # Auto-renewal check
get_statistics() # Get usage statisticsPurpose: Provide Online Certificate Status Protocol (OCSP) responses
Key Features:
- Query certificate status (good/revoked/unknown)
- Generate OCSP responses
- Real-time status lookups
- Support for multiple status types
Statuses:
-
good- Certificate is valid -
revoked- Certificate has been revoked -
unknown- Certificate not found
Key Methods:
get_cert_status() # Get certificate status
generate_ocsp_response() # Generate OCSP responseResponse Format:
{
"response_status": "successful",
"certificate_status": "good|revoked|unknown",
"certificate_serial": 12345678,
"this_update": "2024-10-30T18:00:00Z",
"next_update": null,
"responder_name": "CertMate OCSP Responder",
"revocation_time": null,
"revocation_reason": null
}Purpose: Generate and distribute Certificate Revocation Lists
Key Features:
- Generate CRL with all revoked certificates
- Distribute in PEM and DER formats
- Store CRL metadata and info
- Automatic CRL updates
Key Methods:
get_revoked_serials() # Get revoked certificate serials
update_crl() # Generate/update CRL
get_crl_pem() # Get CRL in PEM format
get_crl_der() # Get CRL in DER format
get_crl_info() # Get CRL metadataPurpose: Track all certificate operations for compliance and debugging
Key Features:
- JSON format logging
- Persistent audit file
- Track operations, users, IP addresses
- Query entries by resource or time
Log Format:
{
"timestamp": "2024-10-30T18:00:00Z",
"operation": "create|revoke|renew|download|batch_import",
"resource_type": "certificate|endpoint",
"resource_id": "cert-001",
"status": "success|failure|denied",
"user": "admin@example.com",
"ip_address": "192.168.1.1",
"details": {},
"error": null
}Log File: logs/audit/certificate_audit.log
Key Methods:
log_certificate_created() # Log cert creation
log_certificate_revoked() # Log revocation
log_certificate_renewed() # Log renewal
log_certificate_downloaded() # Log downloads
log_batch_operation() # Log batch operations
log_api_request() # Log API requests
get_recent_entries() # Get latest audit entries
get_entries_by_resource() # Get entries for a resourcePurpose: Protect API from abuse with request rate limiting
Configuration:
- Default: 100 req/min
- Certificate creation: 30 req/min (expensive)
- Batch operations: 10 req/min (very expensive)
- OCSP status: 200 req/min (cheap)
- CRL download: 60 req/min
Key Classes:
RateLimitConfig # Configuration holder
SimpleRateLimiter # In-memory limiter
rate_limit_decorator # Flask endpoint decoratorResponse on Rate Limit:
{
"error": "Rate limit exceeded",
"message": "Too many requests. Please try again later.",
"retry_after": 60
}HTTP Status: 429 Too Many Requests
User/API Request
↓
ClientCertificateManager.create_client_certificate()
Generate CSR (or accept provided CSR)
Sign CSR with private CA
Create metadata.json
Store cert/key/csr files
Log in audit trail
Return cert data
↓
Response to User
User/API Request (revoke endpoint)
↓
ClientCertificateManager.revoke_certificate()
Load certificate metadata
Update revocation status
Save updated metadata
Log in audit trail
Trigger CRL update
Return success
↓
Response to User
Client OCSP Request (serial number)
↓
OCSPResponder.get_cert_status()
Search certificate by serial
Check revocation status
Return status (good/revoked/unknown)
↓
OCSPResponder.generate_ocsp_response()
Format OCSP response
Add timestamps
Return response
↓
Response to Client
data/certs/
ca/ # Certificate Authority
ca.crt # CA certificate (public)
ca.key # CA private key (0600)
ca_metadata.json # CA metadata
crl.pem # Certificate Revocation List
client/ # Client certificates
api-mtls/ # API mTLS certificates
cert-001/
cert.crt
cert.key
cert.csr
metadata.json
...
vpn/ # VPN certificates
...
other/ # Other usage types
...
crl/ # CRL storage
(generated CRLs)
Each certificate has a metadata.json file containing:
- Certificate identification (CN, serial, fingerprint)
- Subject information (Org, email, location)
- Validity dates
- Revocation status and history
- Renewal configuration
- Custom notes
- File Permissions: 0600 (read/write for owner only)
- Key Format: PEM with OpenSSL Traditional format
- No Key Encryption: Keys stored encrypted at REST if using storage backends
- Signature Algorithm: SHA256withRSA
- Key Size: 4096-bit RSA for CA, 2048/4096-bit for clients
- Validity: Configurable (default 1 year for client certs)
- Authentication: Bearer token on all API endpoints
- Authorization: Token-based (can be extended with roles)
- Rate Limiting: Per-endpoint protection
- All operations logged with timestamp
- User and IP address tracking
- Immutable audit log file
- Query-able for compliance
- Linear Scalability: Directory-based storage
- Capacity: Tested with 30k+ certificates
- Performance: Efficient O(n) directory scans
- Rate Limiting: Prevents resource exhaustion
- Stateless Design: Can run multiple instances
- Batch Operations: Handles 100-30k certs per request
- Scheduled: Daily at 3 AM (configurable)
- Threshold: 30 days before expiry (configurable)
- Graceful: Continues on errors, logs for review
- Python 3.9+
- 100MB disk space for CA and initial certificates
- 50MB for audit logs per 1M operations
- Low memory footprint
- Use storage backend (Azure, AWS, Vault) for HA
- Enable audit logging for compliance
- Configure rate limiting based on load
- Regular CRL updates (daily or on revocation)
- Backup CA keys and metadata
- Monitor audit logs for suspicious activity
For multi-instance deployments:
- Use shared storage backend for certificates
- Synchronize audit logs to central location
- Use load balancer with sticky sessions
- Monitor rate limit counters across instances
- Uses existing CertMate storage backends
- Integrated in app.py managers
- Part of Flask-RESTX API structure
- Scheduled with APScheduler
- Can export certificates via API
- Can query status via OCSP
- Can retrieve CRL for validation
- Supports webhook/callback integration (future)
- CA Password Protection - Encrypt CA keys with password
- Advanced Audit - Role-based access control
- Webhook Notifications - On certificate events
- Certificate Signing - Accept CSRs from external sources
- Hardware Tokens - PKCS#11 support for HSMs
- Storage Backends - Already supports multiple backends
- Audit Sinks - Can send audit logs to external systems
- API Middleware - Add custom authentication/authorization
- Notification System - Integrate with alerting systems
- Certificate counts (total, active, revoked, expiring soon)
- API endpoint performance
- Rate limit violations
- Audit log volume
- Auto-renewal success/failure rate
- CA availability
- Audit logger functionality
- Rate limiter responsiveness
- CRL generation status
CertMate · README · Releases · Report a bug · Request a feature
Getting started
Core configuration
Client certificates
Reference
Project