tutorial

Monitoring KICS IaC Security Scans with Vigilmon: Catch Silent Infrastructure Security Failures

Use Vigilmon heartbeat monitors to detect when KICS infrastructure-as-code security scans stop running — before a misconfigured Terraform or Kubernetes manifest ships to production unreviewed.

Your Terraform configurations haven't been scanned for security misconfigurations in 18 days. A Kubernetes manifest with an overly permissive container security context was merged and deployed last week. KICS would have flagged it immediately — but your KICS CI step was silently removed when someone restructured the pipeline.

KICS (Keeping Infrastructure as Code Secure) from Checkmarx is one of the most comprehensive open-source IaC security scanners available. But like any CI-integrated tool, it can disappear from your pipeline without generating a single alert. This tutorial shows you how to use Vigilmon heartbeat monitors to ensure KICS scans run on schedule and catch infrastructure security blind spots before they matter.

What You'll Cover

  • Heartbeat monitoring for scheduled KICS IaC scans
  • Detecting KICS scan steps silently removed from CI pipelines
  • Multi-environment scan coverage (Terraform, Kubernetes, CloudFormation, Dockerfile)
  • Alert routing for IaC security failures
  • Dashboard setup for infrastructure security posture

Prerequisites

  • KICS installed or available in CI (docker pull checkmarx/kics)
  • Infrastructure-as-code files in your repository (Terraform, Kubernetes YAML, CloudFormation, Dockerfiles, etc.)
  • A free account at vigilmon.online

The Problem: When IaC Security Scans Stop Running

KICS finds problems in your infrastructure code — but only when it runs. Silent scan failures create security blind spots at exactly the wrong moments:

  • A CI pipeline refactor removes the KICS scan step without anyone noticing
  • KICS exits non-zero (found issues) but the CI step is misconfigured with continue-on-error: true, masking both the findings and the scan status
  • A new infrastructure directory is added that isn't covered by the existing KICS scan path
  • A scheduled KICS scan fails silently due to a Docker pull timeout or image change

The result: infrastructure code ships to production without IaC security review, and your security posture silently degrades.

Vigilmon's heartbeat pattern makes the gap visible: KICS pings a URL on successful scan completion, and if that ping doesn't arrive within the expected window, you get alerted.


Step 1: Create a Heartbeat Monitor in Vigilmon

  1. Log in to Vigilmon and click New Monitor → Heartbeat.
  2. Name it clearly: KICS Scan — terraform (daily) or KICS Scan — k8s manifests (weekly).
  3. Set the Expected interval to match your scan schedule:
    • Daily scans on every merge to main: 25 hours
    • Weekly scheduled scans: 8 days
  4. Set the Grace period to 2 hours for daily scans, 12 hours for weekly.
  5. Save and copy the Ping URL — it looks like https://vigilmon.online/api/heartbeat/<unique-id>.

Step 2: Add Heartbeat Monitoring to a GitHub Actions KICS Scan

Here's a complete workflow that runs KICS and pings Vigilmon on completion:

# .github/workflows/kics-scan.yml
name: KICS IaC Security Scan

on:
  push:
    branches: [main]
    paths:
      - "terraform/**"
      - "k8s/**"
      - "**.dockerfile"
      - "Dockerfile*"
  schedule:
    - cron: "0 4 * * 1"  # weekly on Monday at 04:00 UTC
  workflow_dispatch:

jobs:
  kics-scan:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Run KICS scan
        uses: checkmarx/kics-github-action@v2
        with:
          path: "."
          output_path: kics-results/
          output_formats: "json,sarif"
          # Exit code 0 = no findings; 50 = findings found (non-blocking)
          # Use fail_on to control which severities block the pipeline
          fail_on: "critical,high"
          exclude_paths: "node_modules,vendor,.git"

      - name: Upload KICS results as artifact
        uses: actions/upload-artifact@v4
        if: always()
        with:
          name: kics-results
          path: kics-results/

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

      - name: Ping Vigilmon heartbeat
        if: success()
        run: |
          curl -fsS -X POST "${{ secrets.VIGILMON_KICS_SCAN_URL }}" \
            --max-time 10 \
            --retry 3 \
            --retry-delay 2

Important: the heartbeat is sent on if: success() — meaning the KICS action itself must exit 0. The fail_on: "critical,high" option means KICS exits non-zero only when high or critical findings exist. If you want to always send the heartbeat when KICS ran (even with findings), use:

- name: Ping Vigilmon heartbeat
  if: steps.kics-scan.conclusion == 'success' || steps.kics-scan.conclusion == 'failure'
  run: |
    # Only send heartbeat if KICS ran — not if the step was skipped or cancelled
    if [ "${{ steps.kics-scan.conclusion }}" != "cancelled" ]; then
      curl -fsS -X POST "${{ secrets.VIGILMON_KICS_SCAN_URL }}" --max-time 10 --retry 3
    fi

Choose the approach that fits your team's policy: heartbeat on clean scan only, or heartbeat on scan completion regardless of findings.


Step 3: Running KICS Directly (Docker-based)

If you're not using the official GitHub Action, run KICS via Docker and add the heartbeat manually:

- name: Run KICS scan (Docker)
  run: |
    docker run --rm \
      -v "$(pwd):/path" \
      checkmarx/kics:latest scan \
      --path /path \
      --output-path /path/kics-results \
      --output-name results \
      --report-formats "json,sarif" \
      --exclude-paths "node_modules,vendor,.git" \
      --fail-on "critical,high"

- name: Ping Vigilmon heartbeat
  if: success()
  run: |
    curl -fsS -X POST "${{ secrets.VIGILMON_KICS_SCAN_URL }}" \
      --max-time 10 \
      --retry 3

Step 4: GitLab CI Integration

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

kics-iac-scan:
  stage: security
  image: checkmarx/kics:latest
  script:
    - >
      kics scan
      --path .
      --output-path ./kics-results
      --report-formats json,sarif
      --fail-on critical,high
      --exclude-paths "node_modules,vendor,.git"
  artifacts:
    when: always
    paths:
      - kics-results/
    reports:
      sast: kics-results/results.sarif
  only:
    - main
    - schedules

kics-heartbeat:
  stage: notify
  script:
    - >
      curl -fsS -X POST "$VIGILMON_KICS_SCAN_URL"
      --max-time 10
      --retry 3
  when: on_success
  needs: ["kics-iac-scan"]
  only:
    - main
    - schedules

Step 5: Scan Coverage Per Infrastructure Type

KICS supports many infrastructure types. Create a separate heartbeat monitor for each major scan target so you can detect coverage gaps at a granular level:

| Infrastructure type | Scan path | Monitor name | Interval | |---|---|---|---| | Terraform | terraform/ | KICS — Terraform | 8 days | | Kubernetes | k8s/, helm/ | KICS — Kubernetes | 8 days | | Dockerfiles | **/Dockerfile* | KICS — Dockerfiles | 8 days | | CloudFormation | cloudformation/ | KICS — CloudFormation | 8 days |

Split your CI job into per-type scans and map each to its own heartbeat monitor. This makes it clear exactly which infrastructure type lost scan coverage when a pipeline breaks.

kics-scan-terraform:
  # ... scans terraform/ only, pings VIGILMON_KICS_TERRAFORM_URL

kics-scan-k8s:
  # ... scans k8s/ only, pings VIGILMON_KICS_K8S_URL

Step 6: Monitoring KICS Availability in Self-Hosted Environments

Teams running KICS in self-hosted runners or on private infrastructure may want to monitor whether KICS itself is reachable. If your CI agents can't pull the KICS Docker image or the binary is missing, scans fail silently.

Add a lightweight pre-scan check job:

verify-kics-available:
  stage: .pre
  script:
    - docker pull checkmarx/kics:latest
    - docker run --rm checkmarx/kics:latest version
  allow_failure: false

If this job fails, the downstream scan job is never attempted, and the heartbeat is never sent — Vigilmon will alert you.


Step 7: Configure Alert Channels

In Vigilmon, go to Notifications → New Channel and configure:

  • Email — alert to your security team or DevSecOps distribution list
  • Slack webhook — post to #security-alerts or #infrastructure
  • PagerDuty — for environments where IaC security coverage is a compliance requirement

Use separate notification channels for scan failures (heartbeat misses) vs. finding alerts (which come from KICS directly or GitHub Advanced Security). Scan failure alerts mean you've lost coverage — that's a higher-priority signal.

When KICS stops running:

🔴 MISSED HEARTBEAT: KICS — Terraform
Last ping: 9 days ago
Expected interval: 7 days

This tells your team that Terraform configurations have had no IaC security review for 9 days — before a compliance auditor or a production incident surfaces the gap.


What You're Now Catching

| Silent failure mode | How Vigilmon detects it | |---|---| | CI step removed after pipeline refactor | No ping → alert after grace period | | KICS Docker image pull fails | Scan never runs, no ping → alert | | New IaC directory not covered by scan path | Separate monitor per path surfaces gap | | continue-on-error masks scan failure | Heartbeat wired to success only → alert | | Scheduled scan trigger drops off | No ping in expected window → alert | | Self-hosted runner loses KICS binary | Pre-check fails, no ping → alert |


KICS provides comprehensive IaC security coverage across Terraform, Kubernetes, CloudFormation, and dozens of other formats — but only when it runs. Vigilmon's heartbeat monitors give your security team the confidence that IaC security scans are actually executing on schedule, and an immediate alert when they stop.

Start monitoring your KICS scans today — register free at vigilmon.online.

Monitor your app with Vigilmon

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

Start free →