Open-source TLS certificate discovery and lifecycle management.
Discover every certificate before it becomes an outage.
Quick Start • Features • Architecture • Roadmap
TLS certificate management is becoming an automation problem.
As certificate lifetimes continue to shrink, manual inventories, renewal spreadsheets, and undocumented endpoints become increasingly risky.
CertDiscovery follows a simple principle:
Discovery first. Automation second.
Before you can automate certificate renewal, you need to know:
- Which certificates exist
- Where they are deployed
- When they expire
- Which systems depend on them
CertDiscovery provides a centralized view of your certificate estate and the automation foundation required to manage it.
You can't automate certificates you don't know exist.
Certificate lifecycle management is becoming an automation problem.
398 days
↓
200 days
↓
100 days
↓
47 days
Manual certificate inventories and renewal processes won't scale.
TLS certificate lifetimes are getting shorter. CertDiscovery helps you discover certificates across your infrastructure, build a centralized inventory, monitor expiration, and automate certificate lifecycle operations.
See certificate health, upcoming expirations, managed assets, and recent scan activity from a single operational view. The dashboard shown above gives teams an immediate view of their current TLS risk.
Build a searchable source of truth for certificate ownership, validity, issuer, fingerprints, SANs, certificate chains, and the assets where each certificate is used.
Scan CIDR ranges to uncover TLS endpoints that are missing from the known asset inventory, inspect their certificates, and promote discovered endpoints into managed assets.
- Asset-based TLS scanning — HTTPS, TLS, SMTPS, IMAPS, POP3S, LDAPS with scheduled and manual scans
- Network range discovery — CIDR-based TCP+TLS probing with endpoint promotion to assets
- Certificate inventory — fingerprinting, SAN parsing, chain entries, expiration tracking
- Web dashboard — assets, certificates, scan jobs, worker status, and alert thresholds
- REST API + Swagger — full programmatic access at
/swagger - Python asyncio workers — concurrent discovery via API-key-protected job polling
- Vault integration — import from public TLS endpoints, PKI mounts, and KV v2 secrets
- ACME issuance — DNS-01 validation with manual, Cloudflare, AWS Route53 or Azure DNS TXT publishing
- Scheduled ACME renewal — threshold-based renewal with Vault KV storage
- Observability — Prometheus
/metricsand OpenTelemetry instrumentation - Role-based access — Admin and Read roles with cookie authentication
- Docker Desktop
git clone https://github.com/ErtugrulKra/CertDiscovery.git
cd CertDiscovery
docker compose up --build| Service | URL |
|---|---|
| Web UI | http://localhost:8080 |
| Swagger | http://localhost:8080/swagger |
| Prometheus metrics | http://localhost:8080/metrics |
| Dev Vault (Compose only) | http://localhost:8200 |
On first startup, a default admin user is created:
User name: Admin
Password: Admin123
Change this password or disable the account after creating a new Admin user.
Compose reads .env.example by default. For production-like usage, copy it to .env, change the secret values, and update the env_file entry in docker-compose.yml to .env.
The SQLite database is stored on the certificate_sqlite named volume mounted into the certificate-web container.
CertDiscovery follows a discovery-first architecture.
- Infrastructure assets and network ranges are scanned by Python workers.
- Discovery results are submitted through the REST API.
- Certificates are normalized into a centralized inventory.
- ACME and DNS integrations automate issuance and renewal.
- HashiCorp Vault can be used for certificate storage and discovery.
The pre-refactoring lifecycle baseline is documented in
docs/architecture/current-state.md,
docs/architecture/current-acme-flow.md
and docs/architecture/current-data-model.md.
The current plaintext-secret risks are tracked in
docs/security/secret-inventory.md.
Sectigo EAB and persistent ACME account setup is documented in
docs/integrations/sectigo-acme.md.
Certificate lifecycle integrations use explicit provider boundaries:
IAcmeCertificateClientisolates Certes order and issuance behavior.IDnsChallengeProviderand its resolver isolate manual, Cloudflare, Route53 and Azure DNS.ICertificateStoreisolates Vault KV storage.ICertificateDeploymentOrchestratorseparates issuance from lease-based, auditable deployment.ICertificateDeployeradapters implement precheck, backup, deploy, activation, verification and rollback.ICertificateInventoryWriterowns X.509 parsing and inventory persistence.ICertificateRequestStateMachinevalidates lifecycle state transitions.
New DNS and certificate storage integrations should be registered through the provider extension methods instead of adding provider switches to controllers or the request orchestration service.
- Prometheus and OpenTelemetry provide operational visibility.
Discovery first. Automation second.
- .NET SDK 8 or 9
- Python 3.12 recommended (3.11 also works for local tests)
- Docker Desktop (optional, for full stack)
dotnet restore CertificateDiscovery.sln --configfile NuGet.Config
dotnet run --project src/CertificateDiscovery.Web/CertificateDiscovery.Web.csprojThe port may differ depending on launchSettings.json or console output.
cd workers/certificate-discovery-worker
python -m venv .venv
# Linux/macOS
source .venv/bin/activate
pip install -r requirements.txt
export WORKER_API_BASE_URL=http://localhost:5080
export WORKER_API_KEY=dev-worker-key-change-me
python -m worker.main
# Windows PowerShell
.venv\Scripts\python.exe -m pip install -r requirements.txt
$env:WORKER_API_BASE_URL="http://localhost:5080"
$env:WORKER_API_KEY="dev-worker-key-change-me"
.venv\Scripts\python.exe -m worker.mainexport WORKER_API_BASE_URL=http://localhost:5080
export WORKER_API_KEY=dev-worker-key-change-me
export WORKER_NAME=certificate-range-worker-local
python -m worker.range_mainThe EF Core tool manifest is included in .config/dotnet-tools.json.
dotnet tool restore
dotnet tool run dotnet-ef migrations add MigrationName --project src/CertificateDiscovery.Infrastructure --startup-project src/CertificateDiscovery.Web --output-dir Persistence/Migrations
dotnet tool run dotnet-ef database update --project src/CertificateDiscovery.Infrastructure --startup-project src/CertificateDiscovery.WebIn development, if CertificateDiscovery:ApplyMigrationsOnStartup=true, the application applies migrations during startup. Disable this in production through configuration.
Core worker environment variables:
| Variable | Description |
|---|---|
WORKER_API_BASE_URL |
Base URL of the web API |
WORKER_API_KEY |
Shared API key for worker authentication |
WORKER_NAME |
Worker identifier for heartbeat and job claiming |
WORKER_MAX_CONCURRENCY |
Maximum concurrent scan tasks |
WORKER_POLL_INTERVAL_SECONDS |
Job polling interval |
WORKER_REQUEST_TIMEOUT_SECONDS |
Per-scan timeout |
See .env.example for the full list including scheduler, OpenTelemetry, and range worker settings.
Supported worker protocols: HTTPS, TLS, SMTPS, IMAPS, POP3S, LDAPS.
Interactive API documentation is available at /swagger when the web application is running.
Key endpoints:
- Assets —
GET/POST/PUT/DELETE /api/assets,POST /api/assets/{id}/scan - Certificates —
GET /api/certificates,GET /api/certificates/{id}/assets - Scan jobs —
GET/POST /api/scan-jobs - Workers —
GET /api/workers/jobs/next,POST /api/workers/heartbeat,POST /api/workers/scan-results - Metrics —
GET /metrics
Worker endpoints require the X-Worker-Api-Key header.
Important: This application performs outbound TLS connections to user-controlled host/port values. Treat SSRF risk seriously in production deployments.
- Change the default
Admin/Admin123credentials immediately after first login. - Provide the worker API key through environment variables — never embed it in source code.
- ACME account keys, EAB secrets and DNS provider credentials are encrypted through secret references; configure persistent Data Protection keys and an external secret provider before production use.
- Raw PEM data is not shown in UI lists; it is stored in the database.
- For production: enable HTTPS, configure cookie policy, rotate secrets, add audit logging, and apply private network allowlist/denylist controls for worker outbound connections.
- The Docker Compose Vault service runs in dev mode with a
roottoken. Do not use this configuration in production.
The application uses cookie authentication with PBKDF2-SHA256 password hashing.
| Role | Permissions |
|---|---|
Admin |
Full access: assets, scans, users, integrations, network discovery, certificate requests |
Read |
View-only access to Dashboard, Assets, Certificates, and Scan Jobs |
Users are created by an Admin from the /Users screen.
dotnet test CertificateDiscovery.slnPython worker tests:
cd workers/certificate-discovery-worker
python -m venv .venv
source .venv/bin/activate # or .venv\Scripts\activate on Windows
pip install -r requirements.txt
PYTHONPATH=. python -m pytest tests -qUI path: /NetworkDiscovery
Example job configuration:
Name: Datacenter edge scan
CIDR: 10.10.0.0/24
Ports: 443,8443,9443,465,993,995,636
TimeoutSeconds: 3
MaxConcurrency: 100
For safety, the IPv4 CIDR prefix is limited to /16 through /32. The range worker performs a TCP+TLS attempt for every IP/port combination. Discovered endpoints can be promoted to normal Assets by an Admin.
Notes:
- Because connections are made by IP address, SNI may be unknown. Reverse DNS is tried when available.
- STARTTLS ports are not included in the first version of this module.
- For large ranges, choose timeout and concurrency values carefully.
Manage integrations at /Integrations. Issue certificates at /CertificateRequests.
Vault actions:
Scan TLS— import the public TLS certificate from a Vault server endpointImport PKI— import certificates from a HashiCorp Vault PKI mount- Vault KV discovery — scan KV v2 secrets at
/VaultDiscovery
Kubernetes TLS Secret discovery:
- Register an HTTPS Kubernetes API server and protected service-account token.
- Limit discovery to a comma-separated namespace allowlist, or scan the full cluster.
- Import leaf certificates, chains, SANs, validity, issuer and subject from
kubernetes.io/tlsSecrets. - Preserve every cluster / namespace / Secret source while deduplicating certificates by fingerprint.
- Private key material is never displayed, logged, or stored.
See Kubernetes TLS Secret discovery and minimum RBAC.
ACME DNS-01 workflow:
- Create an ACME provider (start with Let's Encrypt Staging).
- Create a Vault integration (Compose dev Vault:
http://vault:8200, tokenroot). - Optionally create a Cloudflare, Route53 or Azure DNS provider for automatic TXT publishing. See enterprise DNS setup.
- Create a certificate request with domain, SANs, and Vault KV path.
- Start the challenge, publish TXT records (automatic or manual), validate, issue, and store in Vault.
Example DNS provider:
Name: Cloudflare example.com
Provider type: Cloudflare
DNS zone: example.com
API token: Cloudflare token with Zone:Read and DNS:Edit permissions
Enabled: enabled
Example certificate request:
Primary domain: example.com
Subject Alternative Names: www.example.com
DNS provider: Cloudflare example.com, or Manual TXT only
Vault KV secret path: secret/certificates/example.com
Scheduled ACME renewal: Enable ScheduleCheck on a certificate request with a validity threshold (default 5 days) and CRON expression (default 0 0 * * *). The built-in renewal worker handles challenge recreation, DNS publishing, issuance, Vault storage, and TXT cleanup.
Prometheus metrics at /metrics include:
certificate_discovery_certificate_not_after_timestamp_secondscertificate_discovery_certificate_expires_in_dayscertificate_discovery_certificate_expiredcertificate_discovery_certificate_chain_entriescertificate_discovery_certificate_status_total
OpenTelemetry export:
CertificateDiscovery__OpenTelemetry__ServiceName=certificate-discovery
CertificateDiscovery__OpenTelemetry__OtlpEndpoint=http://otel-collector:4317
- Add the protocol to the
AssetProtocolenum in the Domain project. - Add it to the worker
SUPPORTED_PROTOCOLSlist. - For protocols requiring pre-handshake negotiation (e.g. STARTTLS), add an adapter in
discovery.py. - Add successful and error-mapping scenarios to worker tests.
- Certificate chain entries depend on worker runtime peer chain retrieval.
- STARTTLS protocols are an extension point, not yet implemented.
- Worker health uses a heartbeat model instead of a worker HTTP endpoint.
- Private network allowlisting for SSRF mitigation is not yet implemented.
- Test coverage covers core domain, service, health, and parser tests; full integration scenarios are not yet automated.
- STARTTLS adapters
- Certificate chain analysis
- OCSP/CRL checking
- Notification system (Email, Teams, Slack)
- Additional DNS provider integrations beyond Cloudflare, Route53 and Azure DNS
- PostgreSQL and RabbitMQ backends
- Multi-tenancy
- Kubernetes deployment manifests
This project is licensed under the MIT License.




