操作系统云原生容器运行时【免费下载链接】linuxkitA toolkit for building secure, portable and lean operating systems for containers项目地址https://gitcode.com/gh_mirrors/li/linuxkit点击查看免费下载本指南以 linuxkit 仓库中 vendored 的github.com/google/go-containerregistry/pkg/authn包 README 为核心骨架结合其源码实现与 linuxkit 构建工具链的实际调用场景系统讲解镜像仓库凭据的获取、解析与认证流程。读完本文你将掌握DefaultKeychain的查找顺序、Dockerconfig.json的字段含义、credential helper 协议的工作原理以及如何用NewMultiKeychain在 LinuxKit 的linuxkit pkg、linuxkit cache等命令中组合多源凭据。一、背景为什么需要一个专门的authn包LinuxKit 是一个用于构建安全、可移植、精简容器操作系统的工具包其src/cmd/linuxkit下的 Go 工具链在构建与发布过程中需要频繁与镜像仓库交互拉取linuxkit/kernel等基础镜像、推送构建产物到自定义 registry。这些操作全部经由 vendored 的 go-containerregistry 完成而其中负责凭据获取与认证的正是pkg/authn子包本文档位于 authn/README.md。该包的设计目标非常明确尽可能模拟docker的认证行为与配置约定使用户只要配置过能配合docker使用的凭据这套库就能开箱即用。官方关于 docker 认证的文档分散在多个网站与 GitHub 仓库中这份 README 把相关要点集中梳理本文在此基础上结合仓库源码进一步展开。从源码结构看authn包的核心抽象只有三个抽象定义文件职责Authenticatorauthn.go生成用于 HTTPAuthorization头的AuthConfigKeychainkeychain.go将一个镜像引用Resource解析为对应的AuthenticatorResourcekeychain.go表示可被认证的 registry 或仓库如gcr.io/my-project或gcr.ioKeychain.Resolve(target)拿到一个Resource返回一个能产出AuthConfig的Authenticator最终由 HTTP 传输层把它放进Authorization请求头。这个解析与认证的两段式设计让凭据来源配置文件、环境变量、云厂商 helper与认证方式Basic、Bearer、OAuth2彻底解耦。二、给包使用者的快速指南tl;dr2.1 默认行为是匿名访问默认情况下pkg/v1/remote 使用Anonymous凭据——也就是没有任何凭据。对大多数 registry 而言这仅允许读取公共镜像。Anonymous是一个单例Authenticator其Authorization()直接返回空的AuthConfig{}见 anon.go。这也是 linuxkit 工具链在未显式配置凭据时的兜底行为所有remote.WithAuthFromKeychain(...)调用点最终都会退化到匿名访问。2.2 使用DefaultKeychain读取 Docker 配置凭据想要使用 Docker config 文件中的凭据只需传入DefaultKeychainpackage main import ( fmt github.com/google/go-containerregistry/pkg/authn github.com/google/go-containerregistry/pkg/name github.com/google/go-containerregistry/pkg/v1/remote ) func main() { ref, err : name.ParseReference(registry.example.com/private/repo) if err ! nil { panic(err) } // 使用默认凭据拉取 manifest img, err : remote.Get(ref, remote.WithAuthFromKeychain(authn.DefaultKeychain)) if err ! nil { panic(err) } // 打印 registry.example.com/private/repo 的 digest fmt.Println(img.Digest) }DefaultKeychain会依次尝试以下位置的凭据具体逻辑见 keychain.go 的ResolveContext实现~/.docker/config.jsonWindows 上为%USERPROFILE%\.docker\config.json若未找到则读取DOCKER_CONFIG环境变量指向的目录下的config.json若仍未找到回退到 Podman 的凭据位置${XDG_RUNTIME_DIR}/containers/auth.json同时兼容REGISTRY_AUTH_FILE环境变量指定的文件以上全部缺失时返回Anonymous。关于该文件的字段含义见下文四、Docker Config 认证。2.3 LinuxKit 中的实际用法在 linuxkit 源码中DefaultKeychain被广泛接入各条镜像操作链路均通过remote.WithAuthFromKeychain(authn.DefaultKeychain)注入镜像拉取cache/pull.go镜像推送cache/push.go、cache/write.go、cache/write.go远端 tag 解析pkg_remotetag.go包编译与索引pkglib/dockerimpl.go、pkglib/index.go这意味着只要你的构建/CI 环境里已经执行过docker login或配置了对应 credential helperlinuxkit pkg、linuxkit cache、linuxkit build等命令就能直接复用同一套凭据访问私有 registry无需额外配置。三、模拟云厂商的 Credential Helper3.1 为什么需要模拟docker 官方依赖形如docker-credential-gcr、docker-credential-ecr-login的可执行文件来获取云厂商短时凭据。但在 Go 程序内部与其依赖外部二进制不如直接调用同功能的 Go 实现。authn包为此提供了两个层次的支持pkg/v1/google.Keychain模拟docker-credential-gcr从环境变量google.NewEnvAuthenticator或 gcloud 配置google.NewGcloudAuthenticator中解析 GCP 凭据NewKeychainFromHelper(helper)把满足 credentials.Helper 接口子集的 Go 实现包装成Keychain。该接口只需实现一个Get(serverURL) (username, password, error)方法见 keychain.go。3.2 模拟 ECR 凭据助手import ( ecr github.com/awslabs/amazon-ecr-credential-helper/ecr-login github.com/awslabs/amazon-ecr-credential-helper/ecr-login/api github.com/google/go-containerregistry/pkg/authn github.com/google/go-containerregistry/pkg/v1/remote ) func main() { // ... ecrHelper : ecr.ECRHelper{ClientFactory: api.DefaultClientFactory{}} img, err : remote.Get(ref, remote.WithAuthFromKeychain(authn.NewKeychainFromHelper(ecrHelper))) if err ! nil { panic(err) } // ... }3.3 模拟 Azure ACR 凭据助手import ( github.com/chrismellard/docker-credential-acr-env/pkg/credhelper github.com/google/go-containerregistry/pkg/authn github.com/google/go-containerregistry/pkg/v1/remote ) func main() { // ... acrHelper : credhelper.NewACRCredentialsHelper() img, err : remote.Get(ref, remote.WithAuthFromKeychain(authn.NewKeychainFromHelper(acrHelper))) if err ! nil { panic(err) } // ... }3.4token约定的特殊处理NewKeychainFromHelper的包装实现keychain.go有一个值得注意的细节当 helper 返回的Username是字面量token时返回的AuthConfig会把Secret/password 放入IdentityToken字段而非Password字段。这与 Docker 官方 credential helper 协议 的约定一致也直接决定了后续走 OAuth2 认证路径见六、与 Registry 的认证。四、Docker Config 认证4.1 明文凭据Plaintext执行docker login后凭据会写入 config 文件内容形如{ auths: { registry.example.com: { auth: QXp1cmVEaWFtb25kOmh1bnRlcjI } } }auths是一个按 registry 为键的映射auth字段的值是username:password经 HTTP Basic Auth 编码后的结果即base64(username:password)。这意味着凭据以明文存储$ echo QXp1cmVEaWFtb25kOmh1bnRlcjI | base64 -d AzureDiamond:hunter2需要强调上述 base64 并非加密只是编码。authn包在解析该字段时的实现authn.go会先判断字符串是否以结尾带填充用base64.StdEncoding不带填充用base64.RawStdEncoding然后按:拆分为用户名与密码。该配置与下面这种写法完全等价{ auths: { registry.example.com: { username: AzureDiamond, password: hunter2 } } }了解这一点非常实用当 CI 系统通过环境变量提供 registry 用户名与密码时你可以不调用docker login直接按此格式手工生成 config 文件。AuthConfig的UnmarshalJSON会在两种形态之间自动双向转换authn.go。4.2 凭据助手Helpersdocker 会警告应使用 credential helper 而不是明文存储凭据——你也应该这么做。配置全局 credential helper{ credsStore: osxkeychain }配置按 registry 区分的 credential helper{ credHelpers: { gcr.io: gcr } }authn包通过github.com/docker/cli/cli/config.Load解析 config 文件并调用必要的 credential helper见 keychain.go 的导入与 L114-L118 的加载逻辑。该函数负责完成ConfigFile registry 域名 →AuthConfig的转换从而决定最终的认证方式。ResolveContext中还会依次用target.String()与target.RegistryStr()两个键去查GetAuthConfig并对 Docker Hub 使用历史遗留键https://index.docker.io/v1/DefaultAuthKey见 keychain.go。五、Credential Helper 协议credential helper 协议允许你配置一个二进制程序来为 registry 提供凭据而不是把凭据硬编码进 config 文件。协议包含多个动词其中authn包最关心的是get。例如使用如下 config{ credHelpers: { gcr.io: gcr, eu.gcr.io: gcr } }要获取gcr.io的凭据时在credHelpers映射中找到其 helper 名为gcr在前面拼接docker-credential-前缀得到二进制名docker-credential-gcr它必须位于$PATH中然后通过 STDIN 传入域名调用$ echo gcr.io | docker-credential-gcr get {Username:_token,Secret:long access token}同一 helper 可以服务多个 registry这也是为什么必须把域名经 STDIN 传入$ echo eu.gcr.io | docker-credential-gcr get {Username:_token,Secret:long access token}5.1 调试 credential helper当配置了 helper 却看起来没生效时调试是件麻烦事。实现一个假 helper 可以帮你定位失败环节。这个假 helper硬编码返回凭据#!/usr/bin/env bash echo {Username:token,Secret:hunter2}这个 helper 把docker-credential-gcr的输出同时打到 stderr 和调用方从而偷听另一个 helper#!/usr/bin/env bash docker-credential-gcr $ | tee (cat 12)把这两个文件放到$PATH中分别命名为docker-credential-hardcoded和docker-credential-tee然后修改 config 使用它们{ credHelpers: { gcr.io: tee, eu.gcr.io: hardcoded } }docker-credential-tee这个技巧对crane和docker都有效$ crane manifest gcr.io/google-containers/pause /dev/null {ServerURL:,Username:_dcgcr_1_5_0_token,Secret:redacted} $ docker pull gcr.io/google-containers/pause Using default tag: latest {ServerURL:,Username:_dcgcr_1_5_0_token,Secret:redacted} latest: Pulling from google-containers/pause a3ed95caeb02: Pull complete 4964c72cd024: Pull complete Digest: sha256:a78c2d6208eff9b672de43f880093100050983047b7b0afe0217d3656e1b0d5f Status: Downloaded newer image for gcr.io/google-containers/pause:latest gcr.io/google-containers/pause:latest5.2 凭据解析的完整调用链从源码角度梳理一遍DefaultKeychain的完整解析流程keychain.go加锁dk.mu.Lock()保证并发场景下解析安全依次探测~/.docker/config.json、$DOCKER_CONFIG/config.json、$REGISTRY_AUTH_FILE、$XDG_RUNTIME_DIR/containers/auth.json四个位置命中其一则用config.Load/config.LoadFromReader解析全部未命中 → 返回Anonymous用target.String()与target.RegistryStr()依次查GetAuthConfig对 Docker Hub 替换为DefaultAuthKey拿到非空AuthConfig后清空其ServerAddress字段再做是否为空判断避免误判见注释引用的 go-containerregistry issue #1510最终通过FromConfig包装为Authenticator返回。FromConfigauth.go只是简单地把AuthConfig原样返回是各种Authenticator的公共底座。六、组合多个 KeychainNewMultiKeychain允许你指定多个Keychain实现需要凭据时按顺序逐一检查。其源码multikeychain.go逻辑非常直接依次对每个Keychain调用Resolve一旦某个返回的Authenticator不是Anonymous就立即采用否则继续下一个全部失败则回退到Anonymous。kc : authn.NewMultiKeychain( authn.DefaultKeychain, google.Keychain, authn.NewKeychainFromHelper(ecr.ECRHelper{ClientFactory: api.DefaultClientFactory{}}), authn.NewKeychainFromHelper(acr.ACRCredHelper{}), )这个组合 keychain 的检查顺序为先查 Docker config 文件中的凭据见上文再查环境中的 GCP 凭据见上文然后模拟 ECR credential helper 获取凭据最后模拟 ACR credential helper 获取凭据。只要任一 keychain 能提供凭据就用它不再咨询后续 keychain若全部无法提供则使用Anonymous。这种优先级链模式非常适合多集群、多云混合的构建环境——例如 LinuxKit 在 AWS 构建机推 ECR、在 GCP 构建机推 GCR 时一份代码即可无缝切换凭据来源。七、与 Registry 的认证Token 与 OAuth2与 registry 认证有两种方式token 与 oauth2。两者都用于获取一个不透明的Bearer令牌即AuthConfig中的RegistryToken字段放进Authorization请求头使用。registry 会在版本检查或常规操作期间返回401 Unauthorized并附带Www-Authenticate质询头指明应如何继续。7.1 Token 方式当拿到的AuthConfig包含Username/Password或Auth字段时走 token 方式认证流程可参照 credhelper-basic.svg 的示意图即Basic 凭据 → 向 registry 换 token → 携带 Bearer token 访问。对应地包内提供了两个内置AuthenticatorBasicbasic.go直接返回Username/PasswordBearerbearer.go直接把已持有的令牌放入RegistryToken字段。7.2 OAuth2 方式当AuthConfig包含IdentityToken字段时走 oauth2 方式认证流程可参照 credhelper-oauth.svg 的示意图。触发条件是credential helper 返回的响应中Username被设置为token注意这不是占位符而是字面字符串token。为什么会这样设计官方自己也表示不太清楚见 moby/moby issue #36926。该包仅支持 oauth2 的refresh_token类型的grant_type见 go-containerregistry issue #629原因是仅凭 registry 响应无法判断该用 oauth 还是 token而 token 方式被绝大多数 registry 广泛实现因此 oauth2 仅作为兼容补充。八、在 LinuxKit 中的端到端实践建议综合以上机制在实际使用 LinuxKit 工具链时可参考以下凭据配置路径单 registry、本机开发直接docker login registryDefaultKeychain自动生效无需任何额外代码CI 环境注入用户名/密码按4.1 明文凭据的username/password格式手工生成$DOCKER_CONFIG/config.json或设置REGISTRY_AUTH_FILE指向该文件云厂商 registryGCR/ECR/ACR优先使用NewMultiKeychain组合DefaultKeychain与各云厂商 helper 的 Go 实现google.Keychain、NewKeychainFromHelper避免依赖外部二进制排查凭据问题利用5.1 调试中的docker-credential-tee技巧确认 helper 是否被正确调用、返回的Username/Secret是否符合预期安全底线理解auth字段是明文 base64 而非加密生产环境务必改用 credential helpercredsStore/credHelpers不要把私钥类敏感凭据写进 config 文件。九、源码速查表关注点源码位置Authenticator/AuthConfig定义与 base64 编解码authn.goKeychain/DefaultKeychain/ helper 适配 / 刷新缓存keychain.goNewMultiKeychain顺序解析multikeychain.go匿名认证单例anon.goBasic/Bearer/FromConfig三种 Authenticatorbasic.go、bearer.go、auth.goLinuxKit 拉取镜像时注入凭据cache/pull.goLinuxKit 推送镜像时注入凭据cache/push.go、cache/write.goLinuxKit 解析远端包 tag 时注入凭据pkg_remotetag.goLinuxKit 包编译/索引时注入凭据pkglib/dockerimpl.go、pkglib/index.go提示keychain.go中还提供了RefreshingKeychainkeychain.go可为内层 keychain 增加按duration周期性刷新凭据的能力——对于短时令牌类凭据如云厂商的 access token这是避免过期失效的常用手段具体可结合自身场景选用。赞分享操作系统云原生容器运行时【免费下载链接】linuxkitA toolkit for building secure, portable and lean operating systems for containers项目地址https://gitcode.com/gh_mirrors/li/linuxkit点击查看免费下载相关推荐KubeSphere 中的容器镜像仓库认证go-containerregistry authn 包完整指南KubeSphere 中的容器镜像仓库认证go containerregistry authn 包完整指南 导读 本文以 KubeSphere 仓库所引入的第后端云原生容器编排微服务Slim(toolkit) 中的容器镜像注册表认证深入解析 go-containerregistry authn 包的凭证获取机制Slim toolkit 中的容器镜像注册表认证深入解析 go containerregistry authn 包的凭证获取机制 导读 本文以 Slim to云原生CLI应用安全Tekton Pipeline 依赖库 go-containerregistry authn 包深度解析容器镜像仓库认证的 Keychain 机制与 Docker 配置兼容Tekton Pipeline 依赖库 go containerregistry authn 包深度解析容器镜像仓库认证的 Keychain 机制与 Dock云原生CI/CDDevOps后端上一篇Shell变量作用域性能优化终极指南gh_mirrors/sh1/sh中的高效缓存策略 下一篇CLIPMLP架构揭秘improved-aesthetic-predictor核心原理详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考