linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Введение
  • Уроки
  • How it works
  • База знаний
  • Шпаргалка
  • Capstone
  • Собеседование
home/terraform/lessons/tf-production-05-checkov

lesson ── terraform-production ── ~13 мин ── 5 шагов

Checkov, an HCL security scanner

Checkov, the scanner from Prisma Cloud, checks HCL and plan.json against roughly 2000 security rules. In this lesson you run it on dirty HCL, watch the findings appear, then try suppression and a baseline.

▶ интерактивный sandbox

Поднимется пара контейнеров: terraform 1.9 и localstack 3.8 в одной сети. В браузере откроется терминал, можно сразу terraform init. Каждый шаг проверяется автоматически. TTL 45 минут, без регистрации.

запустить sandbox →

stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя

Шаги

  1. 01

    A deliberately weak bucket config

    bash
    cd /home/student/tf-checkov
    cat > main.tf <<'EOF'
    resource "aws_s3_bucket" "logs" {
      bucket = "linuxlab-checkov-demo"
    }
    resource "aws_s3_bucket" "data" {
      bucket = "linuxlab-checkov-data"
    }
    EOF

    Two buckets with no encryption, no versioning, no public access block, the classic set of questionable defaults.

    Run checkov:

    bash
    checkov -d . --quiet --no-guide 2>&1 | head -50

    You should see FAILED on CKV_AWS_18, CKV_AWS_19, CKV_AWS_21, CKV_AWS_53 and so on, for both buckets.

    ✓ Checkov found the problems. Now we fix some and suppress the rest.

  2. 02

    Add encryption, most findings disappear

    bash
    cat >> main.tf <<'EOF'
    resource "aws_s3_bucket_server_side_encryption_configuration" "logs" {
      bucket = aws_s3_bucket.logs.id
      rule {
        apply_server_side_encryption_by_default {
          sse_algorithm = "AES256"
        }
      }
    }
    resource "aws_s3_bucket_versioning" "logs" {
      bucket = aws_s3_bucket.logs.id
      versioning_configuration {
        status = "Enabled"
      }
    }
    resource "aws_s3_bucket_public_access_block" "logs" {
      bucket = aws_s3_bucket.logs.id
      block_public_acls       = true
      block_public_policy     = true
      ignore_public_acls      = true
      restrict_public_buckets = true
    }
    EOF
    checkov -d . --quiet --no-guide 2>&1 | tail -10

    There should be fewer fails now, the logs bucket is clean. data stays unfixed for the next step.

    ✓ The logs bucket passed. The data bucket has not yet.

  3. 03

    Suppression, public by design

    The data bucket is public on purpose (web assets, for example). That is an ADR-ed decision. We suppress only the public-access block and add everything else.

    bash
    cat >> main.tf <<'EOF'
    resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
      bucket = aws_s3_bucket.data.id
      rule {
        apply_server_side_encryption_by_default {
          sse_algorithm = "AES256"
        }
      }
    }
    resource "aws_s3_bucket_versioning" "data" {
      bucket = aws_s3_bucket.data.id
      versioning_configuration {
        status = "Enabled"
      }
    }
    EOF

    Now add the suppression in front of the data bucket:

    bash
    sed -i '/resource "aws_s3_bucket" "data"/i\
    # checkov:skip=CKV_AWS_53: Public on purpose (web assets), ADR-014\
    # checkov:skip=CKV_AWS_54: Public on purpose, ADR-014\
    # checkov:skip=CKV_AWS_55: Public on purpose, ADR-014\
    # checkov:skip=CKV_AWS_56: Public on purpose, ADR-014' main.tf
    checkov -d . --quiet --no-guide 2>&1 | tail -10

    Suppressions take effect only for the rules you list explicitly. If a rule is not in the list, it still runs.

    ✓ Suppressions with reasons are added. The reviewer can see why.

  4. 04

    Baseline, pin the current level

    In a real legacy project you cannot fix everything at once. A baseline pins the current findings as "acceptable" and breaks CI only on new ones.

    Create the baseline:

    bash
    checkov -d . --create-baseline --quiet --no-guide 2>&1 || true
    ls -la .checkov.baseline
    cat .checkov.baseline | head -30

    Right now the baseline holds all the current findings (if any are left). Run against the baseline:

    bash
    checkov -d . --baseline .checkov.baseline --quiet --no-guide 2>&1 | tail -10

    It should show that the failed checks dropped, the ones in the baseline. If you add a new bad resource, it is not in the baseline, and CI catches it.

    ✓ The baseline is created. From now on CI flags only new findings.

    The same thing on OpenTofu

    OpenTofu keeps the CLI and state compatible with Terraform for the commands in this step: migration usually goes through mv .terraform .terraform.bak; tofu init -upgrade. On a first switch, though, back up the state and do a run on a feature branch, the differences cluster in the newer features (variables in the backend, state encryption, OCI registry-backed modules). See tf-opentofu-parity for the full matrix.

    • → OpenTofu parity
  5. 05

    A CI-friendly run with an exit code

    A production pipeline shell:

    bash
    cat > checkov-ci.sh <<'EOF'
    #!/usr/bin/env bash
    set -euo pipefail
    checkov \
      -d . \
      --baseline .checkov.baseline \
      --quiet \
      --no-guide \
      --soft-fail-on CKV_AWS_2 \
      --skip-check CKV_AWS_999
    echo "Checkov gate passed."
    EOF
    chmod +x checkov-ci.sh
    ./checkov-ci.sh

    What the flags do:

    • --baseline, ignore the current findings.
    • --quiet / --no-guide, short output without the help.
    • --soft-fail-on, a warning for this rule, not an error.
    • --skip-check, skip globally (use rarely).

    Exit code 0, the gate passed. CI continues.

    ✓ The gate is ready. Any new security fail turns the PR red.

    What Checkov does not catch

    Checkov is boilerplate rules. It does not cover:

    1. Cross-resource policy. "Lambda and RDS in the same VPC", Checkov has no idea. That is the OPA level.

    2. Business logic. "Every bucket carries a CostCenter tag", you can write a custom rule, but OPA is simpler.

    3. Runtime problems. If the HCL is correct but AWS refuses, Checkov stays silent.

    4. Drift. Whatever turned into plain text in the cloud is a job for another tool.

    The check stack for a production repo:

    • terraform fmt / validate / tflint, format and syntax.
    • checkov or trivy config, boilerplate security.
    • OPA/conftest on plan.json, business and cross-resource policy.
    • .tftest.hcl, functional tests for modules.
    • drift detection through a scheduled plan.

    Checkov alone is about 20% of the coverage. The rest comes from the other layers.

    • → Checkov in full
    • → Trivy / tfsec, the alternatives
    • → OPA for complex rules

Что ты узнал

Checkov: checkov -d . on HCL, checkov -f plan.json on a plan. Suppression, #checkov:skip=CKV_AWS_X: reason in the HCL. Baseline, --create-baseline pins the current findings; after that it breaks only on new ones.

команды

  • checkov -d .scan the HCL in a directory.
  • checkov -d . --check CKV_AWS_19one rule only.
  • checkov -d . --create-baselinegenerate .checkov.baseline.
  • checkov -d . --baseline .checkov.baselinerun against the baseline, new findings break CI, old ones do not.

концепции

  • · Checkov without causality is cheaper; with plan.json it is more precise on interpolations
  • · Suppression requires a reason in the comment
  • · Baseline, a transitional tool for legacy repos

← предыдущий

templatefile: render configs from HCL

следующий →

Infracost, estimating the cost of a plan

Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies