GRPC ile ilgili olarak, istemci ve sunucu iletişimleri HTTP/2 üzerinden gerçekleşir. İletilen mesajlar binary verilerdir, ancak iletişim sade metin biçimindedir. Bu örnekte, mesajı TLS/SSL ile şifrelemek için ekstra güvenlik sunacağız.


SSL sertifikalar


Her şeyden önce sunucunun SSL sertifikalarını oluşturmanız gerekir.


$ openssl genrsa -out private.key 4096
Generating RSA private key, 4096 bit long modulus
.............++
.............++
(0x10001)

$ openssl req -new -x509 -sha256 -days 1825 -key private.key -out public.crt
Country Name (2 letter code) []:UK
State or Province Name (full name) []:London
Locality Name (eg, city) []:City of London
Organization Name (eg, company) []:You Ltd
Organizational Unit Name (eg, section) []:Engineering
Common Name (eg, fully qualified host name) []:localhost
Email Address []:you@you.com

Yapı


Bir gRPC uygulaması oluşturduğunuzda, önce bir *.proto dosyası oluşturun ve derleyin, ardından uygulamanızı geliştirmeye başlayın.


├── Makefile
├── Readme.md
├── client
│   ├── cert
│   │   └── public.crt
│   └── main.go
├── go.mod
├── go.sum
├── pkg
│   └── proto
│   └── credit
│   ├── credit.pb.go
│   └── credit.proto
└── server
├── cert
│   ├── private.key
│   └── public.crt
└── main.go

Dosyalar


Makefile


.PHONY: compile
compile: ## Compile the proto file.
protoc -I pkg/proto/credit/ pkg/proto/credit/credit.proto --go_out=plugins=grpc:pkg/proto/credit/

.PHONY: server
server: ## Build and run server.
go build -race -ldflags "-s -w" -o bin/server server/main.go
bin/server

.PHONY: client
client: ## Build and run client.
go build -race -ldflags "-s -w" -o bin/client client/main.go
bin/client

credit.proto


syntax = "proto3";

package credit;

message CreditRequest {
float amount = 1;
}

message CreditResponse {
string confirmation = 1;
}

service CreditService {
rpc Credit(CreditRequest) returns (CreditResponse) {}
}

credit.pb.go


İçeriği buraya eklemiyorum çünkü aşağıdaki komutla üretiliyor.


make compile

client/main.go


package main

import (
"context"
"log"
"time"

"github.com/YOU/bank/pkg/proto/credit"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)

func main() {
log.Println("Client running ...")

creds, err := credentials.NewClientTLSFromFile("./client/cert/public.crt", "localhost")
if err != nil {
log.Fatalln(err)
}

opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithBlock(),
}

conn, err := grpc.Dial(":50051", opts...)
if err != nil {
log.Fatalln(err)
}
defer conn.Close()

client := credit.NewCreditServiceClient(conn)

request := &credit.CreditRequest{Amount: 1990.01}

ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()

response, err := client.Credit(ctx, request)
if err != nil {
log.Fatalln(err)
}

log.Println("Response:", response.GetConfirmation())
}

server/main.go


package main

import (
"context"
"crypto/tls"
"fmt"
"log"
"net"

"github.com/YOU/bank/pkg/proto/credit"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)

type server struct {
credit.UnimplementedCreditServiceServer
}

func main() {
log.Println("Server running ...")

cert, err := tls.LoadX509KeyPair("./server/cert/public.crt", "./server/cert/private.key")
if err != nil {
log.Fatalln(err)
}

opts := []grpc.ServerOption{
// Enable TLS for all incoming connections.
grpc.Creds(credentials.NewServerTLSFromCert(&cert)),
}

lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalln(err)
}

srv := grpc.NewServer(opts...)
credit.RegisterCreditServiceServer(srv, &server{})

log.Fatalln(srv.Serve(lis))
}

func (s *server) Credit(ctx context.Context, request *credit.CreditRequest) (*credit.CreditResponse, error) {
log.Println(fmt.Sprintf("Request: %g", request.GetAmount()))

return &credit.CreditResponse{Confirmation: fmt.Sprintf("Credited %g", request.GetAmount())}, nil
}

Test


$ make server
go build -race -ldflags "-s -w" -o bin/server server/main.go
bin/server
2020/04/04 18:07:37 Server running ...

$ make client
go build -race -ldflags "-s -w" -o bin/client client/main.go
bin/client
2020/04/04 18:07:42 Client running ...
2020/04/04 18:07:42 Response: Credited 1990.01

Yukarıdaki istemci kodunu çalıştırdığınızda, sunucu ayrıca aşağıdaki mesajı da verecektir.


2020/04/04 18:07:42 Request: 1990.01

Eğer public.crt dosyasında değişiklik yaparsanız, istemci aşağıdaki mesajı verecektir.


2020/04/04 22:53:47 credentials: failed to append certificates
make: *** [client] Error 1

Referanslar