Initial commit
This commit is contained in:
40
skills/devsecops/iac-checkov/references/EXAMPLE.md
Normal file
40
skills/devsecops/iac-checkov/references/EXAMPLE.md
Normal 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.
|
||||
237
skills/devsecops/iac-checkov/references/compliance_mapping.md
Normal file
237
skills/devsecops/iac-checkov/references/compliance_mapping.md
Normal 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/)
|
||||
460
skills/devsecops/iac-checkov/references/custom_policies.md
Normal file
460
skills/devsecops/iac-checkov/references/custom_policies.md
Normal 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)
|
||||
431
skills/devsecops/iac-checkov/references/suppression_guide.md
Normal file
431
skills/devsecops/iac-checkov/references/suppression_guide.md
Normal 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)
|
||||
Reference in New Issue
Block a user