0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWS CodeBuildでTetragonを動かしてnpm postinstallの通信を止めてみた

0
Posted at

2026年7月にKubeCon + CloudNativeCon Japan 2026で、Liz Rice氏の「Detecting Compromised CI with eBPF and Cilium Tetragon」を聞きました。

TetragonでCI内の不審な動きを検知・防止する、というセッションで、自分でも試してみたくなったので、GitHub ActionsのジョブをAWS CodeBuild上で実行して、そこでTetragonを動かしてみました。依存パッケージのpostinstallが勝手に通信する状況を作って、それを止められるかどうか確認しました。

Tetragonとは

Tetragonは、Linux上で動くプロセスや、そのプロセスによる通信・ファイルアクセスなどを監視するツールです。eBPFを使ってカーネル側でイベントを捉え、ポリシーに合う操作を記録したり、プロセスを強制終了したりできます。

パッケージに既知の脆弱性があるかを調べるのではなく、実際に動いたときに何をするかを見ます。何を止めるかは、自分でポリシーに書きます。

postinstallからcurlを呼んでみる

検証用に、アプリ役のdemo/victimと、そのアプリにインストールする自作ライブラリdemo/compromised-dependencyを用意しました。自作ライブラリには、/usr/bin/curlを呼び出すpostinstallを仕込んでいます。

アプリ側のpackage.jsonのdependenciesに、この自作ライブラリを登録します。その状態でアプリ側のnpm ciを実行するとライブラリがインストールされ、そのpostinstallからcurlが動きます。「依存ライブラリを入れたら、インストール処理の中で通信された」という状況を再現するための構成です。どちらも同じリポジトリ内に置いてあり、npmには公開していません。

送信できたかを確認するため、CIジョブ内でNode.jsの簡単なHTTPサーバーを起動します。ポート18080で待ち受け、curlから固定のダミー値が届いたら、受信記録をファイルに残します。

送る側のcurlも、受ける側のNode.jsも、同じCodeBuild runner内で動きます。外部の送信先をこの受信プログラムで代用しているので、ダミー値をインターネットへ送る構成ではありません。本物のマルウェアや認証情報も使っていません。

TetragonはCodeBuildのPRE_BUILDで起動し、そのあとGitHub Actionsのjobを実行します。

CodeBuildの設定メモ

ビルドイメージはaws/codebuild/amazonlinux-x86_64-standard:5.0、Host kernelはLINUX_KERNEL_6、Privilegedは有効にしています。

Tetragonは、eBPFプログラムを実行環境のカーネルに合わせて読み込むために、BTFという型情報を使います。今回はBTFを利用できるLinux 6系の環境を選びました。

TetragonがeBPFプログラムをカーネルにロード・アタッチできるよう、この構成では特権モードを使っています。

image.png

ホストカーネルはイメージとは別の設定です。CDKでは次のように指定しました。

const cfnProject = this.runnerProject.node.defaultChild as codebuild.CfnProject;
cfnProject.addPropertyOverride('Environment.HostKernel', 'LINUX_KERNEL_6');

workflowにはbuildspec-override:trueを付けて、PRE_BUILDでTetragonを起動できるようにしています。AWSのrunner設定手順

runs-on:
  - codebuild-tetragon-codebuild-guard-${{ github.run_id }}-${{ github.run_attempt }}
  - buildspec-override:true
  - tetragon-${{ matrix.mode }}

image.png

ポリシーを入れる

条件はシンプルに、/usr/bin/curlが127.0.0.0/8以外へ接続しようとしたらSIGKILL、にしました。

apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: block-curl-egress
spec:
  kprobes:
    - call: tcp_connect
      syscall: false
      args:
        - index: 0
          type: sock
      selectors:
        - matchArgs:
            - index: 0
              operator: NotDAddr
              values:
                - 127.0.0.0/8
          matchBinaries:
            - operator: In
              values:
                - /usr/bin/curl
          matchActions:
            - action: Sigkill

これを、ポリシーなしのbaseline、記録だけ行うobserve、実際に止めるenforceの3パターンで実行します。Tetragon自体は3つとも動かしています。

observeとenforceは、同じYAMLを読み込むときのモードを変えるだけです。ファイルをコピーしたTetragonコンテナ内で、次のコマンドを使います。それぞれ別のrunnerで実行しています。

# observe
tetra tracingpolicy add --mode monitor /tmp/block-curl-egress.yaml

# enforce
tetra tracingpolicy add --mode enforce /tmp/block-curl-egress.yaml

実行結果

モード ポリシーの接続イベント curlの終了結果 ダミー値の受信
baseline 0件 exit 0 あり
observe 1件 exit 0 あり
enforce 1件 SIGKILL なし

enforceだけ、curlがSIGKILLで終了して受信記録が残りませんでした。baselineとobserveでは送信が完了し、npm ciも正常終了しています。

image.png

enforceのjobも緑ですが、これは「止められたら検証成功」にしているためです。模擬攻撃のstepはcontinue-on-errorで続行し、後続のstepで結果を判定しています。画面下にあるenforceのエラーは、その模擬攻撃が失敗した記録です。

postinstallのログにも、curlの終了理由が出ています。

The simulated request did not complete: SIGKILL

image.png

判定では、ポリシーの接続先がテスト用サーバーと一致すること、curlの終了signalがSIGKILLであること、受信記録がないことを確認しました。

おわりに

今回、Tetragonが「この依存パッケージは悪意がある」と判断したわけではなく、curlと接続先の条件で止めています。この設定のままだと、同じ条件に当てはまる普通のダウンロードも止めてしまいます。実際のCIで使うなら、まずobserveで普段どんな通信をしているかを見て、許可するものを整理してからenforceを試したいです。

今度は、CodeBuild上でプロセスの親子関係を追えるか確認して、npmから起動されたcurlに対象を絞れるかも試してみたいです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?