grpc中TLS认证证书问题

场景:

参考gorpc实例进行grpc的TLS验证时出现问题,解决办法参考openssl 证书生成笔记(go 1.15版本以上)

问题:

Error 1

报错:rpc error: code = Unavailable desc = connection error: desc = “transport: authentication handshake failed: x509: certificate is not valid for any names, but wanted to match XXX”
exit status 1

原因:server/main.go启动后长时间未连接导致,重启即可。

Error 2

报错:rpc error: code = Unavailable desc = connection error: desc = “transport: authentication handshake failed: x509: certificate relies on legacy Common Name field, use SANs instead”
exit status 1
原因:golang 1.15+版本上,用 gRPC通过TLS实现数据传输加密时,会报错证书的问题
因为证书并没有开启SAN扩展(默认是没有开启SAN扩展)所造成的,导致客户端和服务端无法建立连接

解决方法:

项目目录:

go/src/goProjects
 -hello
 	-client
 	-keys
 	-proto
 	-server
 	-go.mod
 	-go.sum
 -keys

证书生成:

1.ca根证书生成:

新建ca.conf,填入以下内容:

[ req ]
default_bits       = 4096
distinguished_name = req_distinguished_name

[ req_distinguished_name ]
countryName                 = Country Name (2 letter code)
countryName_default         = CN
stateOrProvinceName         = State or Province Name (full name)
stateOrProvinceName_default = JiangSu
localityName                = Locality Name (eg, city)
localityName_default        = NanJing
organizationName            = Organization Name (eg, company)
organizationName_default    = Step
commonName                  = CommonName (e.g. server FQDN or YOUR name)
commonName_max              = 64
commonName_default          = XXX(自定义)

生成ca.key:

openssl genrsa -out ca.key 4096

生成ca.csr:(直接回车,采用default默认配置值)

openssl req \
 -new \
 -sha256 \
 -out ca.csr \
 -key ca.key \
 -config ca.conf

生成ca.crt:

openssl x509 \
   -req \
   -days 3650 \
   -in ca.csr \
   -signkey ca.key \
   -out ca.crt

2.server证书生成:

在hello/keys目录下:
新建server.conf,填入以下内容:

[ req ]
default_bits       = 2048
distinguished_name = req_distinguished_name

[ req_distinguished_name ]
countryName                 = Country Name (2 letter code)
countryName_default         = CN
stateOrProvinceName         = State or Province Name (full name)
stateOrProvinceName_default = JiangSu
localityName                = Locality Name (eg, city)
localityName_default        = NanJing
organizationName            = Organization Name (eg, company)
organizationName_default    = Step
commonName                  = CommonName (e.g. server FQDN or YOUR name)
commonName_max              = 64
commonName_default          = XXX(自定义,客户端需要此字段做匹配)
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1   = XXX(自定义)
IP      = 127.0.0.1

生成server.key:

openssl genrsa -out ca.key 2048

生成server.csr:(直接回车,采用default默认配置值)

openssl req \
 -new \
 -sha256 \
 -out server.csr \
 -key server.key \
 -config server.conf

生成server.crt:

openssl x509 \
-req \
 -days 3650 \
 -CA ~/go/src/goProjects/keys/ca.crt \
 -CAkey ~/go/src/goProjects/keys/ca.key \
 -CAcreateserial \
 -in server.csr \
 -out server.pem\
 -extensions req_ext \
 -extfile server.conf

服务端与客户端中TLS认证:

1.服务端:

package main

import (
  "fmt"
  "net"
  pb "goProjects/hello/proto/hello" // 引入编译生成的包

  "golang.org/x/net/context"
  "google.golang.org/grpc"
  "google.golang.org/grpc/grpclog"
)

const (
  Address = "127.0.0.1:50052"
)

// 定义helloService并实现约定的接口
type helloService struct{}

// HelloService Hello服务
var HelloService = helloService{}

func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloResponse, error) {
  resp := new(pb.HelloResponse)
  resp.Message = fmt.Sprintf("Hello %s.", in.Name)

  return resp, nil
}
func main() {
  listen, err := net.Listen("tcp", Address)
  if err != nil {
  	grpclog.Fatalf("Failed to listen: %v", err)
  }
  
  creds, err := credentials.NewClientTLSFromFile("../keys/server.pem", "../keys/server.key")
  if err != nil {
  	grpclog.Fatalf("Failed to generate credentials %v", err)
  }
  s := grpc.NewServer(grpc.Creds(creds))
  // 注册HelloService
  pb.RegisterHelloServer(s, HelloService)

  grpclog.Println("Listen on " + Address + " with TLS")

  s.Serve(listen)
}

2.客户端:

package main

import (
	"fmt"
	pb "goProjects/hello/proto/hello" // 引入proto包

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"google.golang.org/grpc/grpclog"
)

const (
	// Address gRPC服务地址
	Address = "127.0.0.1:50052"
)

func main() {
        // TLS连接  记得把server name改成你写的服务器地址
    creds, err := credentials.NewClientTLSFromFile("../keys/server.pem", "server name")
    if err != nil {
        grpclog.Fatalf("Failed to create TLS credentials %v", err)
        fmt.Printf("Failed to create TLS credentials %v", err)
    }

    conn, err := grpc.Dial(Address, grpc.WithTransportCredentials(creds))
    if err != nil {
        grpclog.Fatalln(err)
    }
    defer conn.Close()
	// 初始化客户端
	c := pb.NewHelloClient(conn)

	// 调用方法
	req := &pb.HelloRequest{Name: "gRPC"}
	res, err := c.SayHello(context.Background(), req)

	if err != nil {
		grpclog.Fatalln(err)
	}

	grpclog.Println(res.Message)
	fmt.Println(res.Message)
}

依次启动服务端与客户端即可

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值