grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍

已发表的技术专栏(订阅即可观看所有专栏)
0  grpc-go、protobuf、multus-cni 技术专栏 总入口

1  grpc-go 源码剖析与实战  文章目录

2  Protobuf介绍与实战 图文专栏  文章目录

3  multus-cni   文章目录(k8s多网络实现方案)

4  grpc、oauth2、openssl、双向认证、单向认证等专栏文章目录


1、单向认证原理

  • 单向认证,是客户端对服务器端身份合法性的认证
    • 客户端一侧不需要提供证书,即,不需要加载客户端证书,来证明自己的身份
    • 对服务器端证书合法性的校验,即,判断服务端是否是客户端要访问的服务器,而并非伪造的服务器
  • 主要分为以下几方面的认证校验:
    • 校验服务器端证书是否合法证书
    • 校验客户端提供的访问域名或者访问IP是否合规
    • 校验证书的用途,是否是正确的用途。
      • 如,证书文件里有Key Usage等属性,规定了该证书的用途;
      • 如服务器端证书,只能用在服务器端一侧,如果放在客户端一侧,就会报兼容性不匹配。
  • 客户端一侧:
    • 需要提前准备好我们所认可的CA证书;可以加载一个,也可以加载多个认可的CA证书;
      • 即,这个证书肯定是合法的,大家都认可的。
      • 使用我们认可的证书,对服务器传过来的证书,进行校验;
        • 校验服务器端证书里的信息,如subj数据是否是CA证书颁发的
        • 校验客户端提供的访问域名,访问IP是否在服务器端证书所允许的列表里,如,是否在SAN属性里。
    • 校验方式?
      • 可以通过写代码的方式来验证服务器端的证书
      • 可以通过Postman方式来验证服务器端的证书
      • 可以通过curl方式来校验服务器端的证书
      • 也可以设置不校验服务器证书,直接跳过
  • 服务器端一侧
    • 需要加载服务器端的证书,
    • 用以向客户端发送自己的证书

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 

grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第1张图片

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]"

grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第2张图片

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

grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第3张图片

查看证书签名里,是否有SAN请求信息

openssl req -noout -text -in server.csr

grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第4张图片

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"))

grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第5张图片

查看生成的证书

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凭证的方式

主要可以通过两种方式来获取:

  • credentials.NewServerTLSFromCert()
  • credentials.NewServerTLSFromFile()

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凭证的方式

主要可以通过两种方式来获取:

  • credentials.NewClientTLSFromCert()
  • credentials.NewClientTLSFromFile()

当然,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、https、oauth2等认证专栏实战14:grpc单向认证介绍_第6张图片

要在客户端一侧进行配置,因为是在客户端一侧进行的发起的访问请求

grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第7张图片

关于域名设置,本次测试时,grpc服务器端和grpc客户端都在同一个IP下,

因此,域名里全是127.0.0.1, 自己测试时要根据自己的实际情况设置

测试时,随机从测试代码里选择一个单元测试用例即可。

5.3、Postman测试

注意,使用postman测试grpc的话,需要注册一个账户

登录账户后,才能使用。

当前postman版本:(Mac环境下)
grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第8张图片

grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第9张图片

  • 设置URL
    grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第10张图片
  • 导入proto文件
    grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第11张图片
  • 是否自定义import
    grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第12张图片
    grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第13张图片
  • 添加根证书
    grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第14张图片
    grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第15张图片
  • 测试
    grpc、https、oauth2等认证专栏实战14:grpc单向认证介绍_第16张图片

当前版本,使用postman作为客户端不验证服务器端的证书,这种功能未发现。 https 协议是支持的。

你可能感兴趣的:(grpc-go,protobuf,kubernetes,golang,multus-cni)