Security
Open Source
Deploy Checkov as a Scheduled IaC Scanner
A dedicated scanner VPS that pulls your IaC repos on a schedule, runs Checkov, and produces SARIF for Slack, ticketing, or long-term audit storage.
At a Glance
| Project | Checkov (Bridgecrew / Prisma Cloud) |
| License | Apache 2.0 |
| Recommended Plan | RamNode Cloud VPS 2 GB+ (4 GB+ for image scans) |
| OS | Ubuntu 24.04 LTS |
| Estimated Setup Time | 30 minutes |
1
Prerequisites + Service User
Base packages
sudo apt update && sudo apt -y full-upgrade
sudo apt -y install python3 python3-venv python3-pip python3-dev \
build-essential git curl jq ca-certificatesService user
sudo useradd -r -m -d /opt/checkov -s /bin/bash checkov
sudo -iu checkov2
Install Checkov
As checkov user
python3 -m venv ~/venv
source ~/venv/bin/activate
pip install --upgrade pip setuptools
pip install checkov pre-commit
checkov --version3
Repository Layout + Config
Layout
mkdir -p ~/repos ~/policies ~/reports ~/config ~/bin~/config/checkov.yaml
quiet: true
compact: true
download-external-modules: true
output: sarif
output-file-path: console
external-checks-dir:
- /opt/checkov/policies
skip-check:
- CKV_AWS_18
soft-fail: false~/config/repos.yaml
repos:
- name: platform-terraform
url: git@github.com:tca/platform-terraform.git
branch: main
framework: terraform_plan
scan_target: tf.json
- name: k8s-manifests
url: git@github.com:tca/k8s-manifests.git
branch: main
framework: kubernetes
scan_target: .
- name: helm-charts
url: git@github.com:tca/helm-charts.git
branch: main
framework: helm
scan_target: charts/4
Git Access via Deploy Keys
Generate per-host deploy key
ssh-keygen -t ed25519 -C "checkov@$(hostname)" -f ~/.ssh/checkov_ed25519 -N ""
cat ~/.ssh/checkov_ed25519.pub
# add as read-only deploy key on each repo~/.ssh/config
Host github.com
IdentityFile /opt/checkov/.ssh/checkov_ed25519
IdentitiesOnly yes
StrictHostKeyChecking accept-new5
The Scan Script
~/bin/scan.sh
#!/usr/bin/env bash
set -euo pipefail
CHECKOV_HOME=/opt/checkov
source "$CHECKOV_HOME/venv/bin/activate"
REPOS_FILE="$CHECKOV_HOME/config/repos.yaml"
CONFIG_FILE="$CHECKOV_HOME/config/checkov.yaml"
REPORT_DIR="$CHECKOV_HOME/reports/$(date -u +%Y-%m-%d_%H%M%S)"
mkdir -p "$REPORT_DIR"
count=$(yq '.repos | length' "$REPOS_FILE")
for i in $(seq 0 $((count - 1))); do
name=$(yq ".repos[$i].name" "$REPOS_FILE")
url=$(yq ".repos[$i].url" "$REPOS_FILE")
branch=$(yq ".repos[$i].branch" "$REPOS_FILE")
framework=$(yq ".repos[$i].framework" "$REPOS_FILE")
scan_target=$(yq ".repos[$i].scan_target" "$REPOS_FILE")
repo_dir="$CHECKOV_HOME/repos/$name"
if [[ -d "$repo_dir/.git" ]]; then
git -C "$repo_dir" fetch --quiet origin "$branch"
git -C "$repo_dir" reset --hard "origin/$branch" --quiet
else
git clone --quiet --depth 1 --branch "$branch" "$url" "$repo_dir"
fi
report_path="$REPORT_DIR/${name}.sarif"
(cd "$repo_dir" && checkov --config-file "$CONFIG_FILE" \
--framework "$framework" --directory "$scan_target" \
--output sarif --output-file-path "$report_path" --soft-fail) || true
done
python3 "$CHECKOV_HOME/bin/summarize.py" "$REPORT_DIR" > "$REPORT_DIR/summary.json"
find "$CHECKOV_HOME/reports" -maxdepth 1 -type d -mtime +90 -exec rm -rf {} +Install yq + chmod
sudo wget -O /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
sudo chmod +x /usr/local/bin/yq
chmod +x ~/bin/scan.sh6
Schedule with systemd Timers
/etc/systemd/system/checkov-scan.service
[Unit]
Description=Run Checkov scans across configured repos
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=checkov
Group=checkov
WorkingDirectory=/opt/checkov
ExecStart=/opt/checkov/bin/scan.sh
Nice=10
IOSchedulingClass=best-effort
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/checkov
CPUQuota=80%
MemoryMax=2G/etc/systemd/system/checkov-scan.timer
[Unit]
Description=Hourly Checkov scan
[Timer]
OnCalendar=hourly
AccuracySec=5m
Persistent=true
RandomizedDelaySec=2m
[Install]
WantedBy=timers.targetEnable
sudo systemctl daemon-reload
sudo systemctl enable --now checkov-scan.timer
systemctl list-timers checkov-scan.timer7
Routing Findings
- Slack:
jqfilter onsummary.jsonpiped to an incoming webhook — track finding ID hashes to alert only on new findings - Issue tracker: open Jira/Linear ticket per error-level finding with the SARIF doc URL
- Object storage: tar reports and upload to B2 / R2 for long-term audit
- Custom policies: drop YAML or Python checks into
/opt/checkov/policies
Container Image Scanning (optional)
For SCA / image scans, install Docker and add checkov to the docker group. For tighter isolation, run scans inside the official bridgecrew/checkov image with read-only volume mounts.
