viper從etcd讀取配置失敗的問題

問題描述

Viper (本文環境是Viper 1.1.0)是Go應用程序的完整配置解決方案,在很多項目中都有應用。etcd是一個分佈式KV存儲,最直接的應用是配置中心。

Viper除了支持從文件中讀取配置,還支持從遠程的配置中心讀取配置,使用下面的代碼進行配置。

viper.AddRemoteProvider("etcd",
        "http://127.0.0.1:2379",
        "conf.toml")
viper.SetConfigType("toml")
err := viper.ReadRemoteConfig()
if err != nil {
    panic(err)
}

運行後報錯panic: Remote Configurations Error: No Files Found,檢查後發現etcd開啓了tls,所以需要用https協議訪問etcd的API,更新代碼如下。

viper.AddSecureRemoteProvider("etcd",
        "https://127.0.0.1:2379",
        "conf.toml",
        "key_path")
viper.SetConfigType("toml")
err := viper.ReadRemoteConfig()
if err != nil {
    panic(err)
}

使用AddSecureRemoteProvider方法替換AddRemoteProvider方法,問題依舊。

定位問題

跟蹤源碼發現,最終像etcd發送請求的是go-etcd包(目前go-etcd已經不維護),在go-etcd的requests.go文件中找到了相關的源碼,go-etcd調用了net/http包向etcd發送請求。

這個時候忽然想到etcd的證書是自簽名的,訪問自簽名證書的https接口應該會報錯啊,怎麼會請求到內容呢?如下圖,在Chrome中訪問etcd的自簽名https接口,會提示證書無效。

我們自己使用go實現一段請求etcd https接口的代碼,看看到底是什麼回事,代碼如下。

resp, err := http.Get("https://127.0.0.1:2379/v2/keys/conf.toml?quorum=false&recursive=false&sorted=false")
    if err != nil {
        // handle error
        fmt.Println(err)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(string(body))

果然不一樣,我們的代碼會報錯x509: certificate signed by unknown authority,因爲是自簽名證書,客戶端無法驗證證書真假,所以這個報錯是可以理解的,go-etcd代碼和我們的測試代碼表現不一致,一定是我們落下了什麼,重新梳理go-etcd源碼終於發現了原因。

在client.go文件的initHTTPSClient方法中,發現允許繞過證書驗證,這就可以解釋爲什麼證書無效也能獲取到數據了,繞過了證書的驗證環節,相當於不管證書真假都拿來用。現在可以解釋使用AddRemoteProvider方法訪問https接口爲什麼可以獲取到內容,但是無法解釋AddSecureRemoteProvider方法爲什麼無法從https接口獲取內容,因爲兩個方法在發送http請求階段的代碼是一致的,都忽略了證書驗證。

查看AddSecureRemoteProvider的註釋,發現了原因。

原來...AddSecureRemoteProvider這個Secure指的並不是使用安全鏈接https,而是在請求到內容後加了一個解密的步驟(Secure指請求的是加密過的內容,而不是使用加密鏈接請求),最後一個參數接收的也並不是客戶端證書,而是解密的gpg key... 根據viper的文檔,這個gpg key是可選的,我們這個例子中,如果給gpg key傳入一個空字符串,也是可以正常執行的...

必須吐槽一下viper的命名,哪裏是AddSecureRemoteProvider,明明應該叫AddEncryptedRemoteProvider

總結

出現這個問題,主要是誤會了AddSecureRemoteProvider接口表達的意思,並且go-etcd允許忽略證書驗證,也讓問題變得更加離奇。

當然go-etcd的這種配置是非常合理的,內部系統使用自簽名證書是一個很正常的行爲。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章