DevContainer でエコシステムのサプライチェーン攻撃からマシンを守る

昨今 Node.js を始めとしたエコシステムのパッケージ依存関係を狙ったサプライチェーン攻撃が多発しています.

なんとかならないのか

Node.js は長い年月により枯れたエコシステムです.それに伴い規模は非常に大きいもので,全世界に数百万のパッケージが存在している上に,それらのパッケージは全世界のプロダクトに利用されています.

私個人としては Node.js のエコシステムに関しては 呆れ と 諦念 の感情が強く,この脆弱なシステムはもはやどうしようもないと考えています.

どうにかなってたら恐らく Deno は産まれていませんし,こんなサプライチェーン攻撃が頻繁には行われないでしょう.

(Deno も Node.js / npm を強烈に皮肉っています)

DevContainer とは

エコシステムが脆弱なら,ローカルを最後の砦として守っていかなければなりません.そこで DevContainer を使うことにしました.

https://containers.dev/

何が嬉しいのか

  • 環境をコードとしてリポジトリにコミットできるため,README に手順書を書かなくても,同じ環境を誰でも再現することができます.
  • ローカルにある Docker はもちろん, GitHub Codespaces のようなクラウド環境でも同じ定義が使えます.
    • Codespace 上で作業しているときも,実態としては DevContainer が使用されている.
  • CI 上でも同じ定義を使って,ビルド・テストを回せるため,「ローカルでは動くのに CI では動かない」という問題を減らせるます.

イメージの定義

  • プロジェクトルートに .devcontainer/devcontainer.json を置き,ここに開発環境の定義を書きます.
  • VSCode などの対応ツールがこの JSON を読み,コンテナをビルド・起動し,エディタや拡張機能などを動かしてくれます..
{
  "name": "lightweight-alpine-devcontainer",
  "image": "mcr.microsoft.com/devcontainers/base:alpine",
  "features": {
    "ghcr.io/devcontainers/features/common-utils:2": {
      "installZsh": false,
      "configureZshAsDefaultShell": false
    }
  },
  "postCreateCommand": "echo '=== Dev Container Ready ===' && cat /etc/os-release && du -sh /",
  "customizations": {
    "vscode": {
      "extensions": [
        "streetsidesoftware.code-spell-checker"
      ]
    }
  },
  "forwardPorts": []
}

実際に動かしてみる

実際にこの DevContainer を Zed で開いてみたいと思います.

プロジェクトルートに以下の内容の .devcontainer/devcontainer.json を設置します.

{
  "name": "lt-demo-node20-alpine",
  "image": "node:20-alpine",
  "features": {
    "ghcr.io/devcontainers/features/common-utils:2": {
      "installZsh": false,
      "configureZshAsDefaultShell": false,
      "username": "node"
    }
  },
  "remoteUser": "node",
  "postCreateCommand": "echo '=== Dev Container Ready ===' && cat /etc/os-release && node -v && { du -shx / 2>/dev/null || true; }",
  "customizations": {
    "zed": {
      "extensions": [
        "cspell"
      ]
    },
    "vscode": {
      "extensions": [
        "streetsidesoftware.code-spell-checker"
      ]
    }
  }
}

実際に DevContainer の定義を開いた Zed のエディタ画面

コマンドパレットを開き Projects: open remote を実行すると Connect DevContainer が表示されるので,そのまま Enter.

DevContainer への接続モーダルが表示されている Zed のエディタ画面

そうするとコンテナがビルド・起動され,Zed がそのコンテナに対して接続を行います.

DevContainer に接続された状態の Zed のディレクトリ表示

先ほどの devcontainer.json では Node.js v20 をイメージにコンテナを作成しました.そのため,ローカルとコンテナ間の Node.js が完全に分離された状態で稼働しています.

  "image": "node:20-alpine",

DevContainer とローカルの Node.js の分離を示した写真

万が一サプライチェーン攻撃の疑いがあるパッケージが混入してもパッケージが攻撃できるのは DevContainer で稼働しているコンテナのみのため,ローカルは無傷で済むわけです.

おわりに

DevContainer におけるローカル防御を紹介しました.AI によるハードル低下によって Node.js を狙ったサプライチェーン攻撃は今後増えると考えています.

エコシステムの防御を鵜呑みにせず,自分のマシンは自分で守ることが大切だと思います.

この記事をシェア

2020-2026
弊社では、一緒に会社を面白くしてくれる仲間を募集しています。
お気軽にお問い合わせください!
P.S. よろしければこちらもどうぞ
新明工業クラシックカーレストア blog — クラシックカーのレストアのお仕事の一部を公開しています。
新明工業コンベア blog — コンベアに関する技術情報を発信しています。