Harbor镜像仓库安全加固:修复Redis与Notary默认弱口令漏洞 1. 项目概述一次典型的企业级镜像仓库安全体检最近在帮一个客户做容器化平台的安全加固他们的核心镜像仓库用的是Harbor。在一次常规的端口扫描和组件检查中我们发现了那个“经典”但容易被忽视的问题Harbor默认安装的Redis和Notary服务存在弱口令风险。这可不是危言耸听一旦这个口子被突破攻击者不仅能窃取镜像仓库的会话信息还可能篡改镜像签名导致整个交付链的信任崩塌。今天我就把这个从发现、分析到彻底修复的完整过程拆解一遍无论你是运维工程师、安全工程师还是DevOps负责人都能从中找到可以直接“抄作业”的步骤和避坑指南。简单来说Harbor是一个企业级的容器镜像仓库它内部依赖Redis做缓存和会话存储依赖Notary做镜像内容信任和签名。为了简化部署Harbor为这些内部组件设置了默认的、公开的密码。如果你的生产环境直接使用了这些默认配置就相当于把仓库后门的钥匙放在了大家都知道的地方。这个漏洞的利用门槛低但潜在危害极大从镜像被替换到供应链攻击都可能由此引发。接下来我会带你一步步理解漏洞原理并给出从快速临时加固到永久性安全配置的完整方案。2. 漏洞原理深度剖析默认配置为何成为“阿喀琉斯之踵”2.1 Redis组件缓存与会话的“不设防大门”Harbor使用Redis主要出于两个目的一是作为后端服务的缓存加速元数据访问二是存储UI和API的会话Session信息。在默认的Harbor安装包无论是离线安装包还是通过docker-compose部署中Redis服务的配置是写死在docker-compose.yml和相关配置文件里的。关键问题就出在这里。我们查看默认的docker-compose.yml文件通常会找到类似下面这段Redis服务定义redis: image: goharbor/redis-photon:v2.7.0 container_name: redis restart: always environment: - REDIS_PASSWORDyour_strong_redis_password_here volumes: - /data/redis:/data networks: - harbor看起来好像设置了密码your_strong_redis_password_here但请注意在很多早期版本或特定安装方式下这个密码可能是一个非常简单、公开的默认值比如redis123、password甚至在某些配置示例中直接为空。更重要的是即使你修改了docker-compose.yml里的密码Harbor的核心服务如core、portal也必须使用相同的密码去连接Redis。如果这些服务的环境变量配置没有同步更新就会导致服务启动失败。因此很多管理员在初次部署遇到连接问题时可能会图省事直接改回一个简单密码或使用默认值从而埋下隐患。一旦攻击者能够访问到Redis的端口默认6379且有时可能因网络策略配置不当而暴露并使用默认或弱口令成功连接他就能做很多事情会话劫持通过KEYS *session*等命令查找并导出用户的会话信息可能直接获取管理员权限。数据篡改修改缓存中的项目、镜像元数据扰乱仓库的正常视图。拒绝服务执行FLUSHALL命令清空所有数据导致Harbor UI无法正常显示或服务异常。注意Harbor的Redis通常部署在内网但容器网络或主机网络配置错误、云安全组策略过于宽松都可能使其暴露在更广的网络范围内。2.2 Notary组件镜像信任的“失效公证处”Notary是Harbor实现Docker Content Trust (DCT) 的组件负责对镜像进行签名和验证确保镜像在推送和拉取过程中不被篡改。你可以把它理解为一个负责“公证”的机构。Harbor的Notary服务包含两个部分Notary Server和Notary Signer它们通常共享一个数据库。漏洞点同样在于默认密码。Notary Server的配置文件如notary-server.json和Notary Signer的配置文件如notary-signer.json中包含了连接数据库通常是PostgreSQL或MySQL的凭据。在Harbor的默认安装中这些凭据往往是固定的、公开的。例如在数据库连接字符串中storage: { backend: postgres, db_url: postgres://notaryserver:notary_server_passwordpostgresql:5432/notaryserver?sslmodedisable }这里的notaryserver用户和notary_server_password密码就是攻击目标。如果攻击者通过某种方式如利用其他漏洞获取了数据库访问权限或Notary服务API暴露使用这些凭据其危害是致命的信任根破坏攻击者可以篡改Notary数据库中的信任根Root Key和靶标Targets信息为恶意镜像签署“合法”的签名。镜像替换攻击在用户拉取看似合法的镜像如nginx:latest时实际拉取的是被攻击者替换过的、带有恶意软件的镜像而签名验证却会通过。供应链攻击入口这为更深层次的供应链攻击打开了大门因为基于此镜像构建的所有应用都将继承其风险。这个漏洞与Redis漏洞的不同之处在于它直接破坏了容器镜像供应链的“信任链”其隐蔽性和危害性更高。3. 漏洞检测与风险评估实操指南在动手修复之前我们必须先确认自己的环境是否存在风险以及风险等级如何。盲目修改配置可能导致服务中断。3.1 检测Redis弱口令方法一使用redis-cli直接测试这是最直接的方法。你需要一台能访问Harbor Redis服务端口的机器。# 尝试使用空密码或常见弱密码连接 redis-cli -h 你的Harbor主机IP -p 6379 # 连接后执行一个命令如 info。如果不需要密码就返回了信息说明无密码。 # 如果需要密码会返回 (error) NOAUTH Authentication required. # 使用密码认证 redis-cli -h 你的Harbor主机IP -p 6379 -a 默认密码或猜测的密码 # 或者连接后使用 AUTH 命令 # redis-cli -h IP -p 6379 # 127.0.0.1:6379 AUTH your_password如果使用Harbor文档中常见的示例密码如redis123或空密码能成功执行info命令则漏洞存在。方法二检查Harbor配置文件登录到Harbor宿主机查看Redis的配置来源。# 进入Harbor部署目录 cd /your/harbor/install/path # 查看docker-compose.yml中Redis服务的环境变量 grep -A5 -B5 redis: docker-compose.yml | grep -E REDIS_PASSWORD|environment # 查看Harbor核心组件的.env文件或harbor.yml中关于Redis的配置 # 对于较新版本密码通常在harbor.yml中统一配置 grep -i redis harbor.yml风险评估高风险Redis端口对公网开放且使用默认/弱口令。中风险Redis端口仅对内网开放但内网范围较大如整个VPC且使用弱口令。低风险Redis端口严格限定只对Harbor其他容器访问且使用强口令。但即便如此默认密码也应更改。3.2 检测Notary弱口令Notary的密码检测相对复杂因为通常不直接对外提供数据库服务。重点在于配置审计。方法审查Notary配置文件# 找到Notary Server和Signer的配置文件 # 通常它们位于Notary容器内部或由Harbor在启动时通过卷挂载注入 # 你可以通过docker exec进入容器查看或查看宿主机上的配置文件目录 # 例如查看Notary Server容器内的配置文件 docker exec harbor-notary-server cat /etc/notary/server.json | grep -i db_url docker exec harbor-notary-server cat /etc/notary/server.json | grep -i password # 或者查看Harbor安装目录下的Notary配置模板 find /your/harbor/install/path -name *notary*.json -type f检查db_url连接字符串或配置中的password字段。如果密码是notary_server_password、notary_signer_password等默认值则漏洞存在。风险评估严重风险Notary数据库PostgreSQL端口意外暴露且使用默认凭据。攻击者可直连数据库进行篡改。高风险Notary Server的API接口默认4443端口因网络策略问题被暴露攻击者可能通过API进行恶意操作。中风险配置文件中使用默认密码但网络隔离良好。然而任何容器逃逸或横向移动成功都会立即升级为严重风险。实操心得在检测时不要只满足于“服务能连通”。我曾遇到过一个案例Redis密码是复杂的但因为在docker-compose.override.yml中错误地覆盖了配置导致实际生效的仍是弱密码。务必检查所有可能生效的配置文件层。4. 修复方案全流程从紧急止血到长治久安发现漏洞后修复要分步进行优先阻断风险再完成安全加固。下面以基于docker-compose部署的Harbor v2.x为例。4.1 第一步紧急处置与临时加固如果检测确认存在弱口令且服务有暴露风险应立即进行网络层隔离。修改防火墙/安全组规则确保Redis6379和Notary Server4443的端口仅对Harbor集群内的其他容器或必要的管理IP开放禁止公网和无关内网访问。评估入侵迹象检查Redis和Notary数据库中有无异常键值、操作日志。对于Redis可以检查INFO commandstats查看命令历史对于Notary可以检查数据库中的changefeed表或审计日志如果开启。重置会话由于Redis中存储的会话可能已泄露建议所有用户登出Harbor UI。可以通过重启Harbor的core服务来使现有会话失效这会带来短暂服务中断。4.2 第二步彻底修改Redis密码操作流程如下停止Harbor服务cd /your/harbor/install/path docker-compose down生成强密码使用密码生成器或命令生成一个足够复杂长度大于16位包含大小写字母、数字、特殊字符的密码。例如openssl rand -base64 24假设生成的新密码为A1b2C3d4$E5f6^G7h8*I9j0修改主配置文件harbor.yml# 找到external_redis部分如果使用外部Redis或redis部分 # 对于内置Redis通常是 redis: password: A1b2C3d4$E5f6^G7h8*I9j0 # 其他配置...对于老版本密码可能在docker-compose.yml的Redis服务环境变量中直接设置。但最佳实践是统一在harbor.yml中修改因为Harbor的安装脚本会读取此文件并生成最终的docker-compose.yml。更新所有相关服务的连接密码这是关键Redis密码修改后所有连接它的服务core, portal, jobservice等都必须更新。在harbor.yml中这些服务的Redis连接配置通常由全局的redis部分定义安装脚本会自动处理。但务必确认。 手动检查docker-compose.yml中所有包含REDIS_URL或_REDIS_URL环境变量的服务其URL中的密码部分是否已更新。例如core: ... environment: - REDIS_URLredis://:A1b2C3d4$E5f6^G7h8*I9j0redis:6379/0重新部署配置# 运行Harbor的安装脚本应用新的harbor.yml配置 ./install.sh --with-notary --with-chartmuseum # 根据你的组件选择参数 # 或者使用prepare脚本后再启动 ./prepare docker-compose up -d验证使用新密码连接Redis确认可以访问。访问Harbor UI进行登录、推送、拉取镜像等操作确认所有功能正常。4.3 第三步彻底修改Notary数据库密码Notary的密码修改涉及数据库和两个服务Server, Signer步骤更需谨慎。备份Notary数据库这是必须的连接到Notary使用的PostgreSQL数据库通常在harbor-db容器内或独立实例。# 进入数据库容器 docker exec -it harbor-db bash # 备份notaryserver和notarysigner数据库 pg_dump -U postgres notaryserver /tmp/notaryserver_backup.sql pg_dump -U postgres notarysigner /tmp/notarysigner_backup.sql # 退出容器将备份文件复制到宿主机 docker cp harbor-db:/tmp/notaryserver_backup.sql . docker cp harbor-db:/tmp/notarysigner_backup.sql .生成新的强密码为Notary Server和Notary Signer分别生成两个新的强密码。Notary Server DB 密码Nserver_NewPass123!#Notary Signer DB 密码Nsigner_NewPass456$%^修改数据库用户密码docker exec -it harbor-db bash psql -U postgres在psql命令行中执行ALTER USER notaryserver WITH PASSWORD Nserver_NewPass123!#; ALTER USER notarysigner WITH PASSWORD Nsigner_NewPass456$%^; \q exit修改Harbor配置文件harbor.ymlnotary: server: db_password: Nserver_NewPass123!# signer: db_password: Nsigner_NewPass456$%^重新部署Notary组件Notary的配置在Harbor启动时被注入到容器中。需要重新运行安装脚本或prepare脚本。# 如果使用install.sh确保包含--with-notary参数 ./install.sh --with-notary # 或者先./prepare再单独启动Notary服务 docker-compose up -d notary-server notary-signer验证观察Notary Server和Signer容器的日志确认无数据库连接错误。docker-compose logs -f notary-server在Harbor UI中尝试对镜像进行签名和验证操作测试完整流程是否正常。重要注意事项修改Notary数据库密码后之前已签名的镜像的信任数据仍然有效因为它们存储在数据库里我们只是更改了访问数据库的密码并没有改变签名密钥本身。但如果在这个过程中数据库连接失败可能导致新的签名操作失败。5. 加固与最佳实践构建纵深防御修复默认弱口令只是第一步要构建一个安全的Harbor环境还需要采取以下纵深防御措施5.1 网络隔离与访问控制最小化网络暴露使用Docker自定义网络或Kubernetes NetworkPolicy确保Redis、Notary DB、Notary服务端口只被必需的Harbor服务访问。入口网关防护在Harbor前端配置Ingress Controller如Nginx或API网关实施严格的访问控制列表ACL和速率限制。定期端口扫描从外部和内部网络定期对Harbor主机进行端口扫描确保无意外端口开放。5.2 配置与密钥管理杜绝默认配置任何公开的默认密码、默认路径、默认账号都必须修改。这不仅是Redis和Notary还包括Harbor的admin密码、数据库密码等。使用密钥管理服务在生产环境考虑使用HashiCorp Vault、AWS Secrets Manager或Kubernetes Secrets来管理密码而不是以明文形式写在harbor.yml中。Harbor支持通过环境变量注入密码。配置文件权限确保harbor.yml等配置文件的权限设置为600仅限root或部署用户读取。5.3 审计与监控启用审计日志在harbor.yml中配置审计日志并定期审查关键操作特别是项目创建、用户权限变更、镜像删除和签名操作。监控组件状态对Redis的内存使用、连接数Notary服务的请求延迟和错误率进行监控异常波动可能意味着攻击或配置问题。定期漏洞扫描使用镜像安全扫描工具如Trivy、ClairHarbor已集成扫描仓库中的镜像同时也要定期对Harbor本身的组件进行CVE漏洞扫描。5.4 高可用与备份Redis高可用对于生产环境考虑使用Redis Sentinel或Redis Cluster替代单节点Redis提升可用性和数据安全性。Notary私钥保护Notary的根密钥Root Key非常重要且一旦丢失无法恢复。确保按照Notary官方最佳实践在安全、离线的地方备份根密钥。定期全量备份制定计划定期备份Harbor的数据库PostgreSQL、Redis持久化数据如果开启以及镜像存储卷。6. 故障排查与常见问题实录在修复过程中你可能会遇到以下问题。这里记录了我踩过的坑和解决方案。6.1 修改密码后Harbor服务启动失败问题现象执行docker-compose up -d后harbor-core或harbor-jobservice容器不断重启日志显示Redis connection refused或NOAUTH。排查思路检查密码一致性这是最常见的原因。使用docker-compose config命令查看最终生成的配置确认所有服务连接Redis的URL中的密码是否一致。特别注意jobservice、core、portal这三个服务。检查密码特殊字符如果密码包含、:、/等URL特殊字符需要在连接字符串中进行URL编码。例如应编码为%40。最好在生成密码时就避免使用这些字符。验证Redis服务本身进入Redis容器检查其是否以正确的密码启动。docker exec harbor-redis redis-cli -a 你的新密码 info server查看详细日志docker-compose logs --tail100 core解决方案确保harbor.yml中的redis.password值正确并且重新运行./prepare脚本让Harbor重新生成所有服务的配置文件。如果手动修改了docker-compose.yml请回滚始终以harbor.yml为唯一信源。6.2 Notary服务无法连接数据库问题现象Notary-server或Notary-signer容器日志持续报错dial tcp ... connect: connection refused或pq: password authentication failed for user。排查思路确认数据库服务确保harbor-db容器正常运行并且PostgreSQL监听端口默认5432在容器网络内可访问。验证数据库用户和密码docker exec -it harbor-db bash psql -U notaryserver -d notaryserver -W # 输入修改后的密码看能否登录检查Notary配置文件进入Notary容器查看实际生效的配置文件。docker exec harbor-notary-server cat /etc/notary/server.json | grep db_url确认连接字符串中的主机名如postgresql、端口、数据库名、用户名和密码都正确。注意在容器网络中数据库主机名通常是harbor-db或postgresql。解决方案如果密码验证失败回到数据库重新修改密码。如果连接被拒绝检查harbor-db容器的健康状态和网络连通性。确保在harbor.yml中修改密码后重新执行了安装或prepare步骤。6.3 修改后原有镜像签名验证失败问题现象修改Notary配置后之前已签名的镜像在拉取时提示“签名无效”或“信任数据过期”。排查原因这通常不是修改数据库密码导致的。密码修改不影响已存储的签名数据。更可能的原因是Notary服务数据卷丢失如果Notary的数据库或私钥存储卷在操作中被意外移除或覆盖。系统时间不同步Notary签名具有时效性如果服务器时间发生大幅跳变可能导致签名验证失败。信任根变更如果你完全重新部署了Notary包括初始化新的信任根那么旧签名当然无法验证。解决方案对于原因1从备份中恢复Notary数据库。对于原因2使用NTP同步所有服务器时间。对于原因3这是一个破坏性操作需要通知所有用户重新签名镜像。因此在生产环境操作Notary相关组件时备份是第一要务。6.4 升级Harbor版本后配置回退问题现象升级Harbor版本后发现Redis或Notary的密码又被重置为默认值。排查与预防Harbor的升级脚本有时会基于默认模板生成新的配置文件。在升级前备份当前配置备份整个Harbor安装目录特别是harbor.yml和docker-compose.yml。查阅官方升级文档仔细阅读目标版本的Release Notes和升级指南看是否有配置迁移的说明。在测试环境演练任何升级操作都应在测试环境先行验证。升级后立即检查升级完成后第一时间检查关键服务的配置确认密码等敏感信息是否被保留。7. 自动化安全巡检脚本示例手动检查毕竟低效我们可以编写简单的Shell脚本定期对Harbor进行基础安全巡检。#!/bin/bash # harbor_security_check.sh # 基础Harbor安全配置巡检脚本 set -e HARBOR_DIR/opt/harbor HARBOR_HOSTlocalhost echo [*] 开始Harbor安全巡检 $(date) # 1. 检查Redis密码强度通过配置文件 echo [1] 检查Redis密码配置... REDIS_PASS$(grep -A2 ^redis: $HARBOR_DIR/harbor.yml | grep password: | awk {print $2} | tr -d \) if [[ -z $REDIS_PASS ]]; then echo [严重] harbor.yml中未找到redis密码配置 elif [[ $REDIS_PASS redis123 || $REDIS_PASS password || ${#REDIS_PASS} -lt 12 ]]; then echo [高危] Redis密码强度不足或为默认值: $REDIS_PASS else echo [通过] Redis密码已配置且非明显弱口令。 fi # 2. 检查Redis端口暴露情况本地 echo [2] 检查Redis端口本地监听... if netstat -tlnp | grep :6379 | grep -v grep; then echo [信息] Redis服务正在监听。 # 检查是否绑定在0.0.0.0 if netstat -tlnp | grep :6379 | grep 0.0.0.0; then echo [警告] Redis端口绑定在0.0.0.0请检查网络策略。 fi else echo [信息] 未发现Redis端口本地监听可能为容器内访问模式。 fi # 3. 检查Notary密码配置简化版检查配置文件中的默认值 echo [3] 检查Notary密码配置示例... if grep -r notary_server_password\|notary_signer_password $HARBOR_DIR --include*.yml --include*.json; then echo [高危] 发现疑似Notary默认密码配置 else echo [通过] 未在配置文件中发现明显的Notary默认密码。 fi # 4. 检查关键配置文件权限 echo [4] 检查关键文件权限... for file in $HARBOR_DIR/harbor.yml $HARBOR_DIR/.env; do if [[ -f $file ]]; then perm$(stat -c %a $file) if [[ $perm ! 600 ]]; then echo [警告] 文件 $file 权限为 $perm建议设置为 600。 fi fi done echo [*] 基础巡检完成。请注意此脚本仅为基本检查完整安全评估需结合网络扫描、日志审计等手段。这个脚本提供了基础检查思路你可以根据实际环境扩展比如增加对公网端口扫描、数据库连接测试等功能。定期运行此类脚本能帮助你在问题扩大前及时发现隐患。安全是一个持续的过程修复Harbor的默认弱口令漏洞是一个重要的起点但绝非终点。将它纳入你的常态化安全运维体系结合严格的访问控制、持续的监控和定期的审计才能为你的容器镜像仓库构筑起真正坚固的防线。