You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
124 lines
3.8 KiB
124 lines
3.8 KiB
package security
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"github.com/chrislusf/seaweedfs/weed/util"
|
|
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/peer"
|
|
"google.golang.org/grpc/status"
|
|
"io/ioutil"
|
|
"strings"
|
|
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials"
|
|
|
|
"github.com/chrislusf/seaweedfs/weed/glog"
|
|
)
|
|
|
|
type Authenticator struct {
|
|
AllowedWildcardDomain string
|
|
AllowedCommonNames map[string]bool
|
|
}
|
|
|
|
func LoadServerTLS(config *util.ViperProxy, component string) (grpc.ServerOption, grpc.ServerOption) {
|
|
if config == nil {
|
|
return nil, nil
|
|
}
|
|
|
|
// load cert/key, ca cert
|
|
cert, err := tls.LoadX509KeyPair(config.GetString(component+".cert"), config.GetString(component+".key"))
|
|
if err != nil {
|
|
glog.V(1).Infof("load cert: %s / key: %s error: %v",
|
|
config.GetString(component+".cert"),
|
|
config.GetString(component+".key"),
|
|
err)
|
|
return nil, nil
|
|
}
|
|
caCert, err := ioutil.ReadFile(config.GetString("grpc.ca"))
|
|
if err != nil {
|
|
glog.V(1).Infof("read ca cert file %s error: %v", config.GetString("grpc.ca"), err)
|
|
return nil, nil
|
|
}
|
|
caCertPool := x509.NewCertPool()
|
|
caCertPool.AppendCertsFromPEM(caCert)
|
|
ta := credentials.NewTLS(&tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
ClientCAs: caCertPool,
|
|
ClientAuth: tls.RequireAndVerifyClientCert,
|
|
})
|
|
|
|
allowedCommonNames := config.GetString(component + ".allowed_commonNames")
|
|
allowedWildcardDomain := config.GetString("grpc.allowed_wildcard_domain")
|
|
if allowedCommonNames != "" || allowedWildcardDomain != "" {
|
|
allowedCommonNamesMap := make(map[string]bool)
|
|
for _, s := range strings.Split(allowedCommonNames, ",") {
|
|
allowedCommonNamesMap[s] = true
|
|
}
|
|
auther := Authenticator{
|
|
AllowedCommonNames: allowedCommonNamesMap,
|
|
AllowedWildcardDomain: allowedWildcardDomain,
|
|
}
|
|
return grpc.Creds(ta), grpc.UnaryInterceptor(grpc_auth.UnaryServerInterceptor(auther.Authenticate))
|
|
}
|
|
return grpc.Creds(ta), nil
|
|
}
|
|
|
|
func LoadClientTLS(config *util.ViperProxy, component string) grpc.DialOption {
|
|
if config == nil {
|
|
return grpc.WithInsecure()
|
|
}
|
|
|
|
certFileName, keyFileName, caFileName := config.GetString(component+".cert"), config.GetString(component+".key"), config.GetString("grpc.ca")
|
|
if certFileName == "" || keyFileName == "" || caFileName == "" {
|
|
return grpc.WithInsecure()
|
|
}
|
|
|
|
// load cert/key, cacert
|
|
cert, err := tls.LoadX509KeyPair(certFileName, keyFileName)
|
|
if err != nil {
|
|
glog.V(1).Infof("load cert/key error: %v", err)
|
|
return grpc.WithInsecure()
|
|
}
|
|
caCert, err := ioutil.ReadFile(caFileName)
|
|
if err != nil {
|
|
glog.V(1).Infof("read ca cert file error: %v", err)
|
|
return grpc.WithInsecure()
|
|
}
|
|
caCertPool := x509.NewCertPool()
|
|
caCertPool.AppendCertsFromPEM(caCert)
|
|
|
|
ta := credentials.NewTLS(&tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
RootCAs: caCertPool,
|
|
InsecureSkipVerify: true,
|
|
})
|
|
return grpc.WithTransportCredentials(ta)
|
|
}
|
|
|
|
func (a Authenticator) Authenticate(ctx context.Context) (newCtx context.Context, err error) {
|
|
p, ok := peer.FromContext(ctx)
|
|
if !ok {
|
|
return ctx, status.Error(codes.Unauthenticated, "no peer found")
|
|
}
|
|
|
|
tlsAuth, ok := p.AuthInfo.(credentials.TLSInfo)
|
|
if !ok {
|
|
return ctx, status.Error(codes.Unauthenticated, "unexpected peer transport credentials")
|
|
}
|
|
if len(tlsAuth.State.VerifiedChains) == 0 || len(tlsAuth.State.VerifiedChains[0]) == 0 {
|
|
return ctx, status.Error(codes.Unauthenticated, "could not verify peer certificate")
|
|
}
|
|
|
|
commonName := tlsAuth.State.VerifiedChains[0][0].Subject.CommonName
|
|
if a.AllowedWildcardDomain != "" && strings.HasSuffix(commonName, a.AllowedWildcardDomain) {
|
|
return ctx, nil
|
|
}
|
|
if _, ok := a.AllowedCommonNames[commonName]; ok {
|
|
return ctx, nil
|
|
}
|
|
|
|
return ctx, status.Errorf(codes.Unauthenticated, "invalid subject common name: %s", commonName)
|
|
}
|