「デプロイしてからの修正」はもう古い。IaC静的解析で防ぐインフラの「公開事故」
現場で長年インシデントハンドリングをしていると、溜息が出るほど繰り返される光景がある。それは「S3バケットの公開設定ミス」や「セキュリティグループの全開放(0.0.0.0/0)」による情報漏洩だ。
開発者は「テストだから」「急いでいたから」と言う。しかし、攻撃者はそんな事情を一切考慮してくれない。最新のボットは、CloudFrontやS3のバケット名を総当たりでスキャンし、パブリックアクセスが許可された瞬間にデータを吸い出す。
インフラをコード(IaC)で管理しているなら、「デプロイ後の検知」ではなく「コミット前の弾圧」をルールにしなければならない。今日は、TerraformコードをCIパイプラインで自動スキャンし、脆弱な構成を「死んでもデプロイさせない」ための実践的アプローチを教える。
—
1. なぜ「設定ミス」は起きるのか?(攻撃者の視点)
攻撃者は、わざわざ高度なゼロデイ脆弱性を突く必要はない。なぜなら、Terraformの記述ミスによる「設定の甘さ」というローハング・フルーツ(簡単に収穫できる果実)が世界中に転がっているからだ。
例えば、以下のようなTerraformコードがコミットされたとする。
# 【危険な例】パブリックアクセスを許可してしまったS3バケット
resource "aws_s3_bucket" "webapp_assets" {
bucket = "my-company-app-assets"
acl = "public-read" # これが地獄の入り口
}
このコードをGitHubにプッシュした瞬間、CIツールが自動でデプロイを実行すれば、世界中に社内の機密画像やログが公開される。これを防ぐには、パイプラインに「静的解析」という門番を置くしかない。
—
2. 現場で選ぶべきツール:TFLintとCheckov
Terraformの静的解析にはいくつか選択肢があるが、実務で信頼しているのは以下の2つだ。
- TFLint: AWS固有のルールの検証や、インスタンスタイプの妥当性チェックなど、インフラの「構成ミス」を検知するのに長けている。
- Checkov: CISベンチマークに基づいたセキュリティスキャンに強く、S3の暗号化やIAMポリシーの過剰権限をシビアに弾いてくれる。
今回は、最も導入が簡単で即効性のある Checkov を使った防御の実装を紹介する。
—
3. 実践:GitHub Actionsでの「ガードレール」実装
CIパイプライン(GitHub Actions)で、脆弱なコードが含まれていたら強制的にエラーを出してデプロイを止める設定だ。
.github/workflows/security-scan.yml を作成し、以下の設定を配置する。
name: IaC Security Scan
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
checkov-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: terraform/ # Terraformコードがあるディレクトリ
framework: terraform
# 失敗時は終了コード1を返し、ジョブを失敗させる
soft_fail: false
# 警告レベル以上の脆弱性を検知すると停止
check: CKV_AWS_20,CKV_AWS_52
この設定により、開発者がうっかり public-read を設定したコードをPRに含めると、GitHub Actionsのチェックが真っ赤になり、マージボタンが押せなくなる。これで「手動レビュー漏れ」というヒューマンエラーは構造的に排除される。
—
4. プロの備忘録:IAMポリシーの「最小権限」を強制する
IaCの静的解析で最も重要なのがIAMポリシーだ。多くの現場で Resource: "*" という記述が見受けられるが、これは「宝箱の鍵を誰でも複製できる状態」に等しい。
Checkovでは、以下のような過剰権限を弾くポリシーを個別に定義できる。以下はS3への過剰なアクセスを許容しないためのポリシー設定例だ。
# 【セキュアな実装例】
resource "aws_iam_policy" "limited_access" {
name = "limited-s3-access"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = ["s3:GetObject"]
Effect = "Allow"
# 全バケット(*)ではなく、特定のバケットに限定する
Resource = ["arn:aws:s3:::my-specific-bucket/*"]
}
]
})
}
—
最後に:セキュリティは「性悪説」で設計せよ
セキュリティチーフとして最後に伝えておきたい。「開発者は悪意がないが、ミスはする」。これがインフラ構築の基本原則だ。
「レビューで指摘すればいい」という属人的な運用は、忙しい時期には必ず崩壊する。だからこそ、仕組み(IaCの静的解析)で物理的にデプロイを止めるという「ガードレール」が必要なのだ。
今日のコードをパイプラインに組み込むだけで、あなたのチームは「明日、S3を公開してニュースになる」という悪夢から解放される。まずは明日、最小限のルールから導入してみてほしい。それこそが、エンジニアとしての信頼を勝ち取る第一歩だ。
コメント