mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-15 15:34:56 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user