内容简介:原文地址:项目地址:在上一章节中,我们提出了一个问题。就是如何保证证书的可靠性和有效性?你如何确定你 Server、Client 的证书是对的呢?
带入gRPC:基于 CA 的 TLS 证书认证
原文地址: 带入gRPC:基于 CA 的 TLS 证书认证
项目地址: https://github.com/EDDYCJY/go...
前言
在上一章节中,我们提出了一个问题。就是如何保证证书的可靠性和有效性?你如何确定你 Server、Client 的证书是对的呢?
CA
为了保证证书的可靠性和有效性,在这里可引入 CA 颁发的根证书的概念。其遵守 X.509 标准
根证书
根证书(root certificate)是属于根证书颁发机构(CA)的公钥证书。我们可以通过验证 CA 的签名从而信任 CA ,任何人都可以得到 CA 的证书(含公钥),用以验证它所签发的证书(客户端、服务端)
它包含的文件如下:
- 公钥
- 密钥
生成 Key
openssl genrsa -out ca.key 2048
生成密钥
openssl req -new -x509 -days 7200 -key ca.key -out ca.pem
填写信息
Country Name (2 letter code) []: State or Province Name (full name) []: Locality Name (eg, city) []: Organization Name (eg, company) []: Organizational Unit Name (eg, section) []: Common Name (eg, fully qualified host name) []:go-grpc-example Email Address []:
Server
生成 CSR
openssl req -new -key server.key -out server.csr
填写信息
Country Name (2 letter code) []: State or Province Name (full name) []: Locality Name (eg, city) []: Organization Name (eg, company) []: Organizational Unit Name (eg, section) []: Common Name (eg, fully qualified host name) []:go-grpc-example Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:
CSR 是 Cerificate Signing Request 的英文缩写,为证书请求文件。主要作用是 CA 会利用 CSR 文件进行签名使得攻击者无法伪装或篡改原有证书
基于 CA 签发
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem
Client
生成 Key
openssl ecparam -genkey -name secp384r1 -out client.key
生成 CSR
openssl req -new -key client.key -out client.csr
基于 CA 签发
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in client.csr -out client.pem
整理目录
至此我们生成了一堆文件,请按照以下目录结构存放:
$ tree conf conf ├── ca.key ├── ca.pem ├── ca.srl ├── client │ ├── client.csr │ ├── client.key │ └── client.pem └── server ├── server.csr ├── server.key └── server.pem
另外有一些文件是不应该出现在仓库内,应当保密或删除的。但为了真实演示所以保留着(敲黑板)
gRPC
接下来将正式开始针对 gRPC 进行编码,改造上一章节的代码。目标是基于 CA 进行 TLS 认证
Server
package main import ( "context" "log" "net" "crypto/tls" "crypto/x509" "io/ioutil" "google.golang.org/grpc" "google.golang.org/grpc/credentials" pb "github.com/EDDYCJY/go-grpc-example/proto" ) ... const PORT = "9001" func main() { cert, err := tls.LoadX509KeyPair("../../conf/server/server.pem", "../../conf/server/server.key") if err != nil { log.Fatalf("tls.LoadX509KeyPair err: %v", err) } certPool := x509.NewCertPool() ca, err := ioutil.ReadFile("../../conf/ca.pem") if err != nil { log.Fatalf("ioutil.ReadFile err: %v", err) } if ok := certPool.AppendCertsFromPEM(ca); !ok { log.Fatalf("certPool.AppendCertsFromPEM err") } c := credentials.NewTLS(&tls.Config{ Certificates: []tls.Certificate{cert}, ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: certPool, }) server := grpc.NewServer(grpc.Creds(c)) pb.RegisterSearchServiceServer(server, &SearchService{}) lis, err := net.Listen("tcp", ":"+PORT) if err != nil { log.Fatalf("net.Listen err: %v", err) } server.Serve(lis) }
- tls.LoadX509KeyPair():从证书相关文件中 读取 和 解析 信息,得到证书公钥、密钥对
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { certPEMBlock, err := ioutil.ReadFile(certFile) if err != nil { return Certificate{}, err } keyPEMBlock, err := ioutil.ReadFile(keyFile) if err != nil { return Certificate{}, err } return X509KeyPair(certPEMBlock, keyPEMBlock) }
- x509.NewCertPool():创建一个新的、空的 CertPool
- certPool.AppendCertsFromPEM():尝试解析所传入的 PEM 编码的证书。如果解析成功会将其加到 CertPool 中,便于后面的使用
- credentials.NewTLS:构建基于 TLS 的 TransportCredentials 选项
- tls.Config:Config 结构用于配置 TLS 客户端或服务器
在 Server,共使用了三个 Config 配置项:
(1)Certificates:设置证书链,允许包含一个或多个
(2)ClientAuth:要求必须校验客户端的证书。可以根据实际情况选用以下参数:
const ( NoClientCert ClientAuthType = iota RequestClientCert RequireAnyClientCert VerifyClientCertIfGiven RequireAndVerifyClientCert )
(3)ClientCAs:设置根证书的集合,校验方式使用 ClientAuth 中设定的模式
Client
package main import ( "context" "crypto/tls" "crypto/x509" "io/ioutil" "log" "google.golang.org/grpc" "google.golang.org/grpc/credentials" pb "github.com/EDDYCJY/go-grpc-example/proto" ) const PORT = "9001" func main() { cert, err := tls.LoadX509KeyPair("../../conf/client/client.pem", "../../conf/client/client.key") if err != nil { log.Fatalf("tls.LoadX509KeyPair err: %v", err) } certPool := x509.NewCertPool() ca, err := ioutil.ReadFile("../../conf/ca.pem") if err != nil { log.Fatalf("ioutil.ReadFile err: %v", err) } if ok := certPool.AppendCertsFromPEM(ca); !ok { log.Fatalf("certPool.AppendCertsFromPEM err") } c := credentials.NewTLS(&tls.Config{ Certificates: []tls.Certificate{cert}, ServerName: "go-grpc-example", RootCAs: certPool, }) conn, err := grpc.Dial(":"+PORT, grpc.WithTransportCredentials(c)) if err != nil { log.Fatalf("grpc.Dial err: %v", err) } defer conn.Close() client := pb.NewSearchServiceClient(conn) resp, err := client.Search(context.Background(), &pb.SearchRequest{ Request: "gRPC", }) if err != nil { log.Fatalf("client.Search err: %v", err) } log.Printf("resp: %s", resp.GetResponse()) }
在 Client 中绝大部分与 Server 一致,不同点的地方是,在 Client 请求 Server 端时,Client 端会使用根证书和 ServerName 去对 Server 端进行校验
简单流程大致如下:
- Client 通过请求得到 Server 端的证书
- 使用 CA 认证的根证书对 Server 端的证书进行可靠性、有效性等校验
- 校验 ServerName 是否可用、有效
当然了,在设置了 tls.RequireAndVerifyClientCert
模式的情况下,Server 也会使用 CA 认证的根证书对 Client 端的证书进行可靠性、有效性等校验。也就是两边都会进行校验,极大的保证了安全性 :+1:
验证
重新启动 server.go 和执行 client.go,查看响应结果是否正常
总结
在本章节,我们使用 CA 颁发的根证书对客户端、服务端的证书进行了签发。进一步的提高了两者的通讯安全
这回是真的大功告成了!
参考
本系列示例代码
系列目录
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 带入gRPC:TLS 证书认证
- 带入gRPC:gRPC Deadlines
- 带入gRPC:gRPC及相关介绍
- Serverless,会将工程师带入“不归路”!
- Instana: 将微服务监控带入到服务级别
- 微软推出 Windows ML ,将机器学习带入桌面
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python for Data Analysis
Wes McKinney / O'Reilly Media / 2012-11-1 / USD 39.99
Finding great data analysts is difficult. Despite the explosive growth of data in industries ranging from manufacturing and retail to high technology, finance, and healthcare, learning and accessing d......一起来看看 《Python for Data Analysis》 这本书的介绍吧!