5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

🧊BlackIceを丸裸にせよ|Azure Databricks検証環境を爆速構築⚡

5
Last updated at Posted at 2026-02-07

📌 はじめに

みなさん、自社のLLM、ちゃんとセキュリティテストしてますか? 🤔

「プロンプトインジェクション?うちは大丈夫でしょ」── そう思っていた時期が、私にもありました 😇

💡 この記事でわかること

  • BlackIceの全体像と搭載ツール一覧 🗂️
  • Azure Databricksでの環境構築手順(スクショ級に丁寧)🏗️
  • 15ツールの自動検出ロジックの仕組み 🔍
  • ハマりポイントと注意事項 ⚠️

📢 次回予告: 本記事は環境構築編です!
主要ツール(Garak / PyRIT / Promptfoo)の実行方法は次の記事で解説します ⚡


🤖 BlackIceとは?

2026年1月、Databricksから 「BlackIce」 という超強力なAIセキュリティツールキットが発表されました 🎉

15種類ものセキュリティツールが 1つのDockerコンテナ にまとまっていて、プロンプトインジェクション・ジェイルブレイク・データ漏洩・ハルシネーション...あらゆるAI脅威をテストできます。

🔗 データソース: Databricks公式ブログ - Announcing BlackIce
🔗 データソース: arXiv論文
🔗 データソース: GitHub - databricks/containers/blackice

🎯 何が嬉しいの?

従来のAIセキュリティテストには、こんな 😫 つらみ がありました:

😵 従来のつらみ
├── 🔧 ツールごとにセットアップが必要(依存関係地獄)
├── 💥 Pythonパッケージの依存関係が競合しまくる
├── 📚 ツールが多すぎてどれを使えばいいか分からない
└── 🔄 環境の再現性がない(「俺の環境では動くんだけど...」)

BlackIceは、これを docker pull 一発 で解決します 🎊


🏗️ アーキテクチャ全体像

BlackIceをAzure Databricks上で動かす際の全体構成です。クラスタのカスタムDockerイメージとしてBlackIceを指定し、モデルサービングエンドポイントに対してテストを実行します。
image.png

🔗 データソース: arXiv論文 HTML版
🔗 データソース: GitHub - databricks/containers/blackice


🛠️ 搭載ツール一覧(15種類!)

BlackIceには、業界をリードする 15のAIセキュリティツール が統合されています。各ツールは隔離された環境で依存関係の競合なく動作します。

🟢 グローバルPython環境(SYSTEM_TOOLS)── 4ツール

# ツール名 開発元 用途
1️⃣ PyRIT Microsoft 🏢 AIレッドチーミング自動化フレームワーク
2️⃣ ART (Adversarial Robustness Toolbox) IBM 🔬 敵対的機械学習攻撃&防御
3️⃣ Rigging LLMワークフロー構築
4️⃣ Judges Quotient AI ⚖️ LLM-as-Judge 評価

🟡 隔離venv + グローバルCLI(PYTHON_TOOLS / NODEJS_TOOLS)── 5ツール

# ツール名 開発元 用途
5️⃣ Garak NVIDIA 💚 LLM脆弱性スキャナ
6️⃣ Promptfoo LLMテスト&評価フレームワーク
7️⃣ Fickling Trail of Bits 🔍 Pickleファイル静的解析(サプライチェーン攻撃検出)
8️⃣ Giskard MLモデル品質&バイアステスト
9️⃣ Biasforge Databricks 🧱 バイアス評価ツール(独自開発!)

🔵 隔離venvのみ(GIT_TOOLS)── 6ツール

# ツール名 開発元 用途
🔟 CleverHans 敵対的サンプル生成
1️⃣1️⃣ LM Eval Harness EleutherAI 🧪 LLMベンチマーク評価
1️⃣2️⃣ EasyEdit ZJUNLP 🎓 モデル知識編集
1️⃣3️⃣ CyberSecEval Meta 🌐 サイバーセキュリティ評価
1️⃣4️⃣ FuzzyAI CyberArk 🔐 ファジングテスト
1️⃣5️⃣ Promptmap プロンプトマッピング攻撃

🔗 データソース: arXiv論文 Table I


📂 BlackIceコンテナの内部構造

BlackIceは Kali Linux風の隔離アーキテクチャ を採用しています。各ツールが独立したvenvに隔離されているため、依存関係の衝突を防ぎつつ、統一的なCLIアクセスを提供します。

📁 ディレクトリ構造まとめ

パス 役割
/venvs/<tool>/ 隔離venv本体(bin/python, lib/, source/ /venvs/cyberseceval/
/cli_scripts/<tool>/ CLIラッパースクリプト(shebangでvenvのPythonを指定) /cli_scripts/garak/
/usr/local/bin/<tool> シンボリックリンク → /cli_scripts/ 内のラッパー /usr/local/bin/garak
/patches/<tool>/ カスタムパッチ用ディレクトリ /patches/garak/
/databricks/python3 グローバルPython環境(SYSTEM_TOOLS用) PyRIT, ART 等

🔗 データソース: arXiv論文 Section II, Figure 1
🔗 データソース: GitHub README


🗺️ セキュリティフレームワークとの対応

BlackIceのテスト機能は MITRE ATLASDASF(Databricks AI Security Framework) にマッピングされています。

image.png


✅ 前提条件チェックリスト

始める前に、以下を確認してください 👇

# 項目 要件 確認
1️⃣ Azure Databricksプラン Premium または Enterprise ☑️
2️⃣ ワークスペース管理者権限 DCS有効化に必要 ☑️
3️⃣ モデルサービングエンドポイント テスト対象のLLMがデプロイ済み ☑️
4️⃣ Personal Access Token (PAT) LLM認証用(無くても可能?) ☑️

🚀 セットアップ手順(全体フロー)

今回のセットアップは 4つのSTEP で構成されています。

image.png

⚠️ 重要: STEP 0〜2 は通常のクラスタで実行し、STEP 3 はBlackIceクラスタにアタッチしてから実行します!


📦 事前準備:ライブラリインポート & 認証

まずはノートブックの冒頭で、必要なライブラリをインポートし、Databricksの認証情報を取得します。

📚 インポートライブラリ一覧

ライブラリ 用途
json APIレスポンスのJSON解析
time クラスタ起動待機のスリープ処理
os 環境変数設定、ファイルパス操作
shutil which() によるCLIコマンド検索
subprocess シェルコマンド実行(ツール検出)
databricks.sdk Databricks REST APIへの安全なアクセス
pyspark.pandas Spark上でpandas APIを使用(結果の表示)

🔧 コード

import json, time, os, shutil, subprocess, tempfile, pickle

# 🔧 PyArrowタイムゾーン警告を抑制(pyspark.pandas インポート前に設定が必要)
os.environ["PYARROW_IGNORE_TIMEZONE"] = "1"

import pyspark.pandas as ps
from pyspark.sql import SparkSession
from pyspark.sql.types import StructType, StructField, StringType, IntegerType, TimestampType
from datetime import datetime
from databricks.sdk import WorkspaceClient

# 🔧 Databricksコンテキストから認証情報を取得
host = "https://" + dbutils.notebook.entry_point.getDbutils().notebook().getContext().browserHostName().get()
token = dbutils.notebook.entry_point.getDbutils().notebook().getContext().apiToken().get()
current_user = dbutils.notebook.entry_point.getDbutils().notebook().getContext().userName().get()

# 🔧 WorkspaceClient で安全にAPI呼び出し(トークンをheadersに露出させない)
w = WorkspaceClient(host=host, token=token)

image.png

💡 ポイント: WorkspaceClient を使うことで、トークンを headers 辞書に平文で露出させずに済みます。BlackIceカスタムDockerイメージでは自動認証検出が効かないため、hosttoken を明示的に渡す必要があります。

⚙️ テスト対象エンドポイントの設定

# ⚠️ 以下の値を自分の環境に合わせて変更すること!
API_TOKEN = "token"                              # 👈 自分のPATを設定
ENDPOINT_NAME = " テスト対象のエンドポイント名"    # 👈 テスト対象のエンドポイント名に変更!
ENDPOINT_URL = f"{host}/serving-endpoints/{ENDPOINT_NAME}/invocations"
変数名 説明
API_TOKEN 認証トークン(PATを設定)
ENDPOINT_NAME テスト対象のModel Servingエンドポイント名
ENDPOINT_URL 上記から自動構築されるAPI呼び出し先URL

0️⃣ STEP 0: DCS(Container Services)を有効化する 🔓

BlackIceはカスタムDockerイメージ databricksruntime/blackice:17.3-LTS で動作します。このイメージを使うには、ワークスペースで DCS(Databricks Container Services) を有効化する必要があります。

⚠️ 超重要: Azure DatabricksではDCSの有効化は UIにトグルがありません!REST API経由で設定する必要があります。

🔍 STEP 0-1: DCSの現在の状態を確認

def check_dcs_status():
    """🔍 DCS(Container Services)の有効化状態を確認する"""
    url = f"{host}/api/2.0/workspace-conf"
    params = {"keys": "enableDcs"}
    
    response = requests.get(url, headers=headers, params=params)
    
    if response.status_code == 200:
        result = response.json()
        dcs_enabled = result.get("enableDcs", "false")
        
        if dcs_enabled == "true":
            print("✅ DCS(Container Services)は既に有効化されている!")
            return True
        else:
            print("❌ DCS(Container Services)は無効化されている")
            return False
    else:
        print(f"❌ 状態確認失敗: {response.status_code}")
        return None

dcs_status = check_dcs_status()

image.png

enableDcs の値 状態 意味
"true" ✅ 有効 カスタムDockerクラスタを作成可能
"false" / 未設定 ❌ 無効 BlackIceクラスタは起動不可
HTTP エラー ⚠️ 確認失敗 権限不足 or API接続エラー

🔓 STEP 0-2: DCSを有効化

def enable_dcs():
    """🔓 DCS(Container Services)を有効化する ※ワークスペース管理者権限が必要"""
    url = f"{host}/api/2.0/workspace-conf"
    payload = {"enableDcs": "true"}
    
    print("🔄 DCS有効化を実行中...")
    response = requests.patch(url, headers=headers, data=json.dumps(payload))
    
    if response.status_code in [200, 204]:
        print("✅ DCS有効化に成功した!")
        return True
    else:
        print(f"❌ DCS有効化に失敗: {response.status_code}")
        return False

# 🔓 DCSが無効なら有効化する
if dcs_status == False:
    enable_dcs()
    time.sleep(2)        # 反映を待つ
    check_dcs_status()   # 再確認
elif dcs_status == True:
    print("👍 DCSは既に有効化されているので、スキップする")

image.png

🚨 ハマりポイント: DCSが無効のままクラスタを作ると、CREATING 状態のまま永遠に起動しません!必ず先にDCSを有効化してください。


1️⃣ STEP 1: シークレットスコープを作成する 🔑

APIキーとエンドポイントURLを安全に保存するためのシークレットスコープを作成します。環境変数に直接トークンを書くのは 🙅‍♂️ NG です!

image.png

🔍 既存のシークレットスコープを確認

def list_secret_scopes():
    response = requests.get(f"{host}/api/2.0/secrets/scopes/list", headers=headers)
    if response.status_code == 200:
        scopes = response.json().get("scopes", [])
        if scopes:
            print("📋 既存のシークレットスコープ:")
            for scope in scopes:
                print(f"  🔐 {scope['name']}")
        else:
            print("⚠️ シークレットスコープがまだない!")
        return scopes
    else:
        print(f"❌ 取得失敗: {response.text}")
        return []

scopes = list_secret_scopes()

image.png

🔑 スコープを新規作成

SCOPE_NAME = "blackice-scope"

def create_secret_scope(scope_name):
    url = f"{host}/api/2.0/secrets/scopes/create"
    payload = {"scope": scope_name, "initial_manage_principal": "users"}
    
    print(f"🔄 シークレットスコープ '{scope_name}' を作成中...")
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    
    if response.status_code == 200:
        print(f"✅ シークレットスコープ '{scope_name}' を作成した!")
        return True
    elif "RESOURCE_ALREADY_EXISTS" in response.text:
        print(f"👍 シークレットスコープ '{scope_name}' は既に存在する")
        return True
    else:
        print(f"❌ 作成失敗: {response.status_code}")
        return False

create_secret_scope(SCOPE_NAME)

image.png

レスポンス 意味 処理
200 作成成功 ✅ 正常終了
RESOURCE_ALREADY_EXISTS 既に同名スコープが存在 👍 スキップして続行
その他 作成失敗 ❌ エラー表示

🔐 シークレットを登録

def put_secret(scope_name, key, value):
    """🔐 シークレットを登録する"""
    url = f"{host}/api/2.0/secrets/put"
    payload = {"scope": scope_name, "key": key, "string_value": value}
    
    response = requests.post(url, headers=headers, data=json.dumps(payload))
    
    if response.status_code == 200:
        print(f"{key}: 登録成功")
        return True
    else:
        print(f"{key}: 登録失敗 - {response.text}")
        return False

print(f"🔐 シークレットを登録する(スコープ: {SCOPE_NAME}")
put_secret(SCOPE_NAME, "api-token", API_TOKEN)
put_secret(SCOPE_NAME, "endpoint-url", ENDPOINT_URL)

image.png

キー名 用途
api-token API_TOKEN Databricks REST API認証用PAT
endpoint-url ENDPOINT_URL モデルサービングエンドポイントのURL

🔍 登録確認(シークレット一覧表示)

from datetime import datetime, timezone, timedelta
JST = timezone(timedelta(hours=9))  # 日本標準時

def list_secrets(scope_name):
    """🔍 スコープ内のシークレット一覧を表示する(値は表示されない)"""
    url = f"{host}/api/2.0/secrets/list"
    params = {"scope": scope_name}
    
    response = requests.get(url, headers=headers, params=params)
    
    if response.status_code == 200:
        secrets = response.json().get("secrets", [])
        if secrets:
            print(f"📋 スコープ '{scope_name}' のシークレット:")
            print("-" * 60)
            for secret in secrets:
                key = secret['key']
                ts_ms = secret.get('last_updated_timestamp', 0)
                dt_jst = datetime.fromtimestamp(ts_ms / 1000, tz=JST)
                dt_str = dt_jst.strftime('%Y年%m月%d日 %H:%M:%S')
                print(f"  🔑 {key:<20} 更新日時: {dt_str} (JST)")
            print("-" * 60)

list_secrets(SCOPE_NAME)

image.png

💡 ポイント: Secrets APIではシークレットの 値は返却されません(キー名と更新日時のみ)。セキュリティ上の仕様です。


2️⃣ STEP 2: BlackIceクラスタを作成する 🐳

いよいよBlackIceのDockerイメージを指定してクラスタを作成します!

⚙️ クラスタ設定パラメータ

image.png

🐳 クラスタ設定コード

cluster_config = {
    "cluster_name": "blackice-security-test",
    "spark_version": "17.3.x-scala2.13",       # DBR 17.3 LTS
    "node_type_id": "Standard_D4s_v3",          # 4vCPU / 16GB
    "driver_node_type_id": "Standard_D4s_v3",
    "num_workers": 1,                            # ⚠️ 最低1台必要!
    "autotermination_minutes": 30,               # 30分アイドルで自動停止
    "docker_image": {
        "url": "databricksruntime/blackice:17.3-LTS"  # 🧊 BlackIceイメージ
    },
    "data_security_mode": "SINGLE_USER",         # ⚠️ カスタムDocker時は必須!
    "single_user_name": current_user,
    "spark_env_vars": {
        # 🔑 Secret参照でトークンを安全に注入
        "DATABRICKS_API_KEY": "{{secrets/blackice-scope/api-token}}",
        "MODEL_URL": "{{secrets/blackice-scope/endpoint-url}}"
    }
}

image.png

🚨 ハマりポイント3連発:

  1. data_security_modeSINGLE_USER にしないと カスタムDockerイメージは起動しません 🙅
  2. num_workers最低1台 必要です(0台にするとエラー)
  3. 環境変数には {{secrets/scope/key}} 形式を使うことで、トークンがログに露出しません 🔐

🚀 クラスタ作成関数

既存クラスタの存在チェック → なければ新規作成、という安全な実装になっています。

def create_blackice_cluster():
    # 🔍 既存クラスタをチェック
    print("🔍 既存クラスタをチェック中...")
    list_response = requests.get(f"{host}/api/2.0/clusters/list", headers=headers)
    
    if list_response.status_code == 200:
        clusters = list_response.json().get("clusters", [])
        for cluster in clusters:
            if cluster["cluster_name"] == "blackice-security-test":
                cluster_id = cluster["cluster_id"]
                state = cluster["state"]
                print(f"✅ 既存クラスタを発見! ID: {cluster_id}, 状態: {state}")
                return cluster_id, "existing"
    
    # 🆕 新規作成
    print("🆕 新規クラスタを作成中...")
    create_response = requests.post(
        f"{host}/api/2.0/clusters/create",
        headers=headers,
        data=json.dumps(cluster_config)
    )
    
    if create_response.status_code == 200:
        cluster_id = create_response.json()["cluster_id"]
        print(f"🎉 クラスタ作成成功! ID: {cluster_id}")
        return cluster_id, "created"
    else:
        print(f"❌ クラスタ作成失敗: {create_response.text}")
        return None, "failed"

cluster_id, status = create_blackice_cluster()

image.png

状況 cluster_id status
既存クラスタ発見 ✅ "1234-xxx-abc" "existing"
新規作成成功 🎉 "5678-xxx-def" "created"
作成失敗 ❌ None "failed"

3️⃣ STEP 3: BlackIce搭載ツール存在確認(15ツール)🔍

⚠️ 超重要: ここからは BlackIceクラスタにアタッチして 実行すること!
STEP 2 まではBlackIceクラスタを作成するためのクラスタで作業していましたが、STEP 3 以降はその作成したBlackIceクラスタ自体にアタッチして作業します。

⚠️ 超超超超重要: ライブラリインポートをBlackIceクラスタで再実行する事!

🏗️ なぜ特殊な検出が必要か?

BlackIceはKali Linux風の隔離アーキテクチャを採用しているため、グローバルの pip list / which / import では 大半のツールを検出できません 😱

image.png

段階 検出方法 対象ツール 検出可能数
1️⃣ shutil.which(command) Garak, Promptfoo, Fickling, Giskard, Biasforge 5
2️⃣ import module PyRIT, ART, Rigging, Judges 4
3️⃣ /venvs/ パス確認 CleverHans, LM Eval, EasyEdit, CyberSecEval, FuzzyAI, Promptmap 6

📂 コンテナ内ディレクトリの直接取得

まず、BlackIceコンテナ内の /venvs//cli_scripts/ の中身を確認します。

# 📁 /venvs/ 配下のツール一覧を取得
_venvs_dirs = []
if os.path.isdir("/venvs"):
    _venvs_dirs = os.listdir("/venvs")
    print(f"📁 /venvs/ 配下のツール: {_venvs_dirs}")
else:
    print("⚠️ /venvs/ ディレクトリが見つからない(BlackIceイメージか要確認)")
# 📁 /cli_scripts/ 配下のツール一覧を取得
_cli_scripts_dirs = []
if os.path.isdir("/cli_scripts"):
    _cli_scripts_dirs = os.listdir("/cli_scripts")
    print(f"📁 /cli_scripts/ 配下のツール: {_cli_scripts_dirs}")

🔧 ヘルパー関数:隔離venvの直接検出

find コマンドは使いません(タイムアウトリスクの回避のため)。代わりに既知のパスを直接参照する高速な検出方式を採用しています。

def find_in_isolated_venvs(venv_keys):
    """隔離venvを直接参照で検出するヘルパー関数"""
    for key in venv_keys:
        # 戦略1: /venvs//bin/python の存在確認(最も確実)
        venv_python = f"/venvs/{key}/bin/python"
        if os.path.exists(venv_python):
            return f"/venvs/{key}/ (venv検出)"
        
        # 戦略2: /venvs// ディレクトリ自体の存在確認
        venv_dir = f"/venvs/{key}"
        if os.path.isdir(venv_dir):
            return f"/venvs/{key}/ (ディレクトリ検出)"
        
        # 戦略3: /cli_scripts// の存在確認
        cli_dir = f"/cli_scripts/{key}"
        if os.path.isdir(cli_dir):
            return f"/cli_scripts/{key}/ (ラッパースクリプト検出)"
        
        # 戦略4: /usr/local/bin/ のシンボリックリンク確認
        symlink = f"/usr/local/bin/{key}"
        if os.path.exists(symlink):
            target = os.readlink(symlink) if os.path.islink(symlink) else symlink
            return f"{symlink}{target}"
    
    return None  # 全戦略で見つからず

検出の優先順位は以下のとおりです。最初にヒットした時点で即 return します(短絡評価)。

優先度 チェック対象 条件
🥇 1 /venvs/<key>/bin/python ファイルが存在
🥈 2 /venvs/<key>/ ディレクトリが存在
🥉 3 /cli_scripts/<key>/ ディレクトリが存在
4 /usr/local/bin/<key> ファイル/シンボリックリンクが存在

📋 ツールリスト定義(15ツール)

arXiv論文 Table I に準拠したツール定義です。各ツールの検出方式(type)とカテゴリ、検索キーを定義しています。

tools_to_check = [
    # === 🟢 SYSTEM_TOOLS: グローバルPython環境 ===
    {"name": "1️⃣ PyRIT",           "type": "python", "command": None,        "module": "pyrit",        "category": "SYSTEM_TOOLS"},
    {"name": "2️⃣ ART",             "type": "python", "command": None,        "module": "art",          "category": "SYSTEM_TOOLS"},
    {"name": "3️⃣ Rigging",         "type": "python", "command": None,        "module": "rigging",      "category": "SYSTEM_TOOLS"},
    {"name": "4️⃣ Judges",          "type": "python", "command": None,        "module": "judges",       "category": "SYSTEM_TOOLS"},
    # === 🟡 PYTHON_TOOLS / NODEJS_TOOLS ===
    {"name": "5️⃣ Garak",           "type": "cli",    "command": "garak",     "module": "garak",        "category": "PYTHON_TOOLS"},
    {"name": "6️⃣ Promptfoo",       "type": "cli",    "command": "promptfoo", "module": None,           "category": "NODEJS_TOOLS"},
    {"name": "7️⃣ Fickling",        "type": "cli",    "command": "fickling",  "module": "fickling",     "category": "PYTHON_TOOLS"},
    {"name": "8️⃣ Giskard",         "type": "venv",   "command": "giskard",   "module": "giskard",      "category": "PYTHON_TOOLS", "venv_keys": ["giskard"]},
    {"name": "9️⃣ Biasforge",       "type": "venv",   "command": "biasforge", "module": "biasforge",    "category": "CUSTOM",       "venv_keys": ["biasforge"]},
    # === 🔵 GIT_TOOLS: 隔離venvのみ ===
    {"name": "🔟 CleverHans",       "type": "venv",   "command": None,        "module": "cleverhans",   "category": "GIT_TOOLS",    "venv_keys": ["cleverhans"]},
    {"name": "1️⃣1️⃣ LM Eval Harness","type": "venv",  "command": "lm_eval",   "module": "lm_eval",      "category": "GIT_TOOLS",    "venv_keys": ["lm-eval-harness"]},
    {"name": "1️⃣2️⃣ EasyEdit",      "type": "venv",   "command": None,        "module": "easyeditor",   "category": "GIT_TOOLS",    "venv_keys": ["easyedit", "EasyEdit"]},
    {"name": "1️⃣3️⃣ CyberSecEval",  "type": "venv",   "command": None,        "module": "cyberseceval",  "category": "GIT_TOOLS",    "venv_keys": ["cyberseceval"]},
    {"name": "1️⃣4️⃣ FuzzyAI",       "type": "venv",   "command": None,        "module": "fuzzyai",      "category": "GIT_TOOLS",    "venv_keys": ["fuzzyai", "FuzzyAI"]},
    {"name": "1️⃣5️⃣ Promptmap",     "type": "venv",   "command": None,        "module": "promptmap",    "category": "GIT_TOOLS",    "venv_keys": ["promptmap"]},
]

🔍 3段階検出ロジック(本体)

ネットワーク通信なし、ファイル存在チェックとインポート試行のみなので タイムアウトは原理的に発生しません

print("\n🔍 各ツールの検出を実行中...(/venvs/ 直接参照、即時完了)\n")

results = []
for tool in tools_to_check:
    name = tool["name"]
    module = tool.get("module")
    command = tool.get("command")
    category = tool["category"]
    
    # --- 段階1️⃣: グローバルCLI検索(which) ---
    cli_found = shutil.which(command) if command else None
    
    # --- 段階2️⃣: グローバルPythonインポート ---
    import_ok = False
    if module:
        try:
            exec(f"import {module}")
            import_ok = True
        except ImportError:
            pass
    
    # --- 段階3️⃣: /venvs/ 直接参照(段階1・2で見つからない場合のみ) ---
    venv_location = None
    if not cli_found and not import_ok and tool["type"] == "venv":
        venv_keys = tool.get("venv_keys", [])
        venv_location = find_in_isolated_venvs(venv_keys)
    
    # --- 結果判定 ---
    if cli_found:
        status = "✅ グローバルCLI"
        location = cli_found
    elif import_ok:
        status = "✅ グローバルPython"
        location = f"import {module}"
    elif venv_location:
        status = "✅ 隔離venv検出"
        location = venv_location
    else:
        status = "⚠️ 自動検出失敗"
        location = f"[{category}] 手動確認推奨"
    
    results.append((name, category, status, location))

image.png

📊 結果表示(Spark DataFrame)

from pyspark.sql import Row

rows = [Row(
    No=name.split(" ")[0],           # 番号絵文字
    ツール名=name.split(" ", 1)[1],   # 名前本体
    カテゴリ=cat,
    検出状態=status,
    場所_備考=location
) for name, cat, status, location in results]

df_results = spark.createDataFrame(rows)
df_results.display()

# 📊 サマリー
detected  = sum(1 for r in results if "" in r[2])
uncertain = sum(1 for r in results if "⚠️" in r[2])
print(f"\n📊 サマリー:")
print(f"  ✅ 自動検出成功: {detected}/{len(results)} ツール")
if uncertain > 0:
    print(f"  ⚠️ 自動検出失敗: {uncertain}/{len(results)} ツール")
    print(f"  📝 注意: 検出失敗 ≠ 未インストール!")
    print(f"     venv_keys の推測が実際のディレクトリ名と異なる可能性がある。")
else:
    print(f"  🎉 全15ツールの検出に成功!")

image.png

💡 ポイント: 検出失敗 ≠ 未インストール です!venv_keys(仮想環境のキー名)が実際のディレクトリ名と異なるだけの可能性があります。/venvs/ 配下の実際のディレクトリ一覧と照合して venv_keys を修正してください。


⚠️ ハマりポイントまとめ

image.png


📝 まとめ

🎯 今回やったこと
├── 0️⃣ DCS(Container Services)を有効化 🔓
├── 1️⃣ シークレットスコープ作成 & トークン登録 🔑
├── 2️⃣ BlackIce 17.3-LTS クラスタを作成 🐳
└── 3️⃣ 15ツールの存在を3段階ロジックで自動検出 🔍

これで BlackIceの環境構築は完了 です!🎉

次回の記事では、いよいよ Garak / PyRIT / Promptfoo を使った実際のセキュリティテスト実行に入ります 💪

🔮 次回予告: 「BlackIce完全攻略ガイド【テスト実行編】── LLMの弱点を暴き出せ!」


📚 参考リンク

リソース URL
🏢 Databricks公式ブログ Announcing BlackIce
📄 arXiv論文 arxiv.org/abs/2510.11823
📄 arXiv論文(HTML版) arxiv.org/html/2510.11823v1
💻 GitHub databricks/containers/blackice
🛡️ MITRE ATLAS atlas.mitre.org
📘 DASF Databricks AI Security Framework

📢 この記事が参考になったら「いいね」をお願いします! 👍
質問・フィードバックはコメント欄へ 💬

5
1
1

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
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?