Bring in gRPC: ca-based TLS certificate authentication
Original address:Bring in gRPC: ca-based TLS certificate authentication
Project address:https://github.com/EDDYCJY/go …
Preface
In the previous chapter, we raised a question. How to ensure the reliability and validity of the certificate? How do you make sure your Server and Client certificates are correct?
CA
In order to ensure the reliability and validity of the certificate, the concept of root certificate issued by CA can be introduced here. It complies with the X.509 standard.
Root certificate
The root certificate is a public key certificate belonging to the root certification authority (CA). We can trust the CA by verifying the CA’s signature. Anyone can obtain the CA’s certificate (including the public key) to verify the certificate it issues (client and server)
It contains the following documents:
- Public key
- Key
Generate Key
openssl genrsa -out ca.key 2048
Generate key
openssl req -new -x509 -days 7200 -key ca.key -out ca.pem
Fill in the information
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
Generate 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 is the English abbreviation of CertificateSigning Request, which is a certificate request document. The main function is that CA will use CSR files to sign so that attackers cannot disguise or tamper with the original certificate.
Ca-based issuance
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem
Client
Generate Key
openssl ecparam -genkey -name secp384r1 -out client.key
Generate CSR
openssl req -new -key client.key -out client.csr
Ca-based issuance
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in client.csr -out client.pem
Organize catalogues
So far we have generated a pile of files, please store them in the following directory structure:
$ tree conf
conf
├── ca.key
├── ca.pem
├── ca.srl
├── client
│ ├── client.csr
│ ├── client.key
│ └── client.pem
└── server
├── server.csr
├── server.key
└── server.pem
Other documents should not appear in the warehouse and should be kept confidential or deleted. But for the sake of real demonstration, I kept it (knocking on the blackboard)
gRPC
Next, the gRPC will be formally coded and the code in the previous chapter will be modified. The goal is TLS authentication based on 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 (): from certificate related filesreadAndanalysisInformation, get the certificate public key, key pair
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 (): create a new, empty CertPool
- CertPool.AppendCertsFromPEM (): attempts to resolve the passed PEM-encoded certificate. If the resolution is successful, it will be added to CertPool for later use.
- Newtls: build tls-based TransportCredentials option
- Tls.Config:Config structure is used to configure TLS clients or servers
On the Server, a total of three Config configuration items are used:
(1)Certificates: Set up a certificate chain that can contain one or more
(2)ClientAuth: the client’s certificate must be verified. The following parameters can be selected according to the actual situation:
const (
NoClientCert ClientAuthType = iota
RequestClientCert
RequireAnyClientCert
VerifyClientCertIfGiven
RequireAndVerifyClientCert
)
(3)ClientCAs: sets the set of root certificates, and the verification method uses the mode set in 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())
}
Most of the Clients are consistent with the Server. the difference is that when the Client requests the Server, the client uses the root certificate and ServerName to check the Server.
The simple process is roughly as follows:
- Client obtains server-side certificate through request
- The root certificate authenticated by CA is used to verify the reliability and validity of the certificate on the Server side.
- Verify that ServerName is available and valid
Of course, in setting uptls.RequireAndVerifyClientCert
In CAse of mode, Server will also use the root certificate authenticated by ca to verify the reliability and validity of the client-side certificate. In other words, both sides will check, thus greatly ensuring safety.
Verification
Restart server.go and execute client.go to see if the response results are normal.
Summary
In this chapter, we use the root certificate issued by CA to issue the certificates of client and server. The communication safety between the two is further improved
This time is really accomplished!
References
This series of sample codes
Series catalog
- Bring gRPC:gRPC and Related Introduction
- Bring in grpc: grpcclient and server
- Bring in grpc: grpcstreaming, clientand server
- Bring in gRPC:TLS certificate authentication
- Bring in gRPC: ca-based TLS certificate authentication
- Into grpc: unamry and streaminterceptor
- Bring in gRPC: Let your service provide HTTP interface at the same time
- Bring into gRPC: Make custom authentication for RPC method
- Bring in grpcs: grpcdeals
- Bring in gRPC: distributed link tracking gRPC+Opentracing+Zipkin