kms.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. package plugin
  2. import (
  3. "crypto/sha256"
  4. "fmt"
  5. "os/exec"
  6. "path/filepath"
  7. "github.com/hashicorp/go-hclog"
  8. "github.com/hashicorp/go-plugin"
  9. sdkkms "github.com/sftpgo/sdk/kms"
  10. kmsplugin "github.com/sftpgo/sdk/plugin/kms"
  11. "github.com/drakkan/sftpgo/v2/kms"
  12. "github.com/drakkan/sftpgo/v2/logger"
  13. "github.com/drakkan/sftpgo/v2/util"
  14. )
  15. var (
  16. validKMSSchemes = []string{sdkkms.SchemeAWS, sdkkms.SchemeGCP, sdkkms.SchemeVaultTransit, sdkkms.SchemeAzureKeyVault}
  17. validKMSEncryptedStatuses = []string{sdkkms.SecretStatusVaultTransit, sdkkms.SecretStatusAWS, sdkkms.SecretStatusGCP,
  18. sdkkms.SecretStatusAzureKeyVault}
  19. )
  20. // KMSConfig defines configuration parameters for kms plugins
  21. type KMSConfig struct {
  22. Scheme string `json:"scheme" mapstructure:"scheme"`
  23. EncryptedStatus string `json:"encrypted_status" mapstructure:"encrypted_status"`
  24. }
  25. func (c *KMSConfig) validate() error {
  26. if !util.IsStringInSlice(c.Scheme, validKMSSchemes) {
  27. return fmt.Errorf("invalid kms scheme: %v", c.Scheme)
  28. }
  29. if !util.IsStringInSlice(c.EncryptedStatus, validKMSEncryptedStatuses) {
  30. return fmt.Errorf("invalid kms encrypted status: %v", c.EncryptedStatus)
  31. }
  32. return nil
  33. }
  34. type kmsPlugin struct {
  35. config Config
  36. service kmsplugin.Service
  37. client *plugin.Client
  38. }
  39. func newKMSPlugin(config Config) (*kmsPlugin, error) {
  40. p := &kmsPlugin{
  41. config: config,
  42. }
  43. if err := p.initialize(); err != nil {
  44. logger.Warn(logSender, "", "unable to create kms plugin: %v, config %+v", err, config)
  45. return nil, err
  46. }
  47. return p, nil
  48. }
  49. func (p *kmsPlugin) initialize() error {
  50. killProcess(p.config.Cmd)
  51. logger.Debug(logSender, "", "create new kms plugin %#v", p.config.Cmd)
  52. if err := p.config.KMSOptions.validate(); err != nil {
  53. return fmt.Errorf("invalid options for kms plugin %#v: %v", p.config.Cmd, err)
  54. }
  55. var secureConfig *plugin.SecureConfig
  56. if p.config.SHA256Sum != "" {
  57. secureConfig.Checksum = []byte(p.config.SHA256Sum)
  58. secureConfig.Hash = sha256.New()
  59. }
  60. client := plugin.NewClient(&plugin.ClientConfig{
  61. HandshakeConfig: kmsplugin.Handshake,
  62. Plugins: kmsplugin.PluginMap,
  63. Cmd: exec.Command(p.config.Cmd, p.config.Args...),
  64. AllowedProtocols: []plugin.Protocol{
  65. plugin.ProtocolGRPC,
  66. },
  67. AutoMTLS: p.config.AutoMTLS,
  68. SecureConfig: secureConfig,
  69. Managed: false,
  70. Logger: &logger.HCLogAdapter{
  71. Logger: hclog.New(&hclog.LoggerOptions{
  72. Name: fmt.Sprintf("%v.%v", logSender, kmsplugin.PluginName),
  73. Level: pluginsLogLevel,
  74. DisableTime: true,
  75. }),
  76. },
  77. })
  78. rpcClient, err := client.Client()
  79. if err != nil {
  80. logger.Debug(logSender, "", "unable to get rpc client for kms plugin %#v: %v", p.config.Cmd, err)
  81. return err
  82. }
  83. raw, err := rpcClient.Dispense(kmsplugin.PluginName)
  84. if err != nil {
  85. logger.Debug(logSender, "", "unable to get plugin %v from rpc client for command %#v: %v",
  86. kmsplugin.PluginName, p.config.Cmd, err)
  87. return err
  88. }
  89. p.client = client
  90. p.service = raw.(kmsplugin.Service)
  91. return nil
  92. }
  93. func (p *kmsPlugin) exited() bool {
  94. return p.client.Exited()
  95. }
  96. func (p *kmsPlugin) cleanup() {
  97. p.client.Kill()
  98. }
  99. func (p *kmsPlugin) Encrypt(secret kms.BaseSecret, url string, masterKey string) (string, string, int32, error) {
  100. return p.service.Encrypt(secret.Payload, secret.AdditionalData, url, masterKey)
  101. }
  102. func (p *kmsPlugin) Decrypt(secret kms.BaseSecret, url string, masterKey string) (string, error) {
  103. return p.service.Decrypt(secret.Payload, secret.Key, secret.AdditionalData, secret.Mode, url, masterKey)
  104. }
  105. type kmsPluginSecretProvider struct {
  106. kms.BaseSecret
  107. URL string
  108. MasterKey string
  109. config *Config
  110. }
  111. func (s *kmsPluginSecretProvider) Name() string {
  112. return fmt.Sprintf("KMSPlugin_%v_%v_%v", filepath.Base(s.config.Cmd), s.config.KMSOptions.Scheme, s.config.kmsID)
  113. }
  114. func (s *kmsPluginSecretProvider) IsEncrypted() bool {
  115. return s.Status == s.config.KMSOptions.EncryptedStatus
  116. }
  117. func (s *kmsPluginSecretProvider) Encrypt() error {
  118. if s.Status != sdkkms.SecretStatusPlain {
  119. return kms.ErrWrongSecretStatus
  120. }
  121. if s.Payload == "" {
  122. return kms.ErrInvalidSecret
  123. }
  124. payload, key, mode, err := Handler.kmsEncrypt(s.BaseSecret, s.URL, s.MasterKey, s.config.kmsID)
  125. if err != nil {
  126. return err
  127. }
  128. s.Status = s.config.KMSOptions.EncryptedStatus
  129. s.Payload = payload
  130. s.Key = key
  131. s.Mode = int(mode)
  132. return nil
  133. }
  134. func (s *kmsPluginSecretProvider) Decrypt() error {
  135. if !s.IsEncrypted() {
  136. return kms.ErrWrongSecretStatus
  137. }
  138. payload, err := Handler.kmsDecrypt(s.BaseSecret, s.URL, s.MasterKey, s.config.kmsID)
  139. if err != nil {
  140. return err
  141. }
  142. s.Status = sdkkms.SecretStatusPlain
  143. s.Payload = payload
  144. s.Key = ""
  145. s.AdditionalData = ""
  146. s.Mode = 0
  147. return nil
  148. }
  149. func (s *kmsPluginSecretProvider) Clone() kms.SecretProvider {
  150. baseSecret := kms.BaseSecret{
  151. Status: s.Status,
  152. Payload: s.Payload,
  153. Key: s.Key,
  154. AdditionalData: s.AdditionalData,
  155. Mode: s.Mode,
  156. }
  157. return s.config.newKMSPluginSecretProvider(baseSecret, s.URL, s.MasterKey)
  158. }