Go gRPC Series 5: проверка сертификата TLS на основе ЦС

Go

предисловие

Всем привет, я Frying Fish, и в предыдущей главе мы задали вопрос. Как обеспечить надежность и действительность сертификата? Как проверить правильность сертификатов сервера и клиента?

CA

Для обеспечения надежности и действительности сертификата здесь может быть введено понятие корневого сертификата, выданного ЦС. Он соответствует стандарту X.509

корневой сертификат

Корневой сертификат — это сертификат открытого ключа, принадлежащий корневому центру сертификации (ЦС). Мы можем доверять ЦС, проверив подпись ЦС, и любой может получить сертификат ЦС (включая открытый ключ), чтобы проверить сертификат, который он выдает (клиент, сервер).

Файлы, которые он содержит, следующие:

  • открытый ключ
  • ключ

Сгенерировать ключ

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 — это английская аббревиатура от Certificate Signing Request, который представляет собой файл запроса сертификата. Основная функция заключается в том, что ЦС будет использовать файл CSR для подписи, чтобы злоумышленник не мог замаскировать или подделать исходный сертификат.

Выдано ЦС

openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem

Client

Сгенерировать ключ

openssl ecparam -genkey -name secp384r1 -out client.key

Создать CSR

openssl req -new -key client.key -out client.csr

Выдано ЦС

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 и трансформируем код из предыдущей главы. Цель состоит в том, чтобы выполнить аутентификацию TLS на основе CA 🤫

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 для последующего использования.
  • учетные данные. NewTLS: параметр создания транспортных учетных данных на основе TLS.
  • tls.Config: структура Config используется для настройки клиента или сервера TLS.

В сервере используется всего три элемента конфигурации Config:

(1) Сертификаты: установите цепочку сертификатов, позволяющую одному или нескольким

(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())
}

Большинство клиентов такие же, как и серверы, разница в том, что когда клиент запрашивает сервер, клиент будет использовать корневой сертификат и имя сервера для проверки сервера.

Простой процесс примерно таков:

  1. Клиент получает сертификат на стороне сервера, запрашивая
  2. Используйте корневой сертификат, сертифицированный ЦС, для проверки надежности и действительности сертификата на стороне сервера.
  3. Проверьте, доступно ли имя сервера и действительно ли оно

Конечно, после установкиtls.RequireAndVerifyClientCertВ случае режима сервер также будет использовать корневой сертификат, сертифицированный ЦС, для проверки надежности и действительности сертификата клиента. То есть обе стороны будут проверены, что в значительной степени гарантирует безопасность 👍

проверять

Перезапустите server.go и запустите client.go, чтобы увидеть, нормальный ли ответ.

Суммировать

В этой главе мы используем корневой сертификат, выданный ЦС, для подписи сертификатов клиента и сервера. Дальнейшее улучшение безопасности связи между двумя

На этот раз это действительно сделано!

?

Если у вас есть какие-либо вопросы или ошибки, добро пожаловать вissuesЗадавайте вопросы или вносите исправления, если вам нравится или помогаете, добро пожаловатьStar, является своеобразным поощрением и продвижением автора.

мой публичный аккаунт

image

Ссылаться на

Пример кода для этой серии