コード実行のセキュリティポリシー
機能制限、ネットワーク分離、ファイルシステムの制限、タイムアウトを設定します。
「コード実行のセキュリティポリシー」はCoddyKit上の無料AI Agentsレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはAI Agents学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 AI Agentsコースには全4レッスンが含まれています。
ポリシーだけでは不十分な理由
LLMに「ネットワークにアクセスしないでください」と指示しても、それはセキュリティ制御ではなく、単なるヒントです。LLMが指示を無視したり、脱獄されたりする可能性があり、生成されたコードが間接的にルールに違反することもあります。
実際のセキュリティポリシーは、プロンプトだけでなく実行レイヤーで強制する必要があります。
ケーパビリティ制限の概要
ケーパビリティ制限は、サンドボックス化されたプロセスがOSレベルで実行できる操作を制限します。Linux capabilitiesを使用すると、root権限を細かな権限に分割し、それぞれを個別に削除できます。
必要最小限のケーパビリティ以外をすべて削除することを、最小権限の原則と呼びます。
import docker
client = docker.from_env()
# Drop all Linux capabilities
output = client.containers.run(
'python:3.12-slim',
'python -c "print(\"safe run\")"',
cap_drop=['ALL'],
network_disabled=True,
mem_limit='256m',
auto_remove=True
)
print(output.decode())/tmp以外へのディスク書き込みのブロック
ルートファイルシステムを読み取り専用にし、書き込み可能な状態でマウントするのは/tmpだけにします。これにより、コードがシステムファイルを変更したり、指定された一時領域の外部にデータを永続化したりすることを防止できます。
import tempfile, docker
client = docker.from_env()
with tempfile.TemporaryDirectory() as tmpdir:
output = client.containers.run(
'python:3.12-slim',
'python -c "open(\"/tmp/ok.txt\",\"w\").write(\"ok\"); print(open(\"/tmp/ok.txt\").read())"',
read_only=True,
tmpfs={'/tmp': 'size=64m,mode=1777'},
network_disabled=True,
mem_limit='128m',
auto_remove=True
)
print(output.decode()) # 'ok' — /tmp write allowed
# Writing anywhere else raises ReadOnlyFileSystemseccompプロファイル:システムコールのフィルタリング
seccomp(secure computing mode)を使用すると、許可するシステムコールの許可リストを指定できます。リストにないシステムコールが呼び出されると、プロセスはSIGSYSによって強制終了されます。
Dockerにはデフォルトのseccompプロファイルが付属しています。より厳しく制限するには、カスタムJSONプロファイルを指定できます。
import json, docker
client = docker.from_env()
# Minimal seccomp profile: only allow read, write, open, close, exit
seccomp_profile = json.dumps({
'defaultAction': 'SCMP_ACT_ERRNO',
'architectures': ['SCMP_ARCH_X86_64'],
'syscalls': [
{'names': ['read', 'write', 'open', 'openat', 'close',
'fstat', 'mmap', 'mprotect', 'munmap', 'brk',
'exit', 'exit_group', 'rt_sigaction',
'rt_sigprocmask', 'futex'],
'action': 'SCMP_ACT_ALLOW'}
]
})
output = client.containers.run(
'python:3.12-slim',
'python -c "print(1+1)"',
security_opt=[f'seccomp={seccomp_profile}'],
auto_remove=True
)
print(output.decode())リソース制限:CPU、メモリ、時間
すべてのサンドボックスで適用すべき3つのリソース制限は次のとおりです。
- メモリ:
mem_limit— OOM攻撃を防止します - CPU:
nano_cpusまたはcpu_quota— CPUの枯渇を防止します - 時間:実行タイムアウト — 無限ループを防止します
output = client.containers.run(
'python:3.12-slim',
'python -c "import time; time.sleep(100)"',
mem_limit='128m',
nano_cpus=500_000_000, # 0.5 CPU
network_disabled=True,
auto_remove=True,
timeout=10 # kill after 10 seconds
)
# Raises ReadTimeout after 10 secondsPythonインポートの許可リスト
コードを実行する前に、ASTをスキャンしてimport文を検出します。許可リストにないimportは拒否します。これは多層防御の一環であり、OSレベルの制御に代わるものではありませんが、明らかなポリシー違反を早期に検出するのに役立ちます。
import ast
ALLOWED_IMPORTS = {'math', 'statistics', 'json', 'csv', 'datetime', 'collections', 're'}
def check_imports(code: str) -> list[str]:
tree = ast.parse(code)
blocked = []
for node in ast.walk(tree):
if isinstance(node, ast.Import):
for alias in node.names:
if alias.name.split('.')[0] not in ALLOWED_IMPORTS:
blocked.append(alias.name)
elif isinstance(node, ast.ImportFrom):
if node.module and node.module.split('.')[0] not in ALLOWED_IMPORTS:
blocked.append(node.module)
return blocked
print(check_imports('import socket; print(1)')) # ['socket']
print(check_imports('import math; print(math.pi)')) # []危険なコードパターンの検出
importだけでなく、importの制限を回避するパターンも確認します。__import__、exec()、eval()、compile()、/tmpの外部のパスを指定するopen()などが該当します。
import ast
DANGEROUS_CALLS = {'exec', 'eval', 'compile', '__import__', 'breakpoint'}
def check_dangerous_calls(code: str) -> list[str]:
tree = ast.parse(code)
found = []
for node in ast.walk(tree):
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
if node.func.id in DANGEROUS_CALLS:
found.append(node.func.id)
elif isinstance(node.func, ast.Attribute):
if node.func.attr in DANGEROUS_CALLS:
found.append(node.func.attr)
return found
print(check_dangerous_calls('exec("import os")')) # ['exec']出力サイズの制限
暴走したprintループによって、ギガバイト単位の出力が生成される可能性があります。stdout/stderrを適切なサイズ(例:1MB)に制限し、超過した場合は切り詰めるかコンテナを停止してください。
MAX_OUTPUT_BYTES = 1 * 1024 * 1024 # 1 MB
def run_with_output_limit(client, code: str) -> dict:
container = client.containers.run(
'python:3.12-slim',
f'python -c "{code}"',
mem_limit='256m',
network_disabled=True,
detach=True
)
try:
container.wait(timeout=30)
logs = container.logs(stdout=True, stderr=True)
if len(logs) > MAX_OUTPUT_BYTES:
return {'success': False, 'error': 'Output too large'}
return {'success': True, 'output': logs.decode(errors='replace')}
finally:
container.remove(force=True)
if __name__ == '__main__':
class FakeContainer:
def wait(self, timeout=30): pass
def logs(self, stdout=True, stderr=True): return b'Analysis complete: 42 rows processed.'
def remove(self, force=True): pass
class FakeContainers:
def run(self, *args, **kwargs): return FakeContainer()
class FakeClient:
containers = FakeContainers()
result = run_with_output_limit(FakeClient(), 'print(42)')
print('Success:', result['success'])
print('Output :', result['output'])
No-New-Privilegesフラグ
no-new-privilegesセキュリティオプションは、setuidバイナリやsudoを介してプロセスが追加の権限を取得することを防ぎます。コードがシェルに移行しても、権限を昇格できません。
output = client.containers.run(
'python:3.12-slim',
'python -c "import os; print(os.getuid())"',
user='nobody', # run as non-root
security_opt=['no-new-privileges:true'], # no privilege escalation
cap_drop=['ALL'], # no capabilities
network_disabled=True,
mem_limit='128m',
auto_remove=True
)
print(output.decode()) # numeric UID of 'nobody'すべてのポリシーの組み合わせ
本番運用に耐えるサンドボックスでは、すべての層を組み合わせます。OSのcapabilityの削除、seccompプロファイル、読み取り専用ファイルシステム、no-new-privileges、ネットワークの無効化、リソース制限、タイムアウトを適用します。多層防御により、ある層が回避されても別の層で阻止できます。
import tempfile, json, docker
client = docker.from_env()
def maximum_security_run(code: str) -> dict:
with tempfile.TemporaryDirectory() as tmpdir:
try:
out = client.containers.run(
'python:3.12-slim',
f'python -c "{code}"',
user='nobody',
security_opt=['no-new-privileges:true'],
cap_drop=['ALL'],
network_disabled=True,
read_only=True,
tmpfs={'/tmp': 'size=32m,mode=1777'},
mem_limit='128m',
nano_cpus=500_000_000,
auto_remove=True,
timeout=15
)
return {'success': True, 'output': out.decode()}
except Exception as e:
return {'success': False, 'error': str(e)}ポリシー違反のログ記録
ポリシー違反(ブロックされたimport、危険な呼び出し、タイムアウト)を検出したら、エージェントセッションID、コードスニペットのハッシュ、違反の種類とともにイベントを記録します。これによりセキュリティダッシュボードに情報が送られ、時間の経過に合わせたポリシーの調整に役立ちます。
import hashlib, logging, time
logging.basicConfig(level=logging.INFO)
security_logger = logging.getLogger('sandbox.security')
def policy_check_and_run(code: str, session_id: str) -> dict:
violations = check_imports(code) + check_dangerous_calls(code)
code_hash = hashlib.sha256(code.encode()).hexdigest()[:16]
if violations:
security_logger.warning(
'POLICY_VIOLATION session=%s hash=%s violations=%s',
session_id, code_hash, violations
)
return {'success': False, 'error': f'Blocked: {violations}'}
result = maximum_security_run(code)
security_logger.info(
'EXEC session=%s hash=%s success=%s',
session_id, code_hash, result['success']
)
return resultseccompプロファイルの「defaultAction: SCMP_ACT_ERRNO」設定は何をしますか
seccompプロファイルは、プロセスが実行できるシステムコールを制御します。defaultActionフィールドは、プロファイルに明示的に記載されていないシステムコールに対して何が起きるかを決定します。
セキュリティポリシーのまとめ
効果的なコード実行のセキュリティには、複数の層が必要です。Linux capabilitiesの削除、seccompによるシステムコールのフィルタリング、tmpfsの作業領域を備えた読み取り専用ファイルシステム、no-new-privileges、ネットワークの無効化、メモリ・CPU・時間の制限、ASTレベルのimportチェックを組み合わせます。
単独で十分な層はありません。多層防御では、各層が他の層の回避を補います。
よくある質問
「コード実行のセキュリティポリシー」レッスンは無料ですか?
はい。「コード実行のセキュリティポリシー」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、AI Agentsコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 AI Agentsコースには全4レッスンが含まれています。
「コード実行のセキュリティポリシー」で何を学びますか?
機能制限、ネットワーク分離、ファイルシステムの制限、タイムアウトを設定します。 ブラウザで直接実行するハンズオンコードでAI Agentsを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
AI Agentsを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのAI Agentsは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。
「コード実行のセキュリティポリシー」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このAI Agentsレッスンでコードを書いて実行できますか?
はい。すべてのAI Agentsレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。