GRPC使用openssl证书
加密数据传输过程,保证调用的安全性。
证书生成
自签证书(root CA)
命令解析:https://blog.csdn.net/adminstate/article/details/128662641
生成私钥文件
1
| openssl genrsa -des3 -out private.key 2048
|
创建证书请求
1
| openssl req -new -key private.key -out ca.csr
|
生成ca.crt
1
| openssl x509 -req -days 365 -in ca.csr -signkey private.key -out ca.crt
|
SAN证书
参考:https://blog.csdn.net/a145127/article/details/126311442
SAN证书需要上述生成的根证书。
设置配置文件
- 终端
openssl version -d
可以查找配置文件
- 修改配置文件
生成服务器密钥和证书
1 2 3 4 5 6 7 8
| $ openssl genpkey -algorithm RSA -out ../server/server.key
$ openssl req -new -nodes -key ../server/server.key -out ../server/server.csr -config openssl.cnf -extensions 'v3_req'
$ openssl x509 -req -in ../server/server.csr -out ../server/server.pem -CA ca.crt -CAkey private.key -CAcreateserial -extfile ./openssl.cnf -extensions 'v3_req'
|
生成客户端密钥和证书
1 2 3 4 5 6 7 8
| # 生成客户端私钥,密码输入123456 $ openssl genpkey -algorithm RSA -out ../client/client.key # 使用私钥来签名证书 $ openssl req -new -nodes -key ../client/client.key -out ../client/client.csr -config openssl.cnf -extensions 'v3_req' # 生成SAN证书 $ openssl x509 -req -in ../client/client.csr -out ../client/client.pem -CA ca.crt -CAkey private.key -CAcreateserial -extfile ./openssl.cnf -extensions 'v3_req'
|
目录结构
单项认证
服务端使用证书和私钥
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package main
import ( "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/credentials" pd "grpc_helloworld/server/proto" "log" "net" )
type Server struct { pd.UnimplementedHelloServerServer }
func (s *Server) Say(ctx context.Context, q *pd.HelloReq) (*pd.HelloRep, error) { return &pd.HelloRep{ Say: fmt.Sprintf("%s已经%d岁了", q.Name, q.Age), }, nil } func main() { file, _ := credentials.NewServerTLSFromFile("./server.pem", "./server.key")
listen, _ := net.Listen("tcp", ":8080") newServer := grpc.NewServer(grpc.Creds(file)) pd.RegisterHelloServerServer(newServer, new(Server)) err := newServer.Serve(listen) if err != nil { log.Print("err:", err) } }
|
客户端使用公钥(证书中有公钥)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package main
import ( "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/credentials" pd "grpc_helloworld/client/proto" "log" )
func main() { file, err2 := credentials.NewClientTLSFromFile("../server/server.pem", "*.test.example.com") if err2 != nil { log.Fatal("证书错误", err2) } conn, err := grpc.Dial(":8080", grpc.WithTransportCredentials(file))
if err != nil { fmt.Print(err) } defer conn.Close() client := pd.NewHelloServerClient(conn) feature, err := client.Say(context.Background(), &pd.HelloReq{ Name: "hello", Age: 22, }) if err != nil { log.Print(err) } fmt.Print(feature) }
|
双向认证
服务端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| func main() { cert, err := tls.LoadX509KeyPair("./server.pem", "./server.key") if err != nil { log.Fatal("证书读取错误", err) } certPool := x509.NewCertPool() ca, err := ioutil.ReadFile("../encryption/ca.crt") if err != nil { log.Fatal("ca证书读取错误", err) } certPool.AppendCertsFromPEM(ca) creds := credentials.NewTLS(&tls.Config{ Certificates: []tls.Certificate{cert}, ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: certPool, }) listen, _ := net.Listen("tcp", ":8080") newServer := grpc.NewServer(grpc.Creds(creds))
pd.RegisterHelloServerServer(newServer, new(Server)) err = newServer.Serve(listen) if err != nil { log.Print("err:", err) } }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| func main() { cert, _ := tls.LoadX509KeyPair("./client.pem", "./client.key") certPool := x509.NewCertPool() ca, _ := ioutil.ReadFile("../encryption/ca.crt") certPool.AppendCertsFromPEM(ca) creds := credentials.NewTLS(&tls.Config{ Certificates: []tls.Certificate{cert}, ServerName: "*.test.example.com", RootCAs: certPool, }) conn, err := grpc.Dial(":8080", grpc.WithTransportCredentials(creds))
if err != nil { fmt.Print(err) } defer conn.Close() client := pd.NewHelloServerClient(conn) feature, err := client.Say(context.Background(), &pd.HelloReq{ Name: "hello", Age: 22, }) if err != nil { log.Print(err) } fmt.Print(feature) }
|
token认证
服务端校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| package main
import ( "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" pd "grpc_helloworld/server/proto" "log" "net" )
type Server struct { pd.UnimplementedHelloServerServer }
func (s *Server) Say(ctx context.Context, q *pd.HelloReq) (*pd.HelloRep, error) { return &pd.HelloRep{ Say: fmt.Sprintf("%s已经%d岁了", q.Name, q.Age), }, nil } func main() { var authInterceptor grpc.UnaryServerInterceptor authInterceptor = func( ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (resp interface{}, err error) { err = Auth(ctx) if err != nil { return } return handler(ctx, req) }
listen, _ := net.Listen("tcp", ":8080") newServer := grpc.NewServer(grpc.UnaryInterceptor(authInterceptor))
pd.RegisterHelloServerServer(newServer, new(Server)) err := newServer.Serve(listen) if err != nil { log.Print("err:", err) } } func Auth(ctx context.Context) error { md, ok := metadata.FromIncomingContext(ctx) if !ok { return fmt.Errorf("missing credentials") } var user string var password string
if val, ok := md["user"]; ok { user = val[0] } if val, ok := md["password"]; ok { password = val[0] }
if user != "admin" || password != "123456" { return status.Errorf(codes.Unauthenticated, "token不合法") } return nil }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| package main
import ( "context" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" pd "grpc_helloworld/client/proto" "log" )
type Authentication struct { User string Password string }
func (a *Authentication) GetRequestMetadata(context.Context, ...string) ( map[string]string, error, ) { return map[string]string{"user": a.User, "password": a.Password}, nil }
func (a *Authentication) RequireTransportSecurity() bool { return false } func main() { user := &Authentication{ User: "admin", Password: "123456", } conn, err := grpc.Dial(":8080", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithPerRPCCredentials(user))
if err != nil { fmt.Print(err) } defer conn.Close() client := pd.NewHelloServerClient(conn) feature, err := client.Say(context.Background(), &pd.HelloReq{ Name: "hello", Age: 22, }) if err != nil { log.Print(err) } fmt.Print(feature) }
|