シナリオ
サードパーティ依存関係を含むコンテナ化された Node.js API を保守しています。この API は設定を読み込み、オブジェクトストレージにアクセスし、場合によっては画像処理の子プロセスを起動します。セキュリティチームから、必要なファイル、ネットワーク、子プロセスの許可のみを付与した --permission の適用が提案されました。脅威モデル、権限インベントリ、互換性テスト、モニタリング、ロールバックについて説明してください。
面接官が評価するポイント
- Permission Model が信頼できるコードに対するシートベルトであり、悪意のあるコードに対するサンドボックスではないことを理解しているか。
- ファイル、ネットワーク、子プロセス、ワーカースレッド、ネイティブアドオンの各機能を最小権限に分解できるか。
- シンボリックリンク、既存のファイル記述子(FD)、初期化順序、継承制限を認識しているか。
- カナリアリリース、有用な拒否(denial)テレメトリ、ビジネス影響を与えない安全なロールバックを設計できるか。
前提条件の確認事項
Node のバージョン、エントリポイント、ネイティブアドオン、Worker/FFI/WASI の要件、パスとドメイン、およびアプリケーションがプロセスを生成(spawn)する必要があるかを確認します。Node を唯一の防御策として扱わないよう、seccomp、ユーザーID、読み取り専用ファイルシステムなど、既存のコンテナおよび OS の制御を確認します。
30秒の回答
これを悪意のある依存関係に対する完全な防御策ではなく、信頼できるコードに対する最小権限の制御として扱います。fs.read、fs.write、ネットワーク、子プロセス、Worker の各スコープについて、本番の依存関係とランタイム監査から権限付与リストを構築します。シャドウモードおよびトラフィックの 1% で有効化し、ERR_ACCESS_DENIED とレイテンシを記録しながら、ネイティブアドオン、シンボリックリンク、既存の記述子をテストします。コンテナの分離は維持します。エラー率が悪化したりクリティカルな依存関係でリグレッションが発生した場合は、起動フラグを削除してロールバックし、インベントリを見直します。
段階的な思考プロセス
1. セキュリティ境界の定義
Node は Permission Model をプロセスリソースの制限として説明しており、悪意のあるコードからは保護しないことを明記しています(Node は実行を指示されたコードを信頼します)。信頼できるアプリケーションによる偶発的なアクセスを減らすことはできますが、コンテナ、OS ユーザー、seccomp、依存関係サプライチェーンの制御を代替することはできません。
2. 権限インベントリの構築
デフォルト拒否(default deny)から始めます。--allow-fs-read は設定と静的パスのみに許可し、--allow-fs-write は一時出力に限定し、--allow-net は必要なオブジェクトストレージのドメインに絞り込みます。--allow-child-process、--allow-worker、--allow-addons は、文書化された必要性がある場合にのみ追加します。付与内容をバージョン管理し、サービスオーナーのレビューを必須とします。
3. ランタイム動作の検証
起動、ヘルスチェック、アップロード、画像処理、スケジュールされたジョブ、エラーパスを網羅します。process.permission.has() を確認し、permission.drop() は不可逆であり、以降のチェックにのみ影響すること(既にオープンしている記述子、ソケット、Worker はクローズされないこと)を念頭に置きます。シンボリックリンク、ネイティブアドオン、npx、子プロセスの境界をテストします。
4. カナリアリリースとロールバック
まずステージング環境および 1 つのステートレスインスタンスで有効化します。機密の値を記録することなく、拒否されたリソースクラス、スタックトレース、バージョン、テナントを収集します。エラー率、P95、起動成功率、完了したビジネスジョブをロールアウト拡大の判定基準(ゲート)とします。ロールバックは --permission または該当する --allow-* フラグを削除することです。コンテナレイヤーでの読み取り専用、非ルート(non-root)、ネットワーク制御は維持します。
質の高い模範解答
権限マトリクスを作成します。読み取り専用の設定、書き込み可能な一時ディレクトリ、必要なオブジェクトストレージのドメイン、画像変換の子プロセスを含め、ビジネス上の理由がない限り Worker やネイティブアドオンは許可しません。Permission Model はデフォルトで fs を制限するため、起動パラメータで各機能を明示的に許可します。これらのパラメータをバージョン管理し、最小構成のイメージを用いて CI で統合シナリオを実行し、すべてのルートとバックグラウンドジョブを検証します。カナリアは 1 つのステートレスクラスを対象とし、ERR_ACCESS_DENIED を集約し、リソースパスをハッシュ化します。特にシンボリックリンク、既存の記述子、子プロセスや Worker が同じようにモデルを継承しない点を入念にテストします。悪意のあるコードのリスクに対しては、コンテナと OS の分離で対処し続けます。起動、P95、拒否イベント、ジョブ完了のゲートを通過した後にのみ展開を拡大します。クリティカルな依存関係が拒否されたりエラーが増加した場合は、フラグを削除して元の動作に戻し、インベントリを更新してから再試行します。
よくある間違い
- Permission Model によって悪意のあるサードパーティパッケージを安全に実行できると主張すること。
- 必要がないのに
--allow-fs-read=*や--allow-fs-write=*を許可すること。 - ネイティブアドオン、Worker、子プロセス、WASI、FFI、またはネットワークの制限を無視すること。
permission.drop()によってすでに開いている記述子、ソケット、Worker がクローズされると思い込むこと。- ローカルの起動のみをテストし、npx、シンボリックリンク、または実際のバックグラウンドジョブのテストを漏らすこと。
フォローアップ質問と回答
「コンテナサンドボックスの代わりになりますか?」
いいえ。Node は悪意のあるコードから保護しないと明記しています。非ルート実行、読み取り専用ファイルシステム、seccomp、ネットワークポリシー、依存関係サプライチェーンの制御と組み合わせて使用してください。
「サービスが依然としてファイルを読み込めない原因は何ですか?」
エントリポイントと設定されたパス、ワイルドカードの動作、およびモデル確立後に初期化読み取りが発生しているかを確認してください。permission.has() と拒否イベントを使用して、不足している許可を特定します。
「画像処理をどのように許可しますか?」
--allow-child-process を個別に許可し、実行可能ファイルと入力/出力ディレクトリを制限した上で、OS とコンテナの制限を維持します。ライブラリ呼び出しで子プロセスを代替できる場合は、その権限を付与する代わりにライブラリ化を検討します。