在软件交付这条流水线上,很多人只盯着代码质量和自动化测试,却容易忽略一个“看门”的环节:制品安全扫描。制品是什么?可以把它理解成你最终要运到生产环境的那一箱货物,比如一个Java的jar包、一个Node的npm包、一个Docker镜像,或者一个压缩好的安装包。这些制品一旦被构建出来,就会进入仓库,再被部署到服务器上。如果这一箱货里藏了木马、带漏洞的依赖,或者不干净的许可证,那它就像一颗定时炸弹。而Artifactory,就是这箱货的一个“中转站”。我们可以在中转站装上安检机,让每个制品经过扫描再流向下一站。今天这篇文章,就用一个大白话的思路,带大家把“Artifactory + Xray”这套扫描集成玩明白,看看怎么配置,怎么读结果,以及在实际项目里要注意哪些坑。
一、从一盒快递说起:制品安全扫描为什么重要
你买了一个手机壳,快递小哥把包裹递给你,你是不是得先看看外包装有没有破损?如果是贵重物品,你是不是想打开检查一下?在软件世界里,制品就是那个包裹,Artifactory就是快递驿站。以前很多团队的做法是,构建完制品就往仓库里一推,下游直接下载使用。至于里面用到的开源组件有没有高危漏洞,没人关心。结果往往是上线以后被安全团队通报:“你们这个包用的底层库有CVE漏洞,赶紧修。”
问题出在哪?出在“检查”太晚了。如果等部署到生产环境再查,修复成本高,还可能引发线上事故。所以正确的做法,是在制品进入Artifactory的那一刻,或者下载使用之前,就自动做一次安全扫描。Artifactory本身是个仓库管理工具,它不管安全的事情,但它的“好基友”Xray可以接管这件事。Xray能干很多事:可以扫描制品里的每一个依赖,比对已知的漏洞库,还能检查开源许可证,比如GPL这种具有“传染性”的许可证是否被你误用。
把这个流程做好以后,开发人员还是该怎么构建怎么构建,但仓库会自动拦截掉那些不符合安全策略的制品。比如一个jar包里带了一个高危漏洞,你配置了“高危拒绝”策略,那么这个jar包就会被标记成“不可下载”,下游想拉都拉不下来。这样一来,问题就被挡在了源头,而不是等到了生产环境再火急火燎地修复。
二、Artifactory在扫描里到底扮演什么角色
很多人第一次接触Artifactory,会把它跟“私服”画等号。没错,它可以管理Maven、npm、PyPI、Docker等类型的仓库。但在安全扫描集成中,它并不是被动地存东西,而是主动参与了“数据源”的对接。具体来说,Artifactory里存的是制品的二进制内容、元数据、依赖关系。Xray要扫描,就需要知道这个制品从哪来、依赖了什么、什么时候被上传的。这些信息Artifactory都能提供。
你可以把Artifactory想象成一个仓库管理员,Xray是安检员。管理员把货搬进仓库时,会登记每一件货物的来源和清单。安检员站在传送带旁边,拿起扫描仪对着清单核查。如果发现可疑物品,就在货物上贴一个“禁止放行”的标签。管理员看到标签,就不会把货物发给取货的人。这里的“取货人”就是你的构建服务器、部署脚本,或者其他开发人员。
在配置层面,Artifactory和Xray通常是配合安装的。Xray可以安装在独立的机器上,也可以跟Artifactory用同一个节点。它们之间的通信由JFrog自己搞定,我们只需要在Artifactory上配置好Xray的连接信息,然后把需要扫描的仓库或者构建(Build)接入Xray的监控范围。接入之后,只要那个仓库里有新制品上传,或者有构建发布,Xray就会自动触发一次扫描。这个流程对用户来说是透明的,你不需要手动去调扫描接口,除非你想做更精细的自定义控制。
三、动手配置:让Xray给制品做安检
这一部分我们直接上手操作。为了让示例统一,这一整篇的技术栈都用“Shell + curl + jq”来完成,也就是通过命令行调用Artifactory和Xray的REST API。你可以把下面的命令用在自己平时的自动化脚本里,也可以手动在终端敲。
3.1 准备环境
先假设你已经装好了Artifactory和Xray,并且有一个可以访问它们的域名或IP。下面我用几个变量来统一管理地址和账号,方便后面复用。注意,生产环境不要用明文密码,这里仅做演示。
#!/bin/bash
# 统一配置变量,方便后面命令复用
ARTIFACTORY_URL="http://artifactory.example.com:8081" # Artifactory入口地址
XRAY_URL="http://xray.example.com:8082" # Xray服务地址
ADMIN_USER="admin" # 管理员账号
ADMIN_PWD="your_strong_password" # 管理员密码(生产环境请用密钥管理)
# 创建一个测试仓库,名叫example-libs-local
# -X PUT 表示创建资源,-u 是带权限认证
curl -X PUT -u "${ADMIN_USER}:${ADMIN_PWD}" \
"${ARTIFACTORY_URL}/artifactory/api/repositories/example-libs-local" \
-H "Content-Type: application/json" \
-d '{
"rclass": "local", # 仓库类型:本地仓库
"packageType": "generic", # 通用制品类型,支持任何文件
"repoLayoutRef": "simple-default", # 使用默认的仓库布局
"xrayIndex": true, # 关键!允许Xray索引这个仓库
"description": "Used for demo security scan" # 仓库描述
}'
echo "仓库创建完成。"
注意上面的 "xrayIndex": true 这一项。如果不开启,Xray不会自动去扫描这个仓库里的制品。很多新手就是忘了这一行,导致上传了东西却一直没看到扫描记录。
3.2 建立扫描策略
Xray里最重要的概念是“策略(Policy)”和“看板(Watch)”。策略定义什么情况算违规,比如“高危漏洞必须拦截”“许可证必须是MIT类”。看板则把策略绑定到具体的仓库或构建上。下面我们创建一个策略,名为 block-high-vuln,规则很简单:只要发现高危或严重级别的漏洞,就阻止制品发布。
# 创建一个安全策略:阻断高危和严重漏洞
curl -X POST "${XRAY_URL}/api/v2/policies" \
-u "${ADMIN_USER}:${ADMIN_PWD}" \
-H "Content-Type: application/json" \
-d '{
"name": "block-high-vuln", # 策略名称
"type": "security", # 策略类型:安全策略
"description": "Block artifacts with high or critical CVEs", # 描述信息
"rules": [ # 规则数组
{
"name": "block-high-cve", # 规则名称
"criteria": {
"min_severity": "high" # 最小严重级别是高危
},
"actions": {
"block": true, # 关键动作:阻止违规制品
"notify": true # 同时发送通知给相关人员
}
}
]
}'
echo "策略创建完成。"
创建完策略,还要创建一个看板,把它关联到我们之前创建的仓库上。这样Xray才知道,要拿 block-high-vuln 这个策略去扫描 example-libs-local 仓库里的制品。
# 创建看板,将策略与仓库关联
curl -X POST "${XRAY_URL}/api/v2/watches" \
-u "${ADMIN_USER}:${ADMIN_PWD}" \
-H "Content-Type: application/json" \
-d '{
"name": "example-watch", # 看板名称
"description": "Watch for example-libs", # 看板描述
"assigned_policies": [ # 绑定刚才创建的策略
{
"name": "block-high-vuln"
}
],
"watched_resources": [ # 监控的资源
{
"type": "repository", # 资源类型为仓库
"name": "example-libs-local" # 仓库名称
}
]
}'
echo "看板创建完成。"
到这里,扫描的规则和监控对象都已经配置好了。接下来就是实际推一个制品进去,看看会发生什么。
3.3 推送一个制品触发扫描
我们用一个简单的文本文件冒充制品,实际上生产环境里当然是jar包或者镜像。先创建一个文件,然后用curl上传到Artifactory仓库。
# 创建示例文件
echo "hello artifact security" > demo.txt
# 上传到Artifactory的example-libs-local仓库
curl -X PUT -u "${ADMIN_USER}:${ADMIN_PWD}" \
"${ARTIFACTORY_URL}/artifactory/example-libs-local/demo.txt" \
-T demo.txt
echo "文件已上传。"
# 等待几秒,让Xray完成初次扫描
sleep 10
# 查询这个制品的扫描状态
curl -X GET -u "${ADMIN_USER}:${ADMIN_PWD}" \
"${XRAY_URL}/api/v1/artifacts/example-libs-local/demo.txt" | jq .
如果一切正常,你会看到返回的JSON里包含扫描状态、漏洞数量等信息。因为demo.txt本身没有任何依赖,所以通常不会有漏洞。但如果你上传的是一个真实的jar包,里面带了一个低版本的log4j,Xray就会白纸黑字地告诉你哪儿有问题。
四、扫描结果怎么看:从全绿到“炸弹”
扫描结果不是只看“通过”或“不通过”。很多时候我们需要知道具体是哪个组件有问题,影响范围是什么,能不能升级版本解决。Xray把结果分成了几层,我们先从命令行角度看看能拿到什么信息。
4.1 获取扫描状态
Xray对制品的扫描是异步的。当你上传一个制品后,Xray会先把它加入扫描队列,然后逐步分析。所以查询时可能遇到“还没扫完”的状态。下面这段命令会先获取制品详情,然后专门提取扫描状态和摘要。
# 获取详细扫描报告,并使用jq提取关键字段
curl -X GET -u "${ADMIN_USER}:${ADMIN_PWD}" \
"${XRAY_URL}/api/v1/artifacts/example-libs-local/demo.txt" \
| jq '{
name: .name,
path: .path,
status: .scan_status, # 扫描状态:completed/failed/scanning等
violations: .violations, # 违规数量
vulnerabilities: .vulnerabilities # 漏洞数量
}'
输出可能长这样:
{
"name": "demo.txt",
"path": "example-libs-local/demo.txt",
"status": "completed",
"violations": 0,
"vulnerabilities": 0
}
这里的 violations 指的是违反策略的项。比如你设了“高危漏洞就阻断”,那么一个高危漏洞就会变成一条违规记录。 vulnerabilities 则是全部漏洞,即使没有违反策略也会列出来。
4.2 把漏洞清单变成人能看懂的报告
光有数量不够,还得看明细。Xray的扫描报告里,每个漏洞会包含CVE编号、CVSS评分、受影响的组件、修复版本。我们可以写一个简单Shell脚本,循环展示这些信息。下面这个示例会拉取某个制品的详细漏洞列表,并用jq格式化输出。
# 获取并解析漏洞详情
curl -X GET -u "${ADMIN_USER}:${ADMIN_PWD}" \
"${XRAY_URL}/api/v2/artifacts/example-libs-local/demo.txt" \
> result.json
# 用jq遍历漏洞数组,输出人类可读的文本
jq -r '.violations[]? // empty | "违规类型: \(.type)\n级别: \(.severity)\n描述: \(.description)\n---"' result.json
# 或者直接查看所有漏洞,不区分是否违规
jq -r '.vulnerabilities[]? // empty | "CVE: \(.cve)\nCVSS: \(.cvss_score)\n组件: \(.component)\n修复版本: \(.fixed_versions)\n---"' result.json
注意我在jq里用了 // empty,意思是没有该项时就跳过,避免脚本因为字段不存在而报错。实际使用中,你可能需要根据项目特点去调整字段名称,因为不同版本的Xray API返回结构略有差别。建议先用不带jq的原始返回看一遍,再写解析。
真正到了生产环境,你不会手动每次去查。通常是把这些命令嵌入到Jenkins流水线、GitLab CI或者GitHub Actions里。一旦扫描出现违规,就让流水线失败,不给部署留机会。实现逻辑也很简单:在上传制品后,轮询扫描状态,直到完成,然后检查违规数量是否大于0。
# 轮询扫描状态的小脚本
for i in {1..30}
do
# 获取当前状态
status=$(curl -s -u "${ADMIN_USER}:${ADMIN_PWD}" \
"${XRAY_URL}/api/v1/artifacts/example-libs-local/demo.txt" \
| jq -r '.scan_status')
echo "第 ${i} 次检查,状态:${status}"
# 如果扫描已完成,跳出循环
if [ "$status" == "completed" ] || [ "$status" == "failed" ]; then
break
fi
sleep 5 # 等待5秒再查
done
# 检查违规数量
violations=$(curl -s -u "${ADMIN_USER}:${ADMIN_PWD}" \
"${XRAY_URL}/api/v1/artifacts/example-libs-local/demo.txt" \
| jq -r '.violations')
echo "扫描完成,违规数量:${violations}"
# 如果有违规,直接以非0状态退出,让CI任务失败
if [ "$violations" -gt 0 ]; then
echo "制品不符合安全策略,禁止发布!"
exit 1
else
echo "制品安全,放行。"
fi
这段脚本可以原样放在你的CI任务里。不过别照抄,因为仓库名和制品名要换成实际的。
五、什么样的项目适合这么搞
5.1 典型应用场景
第一类场景是大型企业内部的统一制品平台。多个团队往同一个Artifactory上传制品,安全团队不可能每天手工检查。通过Xray策略,让每个团队各自负责的仓库都有对应的看板,一旦有问题,责任人能立刻收到通知。
第二类场景是合规审计比较严格的行业,比如金融、医疗。它们需要明确地知道某个版本用了哪些开源组件,是否有许可证风险。Xray会记录每次扫描的结果,并且可以导出报告,审计时直接拿出来就能说明问题。
第三类场景是发布频率很高的互联网应用。每天要构建很多次,如果全部依赖人工测试,完全不现实。集成流水线后,每次提交代码、构建镜像时都会自动扫描,发现高危问题就阻断上线,既保证速度,又守住底线。
5.2 要说优点
最大的优点就是“把检查前置了”。以前是上线之后被安全团队打回,现在是进仓库之前就拦住。这个位置选得特别好,因为制品一旦被多个下游使用,修改一个坏制品的成本会成倍增长。在源头拦住,影响面最小。
另外一个优点是“策略可编程”。你可以根据业务容忍度设置不同的规则。比如核心支付系统不允许有任何中危以上漏洞,而内部工具只要没有高危就可以放行。这些都能通过Xray策略灵活配置,不需要改代码。
还有就是生态整合简单。Artifactory和Xray都提供REST API,不管你的CI系统是Jenkins、GitLab还是自研的,都能通过curl或JFrog CLI轻松对接。所以即使你的团队没有很强的安全基础,也能很快落地。
5.3 也要面对缺点
首先是资源占用问题。Xray做深度扫描需要消耗CPU和内存,尤其是大型依赖树或者容器镜像,扫描时间可能长达几分钟。如果团队追求极速构建,那就要考虑把扫描过程异步化,或者只对发布候选制品做全面扫描,日常构建做轻量检查。
其次,漏洞数据库并非实时更新。Xray依赖它自己的漏洞库,虽然更新频率很高,但总会有延迟。新披露的CVE可能过一两天才进库,这期间扫描结果可能会漏报。所以不要把它当成唯一的安全手段,该有的代码安全测试、运行时防护还是得做。
最后,策略误伤问题。有些旧版本的依赖已经停止维护,没有修复版本,Xray会一直报漏洞,导致制品永远无法通过扫描。团队需要建立一套人工评审和豁免机制,对确实无法修复的漏洞记录风险说明,并让负责人签字确认。
六、搞集成时必须注意的几件事
第一,网络和DNS。Artifactory和Xray之间的通信很频繁。如果它们部署在不同机房,中间有防火墙,一定要把端口配好。Xray默认监听8082端口,Artifactory默认8081。很多问题都出在“自检通过但扫描看不到结果”,多半是网络隔离导致Xray回调Artifactory失败。
第二,缓存的坑。Xray有缓存机制,同一个制品如果已经被扫描过,在设定时间内不会重新扫描。如果你上传了一个同名但内容不同的制品,可能会因为哈希变化而触发新扫描,但如果你用相同的内容覆盖,那Xray会认为没有变化,直接沿用之前的扫描结果。这个在特殊场景下要留意。
第三,权限最小化。不要把管理员账号直接写进脚本。建议在Artifactory里创建专门的部署账号,只授予需要上传和下载的仓库权限;在Xray里创建只读或策略管理账号。这样即使密钥泄露,影响范围也可控。
第四,扫描超时和失败重试。大型镜像扫描可能超过CI的默认超时时间。我们前面写的轮询脚本里,最大等待次数要根据实际制品大小调整。另外,Xray偶尔会因为依赖源网络问题扫描失败,脚本里要处理失败状态,必要时做自动重试或者发送告警。
第五,结果保留与归档。合规审计通常需要保留历史扫描记录。Xray的扫描结果默认会保留一定时间,但建议定期导出并归档到对象存储或日志系统。别等到审计前才发现,一年前的扫描记录被清掉了。
第六,重视“忽略规则”。Xray允许你对某些漏洞或组件设置忽略规则,但忽略一定要有理由。最好在规则里附加说明和截止日期,到期后自动提醒重新评估。否则很容易出现“当时临时忽略,后来一直没人管”的情况,最终变成安全黑洞。
七、总结一下
把Artifactory和Xray集成起来做制品安全扫描,说穿了就是三件事:第一,把仓库接入Xray的监控;第二,设置好安全策略和看板;第三,在CI流水线里调用API检查结果。做完这三件事,你的制品从出生到上线,就多了一道可靠的安检门。它不会阻止你正常发布,只会拦下那些带着高危漏洞的坏制品。相比在测试阶段发现漏洞,或者在生产环境被入侵后追责,在仓库入口处拦截是最省心、成本最低的方式。
当然,工具不是万能的。Xray能帮你发现已知漏洞,但发现不了业务逻辑漏洞,也替代不了代码审查和运行时防护。它更像是你流水线上称职的保安,认得出黑名单上的人,但如果有人伪装成新面孔混进来,它也可能被蒙过。所以,看门要有多道,人才是最关键的那个因素。把这套扫描集成玩明白,你的发布流程会安全不少,心里也会踏实很多。
注意:上方 JSON 最后没有代码块,就位于文章末尾。
评论
围绕“制品安全扫描集成中Artifactory的配置与结果分析”参与讨论