I want to secure my grpc traffic and authenticate client based on client certificate just like etcd(I have achieved this on etcd cluster and etcd clients).
I have read the sample code from grpc-auth-support.md, and I think it only acheives server-side authentication, because client does NOT provide its certificate.
So, does grpc-go support TLS mutual authentication? If yes, can anyone show some sample code?
You can use client certs without much difficulty. credentials.NewTLS(c *tls.Config) just takes a plain old crypto/tls.Config so its just like any other go tls program that supports client certs. On the tls.Config you set the client Certificates on the client and the client CAs and ClientAuth: tls.RequireAndVerifyClientCert on the server.
Many thanks to @psanford. Below is my sample code:
client side:
// load peer cert/key, cacert
peerCert, err := tls.LoadX509KeyPair(config.PeerCert, config.PeerKey)
if err != nil {
log.Error("load peer cert/key error:%v", err)
return nil, err
}
caCert, err := ioutil.ReadFile(config.CACert)
if err != nil {
log.Error("read ca cert file error:%v", err)
return nil, err
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
ta := credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{peerCert},
RootCAs: caCertPool,
})
conn, err := grpc.Dial(config.ServerAddr, grpc.WithTransportCredentials(ta))
if err != nil {
return nil, err
}
Server side:
// load peer cert/key, ca cert
peerCert, err := tls.LoadX509KeyPair(config.PeerCert, config.PeerKey)
if err != nil {
log.Error("load peer cert/key error:%v", err)
return
}
caCert, err := ioutil.ReadFile(config.CACert)
if err != nil {
log.Error("read ca cert file error:%v", err)
return
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
ta := credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{peerCert},
ClientCAs: caCertPool,
ClientAuth: tls.RequireAndVerifyClientCert,
})
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", cs.port))
if err != nil {
log.Error("server listen on port %d error:%v", cs.port, err)
return
}
s := grpc.NewServer(grpc.Creds(ta))
proto.RegisterSomerServer(s, cs)
go s.Serve(lis)
Is it possible to allow mutual authentication based on the peers public key and not depending on a CA? I've managed to read the client public key from the server, but not the opposite.
Most helpful comment
Many thanks to @psanford. Below is my sample code:
client side:
Server side: