現在如果使用 brew
更新 AWS CLI 會更新到 version 2,會發現原本使用的 ECR login 指令 $(aws ecr get-login --no-include-email --region us-west-2)
不能用會出現錯誤
usage: aws [options] <command> <subcommand> [<subcommand> ...] [parameters] To see help text, you can run: aws help aws <command> help aws <command> <subcommand> help aws: error: argument operation: Invalid choice, valid choices are: batch-check-layer-availability | batch-delete-image batch-get-image | complete-layer-upload create-repository | delete-lifecycle-policy delete-repository | delete-repository-policy describe-image-scan-findings | describe-images describe-repositories | get-authorization-token get-download-url-for-layer | get-lifecycle-policy get-lifecycle-policy-preview | get-repository-policy initiate-layer-upload | list-images list-tags-for-resource | put-image put-image-scanning-configuration | put-image-tag-mutability put-lifecycle-policy | set-repository-policy start-image-scan | start-lifecycle-policy-preview tag-resource | untag-resource upload-layer-part | get-login-password wait | help
AWS CLI v2 使用方法
因此就一定要使用新的指令來做 ECR Login,使用方法
aws ecr get-login-password | docker login --username AWS --password-stdin https://8888888888888.dkr.ecr.us-west-2.amazonaws.com
與 v1 版本指令不同需要自行輸入 username 為 AWS 與自己 ECR 的 Proxy Endpoint 位置來登入。
安全性分析
v1 版本
使用指令 aws ecr get-login --no-include-email --region us-west-2
會直接輸出
docker login -u AWS -p eyJwYXlsb2FkIjoiS3V3UXZJQ2FWWXBsNlBreHVzeGREekNIOHBaWkphNTFsS0dCelVS ... REFUQV9LRVkiLCJleHBpcmF0aW9uIjoxNTgyNTAwMTM2fQ== https://8888888888888.dkr.ecr.us-west-2.amazonaws.com
所以使用方法是 $(aws ecr get-login --no-include-email --region us-west-2)
把指令帶入,但是這樣可能會發生 shell 紀錄或是日誌紀錄密碼的風險,所以 v2 版本做了改進。
v2 版本
使用指令 aws ecr get-login-password
改為只有輸出密碼
eyJwYXlsb2FkIjoiTXFWWGR4d3BzNVZHbUNacThheDdhZ2Z6TXBwUjJJMVBDU1FETEIy ... REFUQV9LRVkiLCJleHBpcmF0aW9uIjoxNTgyNTAxMDE1fQ==
因此使用方法改為 aws ecr get-login-password | docker login --username AWS --password-stdin https://8888888888888.dkr.ecr.us-west-2.amazonaws.com
,使用 pipe 把密碼送入 docker login 指令,減少將密碼暴露給 shell 紀錄或是日誌紀錄的風險。
Source Code 分析
看了上面的指令使用方法說明我們來看一下指令實作方法哪裡不同。
v1 版本
我們主要關注的實作在於 https://github.com/aws/aws-cli/blob/1.18.5/awscli/customizations/ecr.py#L73 與 https://github.com/aws/aws-cli/blob/1.18.5/awscli/customizations/ecr.py#L77-L85
result = ecr_client.get_authorization_token()
for auth in result['authorizationData']: auth_token = b64decode(auth['authorizationToken']).decode() username, password = auth_token.split(':') command = ['docker', 'login', '-u', username, '-p', password] if parsed_args.include_email: command.extend(['-e', 'none']) command.append(auth['proxyEndpoint']) sys.stdout.write(' '.join(command)) sys.stdout.write('\n')
我們可以在文件看到 get_authorization_token()
回傳的資料
{ 'authorizationData': [ { 'authorizationToken': 'string', 'expiresAt': datetime(2015, 1, 1), 'proxyEndpoint': 'string' }, ] }
所以可以看到 L80 把 username
與 password
的變數塞入製作指令,L83 把 proxyEndpoint
塞入指令,在 L84 使用 stdout 輸出來完成指令的實作。
v2 版本
我們在 v2 版本關注的實作在於 https://github.com/aws/aws-cli/blob/1.18.5/awscli/customizations/ecr.py#L101-L106
result = ecr_client.get_authorization_token() auth = result['authorizationData'][0] auth_token = b64decode(auth['authorizationToken']).decode() _, password = auth_token.split(':') sys.stdout.write(password) sys.stdout.write('\n')
基本上可以看出與 v1 大致上相同,不一樣的地方在於 L104 只有把 password
放入變數,在 L105 輸出實作這個指令。
最後
如果 AWS CLI 版本是 1.17.10 ~ 1.18.5 新舊指令都可以使用,但是如果使用的版本是 2.0.0 就沒有辦法使用舊指令了,不過為了安全問題如果使用的是 1.17.10 以上的版本就建議使用新版指令!
參考資料
- https://docs.aws.amazon.com/cli/latest/userguide/cliv2-migration.html#cliv2-migration-ecr-get-login
- https://github.com/aws/aws-cli
- https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ecr.html
《AWS CDK 完全學習手冊:打造雲端基礎架構程式碼 IaC》
第 12 屆 iT 邦幫忙鐵人賽 DevOps 組冠的《用 CDK 定 義 AWS 架構》
第 11 屆 iT 邦幫忙鐵人賽《LINE bot 好好玩 30 天玩轉 LINE API》
一個熱愛分享的雲端工程師!