Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:51:02 +08:00
commit ff1f4bd119
252 changed files with 72682 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
# Reference Document Template
This file contains detailed reference material that Claude should load only when needed.
## Table of Contents
- [Section 1](#section-1)
- [Section 2](#section-2)
- [Security Standards](#security-standards)
## Section 1
Detailed information, schemas, or examples that are too large for SKILL.md.
## Section 2
Additional reference material.
## Security Standards
### OWASP Top 10
Reference relevant OWASP categories:
- A01: Broken Access Control
- A02: Cryptographic Failures
- etc.
### CWE Mappings
Map to relevant Common Weakness Enumeration categories:
- CWE-79: Cross-site Scripting
- CWE-89: SQL Injection
- etc.
### MITRE ATT&CK
Reference relevant tactics and techniques if applicable:
- TA0001: Initial Access
- T1190: Exploit Public-Facing Application
- etc.

View File

@@ -0,0 +1,237 @@
# Checkov Compliance Framework Mapping
Mapping of Checkov checks to CIS, PCI-DSS, HIPAA, SOC2, NIST, and GDPR compliance requirements.
## CIS Benchmarks
### CIS AWS Foundations Benchmark v1.4
| Check ID | CIS Control | Description | Severity |
|----------|-------------|-------------|----------|
| CKV_AWS_19 | 2.1.1 | Ensure S3 bucket encryption at rest | HIGH |
| CKV_AWS_21 | 2.1.3 | Ensure S3 bucket versioning enabled | MEDIUM |
| CKV_AWS_18 | 2.1.5 | Ensure S3 bucket access logging | MEDIUM |
| CKV_AWS_23 | 4.1 | Security group ingress not 0.0.0.0/0 | HIGH |
| CKV_AWS_24 | 4.2 | Security group ingress not ::/0 | HIGH |
| CKV_AWS_40 | 1.16 | IAM policies no wildcard actions | HIGH |
| CKV_AWS_61 | 2.3.1 | RDS encryption at rest enabled | HIGH |
| CKV_AWS_16 | 2.3.1 | RDS storage encrypted | HIGH |
| CKV_AWS_17 | 2.3.2 | RDS backup retention period | MEDIUM |
| CKV_AWS_7 | 2.9 | EBS encryption by default | HIGH |
| CKV_AWS_93 | 2.4.1 | S3 bucket public access blocked | CRITICAL |
### CIS Kubernetes Benchmark v1.6
| Check ID | CIS Control | Description | Severity |
|----------|-------------|-------------|----------|
| CKV_K8S_16 | 5.2.1 | Container not privileged | HIGH |
| CKV_K8S_22 | 5.2.6 | Read-only root filesystem | HIGH |
| CKV_K8S_28 | 5.2.7 | Minimize capabilities | HIGH |
| CKV_K8S_10 | 5.2.13 | CPU requests configured | MEDIUM |
| CKV_K8S_11 | 5.2.13 | CPU limits configured | MEDIUM |
| CKV_K8S_12 | 5.2.14 | Memory requests configured | MEDIUM |
| CKV_K8S_13 | 5.2.14 | Memory limits configured | MEDIUM |
| CKV_K8S_8 | 5.2.15 | Liveness probe configured | MEDIUM |
| CKV_K8S_9 | 5.2.15 | Readiness probe configured | MEDIUM |
## PCI-DSS v3.2.1
### Requirement 2: Do not use vendor-supplied defaults
| Check ID | PCI Requirement | Description |
|----------|-----------------|-------------|
| CKV_AWS_41 | 2.1 | EKS encryption enabled |
| CKV_AWS_58 | 2.2 | EKS public access restricted |
| CKV_K8S_14 | 2.3 | Image tag not :latest |
### Requirement 3: Protect stored cardholder data
| Check ID | PCI Requirement | Description |
|----------|-----------------|-------------|
| CKV_AWS_19 | 3.4 | S3 bucket encrypted |
| CKV_AWS_61 | 3.4 | RDS encrypted at rest |
| CKV_AWS_7 | 3.4 | EBS encryption enabled |
| CKV_AWS_89 | 3.4 | DynamoDB encryption |
### Requirement 6: Develop and maintain secure systems
| Check ID | PCI Requirement | Description |
|----------|-----------------|-------------|
| CKV_AWS_23 | 6.2 | Security groups not open |
| CKV_AWS_40 | 6.5 | IAM no wildcard permissions |
| CKV_K8S_16 | 6.5 | No privileged containers |
### Requirement 10: Track and monitor all access
| Check ID | PCI Requirement | Description |
|----------|-----------------|-------------|
| CKV_AWS_18 | 10.2 | S3 access logging enabled |
| CKV_AWS_51 | 10.3 | ECR image scanning |
| CKV_AWS_46 | 10.5 | ECS task logging |
## HIPAA Security Rule
### Administrative Safeguards (§164.308)
| Check ID | HIPAA Control | Description |
|----------|---------------|-------------|
| CKV_AWS_40 | §164.308(a)(3) | IAM access controls |
| CKV_AWS_49 | §164.308(a)(4) | CloudTrail logging |
| CKV_AWS_38 | §164.308(a)(5) | EKS RBAC enabled |
### Physical Safeguards (§164.310)
| Check ID | HIPAA Control | Description |
|----------|---------------|-------------|
| CKV_AWS_19 | §164.310(d)(1) | Encryption at rest (S3) |
| CKV_AWS_7 | §164.310(d)(1) | Encryption at rest (EBS) |
| CKV_AWS_61 | §164.310(d)(1) | Encryption at rest (RDS) |
### Technical Safeguards (§164.312)
| Check ID | HIPAA Control | Description |
|----------|---------------|-------------|
| CKV_AWS_23 | §164.312(a)(1) | Access control (network) |
| CKV_AWS_18 | §164.312(b) | Audit logging (S3) |
| CKV_AWS_27 | §164.312(c)(1) | SQS encryption |
| CKV_AWS_20 | §164.312(e)(1) | S3 SSL/TLS enforced |
## SOC 2 Trust Service Criteria
### CC6.1: Logical and Physical Access Controls
| Check ID | TSC | Description |
|----------|-----|-------------|
| CKV_AWS_40 | CC6.1 | IAM least privilege |
| CKV_AWS_23 | CC6.1 | Network segmentation |
| CKV_K8S_21 | CC6.1 | Namespace defined |
### CC6.6: Encryption
| Check ID | TSC | Description |
|----------|-----|-------------|
| CKV_AWS_19 | CC6.6 | S3 encryption |
| CKV_AWS_7 | CC6.6 | EBS encryption |
| CKV_AWS_61 | CC6.6 | RDS encryption |
| CKV_AWS_20 | CC6.6 | S3 SSL enforced |
### CC7.2: System Monitoring
| Check ID | TSC | Description |
|----------|-----|-------------|
| CKV_AWS_18 | CC7.2 | S3 access logging |
| CKV_AWS_49 | CC7.2 | CloudTrail enabled |
| CKV_K8S_8 | CC7.2 | Liveness probe |
## NIST 800-53 Rev 5
### AC (Access Control)
| Check ID | NIST Control | Description |
|----------|--------------|-------------|
| CKV_AWS_40 | AC-3 | IAM least privilege |
| CKV_AWS_23 | AC-4 | Network access control |
| CKV_K8S_16 | AC-6 | Least privilege (containers) |
### AU (Audit and Accountability)
| Check ID | NIST Control | Description |
|----------|--------------|-------------|
| CKV_AWS_18 | AU-2 | S3 access logging |
| CKV_AWS_49 | AU-12 | CloudTrail logging |
| CKV_K8S_35 | AU-9 | Audit log protection |
### SC (System and Communications Protection)
| Check ID | NIST Control | Description |
|----------|--------------|-------------|
| CKV_AWS_19 | SC-28 | Encryption at rest (S3) |
| CKV_AWS_20 | SC-8 | Encryption in transit (S3) |
| CKV_AWS_7 | SC-28 | Encryption at rest (EBS) |
## GDPR
### Article 32: Security of Processing
| Check ID | GDPR Article | Description |
|----------|--------------|-------------|
| CKV_AWS_19 | Art. 32(1)(a) | Encryption of personal data |
| CKV_AWS_7 | Art. 32(1)(a) | EBS encryption |
| CKV_AWS_61 | Art. 32(1)(a) | RDS encryption |
| CKV_AWS_21 | Art. 32(1)(b) | Data backup (S3 versioning) |
| CKV_AWS_18 | Art. 32(1)(d) | Access logging |
### Article 25: Data Protection by Design
| Check ID | GDPR Article | Description |
|----------|--------------|-------------|
| CKV_AWS_93 | Art. 25 | S3 public access block |
| CKV_AWS_23 | Art. 25 | Network isolation |
| CKV_AWS_20 | Art. 25 | Secure transmission |
## Usage Examples
### Scan for CIS Compliance
```bash
# CIS AWS Benchmark
checkov -d ./terraform --check CIS_AWS
# CIS Azure Benchmark
checkov -d ./terraform --check CIS_AZURE
# CIS Kubernetes Benchmark
checkov -d ./k8s --framework kubernetes --check CIS_KUBERNETES
```
### Scan for PCI-DSS Compliance
```bash
# Focus on encryption requirements (Req 3.4)
checkov -d ./terraform \
--check CKV_AWS_19,CKV_AWS_61,CKV_AWS_7,CKV_AWS_89
# Network security (Req 1, 2)
checkov -d ./terraform \
--check CKV_AWS_23,CKV_AWS_24,CKV_AWS_40
```
### Scan for HIPAA Compliance
```bash
# HIPAA-focused scan
checkov -d ./terraform \
--check CKV_AWS_19,CKV_AWS_7,CKV_AWS_61,CKV_AWS_20,CKV_AWS_18,CKV_AWS_40
```
### Generate Compliance Report
```bash
# Comprehensive compliance report
checkov -d ./terraform \
-o json --output-file-path ./compliance-report \
--repo-id healthcare-infra \
--check CIS_AWS,PCI_DSS,HIPAA
```
## Compliance Matrix
| Framework | Checkov Support | Common Checks | Report Format |
|-----------|-----------------|---------------|---------------|
| CIS AWS | ✓ Full | 100+ checks | JSON, CLI, SARIF |
| CIS Azure | ✓ Full | 80+ checks | JSON, CLI, SARIF |
| CIS Kubernetes | ✓ Full | 50+ checks | JSON, CLI, SARIF |
| PCI-DSS 3.2.1 | ✓ Partial | 30+ checks | JSON, CLI |
| HIPAA | ✓ Partial | 40+ checks | JSON, CLI |
| SOC 2 | ✓ Partial | 35+ checks | JSON, CLI |
| NIST 800-53 | ✓ Mapping | 60+ checks | JSON, CLI |
| GDPR | ✓ Mapping | 25+ checks | JSON, CLI |
## Additional Resources
- [CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks/)
- [PCI Security Standards](https://www.pcisecuritystandards.org/)
- [HIPAA Security Rule](https://www.hhs.gov/hipaa/for-professionals/security/index.html)
- [AICPA SOC 2](https://www.aicpa.org/soc4so)
- [NIST 800-53](https://csrc.nist.gov/publications/detail/sp/800-53/rev-5/final)
- [GDPR Portal](https://gdpr.eu/)

View File

@@ -0,0 +1,460 @@
# Checkov Custom Policy Development Guide
Complete guide for creating organization-specific security policies in Python and YAML.
## Overview
Custom policies allow you to enforce organization-specific security requirements beyond Checkov's built-in checks. Policies can be written in:
- **Python**: Full programmatic control, graph-based analysis
- **YAML**: Simple attribute checks, easy to maintain
## Python-Based Custom Policies
### Basic Resource Check
```python
# custom_checks/require_resource_tags.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
class RequireResourceTags(BaseResourceCheck):
def __init__(self):
name = "Ensure all resources have required tags"
id = "CKV_AWS_CUSTOM_001"
supported_resources = ['aws_*'] # All AWS resources
categories = [CheckCategories.CONVENTION]
super().__init__(name=name, id=id, categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf):
"""Check if resource has required tags."""
required_tags = ['Environment', 'Owner', 'CostCenter']
tags = conf.get('tags')
if not tags or not isinstance(tags, list):
return CheckResult.FAILED
tag_dict = tags[0] if tags else {}
for required_tag in required_tags:
if required_tag not in tag_dict:
self.evaluated_keys = ['tags']
return CheckResult.FAILED
return CheckResult.PASSED
check = RequireResourceTags()
```
### Graph-Based Policy
```python
# custom_checks/s3_bucket_policy_public.py
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
class S3BucketPolicyNotPublic(BaseResourceCheck):
def __init__(self):
name = "Ensure S3 bucket policy doesn't allow public access"
id = "CKV_AWS_CUSTOM_002"
supported_resources = ['aws_s3_bucket_policy']
categories = [CheckCategories.IAM]
super().__init__(name=name, id=id, categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf):
"""Scan S3 bucket policy for public access."""
policy = conf.get('policy')
if not policy:
return CheckResult.PASSED
import json
try:
policy_doc = json.loads(policy[0]) if isinstance(policy, list) else json.loads(policy)
except (json.JSONDecodeError, TypeError):
return CheckResult.UNKNOWN
statements = policy_doc.get('Statement', [])
for statement in statements:
effect = statement.get('Effect')
principal = statement.get('Principal', {})
# Check for public access
if effect == 'Allow':
if principal == '*' or principal.get('AWS') == '*':
return CheckResult.FAILED
return CheckResult.PASSED
check = S3BucketPolicyNotPublic()
```
### Connection-Aware Check (Graph)
```python
# custom_checks/ec2_in_private_subnet.py
from checkov.terraform.checks.resource.base_resource_value_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
class EC2InPrivateSubnet(BaseResourceCheck):
def __init__(self):
name = "Ensure EC2 instances are in private subnets"
id = "CKV_AWS_CUSTOM_003"
supported_resources = ['aws_instance']
categories = [CheckCategories.NETWORKING]
super().__init__(name=name, id=id, categories=categories,
supported_resources=supported_resources)
def scan_resource_conf(self, conf, entity_type):
"""Check if EC2 instance is in private subnet."""
subnet_id = conf.get('subnet_id')
if not subnet_id:
return CheckResult.PASSED
# Use graph to find connected subnet
# This requires access to the graph context
# Implementation depends on Checkov version
return CheckResult.UNKNOWN # Implement graph logic
check = EC2InPrivateSubnet()
```
## YAML-Based Custom Policies
### Simple Attribute Check
```yaml
# custom_checks/s3_lifecycle.yaml
metadata:
id: "CKV_AWS_CUSTOM_004"
name: "Ensure S3 buckets have lifecycle policies"
category: "BACKUP_AND_RECOVERY"
severity: "MEDIUM"
definition:
cond_type: "attribute"
resource_types:
- "aws_s3_bucket"
attribute: "lifecycle_rule"
operator: "exists"
```
### Complex Logic
```yaml
# custom_checks/rds_multi_az.yaml
metadata:
id: "CKV_AWS_CUSTOM_005"
name: "Ensure RDS instances are multi-AZ for production"
category: "BACKUP_AND_RECOVERY"
severity: "HIGH"
definition:
or:
- cond_type: "attribute"
resource_types:
- "aws_db_instance"
attribute: "multi_az"
operator: "equals"
value: true
- and:
- cond_type: "attribute"
resource_types:
- "aws_db_instance"
attribute: "tags.Environment"
operator: "not_equals"
value: "production"
```
### Kubernetes Policy
```yaml
# custom_checks/k8s_service_account.yaml
metadata:
id: "CKV_K8S_CUSTOM_001"
name: "Ensure pods use dedicated service accounts"
category: "IAM"
severity: "HIGH"
definition:
cond_type: "attribute"
resource_types:
- "Pod"
- "Deployment"
- "StatefulSet"
- "DaemonSet"
attribute: "spec.serviceAccountName"
operator: "not_equals"
value: "default"
```
## Policy Structure
### Python Policy Template
```python
#!/usr/bin/env python3
from checkov.terraform.checks.resource.base_resource_check import BaseResourceCheck
from checkov.common.models.enums import CheckResult, CheckCategories
class MyCustomCheck(BaseResourceCheck):
def __init__(self):
# Metadata
name = "Check description"
id = "CKV_[PROVIDER]_CUSTOM_[NUMBER]" # e.g., CKV_AWS_CUSTOM_001
supported_resources = ['resource_type'] # e.g., ['aws_s3_bucket']
categories = [CheckCategories.CATEGORY] # See categories below
guideline = "https://docs.example.com/security-policy"
super().__init__(
name=name,
id=id,
categories=categories,
supported_resources=supported_resources,
guideline=guideline
)
def scan_resource_conf(self, conf, entity_type=None):
"""
Scan resource configuration for compliance.
Args:
conf: Resource configuration dictionary
entity_type: Resource type (optional)
Returns:
CheckResult.PASSED, CheckResult.FAILED, or CheckResult.UNKNOWN
"""
# Implementation
if self.check_condition(conf):
return CheckResult.PASSED
self.evaluated_keys = ['attribute_that_failed']
return CheckResult.FAILED
def get_inspected_key(self):
"""Return the key that was checked."""
return 'attribute_name'
check = MyCustomCheck()
```
### Check Categories
```python
from checkov.common.models.enums import CheckCategories
# Available categories:
CheckCategories.IAM
CheckCategories.NETWORKING
CheckCategories.ENCRYPTION
CheckCategories.LOGGING
CheckCategories.BACKUP_AND_RECOVERY
CheckCategories.CONVENTION
CheckCategories.SECRETS
CheckCategories.KUBERNETES
CheckCategories.API_SECURITY
CheckCategories.SUPPLY_CHAIN
```
## Loading Custom Policies
### Directory Structure
```
custom_checks/
├── aws/
│ ├── require_tags.py
│ ├── s3_lifecycle.yaml
│ └── rds_backups.py
├── kubernetes/
│ ├── require_resource_limits.py
│ └── security_context.yaml
└── azure/
└── storage_encryption.py
```
### Load Policies
```bash
# Load from directory
checkov -d ./terraform --external-checks-dir ./custom_checks
# Load specific policy
checkov -d ./terraform --external-checks-git https://github.com/org/policies.git
# List loaded custom checks
checkov -d ./terraform --external-checks-dir ./custom_checks --list
```
## Testing Custom Policies
### Unit Testing
```python
# tests/test_require_tags.py
import unittest
from custom_checks.require_resource_tags import RequireResourceTags
from checkov.common.models.enums import CheckResult
class TestRequireResourceTags(unittest.TestCase):
def setUp(self):
self.check = RequireResourceTags()
def test_pass_with_all_tags(self):
resource_conf = {
'tags': [{
'Environment': 'production',
'Owner': 'team@example.com',
'CostCenter': 'engineering'
}]
}
result = self.check.scan_resource_conf(resource_conf)
self.assertEqual(result, CheckResult.PASSED)
def test_fail_missing_tag(self):
resource_conf = {
'tags': [{
'Environment': 'production',
'Owner': 'team@example.com'
# Missing CostCenter
}]
}
result = self.check.scan_resource_conf(resource_conf)
self.assertEqual(result, CheckResult.FAILED)
def test_fail_no_tags(self):
resource_conf = {}
result = self.check.scan_resource_conf(resource_conf)
self.assertEqual(result, CheckResult.FAILED)
if __name__ == '__main__':
unittest.main()
```
### Integration Testing
```bash
# Test against sample infrastructure
checkov -d ./tests/fixtures/terraform \
--external-checks-dir ./custom_checks \
--check CKV_AWS_CUSTOM_001
# Verify output format
checkov -d ./tests/fixtures/terraform \
--external-checks-dir ./custom_checks \
-o json | jq '.results.failed_checks[] | select(.check_id == "CKV_AWS_CUSTOM_001")'
```
## Common Patterns
### Pattern 1: Naming Convention Check
```python
import re
class ResourceNamingConvention(BaseResourceCheck):
def scan_resource_conf(self, conf):
"""Enforce naming convention: env-app-resource"""
pattern = r'^(dev|staging|prod)-[a-z]+-[a-z0-9-]+$'
name = conf.get('name')
if not name or not isinstance(name, list):
return CheckResult.FAILED
resource_name = name[0] if isinstance(name[0], str) else str(name[0])
if not re.match(pattern, resource_name):
self.evaluated_keys = ['name']
return CheckResult.FAILED
return CheckResult.PASSED
```
### Pattern 2: Environment-Specific Requirements
```python
class ProductionEncryption(BaseResourceCheck):
def scan_resource_conf(self, conf):
"""Require encryption for production resources."""
tags = conf.get('tags', [{}])[0]
environment = tags.get('Environment', '')
# Only enforce for production
if environment.lower() != 'production':
return CheckResult.PASSED
# Check encryption
encryption_enabled = conf.get('server_side_encryption_configuration')
if not encryption_enabled:
return CheckResult.FAILED
return CheckResult.PASSED
```
### Pattern 3: Cost Optimization
```python
class EC2InstanceSizing(BaseResourceCheck):
def scan_resource_conf(self, conf):
"""Prevent oversized instances in non-production."""
tags = conf.get('tags', [{}])[0]
environment = tags.get('Environment', '')
# Only restrict non-production
if environment.lower() == 'production':
return CheckResult.PASSED
instance_type = conf.get('instance_type', [''])[0]
oversized_types = ['c5.9xlarge', 'c5.12xlarge', 'c5.18xlarge']
if instance_type in oversized_types:
self.evaluated_keys = ['instance_type']
return CheckResult.FAILED
return CheckResult.PASSED
```
## Best Practices
1. **ID Convention**: Use `CKV_[PROVIDER]_CUSTOM_[NUMBER]` format
2. **Documentation**: Include guideline URL in check metadata
3. **Error Handling**: Return `CheckResult.UNKNOWN` for ambiguous cases
4. **Performance**: Minimize complex operations in scan loops
5. **Testing**: Write unit tests for all custom policies
6. **Versioning**: Track policy versions in version control
7. **Review Process**: Require security team review before deployment
## Troubleshooting
### Policy Not Loading
```bash
# Debug loading
checkov -d ./terraform --external-checks-dir ./custom_checks -v
# Verify syntax
python3 custom_checks/my_policy.py
# Check for import errors
python3 -c "import custom_checks.my_policy"
```
### Policy Not Triggering
```bash
# Verify resource type matches
checkov -d ./terraform --external-checks-dir ./custom_checks --list
# Test with specific check
checkov -d ./terraform --check CKV_AWS_CUSTOM_001 -v
```
## Additional Resources
- [Checkov Custom Policies Documentation](https://www.checkov.io/3.Custom%20Policies/Custom%20Policies%20Overview.html)
- [Python Policy Examples](https://github.com/bridgecrewio/checkov/tree/master/checkov/terraform/checks)
- [YAML Policy Examples](https://github.com/bridgecrewio/checkov/tree/master/checkov/terraform/checks/graph_checks)

View File

@@ -0,0 +1,431 @@
# Checkov Suppression and Exception Handling Guide
Best practices for suppressing false positives and managing policy exceptions in Checkov.
## Suppression Methods
### Inline Suppression (Recommended)
#### Terraform
```hcl
# Single check suppression with justification
resource "aws_s3_bucket" "public_site" {
# checkov:skip=CKV_AWS_18:Public bucket for static website hosting
bucket = "my-public-website"
acl = "public-read"
}
# Multiple checks suppression
resource "aws_security_group" "legacy" {
# checkov:skip=CKV_AWS_23:Legacy app requires open access
# checkov:skip=CKV_AWS_24:IPv6 not supported by application
name = "legacy-sg"
ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
```
#### Kubernetes
```yaml
# Annotation-based suppression
apiVersion: v1
kind: Pod
metadata:
name: legacy-app
annotations:
checkov.io/skip: CKV_K8S_16=Legacy application requires elevated privileges
spec:
containers:
- name: app
image: myapp:1.0
securityContext:
privileged: true
```
#### CloudFormation
```yaml
Resources:
PublicBucket:
Type: AWS::S3::Bucket
Metadata:
checkov:
skip:
- id: CKV_AWS_18
comment: "Public bucket for CDN origin"
Properties:
BucketName: my-public-bucket
PublicAccessBlockConfiguration:
BlockPublicAcls: false
```
### Configuration File Suppression
#### .checkov.yaml
```yaml
# .checkov.yaml (project root)
skip-check:
- CKV_AWS_8 # Ensure CloudWatch log groups encrypted
- CKV_K8S_43 # Image pull policy Always
# Skip specific paths
skip-path:
- .terraform/
- node_modules/
- vendor/
# Severity-based soft fail
soft-fail-on:
- LOW
- MEDIUM
# Hard fail on critical/high only
hard-fail-on:
- CRITICAL
- HIGH
```
### CLI-Based Suppression
```bash
# Skip specific checks
checkov -d ./terraform --skip-check CKV_AWS_8,CKV_AWS_21
# Skip entire frameworks
checkov -d ./infra --skip-framework secrets
# Skip paths
checkov -d ./terraform --skip-path .terraform/ --skip-path vendor/
```
## Suppression Governance
### Approval Workflow
```yaml
# .github/workflows/checkov-review.yml
name: Review Checkov Suppressions
on:
pull_request:
paths:
- '**.tf'
- '**.yaml'
- '**.yml'
jobs:
check-suppressions:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Check for New Suppressions
run: |
# Count suppressions in PR
SUPPRESSIONS=$(git diff origin/main | grep -c "checkov:skip" || true)
if [ "$SUPPRESSIONS" -gt 0 ]; then
echo "::warning::PR contains $SUPPRESSIONS new suppression(s)"
echo "Security team review required"
# Request review from security team
fi
```
### Suppression Documentation Template
```hcl
resource "aws_security_group" "example" {
# checkov:skip=CKV_AWS_23:TICKET-1234 - Business justification here
# Approved by: security-team@example.com
# Review date: 2024-01-15
# Expiration: 2024-06-15 (review quarterly)
#
# Compensating controls:
# - WAF rule blocks malicious traffic
# - Application-level authentication required
# - IP allow-listing at load balancer
# - 24/7 monitoring and alerting
name = "approved-exception"
# ... configuration
}
```
## Suppression Best Practices
### 1. Always Provide Justification
```hcl
# ❌ BAD: No justification
resource "aws_s3_bucket" "example" {
# checkov:skip=CKV_AWS_18
bucket = "my-bucket"
}
# ✅ GOOD: Clear business justification
resource "aws_s3_bucket" "example" {
# checkov:skip=CKV_AWS_18:Public bucket required for static website hosting.
# Content is non-sensitive marketing materials. CloudFront restricts direct access.
bucket = "marketing-website"
}
```
### 2. Document Compensating Controls
```hcl
resource "aws_security_group" "app" {
# checkov:skip=CKV_AWS_23:Office IP range access required for developers
#
# Compensating controls:
# 1. IP range limited to corporate /24 subnet (203.0.113.0/24)
# 2. MFA required for VPN access to corporate network
# 3. Additional application-level authentication
# 4. Session timeout of 15 minutes
# 5. All access logged to SIEM
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["203.0.113.0/24"]
}
}
```
### 3. Set Expiration Dates
```hcl
resource "aws_instance" "temp" {
# checkov:skip=CKV_AWS_8:Temporary instance for POC
# EXPIRES: 2024-03-31
# After expiration: Remove or apply encryption
ami = "ami-12345678"
instance_type = "t3.micro"
}
```
### 4. Use Granular Suppressions
```hcl
# ❌ BAD: Suppress entire file or directory
# checkov:skip=* (Don't do this!)
# ✅ GOOD: Suppress specific checks on specific resources
resource "aws_s3_bucket" "example" {
# checkov:skip=CKV_AWS_18:Specific reason for this resource only
bucket = "specific-bucket"
}
```
## Exception Categories
### Legitimate Exceptions
#### 1. Public Resources by Design
```hcl
resource "aws_s3_bucket" "website" {
# checkov:skip=CKV_AWS_18:Public bucket for static website
# checkov:skip=CKV_AWS_93:Public access required by design
# Content: Marketing materials (non-sensitive)
# Access: Read-only via CloudFront
bucket = "company-website"
}
```
#### 2. Legacy System Constraints
```yaml
apiVersion: v1
kind: Pod
metadata:
name: legacy-app
annotations:
checkov.io/skip: CKV_K8S_16=Legacy app built before containers, requires host access
# Migration plan: TICKET-5678
# Target date: Q2 2024
spec:
hostNetwork: true
containers:
- name: legacy
image: legacy-app:1.0
```
#### 3. Development/Testing Environments
```hcl
resource "aws_db_instance" "dev_db" {
# checkov:skip=CKV_AWS_17:Dev environment - backups not required
# checkov:skip=CKV_AWS_61:Dev environment - encryption overhead not needed
# Environment: Non-production only
# Data: Synthetic test data (no PII/PHI)
identifier = "dev-database"
backup_retention_period = 0
storage_encrypted = false
tags = {
Environment = "development"
}
}
```
### Temporary Exceptions
```hcl
resource "aws_rds_cluster" "temp_unencrypted" {
# checkov:skip=CKV_AWS_96:Temporary exception during migration
# TICKET: INFRA-1234
# EXPIRES: 2024-02-15
# PLAN: Enable encryption at rest in Phase 2 migration
# OWNER: platform-team@example.com
cluster_identifier = "migration-temp"
storage_encrypted = false
}
```
## Suppression Anti-Patterns
### ❌ Don't: Blanket Suppressions
```yaml
# BAD: Suppress all checks
skip-check:
- "*"
```
### ❌ Don't: Suppress Without Documentation
```hcl
# BAD: No explanation
resource "aws_s3_bucket" "example" {
# checkov:skip=CKV_AWS_18
bucket = "my-bucket"
}
```
### ❌ Don't: Permanent Suppressions for Production
```hcl
# BAD: Permanent suppression of critical security control
resource "aws_rds_cluster" "prod" {
# checkov:skip=CKV_AWS_96:Too expensive
# ^ This is unacceptable for production!
cluster_identifier = "production-db"
storage_encrypted = false
}
```
### ❌ Don't: Suppress High/Critical Without Review
```hcl
# DANGEROUS: Suppressing critical finding without security review
resource "aws_security_group" "prod" {
# checkov:skip=CKV_AWS_23:Need access from anywhere
# ^ Requires security team approval!
ingress {
cidr_blocks = ["0.0.0.0/0"]
}
}
```
## Monitoring Suppressions
### Track Suppression Metrics
```bash
# Count suppressions by type
grep -r "checkov:skip" ./terraform | \
sed 's/.*checkov:skip=\([^:]*\).*/\1/' | \
sort | uniq -c | sort -rn
# Find suppressions without justification
grep -r "checkov:skip=" ./terraform | \
grep -v "checkov:skip=.*:.*"
```
### Suppression Audit Report
```python
#!/usr/bin/env python3
"""Generate suppression audit report."""
import re
import sys
from pathlib import Path
from datetime import datetime
def find_suppressions(directory):
"""Find all Checkov suppressions."""
suppressions = []
for file_path in Path(directory).rglob('*.tf'):
with open(file_path) as f:
content = f.read()
# Find suppressions
matches = re.findall(
r'#\s*checkov:skip=([^:]+):(.*)',
content
)
for check_id, reason in matches:
suppressions.append({
'file': str(file_path),
'check_id': check_id.strip(),
'reason': reason.strip()
})
return suppressions
def generate_report(suppressions):
"""Generate markdown report."""
print("# Checkov Suppression Audit Report")
print(f"\nGenerated: {datetime.now().isoformat()}")
print(f"\nTotal Suppressions: {len(suppressions)}\n")
print("## Suppressions by Check")
check_counts = {}
for s in suppressions:
check_counts[s['check_id']] = check_counts.get(s['check_id'], 0) + 1
for check_id, count in sorted(check_counts.items(), key=lambda x: -x[1]):
print(f"- {check_id}: {count}")
print("\n## All Suppressions")
for s in suppressions:
print(f"\n### {s['file']}")
print(f"**Check:** {s['check_id']}")
print(f"**Reason:** {s['reason'] or '(no justification provided)'}")
if __name__ == '__main__':
directory = sys.argv[1] if len(sys.argv) > 1 else './terraform'
suppressions = find_suppressions(directory)
generate_report(suppressions)
```
## Quarterly Review Process
1. **Generate Suppression Report**: List all active suppressions
2. **Review Expirations**: Check for expired temporary suppressions
3. **Validate Justifications**: Ensure reasons still apply
4. **Verify Compensating Controls**: Confirm controls are still in place
5. **Update or Remove**: Update suppressions or fix underlying issues
## Additional Resources
- [Checkov Suppression Documentation](https://www.checkov.io/2.Basics/Suppressing%20and%20Skipping%20Policies.html)
- [Security Exception Management Best Practices](https://owasp.org/www-community/Security_Exception_Management)