mirror of
https://github.com/paralus/paralus.git
synced 2026-03-06 02:50:20 +00:00
114 lines
3.4 KiB
Go
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
|
|
}
|