📌 はじめに
みなさん、自社の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を指定し、モデルサービングエンドポイントに対してテストを実行します。

🔗 データソース: 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 ATLAS と DASF(Databricks AI Security Framework) にマッピングされています。
✅ 前提条件チェックリスト
始める前に、以下を確認してください 👇
| # | 項目 | 要件 | 確認 |
|---|---|---|---|
| 1️⃣ | Azure Databricksプラン | Premium または Enterprise | ☑️ |
| 2️⃣ | ワークスペース管理者権限 | DCS有効化に必要 | ☑️ |
| 3️⃣ | モデルサービングエンドポイント | テスト対象のLLMがデプロイ済み | ☑️ |
| 4️⃣ | Personal Access Token (PAT) | LLM認証用(無くても可能?) | ☑️ |
🚀 セットアップ手順(全体フロー)
今回のセットアップは 4つのSTEP で構成されています。
⚠️ 重要: 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)
💡 ポイント:
WorkspaceClientを使うことで、トークンをheaders辞書に平文で露出させずに済みます。BlackIceカスタムDockerイメージでは自動認証検出が効かないため、hostとtokenを明示的に渡す必要があります。
⚙️ テスト対象エンドポイントの設定
# ⚠️ 以下の値を自分の環境に合わせて変更すること!
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()
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は既に有効化されているので、スキップする")
🚨 ハマりポイント: DCSが無効のままクラスタを作ると、
CREATING状態のまま永遠に起動しません!必ず先にDCSを有効化してください。
1️⃣ STEP 1: シークレットスコープを作成する 🔑
APIキーとエンドポイントURLを安全に保存するためのシークレットスコープを作成します。環境変数に直接トークンを書くのは 🙅♂️ NG です!
🔍 既存のシークレットスコープを確認
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()
🔑 スコープを新規作成
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)
| レスポンス | 意味 | 処理 |
|---|---|---|
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)
| キー名 | 値 | 用途 |
|---|---|---|
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)
💡 ポイント: Secrets APIではシークレットの 値は返却されません(キー名と更新日時のみ)。セキュリティ上の仕様です。
2️⃣ STEP 2: BlackIceクラスタを作成する 🐳
いよいよBlackIceのDockerイメージを指定してクラスタを作成します!
⚙️ クラスタ設定パラメータ
🐳 クラスタ設定コード
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}}"
}
}
🚨 ハマりポイント3連発:
data_security_modeをSINGLE_USERにしないと カスタムDockerイメージは起動しません 🙅num_workersは 最低1台 必要です(0台にするとエラー)- 環境変数には
{{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()
| 状況 | 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 では 大半のツールを検出できません 😱
| 段階 | 検出方法 | 対象ツール | 検出可能数 |
|---|---|---|---|
| 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))
📊 結果表示(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ツールの検出に成功!")
💡 ポイント:
検出失敗 ≠ 未インストールです!venv_keys(仮想環境のキー名)が実際のディレクトリ名と異なるだけの可能性があります。/venvs/配下の実際のディレクトリ一覧と照合してvenv_keysを修正してください。
⚠️ ハマりポイントまとめ
📝 まとめ
🎯 今回やったこと
├── 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 |
📢 この記事が参考になったら「いいね」をお願いします! 👍
質問・フィードバックはコメント欄へ 💬
















