tutorial

How to Monitor kube-linter with Vigilmon

kube-linter is a static analysis tool that checks Kubernetes YAML manifests and Helm charts for correctness, security best practices, and production readines...

kube-linter is a static analysis tool that checks Kubernetes YAML manifests and Helm charts for correctness, security best practices, and production readiness before they reach a cluster. Engineering teams integrate kube-linter into CI/CD pipelines so that misconfigurations — missing resource limits, containers running as root, missing liveness probes — are caught at PR time rather than discovered during incidents in production. When the services kube-linter depends on are unavailable, CI pipelines skip lint checks silently, insecure or misconfigured manifests merge undetected, and the security posture of the cluster degrades without any alert.

In this tutorial you'll set up uptime monitoring for the infrastructure that kube-linter relies on using Vigilmon — free tier, no credit card required.


Why kube-linter's dependencies need external monitoring

kube-linter runs as a binary in CI/CD pipelines and downloads check definitions from its release infrastructure. Its failure modes span binary availability, check definitions, and CI runner connectivity:

  • kube-linter binary unavailable in CI — if the GitHub Releases endpoint that CI downloads the kube-linter binary from is unavailable or the release is deleted, CI pipelines fall back to skipping the lint step entirely rather than failing, allowing unchecked manifests to pass
  • Check definitions stale or missing — kube-linter bundles its checks into the binary; if an older pinned binary version is cached in CI and the cache becomes corrupted, checks based on current Kubernetes API versions may produce false negatives without any error output
  • Helm chart rendering failure hiding lint errors — kube-linter lints rendered Helm charts; if the Helm binary is unavailable or the chart repository is unreachable during CI, chart rendering fails before kube-linter runs, and manifests are never linted
  • Silent pass on download failure — many CI integrations treat a non-zero exit from the download step as non-fatal; kube-linter never runs, the pipeline passes, and no one is alerted that lint was skipped
  • OCI registry unavailable for container-based linting — teams running kube-linter via its container image depend on a container registry; registry downtime means the lint step is skipped with a pull error rather than a lint failure

External monitoring from Vigilmon watches the download and dependency infrastructure kube-linter relies on and alerts your team when CI lint checks are at risk of being silently skipped.


What you'll need

  • kube-linter installed in your CI/CD environment or local toolchain
  • kubectl access to your monitored cluster
  • A node or LoadBalancer endpoint to host the health check
  • A free Vigilmon account

Step 1: Expose a health endpoint for kube-linter's CI infrastructure

kube-linter has no runtime HTTP interface. Deploy a health exporter that validates the kube-linter binary is reachable from CI and can lint a known-good manifest:

# kube-linter-health.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-linter-health-script
  namespace: observability
data:
  sample-manifest.yaml: |
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sample-app
      namespace: default
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sample-app
      template:
        metadata:
          labels:
            app: sample-app
        spec:
          securityContext:
            runAsNonRoot: true
            runAsUser: 1000
          containers:
            - name: app
              image: nginx:1.25
              resources:
                requests:
                  cpu: 100m
                  memory: 128Mi
                limits:
                  cpu: 500m
                  memory: 256Mi
              livenessProbe:
                httpGet:
                  path: /
                  port: 80
              readinessProbe:
                httpGet:
                  path: /
                  port: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kube-linter-health
  namespace: observability
spec:
  replicas: 1
  selector:
    matchLabels:
      app: kube-linter-health
  template:
    metadata:
      labels:
        app: kube-linter-health
    spec:
      initContainers:
        - name: download-kube-linter
          image: curlimages/curl:latest
          command:
            - /bin/sh
            - -c
            - |
              curl -sSfL https://github.com/stackrox/kube-linter/releases/latest/download/kube-linter-linux.tar.gz \
                -o /tools/kube-linter.tar.gz && \
              tar -xzf /tools/kube-linter.tar.gz -C /tools && \
              chmod +x /tools/kube-linter && \
              echo "kube-linter downloaded" || echo "download_failed" > /tmp/dl_error
          volumeMounts:
            - name: tools
              mountPath: /tools
      containers:
        - name: checker
          image: busybox:latest
          command:
            - /bin/sh
            - -c
            - |
              while true; do
                if [ -x /tools/kube-linter ]; then
                  VERSION=$(/tools/kube-linter version 2>/dev/null || echo "unavailable")
                  if /tools/kube-linter lint /config/sample-manifest.yaml > /tmp/lint_out 2>&1; then
                    echo "healthy version=$VERSION lint=pass" > /tmp/status
                  else
                    ISSUES=$(wc -l < /tmp/lint_out)
                    echo "degraded version=$VERSION lint_issues=$ISSUES" > /tmp/status
                  fi
                else
                  echo "unhealthy kube_linter=missing" > /tmp/status
                fi
                sleep 300
              done
          volumeMounts:
            - name: tools
              mountPath: /tools
            - name: config
              mountPath: /config
            - name: status
              mountPath: /tmp
        - name: health-server
          image: busybox:latest
          command:
            - /bin/sh
            - -c
            - |
              while true; do
                STATUS=$(cat /tmp/status 2>/dev/null || echo "starting")
                if echo "$STATUS" | grep -q "^healthy"; then
                  printf "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: ${#STATUS}\r\n\r\n$STATUS" | nc -l -p 8080 -q 1
                else
                  printf "HTTP/1.1 503 Service Unavailable\r\nContent-Type: text/plain\r\nContent-Length: ${#STATUS}\r\n\r\n$STATUS" | nc -l -p 8080 -q 1
                fi
              done
          ports:
            - containerPort: 8080
              name: health
          volumeMounts:
            - name: status
              mountPath: /tmp
      volumes:
        - name: tools
          emptyDir: {}
        - name: config
          configMap:
            name: kube-linter-health-script
        - name: status
          emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
  name: kube-linter-health
  namespace: observability
spec:
  type: NodePort
  selector:
    app: kube-linter-health
  ports:
    - name: health
      port: 8080
      targetPort: 8080
      nodePort: 30087
kubectl apply -f kube-linter-health.yaml

# Verify
NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[?(@.type=="InternalIP")].address}')
curl http://$NODE_IP:30087/
# healthy version=v0.6.8 lint=pass

Step 2: Validate kube-linter and CI integration

Before setting up monitoring, confirm kube-linter is functional and CI pipelines will not silently skip lint:

#!/bin/bash
# check-kube-linter.sh

echo "=== kube-linter binary check ==="
if kube-linter version > /dev/null 2>&1; then
  echo "OK: $(kube-linter version)"
else
  echo "FAILED: kube-linter not found in PATH"
  exit 1
fi

echo ""
echo "=== Lint a known-good manifest ==="
cat > /tmp/good-manifest.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-app
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-app
  template:
    metadata:
      labels:
        app: test-app
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
      containers:
        - name: app
          image: nginx:1.25
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 500m
              memory: 256Mi
          livenessProbe:
            httpGet:
              path: /
              port: 80
          readinessProbe:
            httpGet:
              path: /
              port: 80
EOF

if kube-linter lint /tmp/good-manifest.yaml; then
  echo "OK: kube-linter passes clean manifest"
else
  echo "WARNING: kube-linter reported issues on known-good manifest — check rules config"
fi

echo ""
echo "=== Lint a known-bad manifest (expect issues) ==="
cat > /tmp/bad-manifest.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: insecure-app
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: insecure-app
  template:
    metadata:
      labels:
        app: insecure-app
    spec:
      containers:
        - name: app
          image: nginx:latest
EOF

ISSUES=$(kube-linter lint /tmp/bad-manifest.yaml 2>&1 | grep -c "error" || true)
echo "Issues found on bad manifest: $ISSUES (expected > 0)"

echo ""
echo "=== GitHub release connectivity ==="
curl -sSf https://github.com/stackrox/kube-linter/releases/latest -o /dev/null && \
  echo "OK: GitHub releases reachable" || \
  echo "WARNING: GitHub releases unreachable — CI binary download may fail"
chmod +x check-kube-linter.sh
./check-kube-linter.sh

Step 3: Set up HTTP monitoring in Vigilmon

With the health endpoint running, add it to Vigilmon:

  1. Log in to vigilmon.online and go to Monitors → New Monitor
  2. Choose HTTP / HTTPS
  3. Add monitors for kube-linter's infrastructure:

| Monitor name | URL | Expected status | |---|---|---| | kube-linter health endpoint | http://your-node-ip:30087/ | 200 | | GitHub Releases (kube-linter binary) | https://github.com/stackrox/kube-linter/releases | 200 | | Quay.io (kube-linter container image) | https://quay.io/repository/stackrox/kube-linter | 200 |

  1. Set the check interval to 5 minutes
  2. Under Expected response, set status code 200 and match healthy in the response body for the health endpoint
  3. Save each monitor

Step 4: Add a TCP monitor for the GitHub release infrastructure

kube-linter binaries are downloaded from GitHub. A TCP monitor catches network-level failures that block CI download steps:

  1. Go to Monitors → New Monitor
  2. Choose TCP Port
  3. Enter objects.githubusercontent.com and port 443
  4. Set the check interval to 5 minutes
  5. Save the monitor

A TCP failure here predicts that CI pipelines will fail at the kube-linter download step, likely causing them to skip lint or abort entirely.


Step 5: Configure alert channels

kube-linter is a security and correctness gate in CI. When it fails silently, misconfigured or insecure manifests reach production clusters unchecked. Alert the platform and security teams immediately.

Email alerts

  1. Go to Alert Channels → Add Channel → Email
  2. Enter your platform engineering, DevOps lead, and security team addresses
  3. Assign the channel to all kube-linter monitors

Webhook alerts

  1. Go to Alert Channels → Add Channel → Webhook
  2. Enter your incident management webhook URL (PagerDuty, Opsgenie, Slack)
  3. Sample Vigilmon webhook payload:
{
  "monitor_name": "kube-linter health endpoint",
  "status": "down",
  "url": "http://your-node-ip:30087/",
  "started_at": "2024-01-15T11:00:00Z",
  "duration_seconds": 180
}

Route this to a runbook that instructs the team to block manifest merges until kube-linter is restored and to manually review any PRs that merged during the downtime window.


Step 6: Correlate Vigilmon alerts with kube-linter diagnostics

When you receive a kube-linter health downtime alert:

# 1. Check kube-linter version and binary integrity
kube-linter version
which kube-linter

# 2. Test lint on a simple manifest
echo 'apiVersion: v1
kind: Pod
metadata:
  name: test
spec:
  containers:
  - name: test
    image: nginx' | kube-linter lint -

# 3. Check GitHub release availability
curl -sI https://github.com/stackrox/kube-linter/releases/latest | head -5

# 4. Check CI runner's download capability
curl -sSfL https://github.com/stackrox/kube-linter/releases/latest/download/kube-linter-linux.tar.gz \
  -o /tmp/kl-test.tar.gz && echo "download OK" || echo "download FAILED"

# 5. Inspect health pod logs
kubectl logs -n observability -l app=kube-linter-health -c checker --tail=20

# 6. Check if CI is currently skipping lint
# (Review recent CI run logs for "kube-linter" step status)

# 7. Verify kube-linter container image availability
docker pull quay.io/stackrox/kube-linter:latest 2>&1 | tail -3

If the GitHub Release endpoint is confirmed down, enable your CI pipeline's lint-skip gate and notify the engineering team that manifest reviews must be done manually until monitoring recovers.


Step 7: Create a status page for Kubernetes manifest quality gates

Make kube-linter's availability visible to the security and platform teams:

  1. Go to Status Pages → New Status Page
  2. Name it: "Kubernetes Manifest Quality Gates (kube-linter)"
  3. Add your kube-linter health monitor, GitHub Releases monitor, and TCP monitor
  4. Share the URL with your security team and lead SREs

When this page shows degraded, the team knows that CI lint checks are at risk and manual manifest review is required for any open PRs.


Summary

| What you set up | What it catches | |---|---| | HTTP monitor on kube-linter health endpoint | Binary unavailability, lint engine failures, check regressions | | HTTP monitor on GitHub Releases | Binary download failures that silently skip CI lint steps | | HTTP monitor on Quay.io | Container image pull failures for container-based lint runs | | TCP monitor on GitHub CDN | Network failures blocking binary downloads | | Email + webhook alert channels | Immediate notification to security and platform teams | | Status page | Visibility into CI manifest quality gate health |

kube-linter is the first line of defense against misconfigured and insecure Kubernetes manifests. External monitoring ensures you know when its CI infrastructure is degraded before insecure manifests slip through unchecked.

Get started at vigilmon.online — free tier, no credit card required.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →