VaultCertsViewer : a lightweight dashboard to track certificate health
Tracking TLS certificates distributed across multiple Vault PKI engines can quickly become tedious: forgotten expirations, emergency renewals, lack of visibility.
VCV (Vault Certificate Viewer) is a lightweight, self-hosted web application that provides a clear and fast view of your certificates issued by Vault — to act before incidents occur.
What problem does VCV solve?#
Organizations using HashiCorp Vault often have to manage:
- Multiple Vault instances and environments
- Multiple PKI mounts (root, intermediate, teams/applications dedicated)
- Certificates that expire at different rates, in different places
- The need for a simple and unique interface
VCV focuses on the essentials: visibility and clarity.
What you get#
A clear certificate inventory#
VCV lists the certificates issued by your Vault PKI engines with the useful information:
- Common Name (CN)
- Issuer / source mount
- Expiration date (the most important)
- Days remaining
- Status (revoked, expired, valid)
The goal: quickly answer questions like:
- “Which certificates are expiring soon?”
- “Which PKI mount produces the most short-lived certificates?”
- “Are we safe for the next X days?”
Configurable expiration thresholds#
Policies vary depending on environments. VCV offers configurable expiration thresholds (for example: warning at 30 days, critical at 7 days) to match your operational practices without modifying the code.
A simple web interface#
VCV is designed to be:
- Easy to run (self-hosted)
- Fast to use
- Accessible to operators
No unnecessary complexity: just the dashboard.
Ready for monitoring (metrics & alerting)#
VCV exposes metrics to integrate with your monitoring stack (e.g. Prometheus or VictoriaMetrics). You can then create alerts such as:
- “Certificates expiring in < 7 days”
- “Vault connectivity issue”
- “Last retrieval too old”
How VCV integrates into your workflow#
VCV does not seek to replace Vault or your monitoring. It complements the ecosystem:
- Vault remains the source of truth
- VCV makes the data easy to consume
- Prometheus/Alertmanager (or equivalent) triggers alerts at the right time
Concretely, teams use VCV as:
- A daily/weekly verification dashboard
- A prevention tool for incidents
- A quick view during PKI Vault diagnostics
For whom?#
VCV is particularly useful if you:
- Exploit Vault PKI in one or multiple instances
- Manage multiple PKI mounts
- Support many internal services with short-lived certificates
- Look for a lightweight UI to spot risks early
Why VCV is deliberately “small”#
Many certificate management platforms become full-fledged ecosystems. VCV remains deliberately focused:
- Minimal operational complexity
- Simple deployment and updates
- Clear UI and immediate value
If you already trust Vault for PKI, VCV helps you trust your visibility.
Application administration#
VCV is designed to remain easy to operate: administrators configure the connection to Vault (addresses and authentication), select the PKI mounts to expose, and adjust expiration thresholds according to the organization’s policy.
Via a password-protected page, the administration area will present forms to add all the paths to the Vault instances you manage. All information is stored in a JSON format file.
VCV does not replace Vault governance: access control and secret management remain handled by Vault; the admin’s challenge is secure configuration, observability, and regular credential rotation.
Deployment with docker#
Prerequisites#
The application configuration information is stored in a settings.json file. You must create this file before launching the container.
Create this settings.json file in the working directory, and enter these details by replacing the values with your own data:
{
"app": {
"env": "prod",
"logging": {
"level": "info",
"format": "json",
"output": "both",
"file_path": "/var/log/app/vcv.log"
},
"port": 52000
},
"certificates": {
"expiration_thresholds": {
"critical": 2,
"warning": 10
}
},
"cors": {
"allowed_origins": ["http://localhost:4321", "http://localhost:3000"],
"allow_credentials": true
},
"vaults": [
{
"id": "vault-main",
"address": "http://vault:8200",
"token": "root",
"pki_mounts": ["pki", "pki_dev", "pki_stage", "pki_production"],
"display_name": "Vault",
"tls_ca_cert_base64": "BASE64_PEM_CA_BUNDLE",
"tls_ca_cert": "",
"tls_ca_path": "",
"tls_server_name": "vault.service.consul",
"tls_insecure": true,
"enabled": true
},
{
"id": "vault-dev",
"address": "http://vault-dev:8200",
"token": "root",
"pki_mounts": ["pki", "pki_corporate", "pki_external", "pki_partners"],
"display_name": "Vault dev",
"tls_ca_cert_base64": "BASE64_PEM_CA_BUNDLE",
"tls_ca_cert": "",
"tls_ca_path": "",
"tls_server_name": "vault-dev.service.consul",
"tls_insecure": true,
"enabled": true
}
]
}Quick test with docker run#
Simply enter this command to launch vcv and access VCV:
docker run -d \
-v "$(pwd)/settings.json:/app/settings.json:rw" \
-v "$(pwd)/logs:/var/log/app:rw" \
--cap-drop=ALL --read-only --security-opt no-new-privileges:true \
-p 52000:52000 jhmmt/vcv:1.6Production deployment with docker-compose#
Create this docker-compose.yml file and enter these details:
---
services:
vcv:
image: jhmmt/vcv:1.6
container_name: vcv
restart: unless-stopped
ports:
- "52000:52000/tcp"
cap_drop:
- ALL
read_only: true
security_opt:
- no-new-privileges:true
environment: # admin password: 'admin'
- VCV_ADMIN_PASSWORD=$$2y$$10$$.SWJT4Amz9tyq4qq2vqQyOZm/KZAf38YVVNxj/6EvYLk4I0C6Q9A2
- SETTINGS_PATH=/app/settings.json
volumes:
- ./settings.json:/app/settings.json:rw
deploy:
resources:
limits:
cpus: "0.50"
memory: 64MDeployment in Kubernetes#
Since VaultCertsViewer is a single-binary image, it is entirely possible to deploy the application in a Kubernetes cluster. Here is the complete manifest to use:
apiVersion: v1
kind: Namespace
metadata:
name: vcv
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: vcv-sa
namespace: vcv
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: vcv
namespace: vcv
labels:
app: vcv
spec:
replicas: 1
selector:
matchLabels:
app: vcv
template:
metadata:
labels:
app: vcv
spec:
serviceAccountName: vcv-sa
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: vcv
image: jhmmt/vcv:1.6
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 52000
protocol: TCP
volumeMounts:
- name: vcv-settings
mountPath: /app/settings.json
subPath: settings.json
readOnly: true
resources:
requests:
cpu: "100m"
memory: "64Mi"
limits:
cpu: "500m"
memory: "128Mi"
readinessProbe:
httpGet:
path: /api/ready
port: http
initialDelaySeconds: 5
periodSeconds: 10
livenessProbe:
httpGet:
path: /api/health
port: http
initialDelaySeconds: 10
periodSeconds: 20
securityContext:
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
volumes:
- name: vcv-settings
secret:
secretName: vcv-settings
---
apiVersion: v1
kind: Secret
metadata:
name: vcv-settings
namespace: vcv
type: Opaque
stringData:
settings.json: |
{
"app": {
"env": "prod",
"port": 52000,
"logging": {
"level": "info",
"format": "json",
"output": "stdout",
"file_path": "/var/log/app/vcv.log"
}
},
"cors": {
"allowed_origins": [],
"allow_credentials": true
},
"certificates": {
"expiration_thresholds": {
"critical": 7,
"warning": 30
}
},
"vaults": [
{
"id": "vault-main",
"address": "https://vault-prod.example.com:8200",
"token": "change-me",
"pki_mounts": [
"pki",
"pki_dev",
"pki_stage",
"pki_production"
],
"display_name": "Vault",
"tls_ca_cert_base64": "BASE64_PEM_CA_BUNDLE",
"tls_ca_cert": "",
"tls_ca_path": "",
"tls_server_name": "vault.service.consul",
"tls_insecure": false,
"enabled": true
},
{
"id": "vault-dev",
"address": "https://vault-dev.example.com:8200",
"token": "change-me",
"pki_mounts": [
"pki",
"pki_corporate",
"pki_external",
"pki_partners"
],
"display_name": "Vault dev",
"tls_ca_cert_base64": "BASE64_PEM_CA_BUNDLE",
"tls_ca_cert": "",
"tls_ca_path": "",
"tls_server_name": "vault-dev.service.consul",
"tls_insecure": false,
"enabled": true
}
]
}
---
apiVersion: v1
kind: Service
metadata:
name: vcv
namespace: vcv
labels:
app: vcv
spec:
selector:
app: vcv
ports:
- name: http
port: 52000
targetPort: http
protocol: TCP
type: ClusterIPAfter this installation, you will need to use your Gateway and create the necessary HTTPRoute to access the app from outside the Kubernetes cluster.
Conclusion#
Certificate expiration is a predictable risk — and yet it remains very common.
VCV facilitates tracking, prioritization, and proactive action by providing a simple view of certificates across multiple Vault PKI engines, with configurable thresholds and metrics ready for monitoring.