关键在于用docker_auth实现Token认证,其流程为:客户端docker pull触发Registry返回401及WWW-Authenticate头,指示去auth服务获取Token;客户端凭 credentials 请求签发含scope的JWT;后续请求携带该Token,由Registry验签并按ACL规则(如dev-用户仅可操作dev/仓库)授权。

要让私有 Registry 在生产环境真正管住谁、能做什么,关键不是加个密码就完事,而是用 Token 认证机制把“身份”和“权限”拆开管——认证归认证,授权归授权。docker_auth 是目前最成熟的选择,它不依赖简单账号密码,而是靠动态签发的短期 Token + 精细 ACL 规则来控制每次 pull/push/delete 请求。
Token 认证的核心流程必须走通
Registry 本身不验人,只看 Token。当客户端执行 docker pull 时,流程是:
- Registry 返回 401,并在
WWW-Authenticate头里明确告诉客户端:“去https://auth.example.com/token拿 Token,你要的操作是repository:prod/app:pull” - 客户端带着用户名密码(或 OAuth 凭据)向 auth 服务发起请求,拿到含签名、有效期、作用域的 JWT
- 客户端用这个 Token 重试拉取,Registry 验签+查 scope+比对策略,放行或拒绝
用 docker_auth 实现按角色/仓库前缀的差异化策略
htpasswd 只能决定“能不能登录”,docker_auth 能决定“能操作哪个镜像、能做什么”。配置示例:
- 开发组:
match: {account: "dev-*"}+actions: ["pull", "push"]+resources: ["repository:dev/*"] - 测试环境节点:
match: {account: "ci-test"}+actions: ["pull"]+resources: ["repository:test/*"] - 运维管理员:
match: {account: "admin"}+actions: ["pull", "push", "delete"]+resources: ["*"]
所有规则按顺序匹配,第一条命中即生效,不继续往下查。
Registry 和 Auth 服务必须解耦部署
不要把认证逻辑塞进 Registry 容器里。标准做法是:
- 单独运行 docker_auth 服务(官方镜像
cesanta/docker_auth),挂载 YAML 配置文件和 TLS 证书 - Registry 配置中只设
auth: token指向该服务地址,不存任何用户数据 - 两者都走 HTTPS,且 Registry 的
service名(如registry.example.com)必须与 docker_auth 配置中的realm严格一致
客户端登录行为要符合 Token 机制预期
docker login 并不直接连 Registry,而是连你配的 auth 服务。它做的事其实是:
- 把用户名密码 POST 到
/token接口,换取一个短期有效 Token - 把 Token 存进
~/.docker/config.json的auths字段(不是明文密码) - 后续所有请求,Docker CLI 自动在 Authorization 头填
Bearer xxx
这意味着:禁用某用户,只需停掉其账号在 docker_auth 中的匹配规则;回收权限,不用改客户端配置,Token 过期即失效。

















