golang工程——grpc TLS配置

TLS配置

非对称加密流程

TLS流程

golang工程——grpc TLS配置_第1张图片
golang工程——grpc TLS配置_第2张图片

这是单向TLS流程

ECDHE握手过程(图片来自透视Http协议课程)

浏览器发送Client Hello消息
  • 客户端向服务器打招呼,消息中包含客户端生成的随机数C,客户单的TLS版本号,可使用的密码套件列表及扩展列表。
  • 后续需要对比TLS版本号,用随机数计算秘钥。
服务器发送Server Hello消息
  • 服务器向客户端打招呼,消息包含服务器生成的随机数S,确认TLS版本号,从客户端可用密码套件列表中选用的密码套件。
  • 还需包含数字证书,用于验证。
  • 以及秘钥交换算法的参数(也就是公钥),需包含签名认证。
  • 并确认已收到了Client Hello信息。
客户端验证并计算主密钥
  • 对收到的证书和签名进行验证。根证书对服务器证书进行验签,根证书一般都是内置和预安装的
  • 验证成功后向服务器发送送秘钥交换算法的参数。
  • 服务器接收到客户端的秘钥交换算法参数(也就是私钥),开始计算master secret。先生成pre-master,根据pre-master和两个随机数算出master secret(主秘钥)。
  • 客户端也进行主秘钥的计算。之所以称为主密钥,是因为根据主密钥可生成多个会话秘钥由于不同的具体加密,如:客户端发送用的会话秘钥、服务端用的会话秘钥。
  • 目前都是明文通信,所以秘钥的生成必须很讲究,各部计算都需随机性极强的算法,保证安全性。
验证加密通信并验证

至此加密通信所用的秘钥都已生成,在此之前都是明文发送。客户端通知服务器启用加密通信并加密发送之前所发信息的摘要,服务器也做一样的事,用于验证加密通信是否可行。发送的两个消息分别是“Change Cipher Spec”和“Finished”。之后就可使用加密的Http请求和响应。

双向认证

上述方式验证了服务器的安全性,而服务器验证客户端可用更多方式,比如账号密码,此时已经达到了加密通信的标准。

更深层次的客户端验证,也可Client Hello中出示客户端证书,用以验证。最终实现更为安全的双向验证。

创建证书

openssl.cnf

[req]
distinguished_name = req_distinguished_name
attributes = req_attributes

[req_distinguished_name]

[req_attributes]

[test_ca]
basicConstraints        = critical,CA:TRUE
subjectKeyIdentifier    = hash
authorityKeyIdentifier  = keyid:always,issuer:always
keyUsage                = critical,keyCertSign

[test_server]
basicConstraints        = critical,CA:FALSE
subjectKeyIdentifier    = hash
keyUsage                = critical,digitalSignature,keyEncipherment,keyAgreement
subjectAltName          = @server_alt_names

[server_alt_names]
DNS.1 = *.grpc.test.com

[test_client]
basicConstraints        = critical,CA:FALSE
subjectKeyIdentifier    = hash
keyUsage                = critical,nonRepudiation,digitalSignature,keyEncipherment
extendedKeyUsage        = critical,clientAuth

#!/bin/bash

# Create the server CA certs. 服务器根证书和私钥
openssl req -x509                                     \
  -newkey rsa:4096                                    \
  -nodes                                              \
  -days 3650                                          \
  -keyout ca_key.pem                                  \
  -out ca_cert.pem                                    \
  -subj /C=US/ST=CA/L=SVL/O=gRPC/CN=test-server_ca/   \
  -config ./openssl.cnf                               \
  -extensions test_ca                                 \
  -sha256

# Create the client CA certs. 客户端根证书和私钥
openssl req -x509                                     \
  -newkey rsa:4096                                    \
  -nodes                                              \
  -days 3650                                          \
  -keyout client_ca_key.pem                           \
  -out client_ca_cert.pem                             \
  -subj /C=US/ST=CA/L=SVL/O=gRPC/CN=test-client_ca/   \
  -config ./openssl.cnf                               \
  -extensions test_ca                                 \
  -sha256

# Generate a server cert.
# 长度4096
# 生成服务器私钥
openssl genrsa -out server_key.pem 4096
# 私钥生成服务器证书请求
openssl req -new                                    \
  -key server_key.pem                               \
  -days 3650                                        \
  -out server_csr.pem                               \
  -subj /C=US/ST=CA/L=SVL/O=gRPC/CN=test-server1/   \
  -config ./openssl.cnf                             \
  -reqexts test_server
  
 # 生成服务器证书
openssl x509 -req           \
  -in server_csr.pem        \
  -CAkey ca_key.pem         \
  -CA ca_cert.pem           \
  -days 3650                \
  -set_serial 1000          \
  -out server_cert.pem      \
  -extfile ./openssl.cnf    \
  -extensions test_server   \
  -sha256
openssl verify -verbose -CAfile ca_cert.pem  server_cert.pem

# Generate a client cert. 客户端证书
# 长度4096
openssl genrsa -out client_key.pem 4096
openssl req -new                                    \
  -key client_key.pem                               \
  -days 3650                                        \
  -out client_csr.pem                               \
  -subj /C=US/ST=CA/L=SVL/O=gRPC/CN=test-client1/   \
  -config ./openssl.cnf                             \
  -reqexts test_client
openssl x509 -req           \
  -in client_csr.pem        \
  -CAkey client_ca_key.pem  \
  -CA client_ca_cert.pem    \
  -days 3650                \
  -set_serial 1000          \
  -out client_cert.pem      \
  -extfile ./openssl.cnf    \
  -extensions test_client   \
  -sha256
openssl verify -verbose -CAfile client_ca_cert.pem  client_cert.pem

rm *_csr.pem


服务器证书:

  • 服务器根证书和私钥
  • 生成服务器私钥
  • 用服务器私钥生成证书请求
  • 服务器根证书和根私钥+证书请求生成服务器证书
go grpc 配置
单向TLS

服务端

package server

import (
	"crypto/tls"
	"crypto/x509"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"log"
	"os"
)
func GetTlsOpt() grpc.ServerOption {
    // 服务端证书、服务端密钥
	creds, err := credentials.NewServerTLSFromFile("x509/server_cert.pem", "x509/server_key.pem")
	if err != nil {
		log.Fatal(err)
	}
	return grpc.Creds(creds)
}

客户端

package client

import (
    "crypto/tls"
    "crypto/x509"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "log"
    "os"
)


// 单向TLS
func GetTlsOpt() grpc.DialOption {
    // 服务端根证书,域名,根证书用来做验签
    creds, err := credentials.NewClientTLSFromFile("x509/ca_cert.pem", "echo.grpc.test.com")
    if err != nil {
        log.Fatal(err)
    }
    opt := grpc.WithTransportCredentials(creds)
    return opt

}
双向TLS

可以理解成多一个反过来的流程,双方对等

服务端

package server

import (
	"crypto/tls"
	"crypto/x509"
	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials"
	"log"
	"os"
)
func GetMTlsOpt() grpc.ServerOption {
	cert, err := tls.LoadX509KeyPair("x509/server_cert.pem", "x509/server_key.pem")
	if err != nil {
		log.Fatal(err)
	}
	ca := x509.NewCertPool()
	caFilePath := "x509/client_ca_cert.pem"
	bytes, err := os.ReadFile(caFilePath)
	if err != nil {
		log.Fatal(err)
	}
	if ok := ca.AppendCertsFromPEM(bytes); !ok {
		log.Fatal("ca append failed")
	}
	tlsConfig := &tls.Config{
		ClientAuth:   tls.RequireAndVerifyClientCert,
		Certificates: []tls.Certificate{cert},
		ClientCAs:    ca,
	}
	return grpc.Creds(credentials.NewTLS(tlsConfig))
}

客户端

package client

import (
    "crypto/tls"
    "crypto/x509"
    "google.golang.org/grpc"
    "google.golang.org/grpc/credentials"
    "log"
    "os"
)


func GetMTlsOpt() grpc.DialOption {
    // 客户端证书和密钥
    cert, err := tls.LoadX509KeyPair("x509/client_cert.pem", "x509/client_key.pem")
    if err != nil {
        log.Fatal(err)
    }
    ca := x509.NewCertPool()
    // 服务端根证书
    caFilePath := "x509/ca_cert.pem"
    bytes, err := os.ReadFile(caFilePath)
    if err != nil {
        log.Fatal(err)
    }
    if ok := ca.AppendCertsFromPEM(bytes); !ok {
        log.Fatal("ca append failed")
    }
    tlsConfig := &tls.Config{
        ServerName:   "echo.grpc.test.com",
        Certificates: []tls.Certificate{cert},
        RootCAs:      ca,
    }
    return grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))
}

你可能感兴趣的:(golang,开发语言,后端)