lesson ── terraform-production ── ~13 мин ── 5 шагов
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 минут, без регистрации.
stack ── terraform · localstack · 1 GB RAM · самоуничтожается через 45 мин простоя
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:
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.
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.
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.
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:
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.
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:
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:
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.
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.
A production pipeline shell:
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.
Checkov is boilerplate rules. It does not cover:
Cross-resource policy. "Lambda and RDS in the same VPC", Checkov has no idea. That is the OPA level.
Business logic. "Every bucket carries a CostCenter tag", you can write a custom rule, but OPA is simpler.
Runtime problems. If the HCL is correct but AWS refuses, Checkov stays silent.
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..tftest.hcl, functional tests for modules.Checkov alone is about 20% of the coverage. The rest comes from the other layers.
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.концепции