Konstraint is a CLI tool that simplifies authoring and managing OPA Gatekeeper constraints and constraint templates. It generates ConstraintTemplate and Constraint CRDs from annotated Rego files, keeping your policy definitions DRY and version-controlled. Combined with OPA Gatekeeper — which enforces those constraints as a Kubernetes admission webhook — Konstraint is part of a policy pipeline that sits directly in the path of all resource creation.
In this tutorial you'll set up monitoring for OPA Gatekeeper and the services that support your Konstraint-based policy workflow using Vigilmon — free tier, no credit card required.
Why your Gatekeeper + Konstraint pipeline needs monitoring
Konstraint itself is a stateless CLI. What needs monitoring is the runtime infrastructure:
- Gatekeeper audit controller down — the audit job that continuously evaluates existing resources against constraints stops running; policy violations accumulate silently without anyone knowing
- Gatekeeper admission webhook unavailable — new resources bypass all policy checks (fail open) or all deployments are blocked (fail closed), depending on your
failurePolicy - Constraint template sync broken — your CI pipeline that runs
konstraint docand applies templates viakubectl applyfails silently; the cluster runs outdated policies - OPA metrics endpoint unreachable — you lose visibility into constraint evaluation rates, violation counts, and audit duration
- Webhook certificate expired — Gatekeeper manages its own TLS certificate; after expiry, the API server refuses to send admission requests to the webhook
What you'll need
- A Kubernetes cluster with OPA Gatekeeper installed
- Konstraint-generated constraint templates applied to the cluster
- A free Vigilmon account
Step 1: Verify Gatekeeper is installed and healthy
Gatekeeper runs as several pods in the gatekeeper-system namespace:
kubectl get pods -n gatekeeper-system
# NAME READY STATUS RESTARTS AGE
# gatekeeper-audit-xxx-yyy 1/1 Running 0 5d
# gatekeeper-controller-manager-xxx-yyy 1/1 Running 0 5d
# gatekeeper-controller-manager-xxx-zzz 1/1 Running 0 5d
Check the existing services:
kubectl get svc -n gatekeeper-system
# NAME TYPE CLUSTER-IP PORT(S) AGE
# gatekeeper-webhook-service ClusterIP 10.96.10.100 443/TCP 5d
# gatekeeper-metrics ClusterIP 10.96.10.101 8888/TCP 5d
Gatekeeper exposes metrics on port 8888 by default. Expose this externally for Vigilmon:
# gatekeeper-monitor-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: gatekeeper-health-monitor
namespace: gatekeeper-system
labels:
app: gatekeeper-monitoring
spec:
type: LoadBalancer
selector:
control-plane: controller-manager
gatekeeper.sh/system: "yes"
ports:
- name: metrics
port: 8888
targetPort: 8888
protocol: TCP
kubectl apply -f gatekeeper-monitor-svc.yaml
kubectl get svc gatekeeper-health-monitor -n gatekeeper-system
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# gatekeeper-health-monitor LoadBalancer 10.96.10.110 203.0.113.55 8888:31800/TCP 2m
Verify:
curl http://203.0.113.55:8888/metrics
# # HELP gatekeeper_violations Total number of audited violations
# gatekeeper_violations{...} 0
Also expose the audit controller metrics:
# gatekeeper-audit-monitor-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: gatekeeper-audit-monitor
namespace: gatekeeper-system
spec:
type: LoadBalancer
selector:
control-plane: audit-controller
gatekeeper.sh/system: "yes"
ports:
- name: metrics
port: 8888
targetPort: 8888
kubectl apply -f gatekeeper-audit-monitor-svc.yaml
kubectl get svc gatekeeper-audit-monitor -n gatekeeper-system
Step 2: Add a health proxy for comprehensive checks
Gatekeeper doesn't expose a dedicated /health endpoint in all versions. Add a thin proxy that checks both the controller and audit components:
# gatekeeper-health-proxy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: gatekeeper-health-proxy
namespace: gatekeeper-system
spec:
replicas: 1
selector:
matchLabels:
app: gatekeeper-health-proxy
template:
metadata:
labels:
app: gatekeeper-health-proxy
spec:
containers:
- name: health-proxy
image: node:20-alpine
command: ["/bin/sh", "-c"]
args:
- |
cat > /app.cjs << 'JSEOF'
const http = require('http');
const { execSync } = require('child_process');
function checkMetrics(host, port, cb) {
const req = http.get({ host, port, path: '/metrics', timeout: 3000 }, (res) => {
cb(null, res.statusCode);
});
req.on('error', (e) => cb(e));
req.on('timeout', () => { req.destroy(); cb(new Error('timeout')); });
}
http.createServer((req, res) => {
if (req.url !== '/health') { res.writeHead(404); res.end(); return; }
checkMetrics('gatekeeper-metrics.gatekeeper-system.svc', 8888, (err, code) => {
const ok = !err && code === 200;
res.writeHead(ok ? 200 : 503, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({
status: ok ? 'ok' : 'error',
gatekeeper_metrics: ok ? 'reachable' : (err ? err.message : code)
}));
});
}).listen(9090, () => console.log('Health proxy on :9090'));
JSEOF
node /app.cjs
ports:
- containerPort: 9090
resources:
requests:
cpu: 10m
memory: 32Mi
---
apiVersion: v1
kind: Service
metadata:
name: gatekeeper-health-proxy
namespace: gatekeeper-system
spec:
type: LoadBalancer
selector:
app: gatekeeper-health-proxy
ports:
- port: 9090
targetPort: 9090
kubectl apply -f gatekeeper-health-proxy.yaml
kubectl get svc gatekeeper-health-proxy -n gatekeeper-system
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# gatekeeper-health-proxy LoadBalancer 10.96.10.120 203.0.113.56 9090:31900/TCP 1m
curl http://203.0.113.56:9090/health
# {"status":"ok","gatekeeper_metrics":"reachable"}
Step 3: Set up HTTP monitoring in Vigilmon
Add your Gatekeeper endpoints to Vigilmon:
- Log in to vigilmon.online and go to Monitors → New Monitor
- Choose HTTP / HTTPS
- Add monitors:
| Monitor name | URL | Expected status |
|---|---|---|
| Gatekeeper Controller Metrics | http://203.0.113.55:8888/metrics | 200 |
| Gatekeeper Audit Metrics | http://AUDIT_EXTERNAL_IP:8888/metrics | 200 |
| Gatekeeper Health Proxy | http://203.0.113.56:9090/health | 200 |
| Konstraint CI Pipeline Health | https://ci.yourdomain.com/health | 200 |
- Set check interval to 1 minute
- Under Expected response, set status code
200; for the health proxy, add body contains"status":"ok" - Save each monitor
The audit metrics monitor is especially important: if the audit controller pod goes down, you lose continuous compliance scanning. Existing violations won't be detected. New violations from already-running workloads won't be reported. Vigilmon will catch this immediately.
Step 4: Monitor the admission webhook TCP port
The Gatekeeper admission webhook is served over HTTPS on port 443. The API server calls it for every resource operation. Monitor at the TCP level:
- Go to Monitors → New Monitor
- Choose TCP Port
- Enter:
- Host: your Gatekeeper webhook service's external hostname (or the LoadBalancer IP if you expose it)
- Port:
443
- Save the monitor
If the webhook service becomes unreachable at the TCP level, the API server will start timing out on admission calls — manifesting as very slow kubectl apply operations that eventually fail or succeed depending on your failurePolicy.
Step 5: Configure alert channels
Gatekeeper outages have two distinct blast radii:
- Controller down: new resources bypass policy checks (fail open) or all creates/updates are blocked (fail closed)
- Audit controller down: existing policy violations go undetected, compliance posture silently drifts
Both are critical but require different responses. Configure alerts for both:
Email alerts
- Go to Alert Channels → Add Channel → Email
- Add your security and platform team emails
- Assign to all Gatekeeper monitors
Webhook alerts
- Go to Alert Channels → Add Channel → Webhook
- Use your PagerDuty or Slack webhook URL
- Vigilmon payload:
{
"monitor_name": "Gatekeeper Audit Metrics",
"status": "down",
"url": "http://AUDIT_IP:8888/metrics",
"started_at": "2024-01-15T09:00:00Z",
"duration_seconds": 300
}
Map this to different alert severity levels: controller downtime → P1 (deployments blocked or unprotected), audit downtime → P2 (compliance scanning paused).
Step 6: Monitor your Konstraint CI pipeline
Konstraint runs in CI to generate and apply constraint templates. If this pipeline breaks, your policy changes stop reaching the cluster. Add a health endpoint to your policy CI pipeline:
#!/usr/bin/env bash
# konstraint-pipeline-health.sh
# Outputs a JSON health check based on when konstraint last ran successfully
LAST_RUN_FILE="/var/state/konstraint-last-success"
if [ ! -f "$LAST_RUN_FILE" ]; then
echo '{"status":"unknown","reason":"no run recorded"}'
exit 1
fi
LAST_RUN=$(cat "$LAST_RUN_FILE")
NOW=$(date +%s)
AGE_MINUTES=$(( (NOW - LAST_RUN) / 60 ))
if [ "$AGE_MINUTES" -gt 120 ]; then
echo "{\"status\":\"stale\",\"last_run_minutes_ago\":$AGE_MINUTES}"
exit 1
fi
echo "{\"status\":\"ok\",\"last_run_minutes_ago\":$AGE_MINUTES}"
Expose this via a simple HTTP service in your CI infrastructure and add it as a Vigilmon monitor. If konstraint hasn't run successfully in two hours, you have a policy drift risk.
Step 7: Correlate Vigilmon alerts with Gatekeeper diagnostics
When a Gatekeeper alert fires:
# 1. Check all Gatekeeper pods
kubectl get pods -n gatekeeper-system
# 2. Check recent events
kubectl get events -n gatekeeper-system --sort-by='.lastTimestamp' | tail -20
# 3. Verify constraint templates are loaded
kubectl get constrainttemplates
# 4. Check constraints and their enforcement status
kubectl get constraints --all-namespaces 2>/dev/null || \
kubectl get $(kubectl get crds -o name | grep constraints.gatekeeper.sh | head -5 | \
xargs -I{} kubectl get {} --all-namespaces --no-headers -o name | head -20 | \
tr '\n' ',' | sed 's/,$//') 2>/dev/null
# 5. Check audit log for violation counts
kubectl logs -n gatekeeper-system -l control-plane=audit-controller --tail=100 | \
grep -E 'violations|audit|error'
# 6. Check webhook config is still pointing to a live service
kubectl describe validatingwebhookconfiguration gatekeeper-validating-webhook-configuration | \
grep -A5 'Service:'
# 7. Run konstraint to verify policy files are valid
konstraint create --output ./generated ./policy/
konstraint doc --output POLICIES.md ./policy/
Step 8: Create a status page for policy governance
- Go to Status Pages → New Status Page
- Name it: "OPA Gatekeeper Policy Governance"
- Add monitors: Controller Metrics, Audit Metrics, Health Proxy, Konstraint CI
- Share with security, compliance, and platform engineering teams
Security and compliance teams can use this page to verify that policy enforcement is active — especially important during security audits or compliance reviews.
Summary
| What you set up | What it catches | |---|---| | HTTP monitor on controller metrics | Gatekeeper controller pod failures | | HTTP monitor on audit metrics | Audit controller down (silent compliance drift) | | HTTP monitor on health proxy | Composite availability check | | HTTP monitor on Konstraint CI | Policy template update pipeline failures | | TCP monitor on webhook port 443 | Certificate / LoadBalancer failures | | Multi-region consensus | Fewer false positives from transient blips | | Separate alert severities | P1 for admission control, P2 for audit |
The combination of Konstraint and OPA Gatekeeper gives you policy-as-code governance across your entire cluster. Vigilmon closes the loop by ensuring the governance infrastructure itself is always healthy — because the worst time to find out your audit controller has been down for a week is during a SOC2 audit.
Get started at vigilmon.online — free tier, no credit card required.