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.

113 lines
3.3 KiB

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