04/04/2020 - GO
As far as gRPC goes, the client and server communications takes place over HTTP/2. The transmitted messages are in binary data but the communication is in plaintext form. In this example we are going to introduce extra security to encrypt message with TLS/SSL.
First of all you need to create server's SSL certificates.
$ 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
When you build a gRPC application, you first create a *.proto
file and compile it then start developing your application.
├── 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
.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
syntax = "proto3";
package credit;
message CreditRequest {
float amount = 1;
}
message CreditResponse {
string confirmation = 1;
}
service CreditService {
rpc Credit(CreditRequest) returns (CreditResponse) {}
}
I am not adding the content here because it is generated with the command below.
make compile
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())
}
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
}
$ 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
When you run client code above, the server will also output message below.
2020/04/04 18:07:42 Request: 1990.01
If you manipulate public.crt
, the client will output message below.
2020/04/04 22:53:47 credentials: failed to append certificates
make: *** [client] Error 1