SOP-007: Tool Permissions Setup
Document Control
| Field | Value |
|---|---|
| Document ID | SOP-007 |
| Version | 1.0 |
| Status | Active |
| Owner | Claude AI Operations |
| Last Updated | 2024-12-01 |
| Review Date | 2025-03-01 |
Overview
This SOP defines procedures for configuring tool permissions and access controls for Claude AI. It covers file system access, code execution permissions, network access controls, and security boundaries to ensure safe and controlled operation.
Permission Architecture
┌─────────────────────────────────────────────────────────────┐
│ Permission Layers │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ File System │ │ Code │ │ Network │ │
│ │ Permissions │ │ Execution │ │ Access │ │
│ │ │ │ │ │ │ │
│ │ • Read │ │ • Sandbox │ │ • Whitelist │ │
│ │ • Write │ │ • Languages │ │ • Protocols │ │
│ │ • Execute │ │ • Timeouts │ │ • Rate Limits│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
├─────────────────────────────────────────────────────────────┤
│ Security Controls │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Access │ │ Audit │ │ Resource │ │
│ │ Controls │ │ Logging │ │ Limits │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘Prerequisites
- Administrative privileges on target systems
- Understanding of security requirements
- Access to privilege management tools
- Knowledge of project requirements
Procedure
Step 1: Permission Framework Setup
1.1 Create Permission Configuration Structure
bash
# Create permission configuration directory
sudo mkdir -p /etc/claude/permissions/{templates,policies,profiles}
sudo mkdir -p /var/log/claude/permissions
sudo chmod 755 /etc/claude/permissions
sudo chmod 750 /var/log/claude/permissions1.2 Base Permission Template
bash
# Base permission configuration
sudo tee /etc/claude/permissions/templates/base.yaml << 'EOF'
# Base Claude Tool Permissions Template
version: "1.0"
metadata:
name: "base-permissions"
description: "Base permission template for Claude AI"
created: "2024-12-01"
# Default deny - explicit allow required
default_policy: "deny"
# File system permissions
filesystem:
read:
enabled: true
allowed_paths:
- "/tmp/claude-*"
- "/var/tmp/claude-*"
- "${HOME}/.config/claude"
- "${PROJECT_ROOT}"
denied_paths:
- "/etc/passwd"
- "/etc/shadow"
- "/root"
- "/var/log/system"
max_file_size: "10MB"
allowed_extensions:
- ".txt"
- ".md"
- ".json"
- ".yaml"
- ".yml"
- ".py"
- ".js"
- ".sh"
write:
enabled: true
allowed_paths:
- "/tmp/claude-*"
- "/var/tmp/claude-*"
- "${HOME}/.config/claude"
- "${PROJECT_ROOT}/src"
- "${PROJECT_ROOT}/docs"
denied_paths:
- "/etc"
- "/usr"
- "/var/log/system"
max_file_size: "5MB"
backup_enabled: true
execute:
enabled: false
allowed_paths: []
denied_paths: ["*"]
# Code execution permissions
code_execution:
enabled: true
sandbox: true
timeout: 30
memory_limit: "512MB"
cpu_limit: "50%"
allowed_languages:
- python
- javascript
- bash
denied_languages:
- binary
- assembly
allowed_modules:
python:
- os
- sys
- json
- requests
- numpy
- pandas
javascript:
- fs
- path
- util
- crypto
bash:
- basic_commands
denied_modules:
python:
- subprocess
- eval
- exec
bash:
- sudo
- su
- chmod
- chown
# Network access permissions
network:
enabled: true
outbound:
allowed_hosts:
- "api.anthropic.com"
- "*.github.com"
- "pypi.org"
- "npmjs.com"
allowed_ports:
- 80
- 443
- 22
protocols:
- "https"
- "ssh"
rate_limit: "100/minute"
inbound:
enabled: false
allowed_ports: []
# Resource limits
resources:
max_concurrent_operations: 5
max_memory_usage: "1GB"
max_disk_usage: "100MB"
max_execution_time: "300s"
# Audit and logging
audit:
enabled: true
log_level: "INFO"
log_file: "/var/log/claude/permissions/audit.log"
log_rotation: "daily"
retention: "30d"
events:
- file_access
- code_execution
- network_request
- permission_denied
- policy_violation
EOFStep 2: Environment-Specific Profiles
2.1 Development Profile
bash
sudo tee /etc/claude/permissions/profiles/development.yaml << 'EOF'
# Development Environment Permissions
extends: "base"
metadata:
name: "development-permissions"
environment: "development"
# More permissive for development
filesystem:
read:
allowed_paths:
- "${PROJECT_ROOT}"
- "${HOME}/projects"
- "/usr/local/src"
- "/opt/projects"
max_file_size: "50MB"
write:
allowed_paths:
- "${PROJECT_ROOT}"
- "${HOME}/projects"
- "/tmp"
- "/var/tmp"
max_file_size: "25MB"
execute:
enabled: true
allowed_paths:
- "${PROJECT_ROOT}/scripts"
- "/usr/local/bin"
- "/usr/bin"
allowed_commands:
- "npm"
- "pip"
- "git"
- "docker"
- "kubectl"
code_execution:
timeout: 120
memory_limit: "1GB"
cpu_limit: "75%"
allowed_languages:
- python
- javascript
- typescript
- bash
- sql
additional_modules:
python:
- subprocess
- multiprocessing
- threading
bash:
- git
- npm
- pip
- docker
network:
outbound:
allowed_hosts:
- "*" # Allow all for development
rate_limit: "500/minute"
resources:
max_concurrent_operations: 10
max_memory_usage: "2GB"
max_disk_usage: "1GB"
max_execution_time: "600s"
# Development-specific tools
tools:
debugging:
enabled: true
breakpoints: true
variable_inspection: true
testing:
enabled: true
test_frameworks: ["pytest", "jest", "mocha"]
coverage_tools: true
version_control:
enabled: true
commands: ["git", "svn", "hg"]
package_managers:
enabled: true
managers: ["npm", "pip", "cargo", "go mod"]
EOF2.2 Production Profile
bash
sudo tee /etc/claude/permissions/profiles/production.yaml << 'EOF'
# Production Environment Permissions
extends: "base"
metadata:
name: "production-permissions"
environment: "production"
# Restrictive permissions for production
filesystem:
read:
allowed_paths:
- "${PROJECT_ROOT}/src"
- "${PROJECT_ROOT}/config"
- "/var/log/claude"
denied_paths:
- "/etc"
- "/root"
- "/home"
max_file_size: "1MB"
write:
allowed_paths:
- "/tmp/claude-prod-*"
- "/var/log/claude"
max_file_size: "1MB"
execute:
enabled: false
code_execution:
enabled: false # No code execution in production
network:
outbound:
allowed_hosts:
- "api.anthropic.com"
- "monitoring.company.com"
allowed_ports:
- 443
protocols:
- "https"
rate_limit: "50/minute"
inbound:
enabled: false
resources:
max_concurrent_operations: 2
max_memory_usage: "256MB"
max_disk_usage: "10MB"
max_execution_time: "30s"
# Enhanced security for production
security:
encryption_required: true
tls_version: "1.3"
certificate_validation: "strict"
session_timeout: "15m"
audit:
log_level: "DEBUG"
events:
- all_operations
- failed_attempts
- security_violations
compliance:
data_classification: "confidential"
retention_policy: "7y"
geographic_restrictions: ["US", "EU"]
EOFStep 3: Permission Management Tools
3.1 Permission Manager Script
bash
sudo tee /usr/local/bin/claude-permissions << 'EOF'
#!/bin/bash
# Claude Permission Management Tool
set -euo pipefail
PERMISSIONS_DIR="/etc/claude/permissions"
LOG_FILE="/var/log/claude/permissions/manager.log"
CURRENT_PROFILE_FILE="/etc/claude/permissions/current-profile"
log_event() {
local level="$1"
local message="$2"
local timestamp=$(date --iso-8601=seconds)
echo "[$timestamp] [$level] $message" | sudo tee -a "$LOG_FILE" >/dev/null
}
show_help() {
cat << 'EOF'
Claude Permission Management Tool
Usage: claude-permissions [COMMAND] [OPTIONS]
Commands:
list-profiles List available permission profiles
show-profile <name> Show profile configuration
set-profile <name> Set active permission profile
current-profile Show current active profile
validate-profile <name> Validate profile configuration
create-profile <name> Create new profile interactively
test-permissions Test current permissions
audit-permissions Show permission audit log
Options:
--environment <env> Target environment (dev/staging/prod)
--user <user> Target user
--dry-run Show what would be done without making changes
--verbose Enable verbose output
Examples:
claude-permissions list-profiles
claude-permissions set-profile development
claude-permissions test-permissions --verbose
claude-permissions create-profile custom-web-dev
EOF
}
list_profiles() {
echo "📋 Available Permission Profiles:"
echo "================================="
if [ -d "$PERMISSIONS_DIR/profiles" ]; then
for profile in "$PERMISSIONS_DIR/profiles"/*.yaml; do
if [ -f "$profile" ]; then
local name=$(basename "$profile" .yaml)
local description=$(yq '.metadata.description // "No description"' "$profile" 2>/dev/null || echo "No description")
local environment=$(yq '.metadata.environment // "unknown"' "$profile" 2>/dev/null || echo "unknown")
echo " 📄 $name"
echo " Environment: $environment"
echo " Description: $description"
echo
fi
done
else
echo "❌ No profiles directory found at $PERMISSIONS_DIR/profiles"
fi
}
show_profile() {
local profile_name="$1"
local profile_file="$PERMISSIONS_DIR/profiles/${profile_name}.yaml"
if [ ! -f "$profile_file" ]; then
echo "❌ Profile not found: $profile_name"
return 1
fi
echo "📄 Profile: $profile_name"
echo "=========================="
# Show metadata
echo "Metadata:"
yq '.metadata' "$profile_file" 2>/dev/null || echo " No metadata found"
echo
echo "File System Permissions:"
yq '.filesystem' "$profile_file" 2>/dev/null || echo " Using defaults"
echo
echo "Code Execution Permissions:"
yq '.code_execution' "$profile_file" 2>/dev/null || echo " Using defaults"
echo
echo "Network Permissions:"
yq '.network' "$profile_file" 2>/dev/null || echo " Using defaults"
}
set_profile() {
local profile_name="$1"
local profile_file="$PERMISSIONS_DIR/profiles/${profile_name}.yaml"
local dry_run="${dry_run:-false}"
if [ ! -f "$profile_file" ]; then
echo "❌ Profile not found: $profile_name"
return 1
fi
# Validate profile before applying
if ! validate_profile "$profile_name" --quiet; then
echo "❌ Profile validation failed"
return 1
fi
if [ "$dry_run" = "true" ]; then
echo "🔍 DRY RUN: Would set profile to $profile_name"
return 0
fi
# Set the current profile
echo "$profile_name" | sudo tee "$CURRENT_PROFILE_FILE" >/dev/null
# Apply profile-specific configurations
apply_profile_config "$profile_name"
log_event "INFO" "Permission profile set to: $profile_name"
echo "✅ Permission profile set to: $profile_name"
}
validate_profile() {
local profile_name="$1"
local quiet="${2:-false}"
local profile_file="$PERMISSIONS_DIR/profiles/${profile_name}.yaml"
[ "$quiet" != "--quiet" ] && echo "🔍 Validating profile: $profile_name"
if [ ! -f "$profile_file" ]; then
[ "$quiet" != "--quiet" ] && echo "❌ Profile file not found"
return 1
fi
# Validate YAML syntax
if ! yq . "$profile_file" >/dev/null 2>&1; then
[ "$quiet" != "--quiet" ] && echo "❌ Invalid YAML syntax"
return 1
fi
# Check required fields
local required_fields=("metadata.name" "filesystem" "code_execution" "network")
for field in "${required_fields[@]}"; do
if ! yq "has(\"$field\")" "$profile_file" | grep -q true; then
[ "$quiet" != "--quiet" ] && echo "❌ Missing required field: $field"
return 1
fi
done
[ "$quiet" != "--quiet" ] && echo "✅ Profile validation passed"
return 0
}
apply_profile_config() {
local profile_name="$1"
local profile_file="$PERMISSIONS_DIR/profiles/${profile_name}.yaml"
echo "🔧 Applying profile configuration..."
# Create profile-specific directories
local temp_dir="/tmp/claude-${profile_name}-$$"
sudo mkdir -p "$temp_dir"
# Set file permissions based on profile
if yq -e '.filesystem.read.allowed_paths[]' "$profile_file" >/dev/null 2>&1; then
while IFS= read -r path; do
if [ -d "$path" ]; then
echo " Setting read permissions for: $path"
# Apply read permissions logic here
fi
done < <(yq -r '.filesystem.read.allowed_paths[]' "$profile_file" 2>/dev/null)
fi
# Configure code execution environment
local sandbox_enabled=$(yq '.code_execution.sandbox // true' "$profile_file" 2>/dev/null)
if [ "$sandbox_enabled" = "true" ]; then
echo " Enabling code execution sandbox"
# Configure sandbox environment
fi
echo "✅ Profile configuration applied"
}
test_permissions() {
local verbose="${verbose:-false}"
echo "🧪 Testing Current Permissions"
echo "=============================="
# Test file system access
echo "📁 Testing file system permissions..."
# Test read permissions
local test_file="/tmp/claude-permission-test-$$"
echo "test content" > "$test_file"
if [ -r "$test_file" ]; then
echo " ✅ File read: OK"
else
echo " ❌ File read: FAILED"
fi
# Test write permissions
if echo "test write" >> "$test_file" 2>/dev/null; then
echo " ✅ File write: OK"
else
echo " ❌ File write: FAILED"
fi
rm -f "$test_file"
# Test code execution
echo "💻 Testing code execution permissions..."
if command -v python3 >/dev/null 2>&1; then
if python3 -c "print('Hello, World!')" >/dev/null 2>&1; then
echo " ✅ Python execution: OK"
else
echo " ❌ Python execution: FAILED"
fi
fi
# Test network access
echo "🌐 Testing network permissions..."
if curl -s --max-time 5 https://api.anthropic.com >/dev/null 2>&1; then
echo " ✅ Network access: OK"
else
echo " ❌ Network access: FAILED"
fi
echo "✅ Permission test completed"
}
# Parse command line arguments
verbose=false
dry_run=false
environment=""
user=""
while [[ $# -gt 0 ]]; do
case $1 in
--verbose)
verbose=true
shift
;;
--dry-run)
dry_run=true
shift
;;
--environment)
environment="$2"
shift 2
;;
--user)
user="$2"
shift 2
;;
list-profiles)
list_profiles
exit 0
;;
show-profile)
if [ -z "${2:-}" ]; then
echo "❌ Profile name required"
exit 1
fi
show_profile "$2"
exit 0
;;
set-profile)
if [ -z "${2:-}" ]; then
echo "❌ Profile name required"
exit 1
fi
set_profile "$2"
exit 0
;;
current-profile)
if [ -f "$CURRENT_PROFILE_FILE" ]; then
echo "Current profile: $(cat "$CURRENT_PROFILE_FILE")"
else
echo "No profile set"
fi
exit 0
;;
validate-profile)
if [ -z "${2:-}" ]; then
echo "❌ Profile name required"
exit 1
fi
validate_profile "$2"
exit 0
;;
test-permissions)
test_permissions
exit 0
;;
help|--help|-h)
show_help
exit 0
;;
*)
echo "❌ Unknown command: $1"
show_help
exit 1
;;
esac
done
show_help
EOF
sudo chmod +x /usr/local/bin/claude-permissions3.2 Permission Enforcement Service
bash
# Create systemd service for permission enforcement
sudo tee /etc/systemd/system/claude-permissions.service << 'EOF'
[Unit]
Description=Claude Permissions Enforcement Service
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/bin/claude-permissions-daemon
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
User=claude
Group=claude
[Install]
WantedBy=multi-user.target
EOF
# Create permission enforcement daemon
sudo tee /usr/local/bin/claude-permissions-daemon << 'EOF'
#!/bin/bash
# Claude Permissions Enforcement Daemon
PIDFILE="/var/run/claude-permissions.pid"
LOGFILE="/var/log/claude/permissions/daemon.log"
start_daemon() {
echo "Starting Claude permissions daemon..."
# Fork to background
(
while true; do
# Monitor permission violations
check_permissions
# Check every 5 seconds
sleep 5
done
) &
# Save PID
echo $! > "$PIDFILE"
echo "Claude permissions daemon started (PID: $!)"
}
check_permissions() {
# Monitor file access
# Monitor network connections
# Monitor process execution
# Log violations
# Placeholder for permission monitoring logic
local timestamp=$(date --iso-8601=seconds)
echo "[$timestamp] Permission check completed" >> "$LOGFILE"
}
stop_daemon() {
if [ -f "$PIDFILE" ]; then
local pid=$(cat "$PIDFILE")
echo "Stopping Claude permissions daemon (PID: $pid)..."
kill "$pid"
rm -f "$PIDFILE"
echo "Claude permissions daemon stopped"
else
echo "Claude permissions daemon not running"
fi
}
case "${1:-start}" in
start)
start_daemon
;;
stop)
stop_daemon
;;
restart)
stop_daemon
sleep 2
start_daemon
;;
status)
if [ -f "$PIDFILE" ] && kill -0 "$(cat "$PIDFILE")" 2>/dev/null; then
echo "Claude permissions daemon is running"
else
echo "Claude permissions daemon is not running"
fi
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
EOF
sudo chmod +x /usr/local/bin/claude-permissions-daemonStep 4: Permission Testing Framework
4.1 Permission Test Suite
bash
cat > ~/.local/bin/claude-permission-tests << 'EOF'
#!/bin/bash
# Claude Permission Test Suite
set -euo pipefail
TEST_DIR="/tmp/claude-permission-tests-$$"
RESULTS_FILE="$TEST_DIR/results.log"
setup_tests() {
mkdir -p "$TEST_DIR"
echo "🧪 Setting up permission tests in: $TEST_DIR"
}
cleanup_tests() {
rm -rf "$TEST_DIR"
echo "🧹 Cleaned up test directory"
}
run_filesystem_tests() {
echo "📁 Running file system permission tests..."
local tests_passed=0
local tests_failed=0
# Test 1: Read allowed path
echo " Test 1: Read allowed path"
if echo "test" > "$TEST_DIR/test-read.txt" 2>/dev/null && cat "$TEST_DIR/test-read.txt" >/dev/null 2>&1; then
echo " ✅ PASS"
((tests_passed++))
else
echo " ❌ FAIL"
((tests_failed++))
fi
# Test 2: Write to allowed path
echo " Test 2: Write to allowed path"
if echo "test write" > "$TEST_DIR/test-write.txt" 2>/dev/null; then
echo " ✅ PASS"
((tests_passed++))
else
echo " ❌ FAIL"
((tests_failed++))
fi
# Test 3: Write to denied path (should fail)
echo " Test 3: Write to denied path (should fail)"
if ! echo "test" > "/etc/claude-test" 2>/dev/null; then
echo " ✅ PASS (correctly denied)"
((tests_passed++))
else
echo " ❌ FAIL (should have been denied)"
((tests_failed++))
rm -f "/etc/claude-test" 2>/dev/null
fi
echo " File system tests: $tests_passed passed, $tests_failed failed"
}
run_execution_tests() {
echo "💻 Running code execution permission tests..."
local tests_passed=0
local tests_failed=0
# Test 1: Python execution
echo " Test 1: Python code execution"
if python3 -c "print('Hello from Python')" >/dev/null 2>&1; then
echo " ✅ PASS"
((tests_passed++))
else
echo " ❌ FAIL"
((tests_failed++))
fi
# Test 2: JavaScript execution
echo " Test 2: JavaScript code execution"
if command -v node >/dev/null && echo "console.log('Hello from Node')" | node >/dev/null 2>&1; then
echo " ✅ PASS"
((tests_passed++))
else
echo " ⚠️ SKIP (Node.js not available)"
fi
# Test 3: Shell command execution
echo " Test 3: Shell command execution"
if echo "echo 'Hello from Shell'" | bash >/dev/null 2>&1; then
echo " ✅ PASS"
((tests_passed++))
else
echo " ❌ FAIL"
((tests_failed++))
fi
echo " Code execution tests: $tests_passed passed, $tests_failed failed"
}
run_network_tests() {
echo "🌐 Running network permission tests..."
local tests_passed=0
local tests_failed=0
# Test 1: API access
echo " Test 1: Anthropic API access"
if curl -s --max-time 5 https://api.anthropic.com >/dev/null 2>&1; then
echo " ✅ PASS"
((tests_passed++))
else
echo " ❌ FAIL"
((tests_failed++))
fi
# Test 2: HTTPS access
echo " Test 2: HTTPS access to allowed host"
if curl -s --max-time 5 https://github.com >/dev/null 2>&1; then
echo " ✅ PASS"
((tests_passed++))
else
echo " ❌ FAIL"
((tests_failed++))
fi
# Test 3: Denied host access (should fail)
echo " Test 3: Access to potentially blocked host"
if ! curl -s --max-time 3 http://example.com >/dev/null 2>&1; then
echo " ✅ PASS (correctly blocked or timed out)"
((tests_passed++))
else
echo " ⚠️ WARNING (access allowed - check if intended)"
fi
echo " Network tests: $tests_passed passed, $tests_failed failed"
}
generate_report() {
echo
echo "📊 Permission Test Report"
echo "========================"
echo "Test run: $(date)"
echo "Test directory: $TEST_DIR"
if [ -f "$RESULTS_FILE" ]; then
echo "Detailed results saved to: $RESULTS_FILE"
fi
echo
echo "Summary:"
echo " File system tests completed"
echo " Code execution tests completed"
echo " Network tests completed"
echo
echo "Review any failed tests and adjust permissions as needed."
}
# Main test execution
trap cleanup_tests EXIT
echo "🔐 Claude Permission Test Suite"
echo "==============================="
setup_tests
# Redirect output to results file as well as stdout
exec > >(tee "$RESULTS_FILE")
run_filesystem_tests
echo
run_execution_tests
echo
run_network_tests
generate_report
EOF
chmod +x ~/.local/bin/claude-permission-testsVerification
Permission Configuration Test
bash
# List available profiles
sudo claude-permissions list-profiles
# Validate a profile
sudo claude-permissions validate-profile development
# Test setting a profile
sudo claude-permissions set-profile development --dry-run
# Run permission tests
claude-permission-testsSecurity Audit
bash
# Check current permissions
sudo claude-permissions current-profile
sudo claude-permissions test-permissions --verbose
# Review audit logs
sudo tail -f /var/log/claude/permissions/audit.log
# Verify service status
sudo systemctl status claude-permissionsTroubleshooting
Common Issues
| Issue | Symptoms | Resolution |
|---|---|---|
| Permission denied errors | File/network access failures | Check profile configuration and paths |
| Profile validation failure | YAML syntax errors | Validate YAML syntax and required fields |
| Service won't start | Daemon startup failures | Check service configuration and permissions |
| Tests failing | Permission tests report failures | Review profile settings and system constraints |
Debug Commands
bash
# Debug permission profile
sudo claude-permissions show-profile development
# Check file permissions
sudo find /etc/claude -type f -exec ls -la {} \;
# Test YAML syntax
yq . /etc/claude/permissions/profiles/development.yaml
# Monitor permission violations
sudo tail -f /var/log/claude/permissions/daemon.logRecovery Procedures
bash
# Reset to base permissions
sudo claude-permissions set-profile base
# Recreate permission structure
sudo rm -rf /etc/claude/permissions
# Re-run Step 1-2 procedures
# Emergency permission reset
sudo systemctl stop claude-permissions
sudo systemctl disable claude-permissions