docker-credential-acr-helper: 一个辅助 docker 获取阿里云 ACR 镜像仓库访问凭证的项目

前言

通常情况下,如果我们想对阿里云容器镜像服务 ACR 上的私有镜像进行 docker pulldocker push 的话, 需要提前通过 docker login 命令配置相应的访问凭证。

通过 docker login 命令配置用户名和密码的方法存在如下几个问题:

  • 需要用户多记录和维护一组 docker 专用的密码,密码的管理是一个比较麻烦的事情。
  • ACR 只支持配置一个无过期时间的固定密码,密码的更换和吊销的成本很高,用户轻易不敢操作。
  • 无法精细化配置固定密码的权限,无法实现类似只允许进行 pull 操作不允许进行 push 操作的权限控制需求。
  • 虽然可以通过 Open API 获取不限量的临时密码,但是 docker login 不支持自动刷新临时密码。 如果使用临时密码进行 docker login 操作的话, 需要用户频繁进行获取临时密码然后再通过 docker login 更新密码的操作,同样是一个很麻烦的事情。

幸好,docker 提供提供了一个叫 Credential helper 的机制, 通过 Credential helper 可以以插件化的方式 扩展 docker 获取访问凭证的方式,不再局限于只能通过 docker login 的方式配置访问凭证。

本文将介绍的 docker-credential-acr-helper 就是一个专为 ACR 开发的辅助 docker 获取 ACR 镜像仓库访问凭证的项目。

介绍

如前面所说, docker-credential-acr-helper 是一个专为 ACR 开发的辅助 docker 获取 ACR 镜像仓库访问凭证的项目。

docker-credential-acr-helper 解决了前面所说的那几个问题:

  • 基于阿里云已有的认证体系,可以直接使用用户熟悉的阿里云访问凭证,无需额外记录和维护 docker 专用的用户名和密码。
  • 自动获取用于进行 docker 操作的临时密码,不依赖固定密码, 也无需手动频繁刷新临时密码。
  • 用户可以通过配置阿里云 RAM 访问控制策略的方式,实现临时密码精细化权限控制的需求,详见 ACR 文档

使用示例

可以通过如下步骤体验这个项目提供的功能:

  1. 前往 github releases 页面下载最新版本的编译好的二进制文件压缩包

  2. 使用页面上的那个 checksums.txt 文件验证压缩包,解压压缩包得到对应的二进制文件 docker-credential-acr-helper

  3. chmod +x docker-credential-acr-helper

  4. cp docker-credential-acr-helper /usr/local/bin

  5. 配置阿里云访问凭证,比如使用配置文件指定访问凭证:

    $ cat ~/.alibabacloud/credentials
    [default]                          # 默认客户端
    type = access_key                  # 认证方式为 access_key
    access_key_id = foo                # Key
    access_key_secret = bar            # Secret
    
  6. 通过 docker logout <acr_registry_domain> 退出要测试的 ACR registry 域名,清理对应已保存的 docker 凭证。

  7. 通过 docker pull <acr_image> 确认当前已无权限访问对应的 ACR 私有镜像。

  8. 修改 docker 配置文件 ~/.docker/config.jsoncredHelpers 配置项, 指定访问某个 ACR registry 域名时,使用 docker-credential-acr-helper 获取访问凭证 (关于这个配置的更多说明详见 Docker 官方文档 或者本项目 README)。 配置示例:

    {
      "credHelpers" : {
        "registry.cn-beijing.aliyuncs.com" : "acr-helper"
      }
    }
    
  9. 通过 docker pull <acr_image> 验证配置完成后又可以访问对应的 ACR 私有镜像了。

作为 golang package 被集成到第三方项目中

同时,也可以把这个项目当成一个 golang package 来使用,将这个项目的能力集成到第三方项目中。

比如,在使用 github.com/google/go-containerregistry/pkg/crane 操作 docker registry 时,可以使用下面的方法在项目中集成 docker-credential-acr-helper 提供的辅助认证能力:

import (
    "github.com/google/go-containerregistry/pkg/authn"
    "github.com/google/go-containerregistry/pkg/crane"
    "github.com/mozillazg/docker-credential-acr-helper/pkg/credhelper"
)

func main() {
    kc := authn.NewMultiKeychain(
            authn.DefaultKeychain,
            authn.NewKeychainFromHelper(credhelper.NewACRHelper()),  // <- here
    )
    ref := os.Getenv("REPO_URL")
    digest, err := crane.Digest(ref, crane.WithAuthFromKeychain(kc))
    if err != nil {
            panic(err)
    }
    fmt.Printf("got digest for %q:\n%s\n", ref, digest)
}

完整示例代码详见: examples/go-containerregistry-auth

FAQ

是否支持 ACR 企业版?

支持。

如何实现不同 ACR 域名使用不同的阿里云访问凭证?

可以通过为不同的访问凭证编写独立的 shell 脚本的方式实现。

比如:

$ cat /usr/local/bin/docker-credential-acr-helper-user-1
#!/usr/bin/env bash

# export ALIBABA_CLOUD_ACCESS_KEY_ID=foo
# export ALIBABA_CLOUD_ACCESS_KEY_SECRET=bar
export ALIBABA_CLOUD_CREDENTIALS_FILE=/path/to/user-1-credentials

exec /usr/local/bin/docker-credential-acr-helper "$@"

$ chmod +x /usr/local/bin/docker-credential-acr-helper-user-1

然后配置 ~/.docker/config.json 实现不同的 ACR 域名使用配置了不同访问凭证的 shell 脚本即可:

{
  "credHelpers" : {
    "registry.cn-beijing.aliyuncs.com" : "acr-helper",
    "registry.cn-hangzhou.aliyuncs.com" : "acr-helper-user-1",
    "registry.cn-shenzhen.aliyuncs.com" : "acr-helper-user-2"
  }
}

Comments