神祕的Docker私有鏡像拉取錯誤no basic auth credentials

最近,咱們遇到了一個Docker私有鏡像拉取的錯誤,用了幾小時研究Docker私有倉庫(Registry)憑證存儲的細節才弄清楚。儘管最終修復起來很容易,但在憑據存儲設計的過程當中瞭解了一兩件事,以及如何對Docker私有倉庫(Registry)憑證進行安全配置。linux

Docker私有鏡像拉取失敗的狀況以下:nginx

Blimp有時須要從Docker私有倉庫(Registry)中拉取私有鏡像。這一般能夠正常工做,可是不幸的是,有時拉取私有鏡像時,會收到如下錯誤消息:git

Get https://1234.dkr.ecr.us-east-1.amazonaws.com/v2/blimp/blimp/manifests/v0.1: no basic auth credentials

要了解咱們是如何解決的,首先你須要瞭解Docker憑證。github

Docker的外部證書存儲

通常建議,存儲Docker憑證要放在外部憑證存儲中。一般位於~/.docker/config.json的Docker配置文件中。docker

企業中使用私有鏡像倉庫,一般都須要開啓認證,認證憑據多是用戶在企業中通用的帳戶。但docker login之後,會在~/.docker/config.json中保存base64之後的用戶名、密碼,這樣,在一些多人使用的服務器上,就會出現帳號泄露的問題。shell

有沒有解決方法呢?json

docker提供credentials store,也就是講密碼存儲到外置的credentials store中。安全

目前支持以下幾種:ruby

D-Bus Secret Service: https://github.com/docker/docker-credential-helpers/releasesApple macOS keychain: https://github.com/docker/docker-credential-helpers/releasesMicrosoft Windows Credential Manager: https://github.com/docker/docker-credential-helpers/releasespass: https://github.com/docker/docker-credential-helpers/releases

對於linux服務器來講,只能選擇pass,由於D-Bus須要X11支持,而Apple和Microsoft看上去就不像是給Linux準備的。服務器

所以,爲了提升Docker憑據的安全性,你能夠在Docker配置文件中使用兩個字段來配置Docker獲取憑據和存儲憑據的方式:credsStore和credHelpers。

credsStore告訴Docker使用哪一個幫助程序與憑證存儲(credentials store)進行交互。全部幫助程序的名稱都以docker-credential-開頭,credsStore的值爲幫助程序名稱的後綴。

若是你使用Mac筆記本電腦,則可能會使用Mac OS鑰匙串。使用Mac OS鑰匙串後的幫助程序的名稱是docker-credential-osxkeychain。所以,你Docker配置文件config.json將包括如下內容:

{ "credsStore": "osxkeychain"}

若是要查看Docker當前爲你提供的憑據是什麼,可使用list命令。例如:

docker-credential-osxkeychain list

輸出信息是一對服務器和用戶名列表。例如:

{ "http://quay.io":"kklin", "https://index.docker.io":"kevinklin"}

credHelpers是幫助程序( helpers ),用於生成短暫的憑據。例如,若是你使用gcr,gcloud會安裝一個credHelper來使用你的Google登陸名獲取令牌的。採用這種方式後,Docker永遠不會直接擁有你的Google憑據, docker-credential-gcloud充當Docker和Google憑據之間的中間人。

但即便咱們對Docker login密碼加密保存,仍然獲得以下的錯誤消息:

Get https://1234.dkr.ecr.us-east-1.amazonaws.com/v2/blimp/blimp/manifests/v0.1: no basic auth credentials

經過上文,咱們知道能夠經過運行docker-credential-osxkeychain list和get命令來查看1234.dkr.ecr.us-east-1.amazonaws.com的憑據,分析判斷那麼爲何會收到一個錯誤消息-沒有任何憑據(no basic auth credentials)?

Docker1.11版本前:私有倉庫密碼存儲在配置文件中

Docker1.11版本前,Docker配置文件config.json經過auths字段來存儲憑據,直到2016年1.11版本纔可以使用外部憑據存儲。

每當你登陸私有倉庫時,Docker都會將auths的值設置爲你的密碼。你的配置文件可能包含如下內容:

{ "auths": { "https://index.docker.io/v1/": { "auth": "YW11cmRhY2E6c3VwZXJzZWNyZXRwYXNzd29yZA==" }, "localhost:5001": { "auth": "aGVzdHVzZXI6dGVzdHBhc3N3b3Jk" } }}

所以在採用credsStore後,當你使用docker login進行登陸時,你的憑據還會被存儲,但其中的字段auths不包含用戶名或密碼。結果看起來像這樣:

{"auths": { "https://index.docker.io/v1/": {}}

但Docker拉取鏡像時從auths 和 credsStore二者同時獲取憑據。所以,Docker拉取鏡像時會有兩份憑據,一份具備正確的用戶名和密碼,而一份則徹底沒有密碼。

不幸的是,Docker偏心使用auths中的https://的憑證,並嘗試使用空憑證拉取鏡像。所以,會有no basic auth credentials錯誤。

經過上文,咱們肯定了問題是一個空憑證被添加到 Docker配置文件config.json 中,咱們就很容易解決該問題。咱們須要作的就是添加一條if語句以跳過空憑據:

具體參考:https://github.com/kelda/blimp/blob/master/cli/up/up.go

addCredentials := func(authConfigs map[string]clitypes.AuthConfig) { for host, cred := range authConfigs { // Don't add empty config sections. if cred.Username != "" || cred.Password != "" || cred.Auth != "" || cred.Email != "" || cred.IdentityToken != "" || cred.RegistryToken != "" { creds[host] = types.AuthConfig{ Username: cred.Username, Password: cred.Password, Auth: cred.Auth, Email: cred.Email, ServerAddress: cred.ServerAddress, IdentityToken: cred.IdentityToken, RegistryToken: cred.RegistryToken, } } }}

Docker憑證安全風險

不少使用Docker的組織,可能仍在使用傳統的auths方法。若是是這樣,你的~/.docker/config.json可能看起來像這樣:

{ "auths": { "https://index.docker.io/v1/": { "auth": "YW11cmRhY2E6c3VwZXJzZWNyZXRwYXNzd29yZA==" }, "localhost:5001": { "auth": "aGVzdHVzZXI6dGVzdHBhc3N3b3Jk" } }}

這看起來很安全,密碼彷佛是一堆亂碼。大家會想,這些密碼確定是加密的吧?

其實,Docker所作的只是使用base64對密碼進行編碼。正如David Rieger在Hacker Noon上指出的那樣,

Base64乍一看可能看起來像加密,但事實並不是如此。Base64是一種編碼方案,不是加密方案。你只需複製Base64字符串,而後在幾秒鐘內將其轉換爲ASCII。

那個看似安全的密碼aGVzdHVzZXI6dGVzdHBhc3N3b3Jk,讀取密碼所須要作的只是對base64進行解碼:

$ echo aGVzdHVzZXI6dGVzdHBhc3N3b3Jk| base64 -Dhestuser:testpassword

所以,若是未對Docker配置文件中的密碼加密,則Docker將以純文本格式存儲你的密碼。純文本格式的好消息是,解決問題很容易,可是也容易被泄露和攻擊。

爲此,Docker提供了credentials store,也就是把密碼存儲到外置的credentials store中。

譯者:王延飛

原文連接:https://dzone.com/articles/what-a-mysterious-bug-taught-us-about-how-docker-s


END

Kubernetes CKA實戰培訓班推薦:

北京站:8月14-16日


本文分享自微信公衆號 - K8S中文社區(k8schina)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索