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.

142 lines
4.2 KiB

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