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.

187 lines
6.0 KiB

3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
  1. package security
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "crypto/x509"
  6. "google.golang.org/grpc/credentials/tls/certprovider/pemfile"
  7. "google.golang.org/grpc/security/advancedtls"
  8. "io/ioutil"
  9. "strings"
  10. "time"
  11. grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
  12. "google.golang.org/grpc"
  13. "google.golang.org/grpc/codes"
  14. "google.golang.org/grpc/credentials"
  15. "google.golang.org/grpc/peer"
  16. "google.golang.org/grpc/status"
  17. "github.com/chrislusf/seaweedfs/weed/glog"
  18. "github.com/chrislusf/seaweedfs/weed/util"
  19. )
  20. const credRefreshingInterval = time.Duration(5) * time.Hour
  21. type Authenticator struct {
  22. AllowedWildcardDomain string
  23. AllowedCommonNames map[string]bool
  24. }
  25. func LoadServerTLS(config *util.ViperProxy, component string) (grpc.ServerOption, grpc.ServerOption) {
  26. if config == nil {
  27. return nil, nil
  28. }
  29. serverOptions := pemfile.Options{
  30. CertFile: config.GetString(component + ".cert"),
  31. KeyFile: config.GetString(component + ".key"),
  32. RefreshDuration: credRefreshingInterval,
  33. }
  34. serverIdentityProvider, err := pemfile.NewProvider(serverOptions)
  35. if err != nil {
  36. glog.Warningf("pemfile.NewProvider(%v) failed: %v", serverOptions, err)
  37. return nil, nil
  38. }
  39. defer serverIdentityProvider.Close()
  40. serverRootOptions := pemfile.Options{
  41. RootFile: config.GetString("grpc.ca"),
  42. RefreshDuration: credRefreshingInterval,
  43. }
  44. serverRootProvider, err := pemfile.NewProvider(serverRootOptions)
  45. if err != nil {
  46. glog.Warningf("pemfile.NewProvider(%v) failed: %v", serverRootOptions, err)
  47. return nil, nil
  48. }
  49. defer serverIdentityProvider.Close()
  50. // Start a server and create a client using advancedtls API with Provider.
  51. options := &advancedtls.ServerOptions{
  52. IdentityOptions: advancedtls.IdentityCertificateOptions{
  53. IdentityProvider: serverIdentityProvider,
  54. },
  55. RootOptions: advancedtls.RootCertificateOptions{
  56. RootProvider: serverRootProvider,
  57. },
  58. RequireClientCert: true,
  59. VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) {
  60. glog.V(0).Infof("Client common name: %s.\n", params.Leaf.Subject.CommonName)
  61. return &advancedtls.VerificationResults{}, nil
  62. },
  63. VType: advancedtls.CertVerification,
  64. }
  65. ta, err := advancedtls.NewServerCreds(options)
  66. if err != nil {
  67. glog.Warningf("advancedtls.NewServerCreds(%v) failed: %v", options, err)
  68. return nil, nil
  69. }
  70. allowedCommonNames := config.GetString(component + ".allowed_commonNames")
  71. allowedWildcardDomain := config.GetString("grpc.allowed_wildcard_domain")
  72. if allowedCommonNames != "" || allowedWildcardDomain != "" {
  73. allowedCommonNamesMap := make(map[string]bool)
  74. for _, s := range strings.Split(allowedCommonNames, ",") {
  75. allowedCommonNamesMap[s] = true
  76. }
  77. auther := Authenticator{
  78. AllowedCommonNames: allowedCommonNamesMap,
  79. AllowedWildcardDomain: allowedWildcardDomain,
  80. }
  81. return grpc.Creds(ta), grpc.UnaryInterceptor(grpc_auth.UnaryServerInterceptor(auther.Authenticate))
  82. }
  83. return grpc.Creds(ta), nil
  84. }
  85. func LoadClientTLS(config *util.ViperProxy, component string) grpc.DialOption {
  86. if config == nil {
  87. return grpc.WithInsecure()
  88. }
  89. certFileName, keyFileName, caFileName := config.GetString(component+".cert"), config.GetString(component+".key"), config.GetString("grpc.ca")
  90. if certFileName == "" || keyFileName == "" || caFileName == "" {
  91. return grpc.WithInsecure()
  92. }
  93. // Initialize credential struct using reloading API.
  94. clientOptions := pemfile.Options{
  95. CertFile: certFileName,
  96. KeyFile: keyFileName,
  97. RefreshDuration: credRefreshingInterval,
  98. }
  99. clientProvider, err := pemfile.NewProvider(clientOptions)
  100. if err != nil {
  101. glog.Warningf("pemfile.NewProvider(%v) failed %v", clientOptions, err)
  102. return grpc.WithInsecure()
  103. }
  104. defer clientProvider.Close()
  105. clientRootOptions := pemfile.Options{
  106. RootFile: config.GetString("grpc.ca"),
  107. RefreshDuration: credRefreshingInterval,
  108. }
  109. clientRootProvider, err := pemfile.NewProvider(clientRootOptions)
  110. if err != nil {
  111. glog.Warningf("pemfile.NewProvider(%v) failed: %v", clientRootOptions, err)
  112. return grpc.WithInsecure()
  113. }
  114. defer clientRootProvider.Close()
  115. options := &advancedtls.ClientOptions{
  116. IdentityOptions: advancedtls.IdentityCertificateOptions{
  117. IdentityProvider: clientProvider,
  118. },
  119. VerifyPeer: func(params *advancedtls.VerificationFuncParams) (*advancedtls.VerificationResults, error) {
  120. return &advancedtls.VerificationResults{}, nil
  121. },
  122. RootOptions: advancedtls.RootCertificateOptions{
  123. RootProvider: clientRootProvider,
  124. },
  125. VType: advancedtls.CertVerification,
  126. }
  127. ta, err := advancedtls.NewClientCreds(options)
  128. if err != nil {
  129. glog.Warningf("advancedtls.NewClientCreds(%v) failed: %v", options, err)
  130. return grpc.WithInsecure()
  131. }
  132. return grpc.WithTransportCredentials(ta)
  133. }
  134. func LoadClientTLSHTTP(clientCertFile string) *tls.Config {
  135. clientCerts, err := ioutil.ReadFile(clientCertFile)
  136. if err != nil {
  137. glog.Fatal(err)
  138. }
  139. certPool := x509.NewCertPool()
  140. ok := certPool.AppendCertsFromPEM(clientCerts)
  141. if !ok {
  142. glog.Fatalf("Error processing client certificate in %s\n", clientCertFile)
  143. }
  144. return &tls.Config{
  145. ClientCAs: certPool,
  146. ClientAuth: tls.RequireAndVerifyClientCert,
  147. }
  148. }
  149. func (a Authenticator) Authenticate(ctx context.Context) (newCtx context.Context, err error) {
  150. p, ok := peer.FromContext(ctx)
  151. if !ok {
  152. return ctx, status.Error(codes.Unauthenticated, "no peer found")
  153. }
  154. tlsAuth, ok := p.AuthInfo.(credentials.TLSInfo)
  155. if !ok {
  156. return ctx, status.Error(codes.Unauthenticated, "unexpected peer transport credentials")
  157. }
  158. if len(tlsAuth.State.VerifiedChains) == 0 || len(tlsAuth.State.VerifiedChains[0]) == 0 {
  159. return ctx, status.Error(codes.Unauthenticated, "could not verify peer certificate")
  160. }
  161. commonName := tlsAuth.State.VerifiedChains[0][0].Subject.CommonName
  162. if a.AllowedWildcardDomain != "" && strings.HasSuffix(commonName, a.AllowedWildcardDomain) {
  163. return ctx, nil
  164. }
  165. if _, ok := a.AllowedCommonNames[commonName]; ok {
  166. return ctx, nil
  167. }
  168. return ctx, status.Errorf(codes.Unauthenticated, "invalid subject common name: %s", commonName)
  169. }