Terraformインフラストラクチャのセキュリティ監査
使用するタイミング
- TerraformデプロイメントのCI/CDパイプラインにセキュリティスキャンを統合する場合
- Terraformプランやモジュールを適用前にセキュリティベストプラクティスに照らしてレビューする場合
- クラウドインフラストラクチャプロビジョニングのためのポリシー・アズ・コードのガードレールを構築する場合
- 既存のTerraform状態ファイルを監査し、デプロイ済みの設定ミスを特定する場合
- 複数のTerraformプロジェクトにわたって組織のセキュリティ標準を強制する場合
使用しないでください:ランタイムセキュリティ監視(CSPMツールを使用)、アプリケーションセキュリティテスト(SAST/DASTツールを使用)、クラウド構成ドリフト検出(デプロイ後はAWS ConfigまたはAzure Policyを使用)には使用しないでください。
前提条件
- Checkovがインストールされていること(
pip install checkov) - tfsecがインストールされていること(
brew install tfsecまたはGitHubからバイナリを入手) - Terrascanがインストールされていること(
brew install terrascan) - Terraform v1.0+(プラン生成用)
- OPA(Open Policy Agent)(カスタムポリシー強制用)
- 監査対象のTerraformコードを含むGitリポジトリ
ワークフロー
ステップ1:CheckovでTerraformコードをスキャン
組み込みポリシーとカスタムポリシーを用いて、包括的なIaCセキュリティスキャンを実行するためにCheckovを実行します。
# Terraformディレクトリをスキャン
checkov -d ./terraform/ --framework terraform
# 特定のチェックカテゴリでスキャン
checkov -d ./terraform/ --check CKV_AWS_18,CKV_AWS_19,CKV_AWS_20,CKV_AWS_21
# 結果をJSONで出力
checkov -d ./terraform/ --output json > checkov-results.json
# より正確な分析のためにTerraformプランファイルをスキャン
terraform init && terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
checkov -f tfplan.json --framework terraform_plan
# 理由を添えて特定のチェックをスキップ
checkov -d ./terraform/ --skip-check CKV_AWS_145 \
--bc-api-key $BRIDGECREW_API_KEY
# Terraformモジュールをスキャン
checkov -d ./modules/ --framework terraform --compact
# 利用可能なすべてのチェックを一覧表示
checkov --list --framework terraform | grep CKV_AWS
ステップ2:tfsecでTerraform固有の問題をスキャン
詳細な修正ガイダンスを含むTerraformネイティブのセキュリティ分析にはtfsecを使用します。
# Terraformディレクトリをスキャン
tfsec ./terraform/
# 最小重大度しきい値を指定してスキャン
tfsec ./terraform/ --minimum-severity HIGH
# CI/CD処理用にJSONで出力
tfsec ./terraform/ --format json > tfsec-results.json
# カスタムチェックでスキャン
tfsec ./terraform/ --custom-check-dir ./custom-checks/
# 特定のルールを除外
tfsec ./terraform/ --exclude-downloaded-modules \
--exclude aws-s3-enable-bucket-logging
# 特定の重大度で失敗させる
tfsec ./terraform/ --minimum-severity CRITICAL --soft-fail
# GitHub Securityタブ用にSARIF出力を生成
tfsec ./terraform/ --format sarif > tfsec.sarif
ステップ3:Terrascanでマルチフレームワーク準拠チェック
CIS、NIST、SOC 2などのフレームワークに対するコンプライアンスチェックのためにTerrascanを実行します。
# CIS AWSベンチマークに照らしてTerraformをスキャン
terrascan scan -t aws -i terraform -d ./terraform/ \
--policy-type aws --verbose
# 特定のコンプライアンスフレームワークに対してスキャン
terrascan scan -t aws -i terraform -d ./terraform/ \
--policy-type aws \
--categories "Compliance Validation"
# JSONで出力
terrascan scan -t aws -i terraform -d ./terraform/ \
--output json > terrascan-results.json
# Terraformプランをスキャン
terrascan scan -t aws -i terraform \
--iac-file tfplan.json \
--iac-type tfplan
# 利用可能なポリシーを一覧表示
terrascan scan --list-policies -t aws
ステップ4:組織標準のためのカスタムOPAポリシーを作成
組織固有のセキュリティ要件のためにRegoポリシーを作成します。
# policy/aws_s3_encryption.rego
package terraform.aws.s3
deny[msg] {
resource := input.resource.aws_s3_bucket[name]
not resource.server_side_encryption_configuration
msg := sprintf("S3バケット'%s'はサーバー側暗号化を有効にする必要があります", [name])
}
# policy/aws_iam_no_wildcards.rego
package terraform.aws.iam
deny[msg] {
resource := input.resource.aws_iam_policy[name]
statement := resource.policy.Statement[_]
statement.Action == "*"
statement.Effect == "Allow"
msg := sprintf("IAMポリシー'%s'はワイルドカード(*)アクションを使用してはいけません", [name])
}
deny[msg] {
resource := input.resource.aws_iam_policy[name]
statement := resource.policy.Statement[_]
statement.Resource == "*"
statement.Effect == "Allow"
contains(statement.Action[_], "*")
msg := sprintf("IAMポリシー'%s'はワイルドカードリソースに対して過度に寛容なアクションを持っています", [name])
}
# policy/aws_no_public_ingress.rego
package terraform.aws.security_group
deny[msg] {
resource := input.resource.aws_security_group_rule[name]
resource.type == "ingress"
resource.cidr_blocks[_] == "0.0.0.0/0"
resource.from_port <= 22
resource.to_port >= 22
msg := sprintf("セキュリティグループルール'%s'は0.0.0.0/0からのSSHを許可しています", [name])
}
# OPAポリシーに対してTerraformプランを評価
terraform show -json tfplan | opa eval \
--data ./policy/ \
--input /dev/stdin \
"data.terraform.aws" \
--format pretty
# Conftestを使ってより簡単なOPAポリシーテストを実行
conftest test tfplan.json --policy ./policy/ --output json
ステップ5:CI/CDパイプラインにセキュリティスキャンを統合
IaCセキュリティスキャンを必須のCI/CDゲートとして追加します。
# GitHub Actions:Terraformセキュリティパイプライン
name: Terraform Security Scan
on:
pull_request:
paths: ['terraform/**']
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Terraformのセットアップ
uses: hashicorp/setup-terraform@v3
- name: Terraform Init & Plan
run: |
cd terraform/
terraform init
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
- name: Checkovスキャン
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/
framework: terraform
output_format: sarif
output_file_path: checkov.sarif
soft_fail: false
- name: tfsecスキャン
uses: aquasecurity/[email protected]
with:
working_directory: terraform/
soft_fail: false
- name: SARIFアップロード
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: checkov.sarif
- name: OPAポリシーチェック
run: |
conftest test terraform/tfplan.json \
--policy ./policy/ \
--output json
ステップ6:デプロイ済みの設定ミスを特定するためにTerraform状態をスキャン
現在のTerraform状態を監査し、すでにデプロイされているセキュリティ問題を特定します。
# 現在の状態をJSONとしてエクスポート
terraform show -json > terraform-state.json
# Checkovで状態をスキャン
checkov -f terraform-state.json --framework terraform_plan
# 特定のセキュリティ問題について状態をクエリ
terraform state list | while read resource; do
terraform state show "$resource" 2>/dev/null | grep -i "public\|0.0.0.0\|encrypt.*false\|password"
done
# 必須タグがないリソースを検索
terraform state list | grep aws_instance | while read resource; do
tags=$(terraform state show "$resource" | grep -A20 "tags")
if ! echo "$tags" | grep -q "Environment"; then
echo "タグ不足:$resource に'Environment'タグがありません"
fi
done
主要概念
| 用語 | 定義 |
|---|---|
| Infrastructure as Code | 手動コンソール操作ではなく、宣言型設定ファイル(Terraform、CloudFormation)を通じてクラウドインフラを管理する手法 |
| Policy as Code | セキュリティとコンプライアンスのポリシーを実行可能なコード(Rego、Python)として表現し、インフラ定義に対して自動評価できるようにする手法 |
| Shift Left Security | プロビジョニング後ではなくデプロイ前にIaCをスキャンすることで、セキュリティチェックを開発ライフサイクルの早期に移動させる手法 |
| Terraform Plan | Terraformが行う変更のプレビューであり、変更を適用する前にセキュリティスキャン用にJSONとしてエクスポートできる |
| Checkov | IaC用のオープンソース静的解析ツール。Terraform、CloudFormation、Kubernetes、Dockerをサポートし、1000以上の組み込みポリシーを備える |
| OPA/Rego | Open Policy Agentとそのポリシー言語Rego。構造化データ入力に対して評価されるカスタムセキュリティルールを定義するためのもの |
ツールとシステム
- Checkov:Terraform、CloudFormation、Kubernetes、ARM、Dockerfile向けの1000以上のポリシーを備えた包括的なIaCスキャナー
- tfsec:Terraform固有の静的解析ツール。詳細な修正ガイダンスとSARIF出力を提供
- Terrascan:ポリシー・アズ・コードを使用してコンプライアンスフレームワーク(CIS、NIST、SOC 2)をサポートするマルチIaCスキャナー
- OPA/Conftest:Rego言語を使用して組織固有のセキュリティルールを定義するためのカスタムポリシーエンジン
- Bridgecrew:Checkov上に構築された商用プラットフォーム。ドリフト検出とサプライチェーンセキュリティを提供
一般的なシナリオ
シナリオ:既存のTerraform CI/CDパイプラインにセキュリティゲートを追加
コンテキスト:あるDevOpsチームはGitHub ActionsでTerraformを介してインフラをデプロイしているが、セキュリティスキャンは行っていない。最近の監査結果により、暗号化されていない複数のS3バケットと、インターネットからのSSHを許可するセキュリティグループが明らかになった。
アプローチ:
- GitHub Actionsワークフローに最初のセキュリティゲートとしてCheckovを追加する
checkov -d ./terraform/を実行して、現在の所見のベースラインを確立する- 既存の所見をトリアージする:CRITICAL問題を修正し、HIGHのチケットを作成し、受け入れられたリスクを抑制する
- Terraform固有のチェックのためにセカンダリスキャナーとしてtfsecを追加する
- 組織標準(必須タグ、命名規則)のカスタムOPAポリシーを作成する
- CRITICALまたはHIGHの所見があるPRをブロックするようにパイプラインを設定する
- GitHub Securityタブ統合用にSARIFレポートを生成する
落とし穴:既存のプロジェクトにセキュリティスキャンを追加すると、最初は数百の所見が発生する。CRITICALのみでブロックすることから始め、徐々にHIGHに拡大する。意図的な例外には、正当な理由を文書化したインライン抑制コメント(#checkov:skip=CKV_AWS_18:静的ウェブサイト用のパブリックバケット)を使用する。
出力形式
Terraform Security Audit Report
==================================
リポジトリ:acme-corp/infrastructure
ブランチ:main
スキャン日:2026-02-23
ツール:Checkov 3.x, tfsec 1.x, OPA カスタムポリシー
スキャン結果:
Checkov チェック合格: 187
Checkov チェック不合格: 34
tfsec チェック合格: 156
tfsec チェック不合格: 28
OPA カスタムポリシー: 12 合格、3 不合格
CRITICAL 発見事項:
[TF-001] S3バケットに暗号化がない
ファイル:modules/storage/main.tf:24
リソース:aws_s3_bucket.data_lake
チェック:CKV_AWS_19
修正:server_side_encryption_configuration ブロックを追加する
[TF-002] セキュリティグループが0.0.0.0/0からのSSHを許可
ファイル:modules/network/security.tf:45
リソース:aws_security_group_rule.ssh_access
チェック:CKV_AWS_24
修正:cidr_blocks を踏み台サブネットに制限する
[TF-003] IAMポリシーにワイルドカードアクションがある
ファイル:modules/iam/policies.tf:12
リソース:aws_iam_policy.developer_policy
チェック:CKV_AWS_1
修正:アクションを必要な特定のサービスに限定する
重大度別の要約:
Critical: 6 件
High: 14 件
Medium: 28 件
Low: 18 件
Info: 12 件