MoE 系列(二)|Golang 擴展從 Envoy 接收配置

圖片

文|朱德江(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

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