preface
Hello, I am fried fish. In the last chapter, we asked a question. How to ensure the reliability and validity of certificates? How do you make sure your Server and Client certificates are correct?
CA
To ensure the reliability and validity of certificates, you can introduce the concept of the root certificate issued by the CA. It complies with the X.509 standard
Root certificate
A root certificate is a public key certificate belonging to the root Certification Authority (CA). We can trust CA by verifying its signature. Anyone can obtain CA’s certificate (including public key) to verify the certificate issued by CA (client, server).
It contains the following files:
- The public key
- The key
To generate the Key
openssl genrsa -out ca.key 2048
Copy the code
Generate the key
openssl req -new -x509 -days 7200 -key ca.key -out ca.pem
Copy the code
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 []:
Copy the code
Server
To generate a CSR
openssl req -new -key server.key -out server.csr
Copy the code
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 []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
Copy the code
CSR is an acronym for Cerificate Signing Request. The main effect is that THE CA will use the CSR file to sign so that the attacker cannot disguise or tamper with the original certificate
CA based Issue
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in server.csr -out server.pem
Copy the code
Client
To generate the Key
openssl ecparam -genkey -name secp384r1 -out client.key
Copy the code
To generate a CSR
openssl req -new -key client.key -out client.csr
Copy the code
CA based Issue
openssl x509 -req -sha256 -CA ca.pem -CAkey ca.key -CAcreateserial -days 3650 -in client.csr -out client.pem
Copy the code
Finishing directory
So far we have generated a bunch of files, please store them in the following directory structure:
└── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ── ─ Server ├ ─ ─ for server CSR ├ ─ ─ for server key └ ─ ─ for server pemCopy the code
In addition, some documents should not appear in the warehouse, should be confidential or deleted. But I’m saving it for the sake of the demonstration. (Knocks on the blackboard)
gRPC
Next, you’ll start coding for gRPC in earnest, transforming the code from the previous chapter. The goal is CA based TLS authentication 🤫
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")
iferr ! = nil { log.Fatalf("tls.LoadX509KeyPair err: %v", err)
}
certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile(".. /.. /conf/ca.pem")
iferr ! = nil { log.Fatalf("ioutil.ReadFile err: %v", err)
}
ifok := 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)
iferr ! = nil { log.Fatalf("net.Listen err: %v", err)
}
server.Serve(lis)
}
Copy the code
- Tls.loadx509keypair () : reads and parses information from the certificate file to obtain the certificate public key and key pair
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
certPEMBlock, err := ioutil.ReadFile(certFile)
iferr ! = nil {return Certificate{}, err
}
keyPEMBlock, err := ioutil.ReadFile(keyFile)
iferr ! = nil {return Certificate{}, err
}
return X509KeyPair(certPEMBlock, keyPEMBlock)
}
Copy the code
- X509.newcertpool () : Creates a new, empty CertPool
- CertPool. AppendCertsFromPEM () : try to parse the incoming PEM encoded certificate. If the parse succeeds, it will be added to CertPool for later use
- NewTLS: Builds the TransportCredentials option based on TLS
- Tls. Config: The Config structure is used to configure the TLS client or server
On the Server, three Config configuration items are used:
(1) Certificates: Set up the chain of Certificates, allowing one or more Certificates
(2) ClientAuth: the client certificate must be verified. You can select the following parameters as required:
const (
NoClientCert ClientAuthType = iota
RequestClientCert
RequireAnyClientCert
VerifyClientCertIfGiven
RequireAndVerifyClientCert
)
Copy the code
(3) ClientCAs: Sets the set of root certificates. The verification mode is 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")
iferr ! = nil { log.Fatalf("tls.LoadX509KeyPair err: %v", err)
}
certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile(".. /.. /conf/ca.pem")
iferr ! = nil { log.Fatalf("ioutil.ReadFile err: %v", err)
}
ifok := 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))
iferr ! = 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",})iferr ! = nil { log.Fatalf("client.Search err: %v", err)
}
log.Printf("resp: %s", resp.GetResponse())
}
Copy the code
In most cases, the Client is the same as the Server. The difference is that the Client uses the root certificate and ServerName to verify the Server when the Client requests the Server
The simple process is as follows:
- The Client obtains the certificate of the Server by request
- Use the CA-authenticated root certificate to verify the reliability and validity of the Server certificate
- Verify that a ServerName is available and valid
. Of course, in setting up the TLS RequireAndVerifyClientCert mode, the Server will use the root certificate of the CA certification on the Client side certificates for reliability and validity check. That is, both sides will be checked, which greatly ensures the safety 👍
validation
Restart server.go and run client.go to check whether the response is normal
conclusion
In this section, we use the root certificate issued by the CA to sign the client and server certificates. Further improve the communication security of the two
This time it’s really done!
?
If you have any questions or mistakes, welcome to raise questions or give correction opinions on issues. If you like or are helpful to you, welcome Star, which is a kind of encouragement and promotion for the author.
My official account
reference
Sample code for this series
- go-grpc-example