文|朱德江(GitHub ID:doujiang24)
MOSN 項目核心開發者螞蟻集團技術專家
專注於雲原生網關研發的相關工作
本文 1445 字 閱讀 5 分鐘
上一篇我們用一個簡單的示例,體驗了用 Golang 擴展 Envoy 的極速上手。
這次我們再通過一個示例,來體驗 Golang 擴展的一個強大的特性:
從 Envoy 接收配置 。
Basic Auth
我們還是從一個小示例來體驗,這次我們實現標準的 Basic Auth 的認證,與上一次示例不同的是,這次認證的用戶密碼信息,需要從 Envoy 傳給 Go,不能在 Go 代碼中寫死了。
完整的代碼可以看 example-basic-auth[1],下面我們展開介紹一番。
獲取配置
爲了更加靈活,在設計上,Envoy 傳給 Go 的配置是 Protobuf 的 Any 類型,也就是說,配置內容對於 Envoy 是透明的,我們在 Go 側註冊一個解析器,來完成這個 Any 配置的解析。
如下示例:
func init() {
// 註冊 parser
http.RegisterHttpFilterConfigParser(&parser{})
}
func (p *parser) Parse(any *anypb.Any) interface{} {
configStruct := &xds.TypedStruct{}
if err := any.UnmarshalTo(configStruct); err != nil {
panic(err)
}
v := configStruct.Value
conf := &config{}
if username, ok := v.AsMap()["username"].(string); ok {
conf.username = username
}
if password, ok := v.AsMap()["password"].(string); ok {
conf.password = password
}
return conf
}
這裏爲了方便,Any 中的類型是 Envoy 定義的 TypedStruct 類型,這樣我們可以直接使用現成的 Go pb 庫。
值得一提的是,這個配置解析,只有在首次加載的時候需要執行,後續在 Go 使用的是解析後的配置,所以,我們解析到一個 Go map 可以擁有更好的運行時性能。
同時,由於 Envoy 的配置,也是有層級關係的,比如 http-filter, virtual host, router, virtual clusters 這四級,我們也支持這四個層級同時有配置,在 Go 側來組織 merge。
當然,這個只有在 Go 側有複雜的 filter 組織邏輯的時候用得上,後面我們在 MOSN 的上層封裝的時候,可以看到這種用法,這裏暫時不做展開介紹。
認證
具體的 Basic Auth 認證邏輯,我們可以參考 Go 標準 net/http 庫中的 Basic Auth 實現。
func (f *filter) verify(header api.RequestHeaderMap) (bool, string) {
auth, ok := header.Get("authorization")
if !ok {
return false, "no Authorization"
}
username, password, ok := parseBasicAuth(auth)
if !ok {
return false, "invalid Authorization format"
}
if f.config.username == username && f.config.password == password {
return true, ""
}
return false, "invalid username or password"
}
這裏面的 parseBasicAuth
就是從 net/http 庫中的實現,是不是很方便呢。
配置
簡單起見,這次我們使用本地文件的配置方式。如下是關鍵的配置:
http_filters:
- name: envoy.filters.http.golang
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.golang.v3alpha.Config
library_id: example
library_path: /etc/envoy/libgolang.so
plugin_name: basic-auth
plugin_config:
"@type": type.googleapis.com/xds.type.v3.TypedStruct
value:
username: "foo"
password: "bar"
這裏我們配置了用戶名密碼:foo:bar
。
預告一下,下一篇我們會體驗通過 Istio 來推送配置,體會一番動態更新配置的全流程。
測試
編譯,運行,跟上篇一樣,我們還是使用 Envoy 官方提供的鏡像即可。
跑起來之後,我們測試一下:
$ curl -s -I 'http://localhost:10000/'
HTTP/1.1 401 Unauthorized
# invalid username:password
$ curl -s -I 'http://localhost:10000/' -H 'Authorization: basic invalid'
HTTP/1.1 401 Unauthorized
# valid foo:bar
$ curl -s -I 'http://localhost:10000/' -H 'Authorization: basic Zm9vOmJhcg=='
HTTP/1.1 200 OK
是不是很簡單呢,一個標準的 Basic Auth 擴展就完成了。
總結
Envoy 是面向雲原生的架構設計,提供了配置動態變更的機制,Go 擴展可以從 Envoy 接受配置,也就意味着 Go 擴展也可以很好的利用這套機制。
Go 擴展的開發者,不需要關心配置的動態更新,只需要解析配置即可,非常的方便~
下一篇我們會介紹,配合 Istio 來動態更新用戶名密碼,體驗一番雲原生的配置變更體驗。
後續還有更多 Golang 擴展的特性介紹,原理解析,以及,更上層的 MOSN 集成體驗,歡迎持續關注。
[1]example-basic-auth:
https://github.com/doujiang24/envoy-go-filter-example/tree/master/example-basic-auth
瞭解更多…
MOSN Star 一下✨:
https://github.com/mosn/mosn