已发表的技术专栏(订阅即可观看所有专栏)
0 grpc-go、protobuf、multus-cni 技术专栏 总入口
1 grpc-go 源码剖析与实战 文章目录
2 Protobuf介绍与实战 图文专栏 文章目录
3 multus-cni 文章目录(k8s多网络实现方案)
4 grpc、oauth2、openssl、双向认证、单向认证等专栏文章目录
1、单向认证原理 |
2、证书制作 |
单向认证时,服务器端的证书,可以使用自签证书,也可以使用非自签证书
2.1、方式一:使用自签证书,作为服务器端的证书 |
就是自己给自己颁发证书
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 365 -out server.crt -subj "/C=CN/ST=beijing/L=beijing/O=baidu/OU=bigdata/CN=www.golang-study.com/[email protected]"
查看生成的证书
openssl x509 -in server.crt -noout -text
2.2、方式二:使用非自签方式 |
2.2.1、制作根证书 |
一次性方式生成根证书
openssl req -newkey rsa:2048 -nodes -keyout ca.key -x509 -days 365 -out ca.crt -subj "/C=CN/ST=beijing/L=beijing/O=baidu/OU=bigdata/CN=www.golang.com/[email protected]"
2.2.2、制作服务器端证书 |
2.2.2.1、第一步:生成服务器端密钥和服务器端证书签名 (SAN类型,即多个域名生效) |
openssl req -newkey rsa:2048 -nodes -keyout server.key \
-subj "/C=CN/ST=beijing/L=beijing/O=baidu/OU=bigdata/CN=www.golang-server.com/[email protected]" \
-reqexts SAN \
-config <(cat /etc/pki/tls/openssl.cnf <(printf "\n[SAN]\nsubjectAltName=DNS:*.org.golang-server.com,DNS:www.golang-server.cn")) \
-out server.csr
查看证书签名里,是否有SAN请求信息
openssl req -noout -text -in server.csr
2.2.2.2、第二步:根据CA证书,来颁发服务器端证书 |
openssl x509 -req -days 365 \
-in server.csr -out server.crt \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-extensions SAN \
-extfile <(cat /etc/pki/tls/openssl.cnf <(printf "[SAN]\nsubjectAltName=DNS:*.org.golang-server.com,DNS:www.golang-server.cn"))
查看生成的证书
openssl x509 -in server.crt -noout -text
3、proto文件 |
syntax = "proto3";
package proto;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
4、服务器端 |
本次测试时,使用的是非自签证书。
4.1、服务器端获取tls凭证的方式 |
主要可以通过两种方式来获取:
4.2、服务器端代码 |
服务器端,只需要加载自己的证书,证书密钥即可。
因为是单向认证,不需要验证客户端的证书,即也就不需要加载客户端的根证书。
package main
import (
"context"
"crypto/tls"
"github.com/CodisLabs/codis/pkg/utils/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"grpc-go-study/8-WithTransportCredentials/rpc/one-way-authentication/proto"
"net"
"testing"
)
const (
port = ":50051"
)
type server struct {
proto.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, in *proto.HelloRequest) (*proto.HelloReply, error) {
return &proto.HelloReply{Message: "---this is gRPC Server---"}, nil
}
func TestNewServerTLSFromFile(t *testing.T) {
// 获取tls凭证
tlsConfig, err := credentials.NewServerTLSFromFile(
"***改成自己的实际路径***server.crt",
"***改成自己的实际路径***server.key")
if err != nil {
panic(err)
}
// 设置凭证
svrOption := grpc.Creds(tlsConfig)
lis, err := net.Listen("tcp", port)
if err != nil {
log.Errorf("failed to listen: %v", err)
}
s := grpc.NewServer(svrOption)
proto.RegisterGreeterServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Errorf("failed to serve: %v", err)
}
}
func TestNewServerTLSFromCert(t *testing.T) {
// 加载证书
cliCert, err := tls.LoadX509KeyPair(
"***改成自己的实际路径***server.crt",
"***改成自己的实际路径***server.key")
if err != nil {
panic(err)
}
// 获取tls凭证
config := credentials.NewServerTLSFromCert(&cliCert)
// 设置凭证
svrOption := grpc.Creds(config)
lis, err := net.Listen("tcp", port)
if err != nil {
log.Errorf("failed to listen: %v", err)
}
// 将证书,添加到grpc服务器里
s := grpc.NewServer(svrOption)
proto.RegisterGreeterServer(s, &server{})
if err := s.Serve(lis); err != nil {
log.Errorf("failed to serve: %v", err)
}
}
启动时,随机选择一个单元测试用例即可。
其实,点击credentials.NewServerTLSFromFile,就会发现,credentials.NewServerTLSFromFile是对credentials.NewServerTLSFromCert包装了一层。
5、客户端 |
5.1、客户端获取tls凭证的方式 |
主要可以通过两种方式来获取:
当然,grpc客户端不一定非得验证服务器端的证书:如下配置
config := &tls.Config{
InsecureSkipVerify: true, // 不用校验服务器证书
}
transportCreds := credentials.NewTLS(config)
conn, err := grpc.Dial("www.golang-server.cn:50051", grpc.WithBlock(), grpc.WithTransportCredentials(transportCreds))
5.2、客户端代码 |
package main
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"github.com/CodisLabs/codis/pkg/utils/log"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"grpc-go-study/8-WithTransportCredentials/rpc/one-way-authentication/proto"
"io/ioutil"
"testing"
"time"
)
func TestNewClientTLSFromCert(t *testing.T) {
caCert, _ := ioutil.ReadFile("*****改成自己的实际地址*****ca.crt")
caCertPool := x509.NewCertPool()
if !caCertPool.AppendCertsFromPEM(caCert) {
panic(errors.New("credentials: failed to append certificates"))
}
config := credentials.NewClientTLSFromCert(caCertPool, "")
conn, err := grpc.Dial("www.golang-server.cn:50051", grpc.WithBlock(), grpc.WithTransportCredentials(config))
if err != nil {
log.Errorf("did not connect: %v", err)
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
ctx := context.Background()
start := time.Now() // 获取当前时间
msg, err := c.SayHello(ctx, &proto.HelloRequest{Name: "hello grpc-server!"})
if err != nil {
panic(err.Error())
}
elapsed := time.Since(start)
fmt.Println("run time :", elapsed)
log.Infof("Greeting: %s", msg.GetMessage())
}
func TestNewClientTLSFromFile(t *testing.T) {
config, err := credentials.NewClientTLSFromFile("*****改成自己的实际地址*****ca.crt", "")
if err != nil {
panic(err)
}
conn, err := grpc.Dial("www.golang-server.cn:50051", grpc.WithBlock(), grpc.WithTransportCredentials(config))
if err != nil {
log.Errorf("did not connect: %v", err)
panic(err)
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
ctx := context.Background()
start := time.Now() // 获取当前时间
msg, err := c.SayHello(ctx, &proto.HelloRequest{Name: "hello grpc-server!"})
if err != nil {
panic(err.Error())
}
elapsed := time.Since(start)
fmt.Println("run time :", elapsed)
log.Infof("Greeting: %s", msg.GetMessage())
}
// 客户端不再验证服务器端的证书
func TestInsecureSkipVerify(t *testing.T) {
config := &tls.Config{
InsecureSkipVerify: true, // 不用校验服务器证书
}
transportCreds := credentials.NewTLS(config)
conn, err := grpc.Dial("www.golang-server.cn:50051", grpc.WithBlock(), grpc.WithTransportCredentials(transportCreds))
if err != nil {
log.Errorf("did not connect: %v", err)
panic(err)
}
defer conn.Close()
c := proto.NewGreeterClient(conn)
ctx := context.Background()
start := time.Now() // 获取当前时间
msg, err := c.SayHello(ctx, &proto.HelloRequest{Name: "hello grpc-server!"})
if err != nil {
panic(err.Error())
}
elapsed := time.Since(start)
fmt.Println("run time :", elapsed)
log.Infof("Greeting: %s", msg.GetMessage())
}
要在客户端一侧进行配置,因为是在客户端一侧进行的发起的访问请求
关于域名设置,本次测试时,grpc服务器端和grpc客户端都在同一个IP下,
因此,域名里全是127.0.0.1, 自己测试时要根据自己的实际情况设置
测试时,随机从测试代码里选择一个单元测试用例即可。
5.3、Postman测试 |
注意,使用postman测试grpc的话,需要注册一个账户
登录账户后,才能使用。
当前版本,使用postman作为客户端不验证服务器端的证书,这种功能未发现。 https 协议是支持的。