Files
paralus/components/common/pkg/grpc/server.go
2021-12-28 14:23:52 +05:30

114 lines
3.4 KiB
Go

package grpc
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io/ioutil"
"strings"
"time"
"google.golang.org/grpc/peer"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/keepalive"
)
var (
serverDefaultOpts = []grpc.ServerOption{
grpc.KeepaliveParams(keepalive.ServerParameters{
Time: time.Second * 30, // server initiated keep alive interval
Timeout: time.Second * 30, // server initiated keep alive timeout
}),
grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{
MinTime: time.Minute, // server enforcement for client keep alive
PermitWithoutStream: true, // allow connection without any active ongoing streams
}),
}
// ErrInvalidClient is returned when client cert is not present in peer context
ErrInvalidClient = errors.New("client has not presented certificate")
)
// NewSecureServerWithPEM creates a secure gRPC service with give PEM encoded cert, key and ca
func NewSecureServerWithPEM(cert, key, ca []byte, opts ...grpc.ServerOption) (*grpc.Server, error) {
certificate, err := tls.X509KeyPair(cert, key)
if err != nil {
return nil, fmt.Errorf("invalid cert/key pair: %s", err)
}
certPool := x509.NewCertPool()
if ok := certPool.AppendCertsFromPEM(ca); !ok {
return nil, fmt.Errorf("failed to append ca cert")
}
creds := credentials.NewTLS(&tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{certificate},
ClientCAs: certPool,
})
opts = append(opts, serverDefaultOpts...)
opts = append([]grpc.ServerOption{grpc.Creds(creds)}, opts...)
return grpc.NewServer(opts...), nil
}
// NewSecureServer returns new grpc server given cert path, key path and ca path
func NewSecureServer(certPath, keyPath, caPath string, opts ...grpc.ServerOption) (*grpc.Server, error) {
certificate, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
return nil, fmt.Errorf("unable to load cert/key : %s", err)
}
certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile(caPath)
if err != nil {
return nil, fmt.Errorf("unable to read ca cert: %s", err)
}
if ok := certPool.AppendCertsFromPEM(ca); !ok {
return nil, fmt.Errorf("failed to append ca cert %s", "")
}
creds := credentials.NewTLS(&tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: []tls.Certificate{certificate},
ClientCAs: certPool,
})
opts = append(opts, serverDefaultOpts...)
opts = append([]grpc.ServerOption{grpc.Creds(creds)}, opts...)
return grpc.NewServer(opts...), nil
}
// NewServer returns new unsecured grpc server
func NewServer(opts ...grpc.ServerOption) (*grpc.Server, error) {
opts = append(opts, serverDefaultOpts...)
return grpc.NewServer(opts...), nil
}
// GetClientName returns client CommonName from client cert
func GetClientName(ctx context.Context) (string, error) {
if p, ok := peer.FromContext(ctx); ok {
tlsInfo := p.AuthInfo.(credentials.TLSInfo)
for _, c := range tlsInfo.State.PeerCertificates {
return c.Subject.CommonName, nil
}
}
return "", ErrInvalidClient
}
// GetClientOU returns client Organization Unit from client cert
func GetClientOU(ctx context.Context) (string, error) {
if p, ok := peer.FromContext(ctx); ok {
tlsInfo := p.AuthInfo.(credentials.TLSInfo)
for _, c := range tlsInfo.State.PeerCertificates {
if len(c.Subject.OrganizationalUnit) > 0 {
return strings.Join(c.Subject.OrganizationalUnit, "-"), nil
}
}
}
return "", ErrInvalidClient
}