tls.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. package security
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "crypto/x509"
  6. "github.com/chrislusf/seaweedfs/weed/util"
  7. grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
  8. "google.golang.org/grpc/codes"
  9. "google.golang.org/grpc/peer"
  10. "google.golang.org/grpc/status"
  11. "io/ioutil"
  12. "strings"
  13. "google.golang.org/grpc"
  14. "google.golang.org/grpc/credentials"
  15. "github.com/chrislusf/seaweedfs/weed/glog"
  16. )
  17. type Authenticator struct {
  18. AllowedWildcardDomain string
  19. AllowedCommonNames map[string]bool
  20. }
  21. func LoadServerTLS(config *util.ViperProxy, component string) (grpc.ServerOption, grpc.ServerOption) {
  22. if config == nil {
  23. return nil, nil
  24. }
  25. // load cert/key, ca cert
  26. cert, err := tls.LoadX509KeyPair(config.GetString(component+".cert"), config.GetString(component+".key"))
  27. if err != nil {
  28. glog.V(1).Infof("load cert: %s / key: %s error: %v",
  29. config.GetString(component+".cert"),
  30. config.GetString(component+".key"),
  31. err)
  32. return nil, nil
  33. }
  34. caCert, err := ioutil.ReadFile(config.GetString("grpc.ca"))
  35. if err != nil {
  36. glog.V(1).Infof("read ca cert file %s error: %v", config.GetString("grpc.ca"), err)
  37. return nil, nil
  38. }
  39. caCertPool := x509.NewCertPool()
  40. caCertPool.AppendCertsFromPEM(caCert)
  41. ta := credentials.NewTLS(&tls.Config{
  42. Certificates: []tls.Certificate{cert},
  43. ClientCAs: caCertPool,
  44. ClientAuth: tls.RequireAndVerifyClientCert,
  45. })
  46. allowedCommonNames := config.GetString(component + ".allowed_commonNames")
  47. allowedWildcardDomain := config.GetString("grpc.allowed_wildcard_domain")
  48. if allowedCommonNames != "" || allowedWildcardDomain != "" {
  49. allowedCommonNamesMap := make(map[string]bool)
  50. for _, s := range strings.Split(allowedCommonNames, ",") {
  51. allowedCommonNamesMap[s] = true
  52. }
  53. auther := Authenticator{
  54. AllowedCommonNames: allowedCommonNamesMap,
  55. AllowedWildcardDomain: allowedWildcardDomain,
  56. }
  57. return grpc.Creds(ta), grpc.UnaryInterceptor(grpc_auth.UnaryServerInterceptor(auther.Authenticate))
  58. }
  59. return grpc.Creds(ta), nil
  60. }
  61. func LoadClientTLS(config *util.ViperProxy, component string) grpc.DialOption {
  62. if config == nil {
  63. return grpc.WithInsecure()
  64. }
  65. certFileName, keyFileName, caFileName := config.GetString(component+".cert"), config.GetString(component+".key"), config.GetString("grpc.ca")
  66. if certFileName == "" || keyFileName == "" || caFileName == "" {
  67. return grpc.WithInsecure()
  68. }
  69. // load cert/key, cacert
  70. cert, err := tls.LoadX509KeyPair(certFileName, keyFileName)
  71. if err != nil {
  72. glog.V(1).Infof("load cert/key error: %v", err)
  73. return grpc.WithInsecure()
  74. }
  75. caCert, err := ioutil.ReadFile(caFileName)
  76. if err != nil {
  77. glog.V(1).Infof("read ca cert file error: %v", err)
  78. return grpc.WithInsecure()
  79. }
  80. caCertPool := x509.NewCertPool()
  81. caCertPool.AppendCertsFromPEM(caCert)
  82. ta := credentials.NewTLS(&tls.Config{
  83. Certificates: []tls.Certificate{cert},
  84. RootCAs: caCertPool,
  85. InsecureSkipVerify: true,
  86. })
  87. return grpc.WithTransportCredentials(ta)
  88. }
  89. func (a Authenticator) Authenticate(ctx context.Context) (newCtx context.Context, err error) {
  90. p, ok := peer.FromContext(ctx)
  91. if !ok {
  92. return ctx, status.Error(codes.Unauthenticated, "no peer found")
  93. }
  94. tlsAuth, ok := p.AuthInfo.(credentials.TLSInfo)
  95. if !ok {
  96. return ctx, status.Error(codes.Unauthenticated, "unexpected peer transport credentials")
  97. }
  98. if len(tlsAuth.State.VerifiedChains) == 0 || len(tlsAuth.State.VerifiedChains[0]) == 0 {
  99. return ctx, status.Error(codes.Unauthenticated, "could not verify peer certificate")
  100. }
  101. commonName := tlsAuth.State.VerifiedChains[0][0].Subject.CommonName
  102. if a.AllowedWildcardDomain != "" && strings.HasSuffix(commonName, a.AllowedWildcardDomain) {
  103. return ctx, nil
  104. }
  105. if _, ok := a.AllowedCommonNames[commonName]; ok {
  106. return ctx, nil
  107. }
  108. return ctx, status.Errorf(codes.Unauthenticated, "invalid subject common name: %s", commonName)
  109. }