предисловие
Всем привет, я 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())
}
Большинство клиентов такие же, как и серверы, разница в том, что когда клиент запрашивает сервер, клиент будет использовать корневой сертификат и имя сервера для проверки сервера.
Простой процесс примерно таков:
- Клиент получает сертификат на стороне сервера, запрашивая
- Используйте корневой сертификат, сертифицированный ЦС, для проверки надежности и действительности сертификата на стороне сервера.
- Проверьте, доступно ли имя сервера и действительно ли оно
Конечно, после установкиtls.RequireAndVerifyClientCert
В случае режима сервер также будет использовать корневой сертификат, сертифицированный ЦС, для проверки надежности и действительности сертификата клиента. То есть обе стороны будут проверены, что в значительной степени гарантирует безопасность 👍
проверять
Перезапустите server.go и запустите client.go, чтобы увидеть, нормальный ли ответ.
Суммировать
В этой главе мы используем корневой сертификат, выданный ЦС, для подписи сертификатов клиента и сервера. Дальнейшее улучшение безопасности связи между двумя
На этот раз это действительно сделано!
?
Если у вас есть какие-либо вопросы или ошибки, добро пожаловать вissuesЗадавайте вопросы или вносите исправления, если вам нравится или помогаете, добро пожаловатьStar, является своеобразным поощрением и продвижением автора.