tutorial

How to Monitor Checkov CI/CD Pipelines with Vigilmon (IaC Security Scanner)

Checkov is the leading open-source static analysis tool for Infrastructure as Code security — scanning Terraform, CloudFormation, Kubernetes manifests, Docke...

Checkov is the leading open-source static analysis tool for Infrastructure as Code security — scanning Terraform, CloudFormation, Kubernetes manifests, Dockerfiles, Helm charts, and ARM templates against thousands of security and compliance policies. Teams run Checkov in CI/CD pipelines to catch misconfigured S3 buckets, over-permissive IAM roles, missing encryption, and public-facing security groups before they reach production.

When Checkov pipeline runs stop completing — silently skipped, hung, or failing to report — your IaC security posture degrades without anyone noticing. In this tutorial you'll set up monitoring for Checkov-integrated workflows using Vigilmon so you get alerted when your security scanning pipeline breaks.


Why Checkov pipeline monitoring matters

Checkov doesn't expose an HTTP API to monitor — it's a CLI tool and CI step. So the monitoring question is different from a web service: you're not monitoring uptime, you're monitoring pipeline liveness and security gate health.

Here are the failure modes that matter:

  • CI pipeline skips the Checkov step — a merge to main bypasses security scanning because a pipeline condition was misconfigured; no alert fires, misconfigurations reach production
  • Checkov version pin breaks — a Docker image update changes the Checkov version; the step starts passing checks it previously failed because of a behavior change
  • Policy threshold misconfigured--soft-fail was added to unblock a deployment and never removed; Checkov now runs and reports findings but never blocks anything
  • Checkov results reporting breaks — findings are no longer uploaded to the security dashboard because an API key rotated; the pipeline passes, your security team sees no data
  • Long-running scans time out silently — a Terraform module with thousands of resources causes Checkov to time out; the CI step is marked as passed due to a timeout exit code misconfiguration
  • Scheduled compliance scans stop running — a cron-based full-repo scan fails to trigger due to a runner capacity issue or scheduler bug

Vigilmon's heartbeat monitoring is the right tool for this class of problem: you configure Checkov to ping a Vigilmon heartbeat URL at the end of each successful scan, and Vigilmon alerts you if the ping stops arriving.


What you'll need

  • Checkov running in a CI/CD pipeline (GitHub Actions, GitLab CI, Jenkins, CircleCI, etc.)
  • A free Vigilmon account (sign up takes 30 seconds)
  • Optional: Checkov results API (Bridgecrew platform or self-hosted reporting)

Step 1: Set up a Vigilmon heartbeat monitor

A heartbeat monitor expects a ping from your Checkov pipeline at regular intervals. If the ping doesn't arrive, Vigilmon alerts you.

  1. Log in to Vigilmon
  2. Click Monitors → New Monitor
  3. Set the Type to Heartbeat
  4. Give it a name: Checkov IaC Security Scan
  5. Set Expected interval to match how often your pipeline runs:
    • Daily cron scan → 24 hours
    • Per-PR scan → 1 hour (if you expect at least one PR per hour in business hours)
    • Continuous integration scan → 30 minutes
  6. Set Grace period to 15 minutes (buffer for CI runner delays)
  7. Click Save

Vigilmon generates a unique heartbeat URL, for example: https://vigilmon.online/heartbeat/abc123xyz

Copy this URL — you'll add it to your Checkov pipeline steps.


Step 2: Integrate heartbeat with GitHub Actions

Here's a complete GitHub Actions workflow that runs Checkov and pings Vigilmon on success:

name: IaC Security Scan

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 6 * * *'  # Daily at 6am UTC

jobs:
  checkov:
    name: Checkov Security Scan
    runs-on: ubuntu-latest

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install Checkov
        run: pip install checkov==3.2.0

      - name: Run Checkov on Terraform
        id: checkov_terraform
        run: |
          checkov \
            --directory ./terraform \
            --framework terraform \
            --output cli \
            --output junitxml \
            --output-file-path ./results \
            --compact \
            --skip-check CKV_AWS_144,CKV_AWS_145  # approved exceptions
        continue-on-error: false  # IMPORTANT: never use soft-fail without tracking

      - name: Run Checkov on Kubernetes manifests
        id: checkov_k8s
        run: |
          checkov \
            --directory ./k8s \
            --framework kubernetes \
            --output cli \
            --compact
        continue-on-error: false

      - name: Run Checkov on Dockerfiles
        id: checkov_docker
        run: |
          checkov \
            --directory . \
            --framework dockerfile \
            --output cli
        continue-on-error: false

      - name: Upload scan results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: checkov-results
          path: ./results/

      - name: Ping Vigilmon heartbeat on success
        if: success()  # Only ping if ALL checkov steps passed
        run: |
          curl -fsS --retry 3 \
            "https://vigilmon.online/heartbeat/YOUR_HEARTBEAT_TOKEN"
        env:
          VIGILMON_HEARTBEAT_URL: ${{ secrets.VIGILMON_HEARTBEAT_URL }}

Critical configuration notes:

  • continue-on-error: false — never allow Checkov to pass silently on error. If this is true, the step passes even when Checkov finds critical vulnerabilities.
  • The heartbeat ping uses if: success() — it only fires when all previous steps completed without error. If Checkov fails, the heartbeat doesn't ping, and Vigilmon alerts.
  • Store the heartbeat URL as a GitHub secret (VIGILMON_HEARTBEAT_URL) to avoid exposing it in logs.

Step 3: Integrate with GitLab CI

# .gitlab-ci.yml
stages:
  - security-scan

checkov:
  stage: security-scan
  image: bridgecrew/checkov:latest
  script:
    - checkov
        --directory .
        --framework terraform,kubernetes,dockerfile
        --output cli
        --compact
        --skip-check CKV_AWS_144
  after_script:
    # Only ping heartbeat if the main script succeeded
    - |
      if [ $CI_JOB_STATUS = "success" ]; then
        curl -fsS --retry 3 "$VIGILMON_HEARTBEAT_URL"
      fi
  variables:
    VIGILMON_HEARTBEAT_URL: $VIGILMON_HEARTBEAT_URL  # Set in GitLab CI/CD variables
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"  # Daily scan
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH  # On merge to main
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"  # On every MR

Step 4: Integrate with Jenkins

// Jenkinsfile
pipeline {
    agent any
    
    triggers {
        cron('H 6 * * *')  // Daily at ~6am
    }
    
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        
        stage('Checkov Security Scan') {
            steps {
                sh '''
                    pip install checkov==3.2.0
                    
                    checkov \
                        --directory ./terraform \
                        --framework terraform \
                        --output cli \
                        --output junitxml \
                        --output-file-path ./results
                    
                    checkov \
                        --directory ./k8s \
                        --framework kubernetes \
                        --output cli
                '''
            }
            post {
                always {
                    junit 'results/results_junitxml.xml'
                }
                success {
                    sh '''
                        curl -fsS --retry 3 \
                          "${VIGILMON_HEARTBEAT_URL}"
                    '''
                }
            }
        }
    }
    
    environment {
        VIGILMON_HEARTBEAT_URL = credentials('vigilmon-heartbeat-url')
    }
}

Step 5: Monitor a Checkov API reporting endpoint

If you use Checkov with the Bridgecrew platform or a self-hosted security dashboard that receives scan results via API, add an HTTP monitor to verify the reporting endpoint is reachable:

  1. Click Monitors → New Monitor
  2. Set the Type to HTTP
  3. Enter your reporting API: https://www.bridgecrew.cloud/api/v1/checkov or your self-hosted endpoint
  4. Set Expected status: 200 or 401 (401 means the endpoint is up but requires auth — that's fine)
  5. Set Check interval: 5 minutes
  6. Click Save

This catches cases where the endpoint goes down and Checkov silently swallows upload errors.


Step 6: Configure alert channels

Navigate to Alerts → New Alert Channel:

Slack — security channel:

# Route heartbeat failure alerts to #security-ops or #platform-security
# In Slack: create incoming webhook → copy URL
# In Vigilmon: Alerts → Slack → paste URL → assign to heartbeat monitor

Email: Add your security team's distribution list. When the heartbeat stops arriving, Vigilmon sends:

Subject: [ALERT] Checkov IaC Security Scan — heartbeat missed

The Checkov IaC Security Scan heartbeat has not been received for the expected interval. Your CI security scanning pipeline may have stopped running.

Last successful ping: 2026-06-01 06:02:14 UTC Expected interval: 24 hours

PagerDuty escalation: For compliance-critical environments where missed security scans violate policy requirements, route to PagerDuty:

{
  "routing_key": "YOUR_PD_INTEGRATION_KEY",
  "event_action": "trigger",
  "payload": {
    "summary": "Checkov security scan pipeline not running — possible compliance gap",
    "severity": "high",
    "source": "vigilmon-heartbeat",
    "component": "checkov",
    "group": "security"
  }
}

Step 7: Triage runbook when heartbeat alerts fire

When Vigilmon alerts that the Checkov heartbeat is missing:

# 1. Check if the pipeline ran at all
# GitHub Actions: check Actions tab for the relevant workflow
# GitLab: check CI/CD → Pipelines

# 2. Check for CI runner capacity issues
# GitHub: check github.com/org/repo/actions → runner usage
# Self-hosted runners: verify runner agents are online

# 3. Check for Checkov step failure (not caught by success condition)
# Look for the Checkov job in the pipeline — did it fail with findings?
# If so, that's the correct behavior — Checkov found issues, investigate the findings

# 4. Verify the heartbeat step itself
# Check the CI logs for the "Ping Vigilmon heartbeat" step
# Common issues: network egress blocked from CI runners, curl not installed in container

# 5. Test the heartbeat URL manually
curl -fsS "https://vigilmon.online/heartbeat/YOUR_HEARTBEAT_TOKEN"
# Should return 200 and reset the timer

# 6. Check for schedule trigger failure
# Cron schedules sometimes stop firing due to CI provider issues
# Verify the scheduled pipeline history going back 48 hours

Decision tree:

  • Pipeline ran, Checkov step failed → Checkov found security issues; this is correct behavior; review findings and fix or approve exceptions
  • Pipeline ran, heartbeat step failed → Network egress issue from CI runner or heartbeat URL misconfigured; check curl output in logs
  • Pipeline didn't run → CI scheduler issue or branch protection rule change; investigate CI provider and trigger configuration
  • Pipeline ran successfully but no heartbeatif: success() condition may not be triggering correctly; check step ordering and condition syntax

Step 8: Create a security status page

For compliance visibility:

  1. Go to Status Pages → New Status Page
  2. Name it: "Security Scanning Status"
  3. Add monitors:
    • Terraform IaC Scan: heartbeat monitor
    • Kubernetes Manifests Scan: separate heartbeat if on a different schedule
    • Dockerfile Scan: heartbeat monitor
    • Reporting API: HTTP monitor for the dashboard endpoint
  4. Publish the page and share with:
    • Security and compliance team
    • CTO/CISO for audit evidence
    • Engineering leadership tracking security posture

A public (or internal) status page showing "Last scan: 2 hours ago" is also valuable audit evidence for compliance frameworks like SOC 2, ISO 27001, and PCI DSS.


Advanced: Full pipeline scan metrics with Checkov SARIF output

For richer integration with GitHub Advanced Security or other SARIF-compatible platforms:

- name: Run Checkov with SARIF output
  run: |
    checkov \
      --directory ./terraform \
      --framework terraform \
      --output sarif \
      --output-file-path ./results/checkov.sarif

- name: Upload SARIF results to GitHub
  uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: ./results/checkov.sarif
  if: always()

- name: Ping Vigilmon heartbeat
  if: success()
  run: curl -fsS "${{ secrets.VIGILMON_HEARTBEAT_URL }}"

The SARIF upload step lets you see Checkov findings inline in pull requests while the Vigilmon heartbeat ensures you know when the pipeline stops running entirely.


Putting it all together

| Monitor | Type | What it catches | |---------|------|----------------| | Checkov daily scan heartbeat | Heartbeat (24h interval) | Scheduled scan stops running | | Checkov per-PR scan heartbeat | Heartbeat (1h interval) | PR-triggered scan fails to complete | | Reporting API endpoint | HTTP | Security dashboard receiving results |

Together these monitors answer the question: "Is our IaC security scanning actually happening?"


What's next

  • Multi-repo coverage — if you have multiple repositories with Checkov, create a heartbeat monitor per repo or per pipeline
  • SSL certificate monitoring — if you run a self-hosted Checkov reporting server, monitor its TLS cert with Vigilmon
  • Incident history — Vigilmon stores downtime history you can use as evidence in compliance audits showing when and how quickly security scanning gaps were detected and resolved

Get started free at vigilmon.online — no credit card, monitors start running in under a minute.

Monitor your app with Vigilmon

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

Start free →