Initial commit - 611 cybersecurity skills across all subdomains

This commit is contained in:
mukul975
2026-02-25 10:47:44 +01:00
commit 22a7ab1462
1765 changed files with 280648 additions and 0 deletions
@@ -0,0 +1,248 @@
---
name: implementing-infrastructure-as-code-security-scanning
description: >
This skill covers implementing automated security scanning for Infrastructure as Code
(IaC) templates using tools like Checkov, tfsec, and KICS. It addresses detecting
misconfigurations in Terraform, CloudFormation, Kubernetes manifests, and Helm charts
before deployment, establishing policy-based governance, and integrating IaC scanning
into CI/CD pipelines to prevent insecure cloud resource provisioning.
domain: cybersecurity
subdomain: devsecops
tags: [devsecops, cicd, iac-security, checkov, tfsec, terraform, secure-sdlc]
version: 1.0.0
author: mahipal
license: MIT
---
# Implementing Infrastructure as Code Security Scanning
## When to Use
- When provisioning cloud infrastructure with Terraform, CloudFormation, or Pulumi and needing automated security validation
- When compliance frameworks require evidence of infrastructure configuration review before deployment
- When preventing common cloud misconfigurations like public S3 buckets, open security groups, or unencrypted storage
- When establishing guardrails that block insecure infrastructure changes in pull requests
- When managing multi-cloud environments requiring consistent security policies across AWS, Azure, and GCP
**Do not use** for scanning application source code (use SAST), for monitoring already-deployed infrastructure drift (use cloud security posture management tools), or for container image vulnerability scanning (use Trivy).
## Prerequisites
- Checkov v3.x installed (`pip install checkov`) or tfsec installed
- Terraform, CloudFormation, or Kubernetes IaC files in the repository
- CI/CD pipeline with access to IaC directories
- Bridgecrew API key (optional, for Checkov platform integration)
## Workflow
### Step 1: Run Checkov Against Terraform Files
```bash
# Scan all Terraform files in a directory
checkov -d ./terraform/ --framework terraform --output cli --output json --output-file-path ./results
# Scan specific file
checkov -f main.tf --output json
# Scan Terraform plan (more accurate for dynamic values)
terraform init && terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
checkov -f tfplan.json --framework terraform_plan
# Scan with specific checks only
checkov -d ./terraform/ --check CKV_AWS_18,CKV_AWS_19,CKV_AWS_20
# Skip specific checks
checkov -d ./terraform/ --skip-check CKV_AWS_145,CKV2_AWS_6
```
### Step 2: Integrate IaC Scanning into GitHub Actions
```yaml
# .github/workflows/iac-security.yml
name: IaC Security Scan
on:
pull_request:
paths:
- 'terraform/**'
- 'cloudformation/**'
- 'k8s/**'
jobs:
checkov:
name: Checkov IaC Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Checkov
uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/
framework: terraform
output_format: cli,sarif
output_file_path: console,checkov.sarif
soft_fail: false
skip_check: CKV_AWS_145
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: checkov.sarif
category: checkov-iac
tfsec:
name: tfsec Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tfsec
uses: aquasecurity/tfsec-action@v1.0.3
with:
working_directory: terraform/
sarif_file: tfsec.sarif
soft_fail: false
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: tfsec.sarif
category: tfsec
```
### Step 3: Create Custom Checkov Policies
```python
# custom_checks/s3_versioning.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
class S3BucketVersioning(BaseResourceCheck):
def __init__(self):
name = "Ensure S3 bucket has versioning enabled"
id = "CKV_CUSTOM_1"
supported_resources = ["aws_s3_bucket"]
categories = [CheckCategories.GENERAL_SECURITY]
super().__init__(name=name, id=id, categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf):
versioning = conf.get("versioning", [{}])
if isinstance(versioning, list) and len(versioning) > 0:
if versioning[0].get("enabled", [False])[0]:
return CheckResult.PASSED
return CheckResult.FAILED
check = S3BucketVersioning()
```
### Step 4: Configure Baseline and Suppressions
```yaml
# .checkov.yaml
branch: main
compact: true
directory:
- terraform/
- cloudformation/
framework:
- terraform
- cloudformation
- kubernetes
output:
- cli
- sarif
skip-check:
- CKV_AWS_145 # S3 default encryption with CMK (using SSE-S3 is acceptable)
- CKV2_AWS_6 # S3 bucket request logging (handled at CloudTrail level)
soft-fail: false
```
### Step 5: Scan Kubernetes Manifests and Helm Charts
```bash
# Scan Kubernetes manifests
checkov -d ./k8s/ --framework kubernetes
# Scan Helm charts (renders templates first)
checkov -d ./charts/myapp/ --framework helm
# Scan with KICS (Keeping Infrastructure as Code Secure)
docker run -v $(pwd)/k8s:/path checkmarx/kics:latest scan \
--path /path \
--output-path /path/results \
--type Kubernetes \
--report-formats json,sarif
```
## Key Concepts
| Term | Definition |
|------|------------|
| IaC Scanning | Automated analysis of infrastructure code templates to detect security misconfigurations before deployment |
| Policy as Code | Security policies defined as executable code that can be version-controlled, tested, and enforced automatically |
| CKV Check ID | Checkov's unique identifier for each security check (e.g., CKV_AWS_18 for S3 public access) |
| Terraform Plan Scanning | Scanning the resolved Terraform plan JSON which includes computed values and module expansions |
| Graph-based Scanning | Checkov's ability to analyze relationships between resources, not just individual resource configs |
| Drift Detection | Identifying differences between IaC definitions and actual deployed infrastructure state |
| Custom Policy | Organization-specific security checks authored in Python or YAML to enforce internal standards |
## Tools & Systems
- **Checkov**: Open-source IaC scanner by Bridgecrew with 2500+ built-in policies covering major cloud providers
- **tfsec**: Terraform-focused static analysis tool by Aqua Security with deep HCL understanding
- **KICS**: Open-source IaC scanner by Checkmarx supporting 15+ IaC frameworks
- **Terrascan**: IaC scanner with OPA Rego policy support for custom policy authoring
- **Snyk IaC**: Commercial IaC scanner integrated with the Snyk platform
## Common Scenarios
### Scenario: Preventing Public S3 Buckets in Terraform
**Context**: A development team repeatedly creates S3 buckets without proper access controls. A recent incident exposed customer data through a public bucket.
**Approach**:
1. Enable Checkov in the CI/CD pipeline for all Terraform changes
2. Enforce CKV_AWS_18 (no public read ACL), CKV_AWS_19 (encryption), CKV_AWS_20 (no public access block disabled)
3. Create a custom policy requiring the `aws_s3_bucket_public_access_block` resource for every S3 bucket
4. Set `soft_fail: false` to block PR merges when S3 security checks fail
5. Provide Terraform modules with security defaults that teams can reuse
**Pitfalls**: Scanning only `.tf` files misses dynamically computed values. Use Terraform plan scanning for higher accuracy. Checkov's resource-relationship checks (CKV2 prefix) require graph analysis mode.
## Output Format
```
IaC Security Scan Report
==========================
Framework: Terraform
Directory: terraform/
Scan Date: 2026-02-23
Checkov Results:
Passed: 187
Failed: 12
Skipped: 3
Unknown: 0
FAILED CHECKS:
CKV_AWS_18 [HIGH] S3 Bucket has public read ACL
Resource: aws_s3_bucket.data_lake
File: terraform/storage.tf:15-28
CKV_AWS_24 [HIGH] CloudWatch log group not encrypted
Resource: aws_cloudwatch_log_group.app
File: terraform/monitoring.tf:3-8
CKV_AWS_79 [MEDIUM] Instance metadata service v1 enabled
Resource: aws_instance.web
File: terraform/compute.tf:12-30
QUALITY GATE: FAILED (2 HIGH severity findings)
```
@@ -0,0 +1,94 @@
# IaC Security Scanning Templates
## Checkov Configuration File
```yaml
# .checkov.yaml
branch: main
compact: true
directory:
- terraform/
- cloudformation/
- k8s/
framework:
- terraform
- cloudformation
- kubernetes
output:
- cli
- sarif
skip-check:
- CKV_AWS_145 # CMK encryption for S3 (SSE-S3 acceptable)
- CKV2_AWS_6 # S3 request logging (CloudTrail covers this)
soft-fail: false
```
## GitHub Actions Pipeline
```yaml
# .github/workflows/iac-security.yml
name: IaC Security
on:
pull_request:
paths: ['terraform/**', 'k8s/**', 'cloudformation/**']
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: bridgecrewio/checkov-action@v12
with:
directory: terraform/
framework: terraform
output_format: cli,sarif
output_file_path: console,checkov.sarif
soft_fail: false
- uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: checkov.sarif
```
## Secure Terraform Module Template
```hcl
# modules/secure-s3-bucket/main.tf
resource "aws_s3_bucket" "this" {
bucket = var.bucket_name
tags = var.tags
}
resource "aws_s3_bucket_versioning" "this" {
bucket = aws_s3_bucket.this.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
bucket = aws_s3_bucket.this.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = var.kms_key_id
}
bucket_key_enabled = true
}
}
resource "aws_s3_bucket_public_access_block" "this" {
bucket = aws_s3_bucket.this.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_logging" "this" {
bucket = aws_s3_bucket.this.id
target_bucket = var.logging_bucket
target_prefix = "s3-access-logs/${var.bucket_name}/"
}
```
@@ -0,0 +1,46 @@
# Standards Reference: IaC Security Scanning
## CIS Cloud Benchmarks
### CIS AWS Foundations Benchmark v3.0
- Maps directly to Checkov CKV_AWS_* checks
- Covers IAM, logging, monitoring, networking, and storage security
- Automated scanning validates 100+ benchmark controls
### CIS Azure Foundations Benchmark v2.1
- Maps to Checkov CKV_AZURE_* checks
- Covers identity, security center, storage, database, and network controls
### CIS GCP Foundations Benchmark v2.0
- Maps to Checkov CKV_GCP_* checks
- Covers IAM, logging, networking, VM, storage, and database controls
## NIST SP 800-53 Mapping
| NIST Control | IaC Check | Checkov ID |
|-------------|-----------|------------|
| AC-3 Access Enforcement | S3 bucket public access | CKV_AWS_18, CKV_AWS_20 |
| AU-2 Audit Events | CloudTrail enabled | CKV_AWS_35 |
| SC-8 Transmission Confidentiality | HTTPS/TLS enforcement | CKV_AWS_2 |
| SC-28 Protection at Rest | Encryption at rest | CKV_AWS_19, CKV_AWS_17 |
| SI-4 System Monitoring | CloudWatch/logging | CKV_AWS_24, CKV_AWS_66 |
## OWASP SAMM - Secure Architecture
### Security Architecture Level 2
- Validate infrastructure configurations against security standards before deployment
- Use automated tools to enforce architecture security requirements
### Security Architecture Level 3
- Custom policies encode organization-specific architecture requirements
- Continuous validation prevents configuration drift from approved patterns
## NIST SSDF (SP 800-218)
### PO.1: Define Security Requirements
- IaC security policies translate security requirements into enforceable checks
- Custom policies capture organization-specific requirements
### PW.5: Configure Software Securely
- PW.5.1: Configure software to have secure settings by default
- IaC scanning enforces secure defaults in infrastructure provisioning
@@ -0,0 +1,76 @@
# Workflow Reference: IaC Security Scanning
## IaC Scanning Pipeline
```
Terraform/IaC Code Change
┌──────────────────┐
│ PR Created │
└──────┬───────────┘
├──────────────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Checkov │ │ tfsec │
│ (2500+ rules)│ │ (Terraform) │
└──────┬───────┘ └──────┬───────┘
│ │
└──────────┬─────────┘
┌──────────────────┐
│ SARIF Upload │
│ to GitHub │
└──────┬───────────┘
┌──────────────────┐
│ Quality Gate │
│ (Block on HIGH+) │
└──────┬───────────┘
┌─────────┴──────────┐
▼ ▼
PASS FAIL
terraform apply Block merge
permitted + Fix required
```
## Checkov Command Reference
| Command | Purpose |
|---------|---------|
| `checkov -d ./terraform/` | Scan directory |
| `checkov -f main.tf` | Scan single file |
| `checkov -f tfplan.json --framework terraform_plan` | Scan Terraform plan |
| `checkov --list` | List all available checks |
| `checkov -d . --check CKV_AWS_18` | Run specific check |
| `checkov -d . --skip-check CKV_AWS_145` | Skip specific check |
| `checkov -d . --bc-api-key KEY` | Upload to Bridgecrew |
| `checkov -d . --create-baseline` | Create baseline file |
| `checkov -d . --baseline BASELINE` | Scan against baseline |
| `checkov -d . --external-checks-dir ./custom/` | Use custom checks |
| `checkov -d . --compact` | Compact output |
| `checkov -d . --output sarif` | SARIF format output |
## Common Misconfigurations by Cloud Provider
### AWS Top 10 IaC Misconfigurations
1. S3 bucket public access enabled (CKV_AWS_18, CKV_AWS_20)
2. Security group with open ingress 0.0.0.0/0 (CKV_AWS_23)
3. RDS instance not encrypted (CKV_AWS_16)
4. CloudTrail not enabled (CKV_AWS_35)
5. EBS volume not encrypted (CKV_AWS_3)
6. IAM policy with wildcard actions (CKV_AWS_1)
7. ALB not using HTTPS (CKV_AWS_2)
8. CloudWatch logs not encrypted (CKV_AWS_24)
9. IMDSv2 not required (CKV_AWS_79)
10. VPC flow logs not enabled (CKV_AWS_9)
### Kubernetes Top Misconfigurations
1. Container running as root (CKV_K8S_6)
2. Privileged container (CKV_K8S_16)
3. No resource limits (CKV_K8S_11, CKV_K8S_13)
4. No readiness/liveness probes (CKV_K8S_9)
5. hostNetwork enabled (CKV_K8S_19)
@@ -0,0 +1,245 @@
#!/usr/bin/env python3
"""
IaC Security Scanning Pipeline Script
Runs Checkov and/or tfsec against IaC directories, aggregates findings,
evaluates quality gates, and generates reports.
Usage:
python process.py --iac-dir ./terraform --framework terraform
python process.py --iac-dir ./k8s --framework kubernetes --output report.json
"""
import argparse
import json
import os
import subprocess
import sys
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Optional
SEVERITY_MAP = {"CRITICAL": 0, "HIGH": 1, "MEDIUM": 2, "LOW": 3}
@dataclass
class IaCFinding:
check_id: str
check_name: str
severity: str
resource: str
file_path: str
guideline: str
framework: str
tool: str
file_line_range: list = field(default_factory=list)
def run_checkov(iac_dir: str, framework: str = "terraform",
skip_checks: Optional[list] = None,
custom_checks_dir: Optional[str] = None,
baseline: Optional[str] = None) -> dict:
"""Run Checkov scan and return JSON results."""
cmd = [
"checkov", "-d", iac_dir,
"--framework", framework,
"--output", "json",
"--compact",
"--quiet"
]
if skip_checks:
cmd.extend(["--skip-check", ",".join(skip_checks)])
if custom_checks_dir:
cmd.extend(["--external-checks-dir", custom_checks_dir])
if baseline:
cmd.extend(["--baseline", baseline])
try:
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
if proc.stdout:
try:
return json.loads(proc.stdout)
except json.JSONDecodeError:
return {"error": "Failed to parse Checkov JSON output"}
return {"error": proc.stderr[:500] if proc.stderr else "No output from Checkov"}
except subprocess.TimeoutExpired:
return {"error": "Checkov scan timed out"}
except FileNotFoundError:
return {"error": "checkov not found. Install with: pip install checkov"}
def run_tfsec(iac_dir: str) -> dict:
"""Run tfsec scan and return JSON results."""
cmd = ["tfsec", iac_dir, "--format", "json", "--no-color"]
try:
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
if proc.stdout:
try:
return json.loads(proc.stdout)
except json.JSONDecodeError:
return {"error": "Failed to parse tfsec JSON output"}
return {"error": proc.stderr[:500] if proc.stderr else "No output from tfsec"}
except FileNotFoundError:
return {"error": "tfsec not found. Install from https://aquasecurity.github.io/tfsec/"}
def parse_checkov_results(checkov_json: dict) -> tuple:
"""Parse Checkov JSON output into findings."""
findings = []
passed_count = 0
skipped_count = 0
results_list = checkov_json if isinstance(checkov_json, list) else [checkov_json]
for result_block in results_list:
for check_type in result_block.get("results", {}):
if check_type == "passed_checks":
passed_count += len(result_block["results"].get("passed_checks", []))
elif check_type == "skipped_checks":
skipped_count += len(result_block["results"].get("skipped_checks", []))
elif check_type == "failed_checks":
for check in result_block["results"].get("failed_checks", []):
severity = check.get("severity", "MEDIUM")
if not severity or severity == "UNKNOWN":
severity = "MEDIUM"
findings.append(IaCFinding(
check_id=check.get("check_id", ""),
check_name=check.get("check_result", {}).get("name", check.get("name", "")),
severity=severity.upper(),
resource=check.get("resource", ""),
file_path=check.get("file_path", ""),
guideline=check.get("guideline", ""),
framework=check.get("check_type", "terraform"),
tool="checkov",
file_line_range=check.get("file_line_range", [])
))
return findings, passed_count, skipped_count
def parse_tfsec_results(tfsec_json: dict) -> list:
"""Parse tfsec JSON output into findings."""
findings = []
for result in tfsec_json.get("results", []):
findings.append(IaCFinding(
check_id=result.get("rule_id", result.get("long_id", "")),
check_name=result.get("rule_description", ""),
severity=result.get("severity", "MEDIUM").upper(),
resource=result.get("resource", ""),
file_path=result.get("location", {}).get("filename", ""),
guideline=result.get("resolution", ""),
framework="terraform",
tool="tfsec",
file_line_range=[
result.get("location", {}).get("start_line", 0),
result.get("location", {}).get("end_line", 0)
]
))
return findings
def evaluate_quality_gate(findings: list, threshold: str) -> dict:
"""Evaluate quality gate based on finding severities."""
threshold_level = SEVERITY_MAP.get(threshold.upper(), 1)
blocking = [f for f in findings if SEVERITY_MAP.get(f.severity, 3) <= threshold_level]
severity_counts = {}
for f in findings:
severity_counts[f.severity] = severity_counts.get(f.severity, 0) + 1
return {
"passed": len(blocking) == 0,
"threshold": threshold.upper(),
"total_findings": len(findings),
"blocking_count": len(blocking),
"severity_counts": severity_counts,
"blocking_details": [
{
"check_id": f.check_id,
"name": f.check_name,
"severity": f.severity,
"resource": f.resource,
"file": f.file_path,
"lines": f.file_line_range
}
for f in blocking[:25]
]
}
def main():
parser = argparse.ArgumentParser(description="IaC Security Scanning Pipeline")
parser.add_argument("--iac-dir", required=True, help="Directory containing IaC files")
parser.add_argument("--framework", default="terraform",
choices=["terraform", "cloudformation", "kubernetes", "helm", "all"])
parser.add_argument("--output", default="iac-security-report.json")
parser.add_argument("--severity-threshold", default="high",
choices=["critical", "high", "medium", "low"])
parser.add_argument("--fail-on-findings", action="store_true")
parser.add_argument("--skip-checks", nargs="*", help="Check IDs to skip")
parser.add_argument("--custom-checks-dir", default=None)
parser.add_argument("--run-tfsec", action="store_true", help="Also run tfsec")
args = parser.parse_args()
iac_dir = os.path.abspath(args.iac_dir)
all_findings = []
print(f"[*] Scanning IaC: {iac_dir} (framework: {args.framework})")
checkov_json = run_checkov(iac_dir, args.framework, args.skip_checks, args.custom_checks_dir)
if "error" in checkov_json:
print(f"[WARN] Checkov: {checkov_json['error']}")
else:
findings, passed, skipped = parse_checkov_results(checkov_json)
all_findings.extend(findings)
print(f" Checkov: {len(findings)} failed, {passed} passed, {skipped} skipped")
if args.run_tfsec and args.framework in ("terraform", "all"):
tfsec_json = run_tfsec(iac_dir)
if "error" not in tfsec_json:
tfsec_findings = parse_tfsec_results(tfsec_json)
all_findings.extend(tfsec_findings)
print(f" tfsec: {len(tfsec_findings)} findings")
quality_gate = evaluate_quality_gate(all_findings, args.severity_threshold)
report = {
"metadata": {
"directory": iac_dir,
"framework": args.framework,
"scan_date": datetime.now(timezone.utc).isoformat()
},
"quality_gate": quality_gate,
"findings": [
{
"check_id": f.check_id, "name": f.check_name,
"severity": f.severity, "resource": f.resource,
"file": f.file_path, "lines": f.file_line_range,
"guideline": f.guideline, "tool": f.tool
}
for f in sorted(all_findings, key=lambda x: SEVERITY_MAP.get(x.severity, 3))
]
}
output_path = os.path.abspath(args.output)
with open(output_path, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report: {output_path}")
if quality_gate["passed"]:
print(f"\n[PASS] Quality gate passed. {quality_gate['total_findings']} findings, none blocking.")
else:
print(f"\n[FAIL] {quality_gate['blocking_count']} blocking findings:")
for d in quality_gate["blocking_details"][:10]:
print(f" [{d['severity']}] {d['check_id']}: {d['resource']} ({d['file']})")
if args.fail_on_findings and not quality_gate["passed"]:
sys.exit(1)
if __name__ == "__main__":
main()