Checkov 与 tfsec 静态扫描
核心问题:怎样在 CI 中自动发现 Terraform 配置和 Kubernetes YAML 中的安全问题,阻止不安全的基础设施上线?
为什么需要 IaC 静态扫描
| 问题 | 后果 |
|---|---|
| S3 存储桶公开访问 | 数据泄露 |
安全组放行 0.0.0.0/0:22 | 服务器暴露在公网 |
| RDS 未加密 | 违反合规要求(GDPR / SOC2) |
| K8s Pod 以 root 运行 | 容器逃逸风险 |
| Secret 明文写在 YAML | 密钥泄露 |
| IAM 用管理员权限 | 权限过度,违反最小权限原则 |
Checkov:全栈 IaC 安全扫描
Checkov 支持 Terraform、Kubernetes YAML、Helm、Dockerfile、CloudFormation 等多种格式:
# 安装
pip install checkov
# 或 Docker
docker pull bridgecrew/checkov
# 扫描 Terraform
checkov -d infra/ --framework terraform
# 扫描 Kubernetes YAML
checkov -d k8s/ --framework kubernetes
# 扫描 Helm Chart
checkov -d charts/ --framework helm
# 扫描 Dockerfile
checkov -f Dockerfile --framework dockerfile
# 输出 JSON(CI 机器解析)
checkov -d infra/ --output json > checkov-results.json
# 跳过特定检查
checkov -d infra/ --skip-check CKV_AWS_18,CKV_AWS_52
常见 Checkov 检查项
Terraform(AWS)
# ❌ 违规:S3 存储桶无版本控制
resource "aws_s3_bucket" "data" {
bucket = "my-data"
}
# ✅ 修复:启用版本控制和加密
resource "aws_s3_bucket" "data" {
bucket = "my-data"
}
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration {
status = "Enabled" # CKV_AWS_52: ensure S3 bucket has versioning enabled
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "data" {
bucket = aws_s3_bucket.data.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256" # CKV_AWS_19: ensure S3 bucket has server side encryption
}
}
}
Kubernetes YAML
# ❌ 违规:以 root 运行,无安全上下文
spec:
containers:
- name: app
image: myapp:1.0
# ✅ 修复:非 root + 只读文件系统 + 禁止特权
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: app
image: myapp:1.0
securityContext:
allowPrivilegeEscalation: false # CKV_K8S_20
readOnlyRootFilesystem: true # CKV_K8S_22
capabilities:
drop: ["ALL"] # CKV_K8S_28
runAsNonRoot: true # CKV_K8S_6
tfsec:专注 Terraform 的深度扫描
# 安装
brew install tfsec
# 或
go install github.com/aquasecurity/tfsec/cmd/tfsec@latest
# 扫描当前目录
tfsec .
# 指定目录
tfsec infra/environments/production/
# SARIF 格式输出(GitHub Code Scanning 支持)
tfsec . --format sarif --out results.sarif
# 只扫描特定严重级别
tfsec . --minimum-severity HIGH
# 忽略特定规则(在代码中添加注释)
resource "aws_instance" "web" {
# tfsec:ignore:aws-ec2-no-public-ip
associate_public_ip_address = true
}
在 CI 中集成扫描
# .github/workflows/security-scan.yml
name: IaC Security Scan
on:
pull_request:
paths:
- 'infra/**'
- 'charts/**'
- 'k8s/**'
jobs:
checkov:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Checkov (Terraform)
uses: bridgecrewio/checkov-action@master
with:
directory: infra/
framework: terraform
output_format: sarif
output_file_path: reports/checkov-terraform.sarif
soft_fail: false # HIGH/CRITICAL 失败则 CI 失败
- name: Run Checkov (Kubernetes)
uses: bridgecrewio/checkov-action@master
with:
directory: k8s/
framework: kubernetes
output_format: sarif
output_file_path: reports/checkov-k8s.sarif
skip_check: CKV_K8S_35 # 豁免特定检查
- name: Upload SARIF to GitHub Security
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: reports/
if: always() # 即使扫描失败也上传结果
tfsec:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run tfsec
uses: aquasecurity/tfsec-action@v1.0.0
with:
working_directory: infra/
format: sarif
additional_args: --minimum-severity HIGH
常见安全规则分类
| 类别 | 规则示例 | Checkov ID |
|---|---|---|
| S3 | 不公开访问、加密、版本控制、日志 | CKV_AWS_18/19/52/53 |
| EC2 | 不公网 IP、EBS 加密、IMDSv2 | CKV_AWS_8/79/130 |
| RDS | 加密、备份保留、Multi-AZ | CKV_AWS_17/23/157 |
| IAM | 最小权限、MFA、禁止 * 权限 | CKV_AWS_1/2/40 |
| K8s | 非 root、只读文件系统、resource limits | CKV_K8S_6/20/22 |
| Helm | 镜像 tag 不为 latest | CKV_K8S_14 |
基线配置:.checkov.yaml
# .checkov.yaml(放在项目根目录)
directory:
- infra/
- charts/
- k8s/
framework:
- terraform
- kubernetes
- helm
check:
# 只扫描这些类别
# 不填则扫描全部
skip-check:
- CKV_AWS_18 # S3 access logging(内部存储桶不需要)
- CKV_K8S_35 # Secrets as env vars(使用 External Secrets 替代方案)
# 阈值:超过多少 CRITICAL 就失败
hard-fail-on:
- CRITICAL
- HIGH
# 输出
output:
- cli
- sarif