插件系统¶
GOST的插件系统建立在gRPC通讯基础之上,通过插件可以将处理逻辑转发给插件服务处理,从而可以对功能进行更灵活的扩展。
使用gRPC通讯方式而不是动态链接库有以下几个优点:
- 支持多种语言,一个插件就是一个gRPC服务,可以使用任何语言实现。
- 部署灵活,可以选择分开独立部署。
- 插件服务的生命周期不会影响到GOST本身。
- 安全,采用网络通讯方式,可以更有效的限制应用之间的数据共享。
目前支持插件的模块有:准入控制器,认证器,分流器,主机IP映射器,域名解析器,Ingress,数据记录器。
使用插件¶
以认证器为例,当配置认证器使用插件服务后,所有的认证请求将转发给插件服务处理。
services:
- name: service-0
addr: ":8080"
handler:
type: http
auther: auther-0
listener:
type: tcp
authers:
- name: auther-0
plugin:
addr: 127.0.0.1:8000
token: gost
tls: {}
addr
(string, required)- 插件服务地址
token
(string)- 认证信息,作为服务认证机制,插件服务可以选择对此信息进行验证。
tls
(duration, default=null)- 设置后将使用TLS加密传输,默认不使用TLS加密。
编写插件¶
使用Go语言编写一个认证器插件服务。
package main
import (
"context"
"flag"
"fmt"
"log"
"net"
"github.com/go-gost/plugin/auth/proto"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
var (
port = flag.Int("port", 8000, "The server port")
)
type server struct {
proto.UnimplementedAuthenticatorServer
}
func (s *server) Authenticate(ctx context.Context, in *proto.AuthenticateRequest) (*proto.AuthenticateReply, error) {
// optional client authentication
token := s.getCredentials(ctx)
if token != "gost" {
return nil, status.Error(codes.Unauthenticated, codes.Unauthenticated.String())
}
reply := &proto.AuthenticateReply{}
if in.GetUsername() == "gost" && in.GetPassword() == "gost" {
reply.Ok = true
}
return reply, nil
}
func (s *server) getCredentials(ctx context.Context) string {
md, ok := metadata.FromIncomingContext(ctx)
if ok && len(md["token"]) > 0 {
return md["token"][0]
}
return ""
}
func main() {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
proto.RegisterAuthenticatorServer(s, &server{})
log.Printf("server listening at %v", lis.Addr())
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
https://github.com/go-gost/plugin/blob/master/auth/example/main.go