AWS ECR Push and Pull Private Image#
Keywords: AWS, Amazon, Elastic Container Registry, ECR, Auth, Authentication, Push, Pull, Private, Image.
What’s the Problem?#
AWS ECR 是一个私有的 Container Registry, 你当然是要鉴权才能够 Pull 和 Pull Container Image 了. AWS 支持用 Docker CLI 客户端来做这件事.
Overview#
执行下面的命令获得一个 token 用于登录某个 aws account, 某个 aws region 下的 ecr:
aws ecr get-login --region <aws-region> --no-include-email --profile <aws-profile>
上面的命令会返回一个 token 字符串, 然后你就可以让你的 client login ECR 了:
docker login -u AWS -p <token-value> https://<aws-account-id>.dkr.ecr.<aws-region>.amazonaws.com.
其中 <token-value> 部分就是验证用的 token. 这个字符串就是登录命令, 可以直接拷贝到命令行中执行. 所以你甚至可以直接使用下面的命令执行它, 免去了复制粘贴的步骤:
$(aws ecr get-login --region <aws-region> --no-include-email --profile <aws-profile>)
根据 docker login 的文档 -p 命令是不安全的, 会将 token 暴漏在 cli 的命令历史记录中, 官方推荐使用 --password-stdin
选项传入 token. 所以最终的命令是这样的:
AWS_REGION="us-east-1"
AWS_PROFILE="my-aws-profile"
ecr_uri="https://111122223333.dkr.ecr.${AWS_REGION}.amazonaws.com"
aws ecr get-login --no-include-email --region ${AWS_REGION} --profile ${AWS_PROFILE} | awk '{printf $6}' | docker login -u AWS ${ecr_uri} --password-stdin
在这之后, docker pull
或是 docker push
就会有操作权限了.
Automation Scripts#
这里我写了一个脚本, 可以非常方便地让 docker cli login 到 ECR, 适合人类用. 脚本内容如下:
ecr_login.py
1# -*- coding: utf-8 -*-
2
3"""
4This shell script automates docker login to AWS ECR.
5
6Requirements:
7
8- Python3.7+
9- `fire>=0.1.3,<1.0.0 <https://pypi.org/project/fire/>`_
10
11Usage:
12
13.. code-block:: bash
14
15 $ python ecr_login.py -h
16"""
17
18import typing as T
19import boto3
20import base64
21import subprocess
22
23import fire
24
25
26def get_ecr_auth_token_v1(
27 ecr_client,
28 aws_account_id,
29) -> str:
30 """
31 Get ECR auth token using boto3 SDK.
32 """
33 res = ecr_client.get_authorization_token(
34 registryIds=[
35 aws_account_id,
36 ],
37 )
38 b64_token = res["authorizationData"][0]["authorizationToken"]
39 user_pass = base64.b64decode(b64_token.encode("utf-8")).decode("utf-8")
40 auth_token = user_pass.split(":")[1]
41 return auth_token
42
43
44def get_ecr_auth_token_v2(
45 aws_region: str,
46 aws_profile: T.Optional[str] = None,
47):
48 """
49 Get ECR auth token using AWS CLI.
50 """
51 args = ["aws", "ecr", "get-login", "--region", aws_region, "--no-include-email"]
52 if aws_profile is not None:
53 args.extend(["--profile", aws_profile])
54 response = subprocess.run(args, check=True, capture_output=True)
55 text = response.stdout.decode("utf-8")
56 auth_token = text.split(" ")[5]
57 return auth_token
58
59
60def docker_login(
61 auth_token: str,
62 registry_url: str,
63) -> bool:
64 """
65 Login docker cli to AWS ECR.
66
67 :return: a boolean flag to indicate if the login is successful.
68 """
69 pipe = subprocess.Popen(["echo", auth_token], stdout=subprocess.PIPE)
70 response = subprocess.run(
71 ["docker", "login", "-u", "AWS", registry_url, "--password-stdin"],
72 stdin=pipe.stdout,
73 capture_output=True,
74 )
75 text = response.stdout.decode("utf-8")
76 return "Login Succeeded" in text
77
78
79def main(
80 aws_profile: T.Optional[str] = None,
81 aws_account_id: T.Optional[str] = None,
82 aws_region: T.Optional[str] = None,
83):
84 """
85 Login docker cli to AWS ECR using boto3 SDK and AWS CLI.
86
87 :param aws_profile: specify the AWS profile you want to use to login.
88 usually this parameter is used on local laptop that having awscli
89 installed and configured.
90 :param aws_account_id: explicitly specify the AWS account id. if it is not
91 given, it will use the sts.get_caller_identity() to get the account id.
92 you can use this to get the auth token for cross account access.
93 :param aws_region: explicitly specify the AWS region for boto3 session
94 and ecr repo. usually you need to set this on EC2, ECS, Cloud9,
95 CloudShell, Lambda, etc ...
96 """
97 boto_ses = boto3.session.Session(
98 region_name=aws_region,
99 profile_name=aws_profile,
100 )
101 ecr_client = boto_ses.client("ecr")
102 if aws_account_id is None:
103 sts_client = boto_ses.client("sts")
104 res = sts_client.get_caller_identity()
105 aws_account_id = res["Account"]
106
107 print("get ecr auth token ...")
108 auth_token = get_ecr_auth_token_v1(
109 ecr_client=ecr_client,
110 aws_account_id=aws_account_id,
111 )
112 if aws_region is None:
113 aws_region = boto_ses.region_name
114 print("docker login ...")
115 flag = docker_login(
116 auth_token=auth_token,
117 registry_url=f"https://{aws_account_id}.dkr.ecr.{aws_region}.amazonaws.com",
118 )
119 if flag:
120 print("login succeeded!")
121 else:
122 print("login failed!")
123
124
125def run():
126 fire.Fire(main)
127
128
129if __name__ == "__main__":
130 run()
初次之外, 我还实现了一个对于 DevOps 脚本友好的 Python 模块 aws_ecr.py. 适合机器用来在 CI/CD 中自动化登录 ECR.