Module 5: Scanning Iac And Dependencies
5. Hands-on: installing and running Checkov
Description
This lesson installs the second inspector from lesson 1's analogy, and sets it walking through the same house Trivy already covered. You're going to install Checkov 3.3.11 — above the minimum 3.2.529 this guide's design pins — run it against the same andes-cargo-infra/ from lesson 4, and compare, finding by finding, what each tool catches. The result won't be an identical list. That difference, documented with real evidence, is this lesson's central content.
Connection to the module
Lesson 4 left eleven Trivy findings on the table. This lesson runs a second, completely independent scanner — a different company, a different engine, a different implementation language — against the exact same HCL, and confirms with evidence why lesson 1 insisted that two inspectors, with two different lists, find different things in the same house.
Step 1 — Installing Checkov
Checkov is a Python package, installed with pip:
pip3 install --break-system-packages checkov
What to expect (summary — the real install pulls in more than forty dependencies, including bc-python-hcl2 to parse HCL and networkx/rustworkx for the graph engine mentioned in lesson 2):
Successfully installed ... checkov-3.3.11 ...
checkov --version
What to expect (literal — run to write this lesson):
3.3.11
Version confirmed: Checkov 3.3.11, above the minimum 3.2.529 this guide's design pins — Checkov, like Trivy, publishes versions frequently; any version equal to or above 3.2.529 brings the coverage you need for this lesson.
Analogy revisited: the second inspector, with a different list
Lesson 1 already previewed the idea: two inspectors, two lists, the same house. Now that Checkov is installed, one more precision is worth adding: this analogy's two inspectors don't just have different lists — one of them (Checkov) also knows how to read blueprints beyond individual rooms. If a service door in the kitchen connects directly to the backyard's back door, without passing through any checkpoint, an inspector who only reviews room by room might not notice — but one who also reviews how the blueprints connect to each other, would. That is, in Checkov's terms, its graph engine: it evaluates relationships between resources, not just each one's configuration in isolation.
Step 2 — Running Checkov against andes-cargo-infra/
checkov -d . --compact --quiet
--compact suppresses the source-code detail per finding (which you already saw in detail with Trivy in lesson 4); --quiet reduces INFO log noise. Even so, you're going to see something real that neither flag suppresses — try it yourself before reading on.
What to expect (literal — first lines, run to write this lesson):
2026-08-14 10:39:25,205 [MainThread ] [WARNI] Failed to get the checkov mappings and guidelines from https://api0.prismacloud.io/bridgecrew/api/v2/guidelines. Skips using BC_* IDs will not work.
Traceback (most recent call last):
...
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='api0.prismacloud.io', port=443): Max retries exceeded with url: /bridgecrew/api/v2/guidelines (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1077)')))
This is real, and honest to name explicitly: Checkov, by default, tries to reach a Bridgecrew/Prisma Cloud API to download identifier mappings (BC_*, the IDs native to Bridgecrew's commercial platform) — a network attempt that, without an account or a trusted outbound connection, fails with a TLS certificate error. This isn't a blocker: Checkov catches that failure and keeps running the complete local scan with its open-source CKV_* rules, which don't depend on any external API. That's why this command finishes with a complete report despite the visible error at the start of the output.
What to expect (literal — the report, after the network error):
terraform scan results:
Passed checks: 113, Failed checks: 15, Skipped checks: 0
Check: CKV_AWS_28: "Ensure DynamoDB point in time recovery (backup) is enabled"
FAILED for resource: aws_dynamodb_table.shipments
File: /dynamodb.tf:4-15
Check: CKV_AWS_119: "Ensure DynamoDB Tables are encrypted using a KMS Customer Managed CMK"
FAILED for resource: aws_dynamodb_table.shipments
File: /dynamodb.tf:4-15
Check: CKV_AWS_50: "X-Ray tracing is enabled for Lambda"
FAILED for resource: aws_lambda_function.process_shipment_manifest
File: /lambda.tf:10-23
Check: CKV_AWS_117: "Ensure that AWS Lambda function is configured inside a VPC"
FAILED for resource: aws_lambda_function.process_shipment_manifest
File: /lambda.tf:10-23
Check: CKV_AWS_116: "Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)"
FAILED for resource: aws_lambda_function.process_shipment_manifest
File: /lambda.tf:10-23
Check: CKV_AWS_272: "Ensure AWS Lambda function is configured to validate code-signing"
FAILED for resource: aws_lambda_function.process_shipment_manifest
File: /lambda.tf:10-23
Check: CKV_AWS_115: "Ensure that AWS Lambda function is configured for function-level concurrent execution limit"
FAILED for resource: aws_lambda_function.process_shipment_manifest
File: /lambda.tf:10-23
Check: CKV_AWS_337: "Ensure SSM parameters are using KMS CMK"
FAILED for resource: aws_ssm_parameter.customs_api_webhook_signing_key
File: /secrets.tf:4-13
Check: CKV_AWS_149: "Ensure that Secrets Manager secret is encrypted using KMS CMK"
FAILED for resource: aws_secretsmanager_secret.customs_api_credentials
File: /secrets.tf:15-18
Check: CKV2_AWS_61: "Ensure that an S3 bucket has a lifecycle configuration"
FAILED for resource: module.shipment_docs_bucket.aws_s3_bucket.this
File: /modules/s3-bucket/main.tf:1-4
Check: CKV2_AWS_6: "Ensure that S3 bucket has a Public Access block"
FAILED for resource: module.shipment_docs_bucket.aws_s3_bucket.this
File: /modules/s3-bucket/main.tf:1-4
Check: CKV2_AWS_57: "Ensure Secrets Manager secrets should have automatic rotation enabled"
FAILED for resource: aws_secretsmanager_secret.customs_api_credentials
File: /secrets.tf:15-18
Check: CKV_AWS_18: "Ensure the S3 bucket has access logging enabled"
FAILED for resource: module.shipment_docs_bucket.aws_s3_bucket.this
File: /modules/s3-bucket/main.tf:1-4
Check: CKV_AWS_145: "Ensure that S3 buckets are encrypted with KMS by default"
FAILED for resource: module.shipment_docs_bucket.aws_s3_bucket.this
File: /modules/s3-bucket/main.tf:1-4
Check: CKV_AWS_144: "Ensure that S3 bucket has cross-region replication enabled"
FAILED for resource: module.shipment_docs_bucket.aws_s3_bucket.this
File: /modules/s3-bucket/main.tf:1-4
One hundred thirteen checks passed, fifteen failed, zero skipped. One hundred thirteen is, by itself, a figure worth noticing: it's the number of security questions on Checkov's list that this project already answers correctly — the accumulated work of Modules 1 through 3, seen from an inspector different from Trivy's.
The overlap, finding by finding, with evidence
This is the lesson's central comparison — not a general claim that "the tools overlap partially," but the exact list, built by cross-referencing Checkov's fifteen findings against Trivy's eleven (lesson 4):
Checkov (CKV_AWS_*) | Trivy (AWS-*) | Relationship |
|---|---|---|
CKV_AWS_28 (DynamoDB PITR) | AWS-0024 | Same finding, different ID |
CKV_AWS_119 (DynamoDB KMS CMK) | AWS-0025 | Same finding, different ID |
CKV_AWS_50 (Lambda X-Ray) | AWS-0066 | Same finding, different ID |
CKV_AWS_149 (Secrets Manager KMS CMK) | AWS-0098 | Same finding, different ID |
CKV_AWS_18 (S3 access logging) | AWS-0089 | Same finding, different ID |
CKV_AWS_145 (S3 KMS default encryption) | AWS-0132 | Same finding, different ID |
CKV2_AWS_6 (S3 Public Access block, one finding) | AWS-0086/0087/0091/0093/0094 (five findings) | Same root cause, different granularity — 1 to 5 |
CKV_AWS_117 (Lambda in VPC) | (none) | Checkov only |
CKV_AWS_116 (Lambda DLQ) | (none) | Checkov only |
CKV_AWS_272 (Lambda code-signing) | (none) | Checkov only |
CKV_AWS_115 (Lambda concurrency limit) | (none) | Checkov only |
CKV_AWS_337 (SSM Parameter KMS CMK) | (none) | Checkov only |
CKV2_AWS_61 (S3 lifecycle) | (none) | Checkov only |
CKV2_AWS_57 (Secrets Manager rotation) | (none) | Checkov only |
CKV_AWS_144 (S3 cross-region replication) | (none) | Checkov only |
Six findings match 1 to 1 between both tools, on the same resource and the same problem, with completely different IDs. One matches, but at a different granularity: where Checkov asks a single binary question ("does the bucket have a public-access block?"), Trivy breaks it down into the four real API flags plus the resource's absence — five questions where Checkov asks one. And eight findings are exclusive to Checkov in this run — Trivy, with its current rule set, didn't flag them at all.
Notice a pattern within those eight: five of them are about the Lambda function (CKV_AWS_117, 116, 272, 115, plus CKV_AWS_50 which does match) — Checkov, for this specific resource type, brings noticeably deeper coverage than the single Lambda rule Trivy triggered (AWS-0066, tracing). CKV_AWS_272 — code signing for Lambda — is, in particular, the finding that anticipates exactly the problem Module 6 of this guide resolves with cosign: the process-shipment-manifest .zip isn't signed. No infrastructure scanner solves that problem on its own — signing an artifact is a supply-chain discipline, not a configuration one —, but it's notable that Checkov, knowing nothing about Module 6, is already pointing in the right direction.
REAL, MEASURED OVERLAP — not an abstract figure
Trivy (11 findings) Checkov (15 findings)
┌─────────────────────┐ ┌─────────────────────┐
│ 6 match 1:1 │◄─────────►│ 6 match 1:1 │
│ 5 are AWS-0086/87/ │◄────5:1──►│ 1 is CKV2_AWS_6 │
│ 91/93/94 │ │ │
└─────────────────────┘ │ 8 exclusive to │
│ Checkov │
│ (5 about Lambda) │
└─────────────────────┘
No Trivy finding was left without a Checkov counterpart in this run —
but Checkov found nearly twice as many distinct categories over the same HCL.
Why the partial overlap is normal, not a flaw
It's tempting to read this comparison as a verdict — "Checkov is better, it found more" — but that reading misses lesson 1's central point: neither tool claims to be exhaustive on its own. Trivy prioritizes speed and a broad surface of scan types (IaC, secrets, SBOM, container vulnerabilities, all in one binary); Checkov prioritizes policy depth and relationships between resources via its graph engine. They're open-source projects, maintained by different communities, with different coverage priorities — the same kind of difference you'd find between two human security auditors with different training, reviewing the same system.
The practical, non-philosophical consequence: a team that runs only one of the two tools has a real, measurable blind spot, like the one you just saw with the five Lambda findings that only Checkov caught in this run. Running both isn't redundancy — it's the same "defense in depth" logic you already saw in Module 4 with conftest, and in this module with community scanners, now applied between two community scanners, not just between your own rules and community rules.
Common mistakes
Interpreting the SSL error at the start of the output as Checkov failing entirely (incomplete-reading mistake). What happens: someone sees the Traceback and the SSLCertVerificationError at the start of the output, and concludes the command didn't work. How to spot it: if your first instinct is to look for how to "fix" that network error before checking whether the local scan report actually got generated. How to fix it: scroll to the end of the output — terraform scan results: with the Passed/Failed/Skipped count confirms the local scan, with the open-source CKV_* rules, ran completely. The network error only affects the optional BC_* ID mapping feature from the commercial platform, which this guide never uses.
Looking for the same finding with the same ID in both tools (shared-naming expectation mistake). What happens: someone searches for AWS-0024 in Checkov's output, expecting to find it under that exact name. How to spot it: if your text search over Checkov's output, using a Trivy ID, finds nothing, even though the equivalent finding is right there. How to fix it: each tool has its own identifier scheme — AWS-XXXX for Trivy, CKV_AWS_XXX/CKV2_AWS_XXX for Checkov —, with no automatic correspondence between the two. This lesson's table is, precisely, the manual mapping you had to build to cross-reference both sets.
Concluding Checkov "found more" because it has more total findings, without adjusting for the bucket's different granularity. What happens: someone compares 15 (Checkov) against 11 (Trivy) and directly concludes Checkov covers more ground. How to spot it: if your comparison is purely arithmetic, without considering that five of Trivy's eleven findings are, in reality, a single root cause that Checkov counts as one. How to fix it: the correct comparison isn't of total count, but of distinct problem categories — adjusting for that granularity, Trivy covered seven categories (six plus the bucket's) and Checkov covered fourteen (six plus the bucket's plus eight exclusive ones). The real difference is in Checkov's eight exclusive categories, not in the raw count.
Exercises
Exercise 1 — Find the Checkov finding that anticipates Module 6 of this guide. Without looking back at the lesson, search the overlap table for which of Checkov's fifteen findings is directly related to what cosign is going to solve later in this guide.
See solution
CKV_AWS_272: "Ensure AWS Lambda function is configured to validate code-signing" — Checkov is flagging, knowing nothing about Module 6, that process-shipment-manifest has no code-signing validation configured. It's, conceptually, the same problem TM-02 from THREAT-MODEL.md documented in Module 1 ("deployment artifact has no signature"), now confirmed by a community scanner — and resolved, on the AWS Lambda Code Signing side specifically, outside this guide's direct scope (which uses cosign/Sigstore independently of the artifact, not Lambda's native feature), but pointing in the same risk direction.
Exercise 2 — Explain why CKV2_AWS_6 counts as a single finding, while Trivy uses five. To a colleague who asks whether this means Checkov is "less strict" about the public-access block, correct them with what you learned in this lesson.
See solution
It's not less strict — it's a different design decision about reporting granularity, not rigor. CKV2_AWS_6 checks the existence and correct configuration of the aws_s3_bucket_public_access_block resource as a single compound question (does it exist, and are all four flags correct?); if any condition fails, the whole check fails as one unit. Trivy, by contrast, separates each real API flag into its own independent rule, allowing, in theory, a bucket to pass four of the five questions and fail only one. Both approaches reach the same underlying conclusion about this lesson's HCL (the bucket isn't protected), just reported at a different level of detail.
Exercise 3 — Design your team's decision rule: run one tool, or both? Based on this lesson's evidence — not a general opinion about security tools —, write in two or three sentences the recommendation you'd give a team asking whether the operational cost of maintaining two scanners in their pipeline is worth it.
See solution
A complete recommendation, based on this specific lesson's evidence, sounds like this: "On this concrete project, running only Trivy would have left eight finding categories undetected — five of them about the system's only Lambda function —, including one that points directly at the supply-chain problem Module 6 solves. The cost of running both tools is CI time (seconds, not minutes, for a project this size) and a correspondence table that has to be maintained by hand when both flag the same problem. For a project with sensitive data and no budget for a paid product that unifies both catalogs, that cost is low compared to the blind spot running only one would leave."
Summary and next step
In this lesson you installed Checkov 3.3.11 and ran it against the same andes-cargo-infra/ from lesson 4: one hundred thirteen checks passed, fifteen failed, zero skipped. You cross-referenced, finding by finding, Checkov's fifteen results against Trivy's eleven: six match exactly, one matches at a different granularity (five Trivy rules against one from Checkov, same bucket), and eight are exclusive to Checkov — five of them about the Lambda function, including one finding that directly anticipates Module 6's work. You confirmed, with measured evidence rather than a general claim, why partial overlap between two community scanners is the expected norm, not a flaw in either one.
Before moving on you should be able to: install and run Checkov against any Terraform project; explain why a network error at the start of the output doesn't invalidate the local scan; and build, for any pair of scanners, a correspondence table like this lesson's.
Lesson 6 takes these twenty-six combined findings (eleven from Trivy, fifteen from Checkov, with the overlap already mapped) and decides, for three concrete cases, whether to fix, suppress with a documented reason, or accept the risk as it stands.
Resources
- www.checkov.io — Terraform Scanning — Checkov's official Terraform scanning documentation.
- GitHub — bridgecrewio/checkov — official repository, with the complete
CKV_AWS_*/CKV2_AWS_*check catalog. - www.checkov.io — Suppressing and Skipping Policies — official suppression reference, the basis for lesson 6.
- This course, Module 1,
THREAT-MODEL.md—TM-02, the findingCKV_AWS_272independently confirms in this lesson.