Before Lab 3.4: Infrastructure-as-Code Security with Checkov
Before Lab 3.4: Infrastructure-as-Code Security with Checkov
What You'll Learn
Infrastructure misconfigurations are among the most common cloud security risks. A storage account left public, a database without encryption, or a network security group allowing unrestricted access can expose your entire application.
Checkov scans your Terraform (or CloudFormation, ARM, Kubernetes manifests) and checks each resource against hundreds of security and compliance policies before you deploy.
This lab focuses on:
- Policy-as-code: Codified security checks that run automatically in your pipeline
- Azure-specific risks: Storage encryption, NSG rules, Key Vault settings, diagnostic logging
- Findings workflow: Review → classify → fix or suppress with justification
Infrastructure-as-Code as a Security Boundary
IaC as the Source of Truth
Infrastructure-as-Code files (*.tf, *.yml) define the allowed infrastructure configuration. Once committed and approved, they become the security boundary — the only legitimate way to change infrastructure.
Why this matters:
| Approved Path (IaC) | Bypassed Path (Manual) |
|---|---|
| Code review required | No review |
| Checkov scans for misconfigurations | No security checks |
| Git history tracks who/when/why | No audit trail |
| Repeatable and testable | One-off change |
| Production matches code | Configuration drift |
The Risk of Manual Changes
Scenario: A developer needs to fix a production issue quickly and modifies an NSG rule directly in the Azure Portal.
Consequences:
- Checkov never scanned the change
- No pull request or code review
- Terraform state is now out of sync (drift)
- Next
terraform applymay revert the manual change - Security team has no visibility into the change
Correct approach: Update the .tf file, run Checkov locally, create a PR, let the pipeline deploy after approval.
Detecting Configuration Drift
Drift = deployed infrastructure differs from IaC definitions.
Detect drift with:
# Check if Azure resources match Terraform state
terraform plan -var-file="prod.tfvars"
# Expected: "No changes. Infrastructure is up-to-date."
# Drift detected: "Plan: X to add, Y to change, Z to destroy."Drift detection strategies:
- Run
terraform planin read-only mode daily (via scheduled pipeline) - Alert on any differences between code and deployed resources
- Require manual changes to be "imported" back into IaC files
Enforcement: Treat IaC as the security perimeter. Manual changes = policy violation.
Why Scan Infrastructure-as-Code?
Shift-Left for Infrastructure
Just as Semgrep finds code vulnerabilities before deployment, Checkov finds infrastructure vulnerabilities before provisioning.
Traditional approach: Deploy → discover misconfiguration → scramble to fix production resources
IaC security approach: Scan Terraform → fix misconfiguration in code → deploy secure resources
The Cost of Misconfiguration
Real-world breaches often stem from simple infrastructure mistakes:
| Misconfiguration | Risk | Azure Example |
|---|---|---|
| Public storage account | Data exposure | allow_blob_public_access = true |
| Database without encryption | Compliance violation | infrastructure_encryption_enabled = false |
| NSG allowing 0.0.0.0/0 | Unrestricted network access | source_address_prefix = "*" |
| Missing diagnostic logs | No audit trail for incidents | No azurerm_monitor_diagnostic_setting |
Checkov catches these before they reach production.
How Checkov Works
Policy-as-Code Model
Checkov includes 1,000+ built-in policies mapped to frameworks like CIS, PCI-DSS, HIPAA, and cloud-specific best practices.
Each policy checks a specific resource attribute:
Example: CKV_AZURE_33 checks if a storage account requires secure transfer (HTTPS)
# FAIL: Allows HTTP connections
resource "azurerm_storage_account" "bad" {
https_traffic_only_enabled = false
}
# PASS: Enforces HTTPS
resource "azurerm_storage_account" "good" {
https_traffic_only_enabled = true
}Azure-Specific Checks
For your Day 3 infrastructure, Checkov will scan a number of CKV_AZURE_X items for the full list see: Checkov List
Scanning Your Terraform
Configuration File
Checkov is configured via .checkov.yml in your repository root:
framework:
- terraform
directory:
- infrastructure/day-3
output:
- cli
- json
# Example suppression (use sparingly!)
skip-check:
# - CKV_AZURE_35:infrastructure/day-1/main.tf # Reason: dev environment onlyReviewing and Handling Findings
Checkov Output Format
Check: CKV_AZURE_3: "Ensure storage account requires secure transfer"
FAILED for resource: azurerm_storage_account.db_storage
File: /infrastructure/day-2/main.tf:360-390
Guide: https://docs.bridgecrew.io/docs/ensure-secure-transfer-required-is-enabled
360 | resource "azurerm_storage_account" "db_storage" {
361 | name = "dbstorage${random_string.unique.result}"
362 | resource_group_name = azurerm_resource_group.rg.name
363 | location = azurerm_resource_group.rg.location
364 | account_tier = "Standard"
365 | account_replication_type = "LRS"
366 | https_traffic_only_enabled = false # Issue here
...

Each finding includes:
- Policy ID and description: What rule failed
- Resource location: Exact file and line number
- Remediation guide: Link to Bridgecrew/Checkov docs
Decision Workflow
For each finding:
- Review severity and context: Does this apply to your environment?
- Fix in Terraform: Update the resource configuration
- Suppress with justification (if false positive or accepted risk):
resource "azurerm_storage_account" "db_storage" {
# checkov:skip=CKV_AZURE_43:Customer-managed keys not required for dev environment
name = "dbstorage${random_string.unique.result}"
...
}- Document in
.trivyignoreor.checkov.yml: For global suppressions
Common Azure Findings
| Finding | Typical Cause | Fix |
|---|---|---|
| Missing HTTPS enforcement | Default allows HTTP | https_traffic_only_enabled = true |
| Public blob access allowed | Default allows anonymous access | allow_blob_public_access = false |
| Encryption at rest disabled | Not explicitly enabled | infrastructure_encryption_enabled = true |
| NSG allows 0.0.0.0/0 | Overly permissive rule | Restrict source_address_prefix to specific IPs/ranges |
| Missing diagnostic logs | No monitoring configured | Add azurerm_monitor_diagnostic_setting |
Key Questions Before Starting
Why scan Terraform instead of deployed resources?
Scanning Terraform catches issues before provisioning. Scanning deployed resources means you already have insecure infrastructure in production. IaC scanning is true "shift-left" for infrastructure.
Should all Checkov findings fail the pipeline?
Not initially. Start in audit mode (exit-code: 0 or continueOnError: "true") to understand your baseline. Gradually enforce critical checks (encryption, public access) while documenting suppressions for accepted risks.
What's the difference between Checkov and Trivy IaC scanning?
Both scan Terraform, but Checkov has deeper Azure/AWS/GCP policy coverage (1,000+ checks), while Trivy focuses on container/dependency vulnerabilities with lighter IaC support. Use Checkov for comprehensive infrastructure policy enforcement.
How do you handle findings that don't apply to dev environments?
Suppress with inline comments in Terraform (visible justification) or skip-check in .checkov.yml. Always document why: "Customer-managed keys not required for ephemeral dev environment."
What You'll Do in Lab 3.4
- Run Checkov against your Day 1-2 Terraform infrastructure
- Review findings for storage accounts, network security groups, web apps, Key Vault
- Fix critical misconfigurations (HTTPS enforcement, public access, encryption)
- Suppress false positives with justification comments
- Verify pipeline integration and artifact publishing of Checkov reports