已发表的技术专栏(订阅即可观看所有专栏) 0??grpc-go、protobuf、multus-cni 技术专栏 总入口
1??grpc-go 源码剖析与实战??文章目录
2??Protobuf介绍与实战 图文专栏??文章目录
3??multus-cni ??文章目录(k8s多网络实现方案)
4??grpc、oauth2、openssl、双向认证、单向认证等专栏文章目录
- 单向认证,是客户端对服务器端身份合法性的认证
- 客户端一侧不需要提供证书,即,不需要加载客户端证书,来证明自己的身份
- 对服务器端证书合法性的校验,即,判断服务端是否是客户端要访问的服务器,而并非伪造的服务器
- 主要分为以下几方面的认证校验:
- 校验服务器端证书是否合法证书
- 校验客户端提供的访问域名或者访问IP是否合规
- 校验证书的用途,是否是正确的用途。
- 如,证书文件里有Key Usage等属性,规定了该证书的用途;
- 如服务器端证书,只能用在服务器端一侧,如果放在客户端一侧,就会报兼容性不匹配。
- 客户端一侧:
- 需要提前准备好我们所认可的CA证书;可以加载一个,也可以加载多个认可的CA证书;
- 即,这个证书肯定是合法的,大家都认可的。
- 使用我们认可的证书,对服务器传过来的证书,进行校验;
- 校验服务器端证书里的信息,如subj数据是否是CA证书颁发的
- 校验客户端提供的访问域名,访问IP是否在服务器端证书所允许的列表里,如,是否在SAN属性里。
- 校验方式?
- 可以通过写代码的方式来验证服务器端的证书
- 可以通过Postman方式来验证服务器端的证书
- 可以通过curl方式来校验服务器端的证书
- 也可以设置不校验服务器证书,直接跳过
- 服务器端一侧
- 需要加载服务器端的证书,
- 用以向客户端发送自己的证书
单向认证时,服务器端的证书,可以使用自签证书,也可以使用非自签证书
就是自己给自己颁发证书
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/emailAddress=123456789@qq.com"
查看生成的证书
openssl x509 -in server.crt -noout -text
一次性方式生成根证书
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/emailAddress=000000@qq.com"
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/emailAddress=123456789@qq.com" \
-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
syntax = "proto3";
package proto;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
本次测试时,使用的是非自签证书。
主要可以通过两种方式来获取:
- credentials.NewServerTLSFromCert()
- credentials.NewServerTLSFromFile()
服务器端,只需要加载自己的证书,证书密钥即可。
因为是单向认证,不需要验证客户端的证书,即也就不需要加载客户端的根证书。
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) {
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)
}
config := credentials.NewServerTLSFromCert(&cliCert)
svrOption := grpc.Creds(config)
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)
}
}
启动时,随机选择一个单元测试用例即可。
其实,点击credentials.NewServerTLSFromFile,就会发现,credentials.NewServerTLSFromFile是对credentials.NewServerTLSFromCert包装了一层。
主要可以通过两种方式来获取:
- 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))
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, 自己测试时要根据自己的实际情况设置
测试时,随机从测试代码里选择一个单元测试用例即可。
注意,使用postman测试grpc的话,需要注册一个账户
登录账户后,才能使用。
当前postman版本:(Mac环境下)
- 设置URL
- 导入proto文件
- 是否自定义import
- 添加根证书
- 测试
当前版本,使用postman作为客户端不验证服务器端的证书,这种功能未发现。 https 协议是支持的。
|