拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI基础设施安全实战:技能扫描与Docker部署全解析

AI基础设施安全实战:技能扫描与Docker部署全解析

1. 项目定位:它到底解决了什么问题

做AI基础设施维护的朋友应该都有同感:今年圈子里的核心焦虑,已经从"模型怎么训"慢慢转移到"模型上线之后怎么保证不出事"。模型服务、Agent框架、RAG管道、推理网关……这些东西越来越多地接入生产环境,但对应的安全观测手段还停留在传统WAF和网络ACL层面。AI-Infra-Guard这个项目我第一次看到的时候其实没太当回事,直到自己在测试环境里跑了一回技能扫描,才发现它对AI Agent场景的针对性比我想象中要强不少。

先说清楚AI-Infra-Guard是个什么角色。它本质上是一个面向AI基础设施的安全检测工具,核心动作是"技能扫描"——也就是对运行中的AI组件做一次系统性的能力与暴露面检查,看哪些模型服务、哪些工具调用接口、哪些Agent技能处于可以被外部触达的状态,再对照规则库判断这些暴露是否构成风险。这里说的"技能"就是Agent的工具集,比如数据库查询工具、外部API调用工具、文件读写工具等。这类技能的注册信息通常散落在Agent配置、模型上下文协议(MCP)服务列表、插件市场或推理服务的元数据里,AI-Infra-Guard做的事就是把这些散落的技能资产找出来,统一做一次安全体检。

这个工具的适用对象很明确:自己维护过Agent服务、部署过RAG检索链路、或者让模型通过function calling接过程序调用的团队。它不是你想象中那种装完就跑一次的扫描器,而是要持续运行、持续更新规则库的常驻组件。用Docker来部署,是我个人比较推荐的方式,后面的实战记录也全部基于Docker环境。

1.1 为什么需要AI-Infra-Guard

可能有人会问:传统漏洞扫描器不是也能扫端口、扫服务、扫Web应用吗?为什么要单独搞一个AI基础设施的扫描工具?我的实际体会是,传统扫描器解决不了AI场景下的"能力暴露"问题。传统扫描器关心的是端口开没开、版本老不老、组件有没有已知漏洞,但AI Agent的问题往往不是端口暴露,而是"一个本该只在内部使用的工具技能,被模型在特定上下文里错误地暴露给了外部用户"。

举例来说,Agent系统里可能注册了一个"查询用户订单"的工具,这个工具本身没有独立的IP和端口,它的存在方式是一个函数描述,是Agent框架里的一段JSON Schema。传统扫描器就算把整个网段翻个底朝天,也看不到这个技能。AI-Infra-Guard的技能扫描做的就是这个事:它从Agent框架的配置中心、MCP服务注册表、模型网关的路由表、甚至日志系统里提取技能调用信息,再对这些技能做风险匹配。这个思路和我之前用过的API资产测绘工具有点像,但扫描对象从HTTP接口换成了Agent技能,检测逻辑也从"路径+参数"变成了"工具描述+上下文可见性"。

AI-Infra-Guard另一个让我觉得有用的点,是它对推理网关的检测。现在不少团队会用网关统一转发OpenAI、本地模型或者私有化部署的推理服务,网关层面往往会挂一些模型白名单、上下文过滤之类的策略。AI-Infra-Guard在扫描时会对网关策略做一次"实配检查",对比配置声明和实际生效情况。这个功能在一次演练里帮我发现了一个网关策略配置错误:规则文件里写了对某些敏感输入的拦截,但实际生效的版本是旧的,等于拦截没有真正启用。这类问题靠人眼审查配置是很容易漏掉的。

1.2 技能扫描在安全体系里的位置

从体系角度来看,技能扫描不是替代漏洞扫描,而是补上"AI资产发现"这一环。传统资产管理系统管的是服务器、数据库、中间件,但对AI推理服务、Embedding模型、向量库、Agent技能这些新资产基本是空白。AI-Infra-Guard跑一轮技能扫描之后,产出的技能资产清单可以直接对接CMDB或者资产盘点流程,至少让团队知道自己到底暴露了什么。

另一个位置是上线准入。我们现在的流程是所有Agent技能上线之前先过一遍AI-Infra-Guard扫描,扫描结果里出现高危项就不允许注册到生产环境。这条规则在刚开始执行的时候阻力不小,很多人觉得"不过是一个内部工具,哪有那么严重",后来发生的一次越权调用事件改变了团队的看法——某个开发环境的Agent技能因为没有限制可调用身份,被测试人员拼出来的恶意提示词连续调用了十几次内部查询接口。虽然不是真正的攻击,但这件事已经足够说明问题。AI-Infra-Guard扮演的就是一道自动化闸门,把"该不该暴露""谁能调用""调用后干了什么"这些约束落成可扫描、可验证的规则。

2. Docker 一键部署:从拉镜像到跑起来

部署工具历来有个矛盾:功能越多,部署越复杂。AI-Infra-Guard本身包含扫描引擎、规则库、Web控制台、以及一个轻量的任务调度模块,如果全部手动装,光是依赖关系就够折腾的。好在项目提供了Docker镜像和一键编排文件,我个人的体验是,只要先把Docker环境理顺,后面基本不会卡太久。

下面我把完整部署过程记录下来,用的是目前稳定版本。我假设你已经有Docker和Docker Compose的基础,如果还没有,先花十分钟把Docker装好,再继续后面的操作。

2.1 部署前的环境检查和镜像选型

先确认三件事:Docker版本、可用的磁盘空间、以及端口占用情况。AI-Infra-Guard的Web控制台默认监听在9527端口,扫描任务的后台服务会通过内网RabbitMQ队列转发,默认占用5672和15672端口。如果你本机已经有RabbitMQ或者端口被其他服务占用,建议直接改编排文件里的端口映射。

磁盘空间建议预留至少30GB。镜像本身不算大,但扫描任务的中间产物、规则库更新缓存、还有扫描结果快照都会落盘,时间久了增长很明显。我在测试环境里跑了两个月,数据目录大概增长了16GB,这个量级要注意。

镜像方面需要拉取的包括:

  • ainfra/guard-server:latest:主服务,包含Web控制台和API
  • ainfra/guard-scanner:latest:扫描执行器,实际跑技能扫描任务的组件
  • ainfra/guard-rules:latest:规则库同步镜像,负责定期拉取最新检测规则
  • rabbitmq:3.13-management:任务队列
  • postgres:16-alpine:元数据存储

下命令之前先确认一下本地Docker是否正常:

docker info docker compose version

如果docker info输出正常,compose version能打印出版本号,就可以继续了。如果docker info报权限错误,多半是当前用户不在docker组里,执行sudo usermod -aG docker $USER后重新登录即可。

2.2 docker-compose 编排实战

项目仓库里自带一份docker-compose.yml,但我更建议自己写一份精简版,把不需要的服务裁掉,方便理解整个依赖链。下面是我实际使用的编排文件:

version: "3.8" services: rabbitmq: image: rabbitmq:3.13-management container_name: aig-rabbitmq restart: always environment: RABBITMQ_DEFAULT_USER: aig_user RABBITMQ_DEFAULT_PASS: aig_pass_2024 volumes: - ./data/rabbitmq:/var/lib/rabbitmq ports: - "5672:5672" - "15672:15672" postgres: image: postgres:16-alpine container_name: aig-postgres restart: always environment: POSTGRES_DB: aig_guard POSTGRES_USER: aig_admin POSTGRES_PASSWORD: aig_pg_2024 volumes: - ./data/postgres:/var/lib/postgresql/data ports: - "5432:5432" guard-server: image: ainfra/guard-server:latest container_name: aig-server restart: always depends_on: - rabbitmq - postgres environment: GUARD_DB_DSN: postgresql://aig_admin:aig_pg_2024@postgres:5432/aig_guard GUARD_RABBITMQ_URL: amqp://aig_user:aig_pass_2024@rabbitmq:5672/ GUARD_WEB_PORT: "9527" GUARD_RULES_AUTO_UPDATE: "true" ports: - "9527:9527" guard-scanner: image: ainfra/guard-scanner:latest container_name: aig-scanner restart: always depends_on: - guard-server environment: GUARD_SERVER_ENDPOINT: http://guard-server:9527 GUARD_RABBITMQ_URL: amqp://aig_user:aig_pass_2024@rabbitmq:5672/ GUARD_SCANNER_NETWORK_MODE: bridge guard-rules: image: ainfra/guard-rules:latest container_name: aig-rules restart: always depends_on: - guard-server environment: GUARD_SERVER_ENDPOINT: http://guard-server:9527

几个关键的配置点说一下。GUARD_RULES_AUTO_UPDATE我建议在生产环境里设为true,让规则库每天自动同步;但如果你的环境是完全离线的内网,就要改成false,手动把规则包拷进去。GUARD_SCANNER_NETWORK_MODE这个参数在容器网络里很容易被忽略,默认是bridge模式,如果你打算让扫描器探测宿主机上的Agent服务,需要把扫描器容器加到宿主机的网络命名空间里,也就是改成host,否则扫描器访问不到宿主机的回环地址。

2.3 初始化配置与验证

编排文件准备好之后,执行:

docker compose up -d

第一次启动会拉取镜像,耐心等一会儿。启动完成后用docker compose ps看一下状态,所有服务都应该是Up状态。如果rabbitmq或者postgres启动失败,大多数情况是端口冲突,优先检查这两个基础组件。

服务起来之后,打开浏览器访问http://localhost:9527,会看到AI-Infra-Guard的Web控制台。首次登录会让设置管理员账号,这一步正常设置即可。登录后第一件事不是急着创建扫描任务,而是先到"系统设置"里确认规则库版本已经加载。规则库初始版本一般会随镜像打包一份,控制台会显示"规则库更新时间"和"规则总数",如果显示0条规则,说明规则加载没成功,需要检查guard-rules容器的日志:

docker logs aig-rules --tail 50

我遇到过的情况是规则容器连不上guard-server,报错信息通常是connection refused。这个时间点可以先确认一下几个容器是否在同一网络里,最简单的办法是用docker compose exec guard-server curl http://guard-rules:9527/health测试联通性,不通就检查compose文件里的服务名拼写。

基础验证通过之后,可以创建一个试探性的扫描任务,扫描对象填一个本地的测试环境地址。注意AI-Infra-Guard的扫描目标可以是IP、域名,也可以是Agent配置中心的API端点。第一次扫描建议选择"轻量模式",只做资产发现不做深度检测,先确认数据链路是通的,再放开手脚跑完整规则集。

3. 技能扫描的核心逻辑:规则、模型与调度

部署只是起点,真正需要理解的是技能扫描的运行原理。这个工具为什么能发现传统扫描器发现不了的问题?它靠的是"数据源采集+规则匹配+上下文判断"三条腿走路。实测下来,三条腿缺一条都会明显影响扫描质量。

3.1 扫描对象与数据源

技能扫描的扫描对象有三类。第一类是显式技能注册表,包括Agent框架(比如LangChain、LlamaIndex、Dify等)里的工具注册信息、MCP服务列表、以及企业自研Agent平台的功能清单。这类数据源结构化程度高,扫描器可以直接通过API拉取,识别效率最高。第二类是隐式技能痕迹,包括推理网关日志里的function_call记录、模型服务路由规则、以及Agent交互日志里出现的特殊指令块。这些数据源没有明确的"技能清单",但能从调用痕迹中反推技能的存在。第三类是外部可触达面,包括Agent服务的对外API端点、模型服务暴露的管理接口、以及向量数据库的查询端口。

采集方式上,扫描器支持主动模式和被动模式。主动模式是扫描器自己去访问Agent配置中心或者服务注册表,拉取技能元数据做匹配;被动模式则是通过接入日志流或者消息队列,对线上流量做实时分析,从中提取技能调用特征。我的建议是两种模式都开启:主动模式每天跑一次全量扫描,被动模式保持常驻监听。只开主动模式的问题在于,如果某个技能在扫描时点不存在(比如临时下线的工具),就会被漏掉;只开被动模式又会有时间盲区,新注册的技能可能要等日志积累到一定量才会被发现。

3.2 规则引擎与检测策略

拿到技能信息之后,AI-Infra-Guard会交给规则引擎做评估。规则引擎的核心是"技能描述+上下文约束"的双重检测。技能描述检测看的是这个技能的名字、描述、输入参数Schema里有没有危险特征,比如技能描述里出现"执行任意命令""删除数据""绕过权限校验""访问内部DNS"之类的关键词,或者工具的参数名出现command、shell、base_url、internal_ip这类高敏字段,规则引擎就会给出中高危评分。上下文约束检测看的是技能是否被限制在特定的租户、用户或IP段内,一个技能如果没有配置调用身份限制,或者允许的来源网段是0.0.0.0/0,即使技能本身人畜无害,也会被标记为风险项。

规则引擎里的检测规则可以按严重级别配置:

级别含义典型场景
严重可能造成直接的数据泄露或命令执行技能支持动态shell指令输入,且无身份限制
高危可能跨越权限边界访问敏感资源内部数据库查询工具对所有对话上下文可见
中危暴露面过大但尚无直接利用链模型网关管理API未设置访问鉴权
低危存在合规或运维隐患Agent技能描述中的测试信息未清理

配置扫描任务的时候,强烈建议在"忽略白名单"里把确实需要放行的技能加进去。不过要小心白名单"放之过宽"的问题——我见过有人图省事直接把某个Agent的全部技能都加进白名单,结果等于没扫。白名单应该精确到具体的技能ID,而不是按Agent名称或服务名批量放行。

3.3 扫描报告解读

扫描完成后,AI-Infra-Guard会生成一份包含技能资产清单、风险分布、规则命中明细的报告。资产清单部分列出了发现的所有技能及数据来源,这一页先看数量——如果你确认线上Agent有大约10个技能,而报告里只列出来3个,那大概率是采集链路出了问题,不是线上真的只有3个技能。风险分布部分会按严重级别统计,值得注意的是中危项一定不要直接忽略,中危往往意味着技能没有身份限制或者暴露面过宽,攻击者组合利用时杀伤力会放大。

规则命中明细是我每次必看的页面,它列出了每一个命中规则的技能、命中的规则编号、以及触发上下文。如果报告显示某个技能命中了"内部地址可访问"的规则,我会点进去确认它的base_url是否真的指向内网IP,如果是,再看这个技能当前是否被外部可见。这里有一个个人习惯:不要只看HTML报告,建议把扫描器生成的JSON格式结果导出来留档,后续做对比分析更方便。Web控制台里导出的CSV只包含汇总字段,JSON导出才包含每条规则命中的完整证据链。

4. 一次"漏报"的完整复盘

标题里写到的漏报事件,正是我在这个工具上印象最深的一次经历。准确地说,它不是一次真正的漏报,而是一次"看起来漏了、其实是扫描器够不着"的误读,但从结果上看,我们确实在扫描报告中找不到那个出问题的技能。整个过程值得复盘一遍,很可能你以后也会遇到。

4.1 事故现象

事情是这样的:我们内部有一个知识库问答Agent,它的工具集里注册了一个"查询内部项目文档"的技能,这个技能通过一个内部API网关访问后端的文档服务。某次新版本发布之后,运维同学反映从外部网络可以直接访问这个内部API网关的某些路径。按道理,AI-Infra-Guard每天跑一次全量扫描,如果技能暴露出去了,扫描报告应该能看到风险提示。但翻遍了最近一周的扫描报告,这个技能一次都没出现过,状态一直停留在"未发现"。

当时的第一反应是扫描规则库有问题,要么是技能注册信息没有进入扫描器视野,要么是检测规则对这类内部API网关注册的方式不识别。我们花了不少时间检查规则库更新状态,确认规则已经是最新的,手动触发了几次重扫,结果还是一样——"未发现"。

4.2 排查链路

后来顺着扫描器的数据链路一层层往下查,才找出真正原因。AI-Infra-Guard的技能扫描在主动模式下,是通过Agent配置中心的API获取技能注册表的。我们的Agent配置中心部署在公司的NAT网关后面,配置中心的API只允许内网IP访问。而我们的扫描器容器跑在一台独立的云服务器上,虽然能访问Agent的对外域名,但访问配置中心的内部API时,网络包到不了那个网段。

问题就出在这里:技能扫描器能够从Agent的域名拿到一些公开的模型服务信息,但拿不到配置中心里完整的技能注册数据,所以扫描报告里只能看到一小部分技能,那个内部API网关的"查询文档"技能恰恰不在可见范围内。扫描器不是"漏检",而是"没看到"。

这个案例真正值得反思的是,我们在设计扫描任务的时候,把扫描器放在了网络外层,想当然地以为只要它能访问Agent域名,就能拿到所有元数据。实际上,Agent配置中心的API和Agent推理服务是两套不同的网络路径。配置中心在NAT后面,意味着很多内网技能描述根本出不了网。这个教训让我重新理解了"技能扫描"的前提条件——它不只是规则和镜像的问题,扫描器自身的网络位置决定了它能感知到多大的攻击面。

4.3 根因与修复

修复方案分三步。第一步,把扫描器的部署位置调整到能访问配置中心API的内网区域。我们原来的云服务器单独跑,现在改成在Kubernetes集群内部署一个扫描器副本,分配一个可以直接访问配置中心的内网服务账号,这样至少能保证主动模式的数据采集链路是畅通的。如果你的环境没有Kubernetes,也可以用Docker的network_mode: host直接跑在能访问内网配置中心的宿主机上,效果类似。

第二步,给扫描任务增加"来源覆盖检查"。AI-Infra-Guard这个工具本身没有这个功能,但可以在每次扫描完成后,对比扫描报告里的技能数量和Agent配置中心里实际注册的技能数量。我们写了一个小脚本,每天早上定时调配置中心API数一下技能数,再跟扫描报告里的技能数做对比,不一致就告警。这个机制可以暴露"扫描器够不着数据源"的问题,避免出现盲区。

第三步,把被动模式接入Agent日志流。主动模式采集不到完整技能时,被动模式至少可以从调用日志里提取技能痕迹。我们把Agent的日志接入Kafka,AI-Infra-Guard的被动扫描器直接消费Kafka里的技能调用事件,这样即使某个技能没有出现在配置中心的可见范围里,只要线上有人调用过它,被动扫描器就能捕捉到痕迹并触发规则匹配。

这次复盘之后,我在团队里定了一条规矩:所有AI安全扫描任务上线前,必须画一张"扫描器到数据源的网络路径图",确认每个数据源都能被扫描器实际上触达,再谈规则配置。工具再强,装在一个够不着目标的位置上,也是白搭。

5. 常见问题速查与调优建议

用AI-Infra-Guard这段时间,从部署到每天跑扫描,踩过不少坑,也摸索出一些规律。整理成一份速查表,方便你遇到问题时直接对号入座。

5.1 高频问题清单

现象可能原因解决办法
扫描任务一直处于Pending状态扫描器容器未成功连接RabbitMQ队列查看docker logs aig-scanner,确认GUARD_RABBITMQ_URL中的账号密码与rabbitmq服务一致
控制台显示0条规则规则库容器同步失败重启aig-rules容器,检查能否访问guard-server:9527的API
扫描速度慢到无法接受规则集过大或扫描目标响应慢在任务里按技能名称前缀做分片,拆成多个子任务并行扫描
报告里技能数量远少于预期扫描器网络路径够不到配置中心参考第4节,调整扫描器部署位置或接入被动模式
某个已知风险技能长期不告警技能被误加入全局白名单检查"忽略白名单"里是否有按服务名批量添加的条目,改为精确到技能ID
Web控制台能打开但登录后白屏浏览器缓存了老版本前端资源强制刷新或清缓存,确认guard-server镜像版本是最新

这些坑里,白名单误配置是最隐蔽的。有一次我们排查某高风险的"外部API调用"技能为什么没有告警,查了半天才发现是之前测试时将整个Agent名称加进了白名单。恢复精确匹配之后,告警立刻恢复了。经验是:白名单坚决不按Agent名称或服务路径批量加,必须下沉到具体技能ID。

5.2 规则质量与性能调优

规则库随镜像自动更新可以省很多事,但完全迷信默认规则也不现实。第三方规则库往往偏向通用场景,对内部业务的"正常技能"识别能力有限。我的做法是建立一层自己的规则叠加:把企业内部命中率最高的几类风险(比如"技能可访问内部管理接口""工具参数支持任意URL跳转""技能描述包含生产库密码字样")写成自定义规则,放到/opt/aig/custom_rules/目录下,挂载进guard-server容器:

guard-server: image: ainfra/guard-server:latest volumes: - ./custom_rules:/opt/aig/custom_rules

自定义规则文件用JSON格式,核心结构如下:

{ "rule_id": "CUSTOM-001", "name": "skill_sensitive_db_conn", "severity": "high", "condition": { "match_field": "skill.description", "keywords": ["jdbc:", "postgres://", "password="] } }

写好之后在控制台点一下"重新加载规则",不用重启容器。这里有个细节:规则里的match_field可以引用技能描述、参数名、参数必填标记等多个字段,多字段组合规则比单关键词规则误报率低很多。我踩过的坑是写规则时只匹配了skill.description,结果很多技能把敏感信息放在参数示例里,遗漏了一部分命中。后来改成同时匹配skill.parameters字段,检出率才真正提上来。

性能调优方面,扫描任务建议设置并发上限,避免同时向Agent配置中心发起过多请求把它们打挂。我这边通常把并发线程数控制在8左右,对几百个技能的注册表来说,扫描一轮大约在5分钟以内,不会对业务造成压力。另一个容易被忽略的点是扫描结果快照的保留周期,默认可能无限期保留,时间长了磁盘会很紧张。建议在系统设置里把快照保留周期设为90天,配合定时清理任务,能省下不少存储空间。

6. 最后再分享一个小技巧

在一次复盘之后,我养成了一个习惯:每次扫描任务跑完,不只看报告上的高危项,还会顺手导出一份完整的技能资产清单,跟上一周做一次diff。这个习惯让我在两次真正的攻击还没发生前就发现了异常——某个技能在一个版本迭代里悄悄多出了两个调用参数,恰好指向内网存储路径。如果没有这轮diff,那个技能的问题可能会持续暴露好几天。

AI-Infra-Guard这类工具最有价值的地方,不是它能百发百中地拦住所有风险,而是它把"AI基础设施到底暴露了哪些能力"这件事变成了一个可以被持续观测、持续比对的过程。部署它只需要一页docker-compose配置,但真正让它发挥作用的,是你愿不愿意定期去看那些报表之外的变化。希望这篇实战记录能帮你少走一些弯路。

返回列表