第 10 期 | Hermes Agent 的安全模型与权限控制
好的,这是为 Hermes Agent 教程撰写的第 10 期文章。
副标题:理解信任边界、执行前确认机制、沙箱隔离策略,在开放能力与安全防护之间取得平衡。
学习目标
在本期课程中,你将深入探索 Hermes Agent 的安全核心。完成本章学习后,你将能够:
- 理解 Agent 安全的必要性:认识到赋予 Agent 执行能力的双刃剑效应,并理解为何安全是首要议题。
- 掌握核心安全概念:清晰地定义并解释信任边界 (Trust Boundary)、执行前确认 (Pre-execution Confirmation) 和沙箱隔离 (Sandbox Isolation) 在 Agent 架构中的作用。
- 配置安全策略:学会通过修改 Hermes Agent 的配置文件,启用或禁用关键安全特性,并根据实际需求进行调整。
- 实践沙箱环境搭建:了解如何使用 Docker 为 Agent 的代码执行创建一个隔离、受控的沙箱环境,遵循权限最小化原则 (Principle of Least Privilege)。
- 做出明智的权衡:在 Agent 的自主性、能力开放性与系统安全性之间,做出合理的决策与平衡。
核心概念讲解
随着我们在前几期课程中不断解锁 Hermes Agent 的强大能力——从调用外部工具 (Skills) 到拥有长期记忆 (Memory),一个至关重要的问题浮出水面:我们如何确保这个日益强大的 AI 实体是安全、可控且值得信赖的?
当一个 Agent 能够生成代码、执行系统命令、访问文件系统、调用外部 API 时,它就不再仅仅是一个聊天机器人。它变成了一个具备潜在行动能力的执行者。这种能力带来了巨大的效率提升,但也引入了同等级别的风险。一个无意的错误指令,或是一次恶意的提示注入 (Prompt Injection),都可能导致数据泄露、系统损坏甚至更严重的后果。
Hermes Agent 的设计哲学是在提供强大功能的同时,内置一个分层、可配置的安全模型。这个模型主要由以下几个核心概念构成。
1. 信任边界 (Trust Boundary)
信任边界是一个理论上的分界线,用于区分系统中可信和不可信的组件。在 Hermes Agent 的世界里,这个边界至关重要。
边界之内 (Trusted):
- Hermes Agent 核心框架:我们编写和部署的 Agent 主程序代码是可信的。
- 配置文件:由我们自己定义的
config.yml、skills.yml等是可信的。 - 系统环境:运行 Agent 的服务器或本地机器是可信的。
边界之外 (Untrusted):
- 大型语言模型 (LLM) 的输出:这是最关键的不可信来源。LLM 生成的任何内容,无论是自然语言的思考链 (Chain of Thought),还是准备执行的代码片段 (如 Python, Shell),都绝对不能被无条件信任。它可能会产生有 Bug 的、低效的,甚至是恶意的代码。
- 用户输入 (User Input):用户的提示可能包含无意的错误,也可能包含恶意的指令,试图绕过安全限制(即 Prompt Injection 攻击)。
- 外部工具/API 的返回值:Agent 调用的外部 API 或工具返回的数据也应被视为不可信,需要进行适当的验证和清理。
Hermes Agent 的所有安全机制,都建立在“绝不盲目信任边界之外的任何输入”这一基本原则之上。
2. 执行前确认 (Pre-execution Confirmation)
这是第一道,也是最直观的一道防线。它是一种“人类在环”(Human-in-the-Loop) 的安全机制。
当 Agent 的规划器 (Planner) 决定需要执行一个具有潜在副作用的动作时(例如,执行一段代码、调用一个会修改数据的 API、执行一条 Shell 命令),它不会立即执行。相反,它会将完整的执行计划和将要执行的具体代码/命令呈现给用户,并暂停等待用户的明确授权。
工作流程如下:
- Agent 接收任务,进行思考和规划。
- Agent 生成一个或多个具体的操作步骤,例如一段 Python 代码。
- 在执行这段代码之前,Agent 在控制台或消息网关中输出:
- 意图 (Intent): "我将要下载网页内容并分析标题。"
- 代码/命令 (Code/Command):
requests.get('...'),os.makedirs(...)等。 - 确认提示 (Confirmation Prompt):
[y/n]
- 只有当用户输入
y(yes) 并回车后,Agent 才会继续执行。如果用户输入n(no) 或其他任何内容,操作将被中止。
这个机制简单而极其有效,它将最终的执行权交还给了人类监督者,防止了 Agent 的“自主失控”,尤其是在开发和调试阶段。
3. 沙箱隔离 (Sandbox Isolation)
如果说“执行前确认”是策略层面的防护,那么“沙箱隔离”就是技术层面的硬隔离。即使我们同意执行一段代码,我们也不希望它能在我们的主系统上为所欲为。
沙箱是一个受限制的、隔离的运行环境。在沙箱内执行的程序,其能力受到严格的控制。它无法访问沙箱之外的文件系统、网络或进程。这就像在一个带锁的、防弹的房间里测试一个潜在的危险设备。
对于 Hermes Agent 这样需要执行 LLM 生成代码的系统,沙箱是必不可少的。最常用和最强大的沙箱技术之一就是 Docker 容器。
使用 Docker 作为沙箱的优势:
- 文件系统隔离:容器拥有自己独立的文件系统。我们可以精确地控制将主机的哪个目录挂载到容器的哪个位置,防止 Agent 访问或修改主机上的敏感文件(如
/etc/passwd,~/.ssh)。 - 网络隔离:可以为容器配置独立的网络模式。例如,完全禁止网络访问,或者只允许访问特定的 IP 和端口,有效防止代码向外泄露数据或从未知来源下载恶意软件。
- 进程隔离:容器内的进程与主机进程隔离,无法干扰或嗅探主机上的其他应用程序。
- 资源限制:可以限制容器能使用的 CPU 和内存量,防止“代码炸弹”(Code Bomb) 耗尽主机资源。
- 环境一致性:为 Agent 的代码执行提供一个干净、可复现、包含所有必要依赖(如
requests,pandas)的运行环境。
通过将所有代码执行任务都委托给一个临时的、用完即弃的 Docker 容器,我们极大地降低了潜在风险。即使 LLM 生成了 rm -rf / 这样的恶意代码,并且用户不小心确认了,它也只会删除容器内的根目录,而不会对主机系统造成任何伤害。
4. 权限最小化原则 (Principle of Least Privilege - POLP)
这是一个贯穿所有安全设计的黄金法则。它要求任何组件(无论是 Agent 本身,还是其执行代码的沙箱)只应被授予完成其任务所必需的最小权限。
- 对于 Agent 进程:如果 Agent 不需要写文件,就不要以可写权限运行它。
- 对于 API 密钥:提供给 Agent 的云服务(如 AWS, GCP)API Key,应该使用 IAM (Identity and Access Management) 等工具创建具有严格范围限制的密钥,而不是使用拥有完全权限的根密钥。
- 对于沙箱容器:
- 非 Root 用户:在 Dockerfile 中,应创建一个非 root 用户,并使用
USER指令切换到该用户。这可以防止容器内的进程拥有过高的权限。 - 精确挂载:只挂载一个专门的工作目录(如
./workspace),而不是整个项目目录或用户主目录。 - 受限网络:如果任务不需要访问互联网,就使用
--network=none来运行容器。
- 非 Root 用户:在 Dockerfile 中,应创建一个非 root 用户,并使用
将这四大概念结合起来,Hermes Agent 构建了一个纵深防御体系:在清晰的信任边界之上,通过执行前确认进行决策把关,再利用沙大箱隔离技术限制破坏半径,并始终遵循权限最小化原则来收紧所有环节的权限。
💻 实战演示
接下来,我们将通过修改 Hermes Agent 的配置文件,亲身体验这些安全机制如何工作。
假设我们的任务是:“请帮我获取 Hermes Agent 在 GitHub 上的 README.md 文件的内容,并统计其中有多少个 'Agent' 单词,最后将结果保存到 analysis_result.txt 文件中。”
这个任务涉及:
- 网络请求 (访问 GitHub)
- 文件系统写入 (保存结果)
这是一个典型的需要安全审查的操作。
场景 1: 完全开放模式(危险!仅供演示)
首先,我们模拟一个完全信任 Agent 的、极不安全的配置。
修改配置文件 打开
config/config.yml,找到security部分(如果不存在,请自行添加),并进行如下配置:# config/config.yml # ... other configurations ... security: # 是否在执行代码或命令前需要用户确认 require_confirmation: false # 执行环境配置 execution_environment: # 'local' 表示直接在主机上执行,非常危险! type: "local"启动 Agent 并下达指令
./hermes-agent run在 Agent 的交互界面中输入我们的任务:
User: 请帮我获取 Hermes Agent 在 GitHub 上的 README.md 文件的内容,并统计其中有多少个 'Agent' 单词,最后将结果保存到
analysis_result.txt文件中。观察行为 你会看到 Agent 思考后,不经任何询问,直接开始执行。它的日志中可能会显示类似以下的输出:
[INFO] Planner: I need to use Python to perform this task. I will fetch the URL, count the word, and write to a file. [INFO] Executor: Executing the following code directly on the local machine: import requests url = "https://raw.githubusercontent.com/hermes-project/hermes-agent/main/README.md" try: response = requests.get(url) response.raise_for_status() content = response.text count = content.lower().count('agent') result_message = f"The word 'Agent' appears {count} times." with open("analysis_result.txt", "w") as f: f.write(result_message) print(result_message) print("Result saved to analysis_result.txt") except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") [INFO] Execution finished. The word 'Agent' appears 12 times. Result saved to analysis_result.txt此时,项目根目录下会凭空出现一个
analysis_result.txt文件。这个过程非常顺滑,但也极其危险。如果 LLM 生成的代码是import os; os.system('rm -rf ~'),你的用户主目录可能就遭殃了。
场景 2: 启用执行前确认(推荐的基本安全配置)
现在,我们开启第一道防线。
修改配置文件 将
require_confirmation改为true。# config/config.yml security: require_confirmation: true # <--- 改为 true execution_environment: type: "local"再次执行任务 重启 Agent,输入相同的指令。
观察行为 这次,Agent 的行为完全不同。在生成代码后,它会停下来等待你的许可:
[INFO] Planner: I need to use Python to perform this task. I will fetch the URL, count the word, and write to a file. [CONFIRMATION REQUIRED] The agent plans to execute the following Python code. Please review it carefully. Actions to be taken: - Make a network request to https://raw.githubusercontent.com - Write to the local file: analysis_result.txt Code: ---------------------------------------------------------------------- import requests url = "https://raw.githubusercontent.com/hermes-project/hermes-agent/main/README.md" try: response = requests.get(url) response.raise_for_status() content = response.text count = content.lower().count('agent') result_message = f"The word 'Agent' appears {count} times." with open("analysis_result.txt", "w") as f: f.write(result_message) print(result_message) print("Result saved to analysis_result.txt") except requests.exceptions.RequestException as e: print(f"Error fetching URL: {e}") ---------------------------------------------------------------------- Do you approve this action? [y/n]:现在,你有机会审查代码。你看到它确实是在执行你要求的任务,没有恶意行为。于是你输入
y并回车,Agent 才会继续执行,并最终完成任务。如果你输入n,它会中止操作并告知你用户拒绝了执行。
场景 3: 启用 Docker 沙箱隔离(最高安全级别)
最后,我们启用终极防护:Docker 沙箱。
准备 Docker 环境 首先,确保你已经安装了 Docker。然后,我们需要创建一个用于代码执行的 Docker 镜像。
在你的项目根目录下,创建一个名为
sandbox的文件夹,并在其中创建一个Dockerfile文件:mkdir sandbox cd sandbox touch Dockerfile编辑
Dockerfile内容如下:# Dockerfile # 使用一个轻量的 Python 镜像作为基础 FROM python:3.10-slim # 安装必要的库,例如我们的任务需要 requests RUN pip install requests # --- 权限最小化原则实践 --- # 创建一个工作目录 WORKDIR /app/workspace # 创建一个没有特权的普通用户 hermesuser RUN useradd -m -d /app hermesuser # 切换到这个非 root 用户 USER hermesuser # 默认情况下,容器启动后不做任何事,等待 Agent 传入命令 CMD ["/bin/bash"]构建 Docker 镜像 在
sandbox目录下,执行构建命令:# 在 sandbox 文件夹内执行 docker build -t hermes/python-sandbox:latest .这会创建一个名为
hermes/python-sandbox的镜像,我们将在配置中引用它。修改配置文件 现在,我们来配置 Hermes Agent,让它使用这个 Docker 沙箱。
# config/config.yml security: require_confirmation: true execution_environment: type: "docker" # <--- 改为 docker docker: # 我们刚刚构建的镜像 image: "hermes/python-sandbox:latest" # 容器内的工作目录 working_dir: "/app/workspace" # 将主机的 ./workspace 目录挂载到容器的工作目录 # 这允许 Agent 与主机交换文件,但仅限于这个受控的目录 volume_mounts: - type: bind source: "./workspace" # 主机上的相对路径 target: "/app/workspace" # 容器内的绝对路径 # 网络模式。'bridge' 是默认模式,允许访问外部网络。 # 如果任务不需要联网,可以设为 'none'。 network_mode: "bridge" # 资源限制(可选) # mem_limit: "256m" # cpus: "0.5"注意: 你需要在项目根目录下手动创建一个
workspace文件夹,用于与容器共享文件。# 在项目根目录 mkdir workspace再次执行任务 重启 Agent,输入相同的指令。
观察行为 这次,流程如下:
- Agent 依然会请求你的确认(因为
require_confirmation是true)。 - 当你输入
y之后,日志会显示与之前不同的信息:
[INFO] User approved the action. [INFO] Execution Environment: Docker. Preparing container... [INFO] Starting Docker container from image 'hermes/python-sandbox:latest'. [INFO] Mounting local './workspace' to '/app/workspace' in container. [INFO] Executing code inside the Docker sandbox... [DOCKER_STDOUT] The word 'Agent' appears 12 times. [DOCKER_STDOUT] Result saved to analysis_result.txt [INFO] Execution finished. Container stopped and removed.现在,
analysis_result.txt文件会出现在你主机的./workspace目录下,而不是项目根目录。我们成功地将代码执行限制在了 Docker 容器内。代码对文件系统的写操作被重定向到了受控的
workspace目录。它在容器内以非 root 用户hermesuser运行。即使这段代码有漏洞或恶意行为,它能造成的破坏也被牢牢地限制在了这个临时的、隔离的容器之内。- Agent 依然会请求你的确认(因为
涉及命令
mkdir sandbox workspace: 创建沙箱配置和工作区目录。touch sandbox/Dockerfile: 创建 Dockerfile 文件。docker build -t hermes/python-sandbox:latest .: 构建用于沙箱的 Docker 镜像。vim config/config.yml: (或使用你喜欢的编辑器) 修改 Agent 的安全配置。./hermes-agent run: 启动 Hermes Agent。
要点回顾
- 安全不是可选项:对于能够执行代码的 Agent 来说,安全是设计的基石。
- 分层防御:Hermes Agent 的安全模型是分层的,包括策略层(确认机制)和技术层(沙箱隔离)。
- 永不信任 LLM:必须将 LLM 的输出视为不可信的外部输入,进行审查和隔离。
- 人类在环是关键:
require_confirmation: true是最简单有效的安全开关,它确保了最终决策权在你手中。 - 沙箱是终极保障:使用 Docker 等技术创建沙箱环境,可以从根本上限制潜在恶意代码的破坏范围,是生产环境部署的推荐实践。
- 权限最小化:无论是 Agent 进程、API 密钥还是沙箱配置,始终遵循权限最小化原则,只授予必要的权限。
- 安全与便利的权衡:
local模式最方便但最危险,docker模式最安全但配置稍复杂。你需要根据应用场景(开发、个人使用、生产部署)来选择合适的安全级别。
通过本期的学习,你已经掌握了保护 Hermes Agent 的核心知识和技能。在未来的探索中,请始终将安全意识放在首位,负责任地构建和使用强大的 AI Agent。
参考资料
- OWASP Top 10 for Large Language Model Applications: 了解针对 LLM 应用的常见安全风险。
- Docker official documentation - Security: 深入学习 Docker 的安全特性。
- The Principle of Least Privilege (POLP): 理解权限最小化原则的核心思想。