皆さん、こんにちは!セキュリティの世界へようこそ。
今回は、私たちが日々構築しているITインフラの「設計図」とも言えるIaC(Infrastructure as Code)に焦点を当てて、デプロイ前に潜むセキュリティの落とし穴をどうやって見つけ、どうやって塞ぐか、その具体的な方法を一緒に学んでいきましょう。
「IaCって何だか難しそう…」「セキュリティって専門用語が多くて苦手…」そう思われるかもしれませんが、大丈夫です!まるで家の鍵をかけるように、泥棒から身を守るように、身近な例えを交えながら、一歩ずつ対策を学んでいきましょうね。
—
デプロイ前のTerraformを徹底チェック!IaC静的解析でセキュリティの落とし穴を未然に防ぐ方法
IaCって、そもそも何?セキュリティとの関係は?
まず、IaC(Infrastructure as Code)とは、その名の通り「インフラをコードで管理する」という考え方です。これまでの手作業でのサーバー構築やネットワーク設定とは違い、プログラムコードを書くようにインフラを定義し、自動的にデプロイできるようになります。TerraformやCloudFormationがその代表例ですね。
まるで、「家を建てる設計図」をコードで書くようなものです。この設計図があれば、何度でも同じ家(インフラ)を、ボタン一つで建てられるようになります。すごく便利ですよね!
でも、ちょっと考えてみてください。もしその「家の設計図」に、うっかり「窓の鍵がない」とか「裏口のドアが開けっぱなし」という記述があったらどうなるでしょう?その設計図を使って建てられた家は、すべて鍵なしの窓や開けっぱなしのドアを持ってしまうことになります。泥棒にとっては、まさにパラダイス、ですよね?
ITインフラも同じです。IaCのコードにセキュリティ上の設定ミスが含まれていると、そのコードから作られるすべてのインフラに、同じセキュリティホールができてしまいます。しかも、IaCは大規模なインフラを扱うことが多いので、その影響は甚大になりがちなんです。
設定ミスはなぜ起きるのか?攻撃者はどこを狙う?
「そんなうっかりミス、するわけないよ!」と思うかもしれません。でも、これが意外と起こりやすいんです。なぜなら、IaCのコードは非常に複雑になりやすく、多くの設定項目があるからです。
泥棒の視点に立ってみましょう。彼らは、最も簡単な方法で家に侵入しようとします。頑丈な壁を壊すより、開けっぱなしの窓を探す方がずっと楽ですよね。サイバー攻撃者も同じで、システムの巧妙な脆弱性を突くよりも、「設定ミス」という、作り手側のうっかりミスや思い込みを狙うことが多いんです。
例えば、こんなケースはよくあります。
- S3バケットの公開設定ミス: AWS S3バケットは、ファイルを保存する場所ですが、設定によってはインターネット上に公開されてしまいます。開発者がテストのために一時的に公開したまま、本番環境でもその設定が残ってしまい、機密情報が全世界に漏洩…なんて事件も実際に起こっています。
- 攻撃者の視点: 「とりあえずS3バケットを検索ツールで探してみて、公開設定になってるやつがないかチェックしよう。見つかったら、中身を漁るだけ!」
- セキュリティグループの全開放: サーバーへのアクセス制御を行うセキュリティグループで、本来は特定のIPアドレスからしかアクセスできないようにするべきところを、誤って「
0.0.0.0/0(全インターネットからのアクセスを許可)」としてしまうケース。 - 攻撃者の視点: 「このIPアドレスのサーバー、ポート22(SSH)が全世界に開いてるぞ!あとはブルートフォース(総当たり攻撃)を仕掛けるだけだ!」
- 不要な権限の付与: データベースへのアクセス権限など、特定のサービスやユーザーに必要以上の広すぎる権限を与えてしまう。
- 攻撃者の視点: 「このLambda関数、S3バケットの全削除権限持ってるのか。じゃあ、この関数に脆弱性を見つけて、踏み台にしてS3の中身を全部消しちゃおう!」
これらはすべて、コードで定義される「設定」が原因で発生するセキュリティホールです。一度コードに書き込まれた設定ミスは、修正しない限り、ずっとそこに残り続けてしまいます。
IaC静的解析ツールとは?「デプロイ前の警備員」
そこで登場するのが、「IaC静的解析ツール」です。これは例えるなら、「家の設計図をデプロイする前に、セキュリティの抜け穴がないか自動でチェックしてくれる警備員」のようなものです。
私たちが手作業で何百行、何千行ものIaCコードを一つ一つ目視で確認するのは、現実的ではありません。見落としも必ず発生します。静的解析ツールは、決められたルールに基づいてコードを自動でスキャンし、「ここ、セキュリティ設定が甘いですよ!」「この設定は危険ですよ!」と教えてくれるんです。
手動チェックの限界を補い、デプロイ前に問題を発見・修正することで、安全なインフラを構築できるようになります。今回は、特にTerraformコードの解析に強いtfsecとCheckovという2つのツールをご紹介します。
tfsecとCheckovを使ってみよう!
tfsecとCheckovは、どちらもTerraformコードの静的解析に特化したツールですが、それぞれ特徴があります。
- tfsec: Terraformに特化しており、高速なスキャンと分かりやすい出力が特徴です。AWS、Azure、GCPなどのクラウドプロバイダー固有のセキュリティ設定ミスを検出してくれます。
- Checkov: Terraformだけでなく、CloudFormation、Kubernetes、Helmなど、より多様なIaCフレームワークに対応しています。ポリシー(ルール)のカスタマイズが容易な点も魅力です。
どちらも非常に強力なので、両方を試してみて、ご自身のプロジェクトに合うものを選ぶのが良いでしょう。今回は両方の基本的な使い方をご紹介します。
1. ツールのインストール
まずは、ご自身の環境にツールをインストールしましょう。
tfsecのインストール(macOS/Linuxの場合)
macOSやLinuxでは、Homebrewを使えば簡単にインストールできます。
# Homebrewでtfsecをインストール
brew install tfsec
Windowsの場合は、GitHubリリースページから実行ファイルをダウンロードしてパスを通すか、WSL(Windows Subsystem for Linux)を使うのが便利です。
Checkovのインストール(Pythonのpipを使用)
CheckovはPythonで書かれているため、pipコマンドでインストールするのが一般的です。
# Pythonのpipを使ってCheckovをインストール
pip install checkov
2. 基本的な使い方とコード例
適当なTerraformプロジェクトのディレクトリに移動して、main.tfなどの設定ファイルを作成してみましょう。ここでは、セキュリティ的に問題のあるS3バケットを定義するコードと、それを修正するコードを例に見ていきます。
まずは、セキュリティ的に問題のあるTerraformコードから。
このコードは、S3バケットをインターネットに公開してしまいます。
# main.tf (悪い例:S3バケットがインターネットに公開される可能性のある設定)
resource "aws_s3_bucket" "bad_example_bucket" {
bucket = "my-insecure-public-bucket-12345" # バケット名はユニークなものにしてください
# ACL (Access Control List) を 'public-read' に設定すると、
# バケットの中身がインターネットから読み取り可能になります。
acl = "public-read"
tags = {
Name = "BadExampleBucket"
Environment = "Dev"
}
}
このmain.tfファイルを作成したディレクトリで、それぞれのツールを実行してみましょう。
tfsecの実行
# tfsecを実行
tfsec .
実行すると、以下のような出力が表示されるはずです(バージョンや環境によって多少異なります)。
# tfsecの出力例 (一部抜粋)
Result #1
───────────────────────────────────────────
my-insecure-public-bucket-12345 (aws_s3_bucket.bad_example_bucket)
[AVD-AWS-0096] S3 bucket has an ACL configured which allows public access.
The S3 bucket should not allow public access.
Impact: Public access to S3 buckets can lead to data leakage.
Resolution: Don't set the ACL to public-read or public-read-write.
More information:
- https://aquasecurity.github.io/tfsec/v1.28.1/checks/aws/s3/no-public-access-with-acl/
───────────────────────────────────────────
tfsecは、「S3 bucket has an ACL configured which allows public access. (S3バケットに、パブリックアクセスを許可するACLが設定されています)」と明確に指摘してくれましたね!さらに、「Impact: Public access to S3 buckets can lead to data leakage. (S3バケットへのパブリックアクセスは、データ漏洩につながる可能性があります)」と、その影響まで教えてくれます。
Checkovの実行
次にCheckovを実行してみましょう。
# Checkovを実行
checkov -d .
Checkovも同様に、問題点を指摘してくれます。
# Checkovの出力例 (一部抜粋)
...
Check: CKV_AWS_18: "S3 bucket should not have public ACL"
FAILED for resource: aws_s3_bucket.bad_example_bucket
File: /main.tf:2-12
Guide: https://docs.bridgecrew.io/docs/s3_18
...
Checkovも「S3 bucket should not have public ACL (S3バケットはパブリックACLを持つべきではありません)」と、問題点を指摘してくれました。どちらのツールも、どのファイル(main.tf)の何行目(2-12行目)に問題があるかまで教えてくれるので、修正箇所がすぐに分かります。これは本当に助かりますよね!
3. セキュリティを考慮したコードへの修正例
指摘された問題を修正してみましょう。S3バケットをパブリックアクセス不可にするには、aclをprivateにするか、そもそもaclを設定しない(デフォルトでprivateになる)のが一般的です。
# main.tf (良い例:S3バケットが公開されない設定)
resource "aws_s3_bucket" "good_example_bucket" {
bucket = "my-secure-private-bucket-67890" # ユニークなバケット名にしてください
# aclを'private'に設定するか、
# またはこの行自体を削除してデフォルトの非公開設定にするのが安全です。
acl = "private"
# AWS S3のブロックパブリックアクセス設定を有効にするのは非常に重要です。
# これにより、バケットレベルで公開設定をブロックできます。
# 組織全体でこの設定を強制することも可能です。
# この設定がtrueの場合、acl = "public-read" のような設定をしても、
# S3はそれを拒否して公開されません。
# 今回の例では、tfsec/checkovの指摘を明確にするために
# あえてacl="private"と記述していますが、通常は以下のブロックも強く推奨されます。
# bucket_ownership_controls ブロックはACLを無効化する推奨設定です。
# ACLに依存せず、IAMポリシーでアクセス制御を行う現代的なベストプラクティス。
# rule に 'BucketOwnerPreferred' を設定することで、
# オブジェクトのACL設定に関わらず、バケットオーナーが常にオブジェクトを所有し、
# アクセス制御はバケットポリシーで行うようになります。
# resource "aws_s3_bucket_ownership_controls" "example" {
# bucket = aws_s3_bucket.good_example_bucket.id
# rule {
# object_ownership = "BucketOwnerPreferred"
# }
# }
# S3バケットのパブリックアクセス設定をブロックするリソース
# これを有効にすることで、万が一ACLやバケットポリシーで
# パブリックアクセスを許可しようとしても、S3側でブロックされます。
resource "aws_s3_bucket_public_access_block" "example" {
bucket = aws_s3_bucket.good_example_bucket.id
# 新しいACLやポリシーでパブリックアクセスを許可するのをブロック
block_public_acls = true
ignore_public_acls = true
block_public_policy = true
restrict_public_buckets = true
}
tags = {
Name = "GoodExampleBucket"
Environment = "Prod"
}
}
この修正済みコードで再度tfsecやCheckovを実行すると、今度は「問題なし」と表示されるはずです。これで、この設計図から建てられる家は、しっかりと鍵がかかった安全な家になりますね!
CI/CDパイプラインへの組み込み方
セキュリティチェックは、一度やったら終わりではありません。新しいコードが追加されたり、既存のコードが変更されたりするたびに、常にチェックし続けることが重要です。まるで、家をリフォームするたびに、鍵がしっかりかかっているか確認するようなものですね。
そこで、IaC静的解析ツールをCI/CD(継続的インテグレーション/継続的デリバリー)パイプラインに組み込むことを強くお勧めします。これにより、コードがデプロイされる前に、自動的にセキュリティチェックが実行されるようになります。
例えば、GitHub Actionsを使って、プルリクエスト(PR)が作成されたり、メインブランチにマージされる前にIaCコードをスキャンするワークフローを設定できます。
以下に、GitHub ActionsでtfsecとCheckovを組み込むためのyamlファイルの例を示します。
# .github/workflows/iac-security-scan.yml
name: IaC Security Scan
on:
pull_request: # プルリクエストが作成・更新されたときに実行
branches:
- main # mainブランチへのプルリクエストを対象
push: # mainブランチへのプッシュ時にも実行
branches:
- main
jobs:
iac_scan:
runs-on: ubuntu-latest # Ubuntu環境で実行
steps:
- name: Checkout code # リポジトリのコードをチェックアウト
uses: actions/checkout@v3
- name: Setup Terraform # Terraformをセットアップ (tfsecがTerraformのバージョンを認識するために必要)
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0 # 使用しているTerraformのバージョンを指定
- name: Install tfsec # tfsecをインストール
run: |
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_tfsec.sh | bash
sudo mv ./tfsec /usr/local/bin/
- name: Run tfsec scan # tfsecを実行し、Terraformコードをスキャン
run: |
# tfsecはデフォルトでカレントディレクトリ内のすべてのtfファイルをスキャンします
# --soft-fail をつけると、エラーがあってもCIを失敗させず、警告として扱います
# 初めて導入する際は --soft-fail から始めて、徐々に厳しくしていくのがおすすめです
tfsec . --soft-fail
- name: Install Python and pip # CheckovのためにPythonとpipをインストール
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install Checkov # Checkovをインストール
run: pip install checkov
- name: Run Checkov scan # Checkovを実行し、Terraformコードをスキャン
run: |
# Checkovもカレントディレクトリ内のすべてのIaCファイルをスキャンします
# --soft-fail をつけると、エラーがあってもCIを失敗させず、警告として扱います
# 初めて導入する際は --soft-fail から始めて、徐々に厳しくしていくのがおすすめです
checkov -d . --soft-fail
この設定により、開発者がGitHubにコードをプッシュしたり、プルリクエストを作成したりすると、自動的にIaC静的解析が実行されます。もしセキュリティ上の問題が見つかれば、CI/CDパイプラインが警告を出したり、ビルドを失敗させたりすることで、問題のあるコードが本番環境にデプロイされるのを未然に防ぐことができます。
攻撃者の視点から見たIaC静的解析の意義
さて、ここで少しだけ、レッドチーム(攻撃側)エンジニアとしての私の視点からお話しさせてください。
IaCの静的解析ツールは、非常に強力な「最初の防衛線」です。これを導入しているチームのIaCコードは、明らかにセキュリティのレベルが上がります。なぜなら、攻撃者が狙うような「典型的な設定ミス」の多くを、デプロイ前に潰してしまうからです。
しかし、残念ながら、静的解析ツールは「万能ではない」という現実も知っておくべきです。泥棒も進化しますからね。
静的解析ツールは、あくまで「事前に定義されたルール」に基づいてコードをチェックします。そのため、以下のような種類の脆弱性は見つけられないことがあります。
1. 論理的な脆弱性: たとえば、2つのIaCリソースがそれぞれは適切に設定されていても、それらが連携することで意図しない権限昇格や情報漏洩が発生するようなケース。これはツールのルールでは判断が難しい場合があります。
- 例:「このS3バケットは非公開。このLambda関数も最小権限。でも、Lambda関数が使うIAMロールに、別のバケットへの過剰なアクセス権限が付与されていて、そこを経由して情報が抜き取られる可能性がある」
2. ビジネスロジックに起因する脆弱性: インフラ設定そのものではなく、その上で動くアプリケーションのビジネスロジックに起因する脆弱性は、IaCツールでは検知できません。
- 例:「S3の設定は完璧だが、Webアプリケーションの認証処理に脆弱性があり、S3にアップロードされたファイルを不正にダウンロードできてしまう」
3. 多層的な設定ミス: 複数の設定ファイルやモジュールにまたがる、複雑な設定の組み合わせによって初めてセキュリティホールが生まれるケース。
- 例:「TerraformモジュールAでセキュリティグループを適切に設定しているが、モジュールBでそのセキュリティグループを上書きしてしまっている。静的解析はそれぞれのモジュール単体でしか見ていないため、全体の矛盾に気づけない可能性がある。」
だからこそ、静的解析はあくまで「セキュリティ対策の第一歩」であり、これだけで安心しきってはいけません。
重要なのは、「多層防御」の考え方です。
- 静的解析: デプロイ前のコードチェック(今回紹介した方法)
- 動的解析: デプロイ後の稼働中のシステムに対して脆弱性診断を行う
- ランタイムセキュリティ: 実際に稼働しているインフラの異常を監視する
- 人間の目によるレビュー: 熟練のエンジニアによるコードレビュー(特に複雑な論理や意図しない組み合わせがないか)
- 脅威モデリング: システム設計段階で、攻撃者の視点から潜在的な脅威を洗い出す
IaC静的解析は、泥棒が侵入する「開けっぱなしの窓」や「施錠されていないドア」を見つけるのに非常に効果的です。しかし、泥棒は常に新しい手口を考えます。だからこそ、私たちも常に学び、対策を重ねていく必要があるんですね。
まとめ:一歩ずつ、安全なインフラを構築していきましょう!
今回は、IaCのセキュリティ対策として、デプロイ前にTerraformコードをスキャンし、設定ミスを自動的に検出するtfsecとCheckovの導入方法、そしてCI/CDパイプラインへの組み込み方をご紹介しました。
IaCは非常に便利で強力なツールですが、その強力さゆえに、セキュリティ上の設定ミスが大きなリスクにつながる可能性があります。まるで、高性能な家を建てる設計図に、ちょっとしたミスで大きな落とし穴を作ってしまうようなものです。
今回ご紹介した静的解析ツールは、そんな落とし穴をデプロイ前に見つけ出し、塞ぐための強力な味方になります。まずは、ご自身のプロジェクトに導入してみて、どんな問題が見つかるか試してみてください。最初はたくさんの指摘が出てくるかもしれませんが、一つずつ修正していくことで、着実に安全なインフラへと近づいていきます。
セキュリティは終わりなき旅ですが、「一歩ずつ対策を学んでいきましょう!」。今日の学びが、皆さんのプロジェクトのセキュリティレベルを大きく向上させる一助となれば幸いです。
これからも、一緒にサイバーセキュリティの知識を深めていきましょうね!
コメント