kms.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. // Copyright (C) 2019 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. // Package kms provides Key Management Services support
  15. package kms
  16. import (
  17. "encoding/json"
  18. "errors"
  19. "strings"
  20. "sync"
  21. sdkkms "github.com/sftpgo/sdk/kms"
  22. "github.com/drakkan/sftpgo/v2/internal/logger"
  23. "github.com/drakkan/sftpgo/v2/internal/util"
  24. )
  25. // SecretProvider defines the interface for a KMS secrets provider
  26. type SecretProvider interface {
  27. Name() string
  28. Encrypt() error
  29. Decrypt() error
  30. IsEncrypted() bool
  31. GetStatus() sdkkms.SecretStatus
  32. GetPayload() string
  33. GetKey() string
  34. GetAdditionalData() string
  35. GetMode() int
  36. SetKey(string)
  37. SetAdditionalData(string)
  38. SetStatus(sdkkms.SecretStatus)
  39. Clone() SecretProvider
  40. }
  41. const (
  42. logSender = "kms"
  43. )
  44. // Configuration defines the KMS configuration
  45. type Configuration struct {
  46. Secrets Secrets `json:"secrets" mapstructure:"secrets"`
  47. }
  48. // Secrets define the KMS configuration for encryption/decryption
  49. type Secrets struct {
  50. URL string `json:"url" mapstructure:"url"`
  51. MasterKeyPath string `json:"master_key_path" mapstructure:"master_key_path"`
  52. MasterKeyString string `json:"master_key" mapstructure:"master_key"`
  53. masterKey string
  54. }
  55. type registeredSecretProvider struct {
  56. encryptedStatus sdkkms.SecretStatus
  57. newFn func(base BaseSecret, url, masterKey string) SecretProvider
  58. }
  59. var (
  60. // ErrWrongSecretStatus defines the error to return if the secret status is not appropriate
  61. // for the request operation
  62. ErrWrongSecretStatus = errors.New("wrong secret status")
  63. // ErrInvalidSecret defines the error to return if a secret is not valid
  64. ErrInvalidSecret = errors.New("invalid secret")
  65. validSecretStatuses = []string{sdkkms.SecretStatusPlain, sdkkms.SecretStatusAES256GCM, sdkkms.SecretStatusSecretBox,
  66. sdkkms.SecretStatusVaultTransit, sdkkms.SecretStatusAWS, sdkkms.SecretStatusGCP, sdkkms.SecretStatusRedacted}
  67. config Configuration
  68. secretProviders = make(map[string]registeredSecretProvider)
  69. )
  70. // RegisterSecretProvider register a new secret provider
  71. func RegisterSecretProvider(scheme string, encryptedStatus sdkkms.SecretStatus,
  72. fn func(base BaseSecret, url, masterKey string) SecretProvider,
  73. ) {
  74. secretProviders[scheme] = registeredSecretProvider{
  75. encryptedStatus: encryptedStatus,
  76. newFn: fn,
  77. }
  78. }
  79. // NewSecret builds a new Secret using the provided arguments
  80. func NewSecret(status sdkkms.SecretStatus, payload, key, data string) *Secret {
  81. return config.newSecret(status, payload, key, data)
  82. }
  83. // NewEmptySecret returns an empty secret
  84. func NewEmptySecret() *Secret {
  85. return NewSecret("", "", "", "")
  86. }
  87. // NewPlainSecret stores the give payload in a plain text secret
  88. func NewPlainSecret(payload string) *Secret {
  89. return NewSecret(sdkkms.SecretStatusPlain, strings.TrimSpace(payload), "", "")
  90. }
  91. // Initialize configures the KMS support
  92. func (c *Configuration) Initialize() error {
  93. if c.Secrets.MasterKeyPath != "" {
  94. mKey, err := util.ReadConfigFromFile(c.Secrets.MasterKeyPath, "")
  95. if err != nil {
  96. return err
  97. }
  98. c.Secrets.masterKey = mKey
  99. } else if c.Secrets.MasterKeyString != "" {
  100. c.Secrets.masterKey = c.Secrets.MasterKeyString
  101. }
  102. config = *c
  103. if config.Secrets.URL == "" {
  104. config.Secrets.URL = sdkkms.SchemeLocal + "://"
  105. }
  106. for k, v := range secretProviders {
  107. logger.Info(logSender, "", "secret provider registered for scheme: %q, encrypted status: %q",
  108. k, v.encryptedStatus)
  109. }
  110. return nil
  111. }
  112. func (c *Configuration) newSecret(status sdkkms.SecretStatus, payload, key, data string) *Secret {
  113. base := BaseSecret{
  114. Status: status,
  115. Key: key,
  116. Payload: payload,
  117. AdditionalData: data,
  118. }
  119. return &Secret{
  120. provider: c.getSecretProvider(base),
  121. }
  122. }
  123. func (c *Configuration) getSecretProvider(base BaseSecret) SecretProvider {
  124. for k, v := range secretProviders {
  125. if strings.HasPrefix(c.Secrets.URL, k) {
  126. return v.newFn(base, c.Secrets.URL, c.Secrets.masterKey)
  127. }
  128. }
  129. logger.Warn(logSender, "", "no secret provider registered for URL %v, fallback to local provider", c.Secrets.URL)
  130. return NewLocalSecret(base, c.Secrets.URL, c.Secrets.masterKey)
  131. }
  132. // Secret defines the struct used to store confidential data
  133. type Secret struct {
  134. sync.RWMutex
  135. provider SecretProvider
  136. }
  137. // MarshalJSON return the JSON encoding of the Secret object
  138. func (s *Secret) MarshalJSON() ([]byte, error) {
  139. s.RLock()
  140. defer s.RUnlock()
  141. return json.Marshal(&BaseSecret{
  142. Status: s.provider.GetStatus(),
  143. Payload: s.provider.GetPayload(),
  144. Key: s.provider.GetKey(),
  145. AdditionalData: s.provider.GetAdditionalData(),
  146. Mode: s.provider.GetMode(),
  147. })
  148. }
  149. // UnmarshalJSON parses the JSON-encoded data and stores the result
  150. // in the Secret object
  151. func (s *Secret) UnmarshalJSON(data []byte) error {
  152. s.Lock()
  153. defer s.Unlock()
  154. baseSecret := BaseSecret{}
  155. err := json.Unmarshal(data, &baseSecret)
  156. if err != nil {
  157. return err
  158. }
  159. if baseSecret.isEmpty() {
  160. s.provider = config.getSecretProvider(baseSecret)
  161. return nil
  162. }
  163. if baseSecret.Status == sdkkms.SecretStatusPlain || baseSecret.Status == sdkkms.SecretStatusRedacted {
  164. s.provider = config.getSecretProvider(baseSecret)
  165. return nil
  166. }
  167. for _, v := range secretProviders {
  168. if v.encryptedStatus == baseSecret.Status {
  169. s.provider = v.newFn(baseSecret, config.Secrets.URL, config.Secrets.masterKey)
  170. return nil
  171. }
  172. }
  173. logger.Error(logSender, "", "no provider registered for status %q", baseSecret.Status)
  174. return ErrInvalidSecret
  175. }
  176. // IsEqual returns true if all the secrets fields are equal
  177. func (s *Secret) IsEqual(other *Secret) bool {
  178. if s.GetStatus() != other.GetStatus() {
  179. return false
  180. }
  181. if s.GetPayload() != other.GetPayload() {
  182. return false
  183. }
  184. if s.GetKey() != other.GetKey() {
  185. return false
  186. }
  187. if s.GetAdditionalData() != other.GetAdditionalData() {
  188. return false
  189. }
  190. if s.GetMode() != other.GetMode() {
  191. return false
  192. }
  193. return true
  194. }
  195. // Clone returns a copy of the secret object
  196. func (s *Secret) Clone() *Secret {
  197. s.RLock()
  198. defer s.RUnlock()
  199. return &Secret{
  200. provider: s.provider.Clone(),
  201. }
  202. }
  203. // IsEncrypted returns true if the secret is encrypted
  204. // This isn't a pointer receiver because we don't want to pass
  205. // a pointer to html template
  206. func (s *Secret) IsEncrypted() bool {
  207. s.RLock()
  208. defer s.RUnlock()
  209. return s.provider.IsEncrypted()
  210. }
  211. // IsPlain returns true if the secret is in plain text
  212. func (s *Secret) IsPlain() bool {
  213. s.RLock()
  214. defer s.RUnlock()
  215. return s.provider.GetStatus() == sdkkms.SecretStatusPlain
  216. }
  217. // IsNotPlainAndNotEmpty returns true if the secret is not plain and not empty.
  218. // This is an utility method, we update the secret for an existing user
  219. // if it is empty or plain
  220. func (s *Secret) IsNotPlainAndNotEmpty() bool {
  221. s.RLock()
  222. defer s.RUnlock()
  223. return !s.IsPlain() && !s.IsEmpty()
  224. }
  225. // IsRedacted returns true if the secret is redacted
  226. func (s *Secret) IsRedacted() bool {
  227. s.RLock()
  228. defer s.RUnlock()
  229. return s.provider.GetStatus() == sdkkms.SecretStatusRedacted
  230. }
  231. // GetPayload returns the secret payload
  232. func (s *Secret) GetPayload() string {
  233. s.RLock()
  234. defer s.RUnlock()
  235. return s.provider.GetPayload()
  236. }
  237. // GetAdditionalData returns the secret additional data
  238. func (s *Secret) GetAdditionalData() string {
  239. s.RLock()
  240. defer s.RUnlock()
  241. return s.provider.GetAdditionalData()
  242. }
  243. // GetStatus returns the secret status
  244. func (s *Secret) GetStatus() sdkkms.SecretStatus {
  245. s.RLock()
  246. defer s.RUnlock()
  247. return s.provider.GetStatus()
  248. }
  249. // GetKey returns the secret key
  250. func (s *Secret) GetKey() string {
  251. s.RLock()
  252. defer s.RUnlock()
  253. return s.provider.GetKey()
  254. }
  255. // GetMode returns the secret mode
  256. func (s *Secret) GetMode() int {
  257. s.RLock()
  258. defer s.RUnlock()
  259. return s.provider.GetMode()
  260. }
  261. // SetAdditionalData sets the given additional data
  262. func (s *Secret) SetAdditionalData(value string) {
  263. s.Lock()
  264. defer s.Unlock()
  265. s.provider.SetAdditionalData(value)
  266. }
  267. // SetStatus sets the status for this secret
  268. func (s *Secret) SetStatus(value sdkkms.SecretStatus) {
  269. s.Lock()
  270. defer s.Unlock()
  271. s.provider.SetStatus(value)
  272. }
  273. // SetKey sets the key for this secret
  274. func (s *Secret) SetKey(value string) {
  275. s.Lock()
  276. defer s.Unlock()
  277. s.provider.SetKey(value)
  278. }
  279. // IsEmpty returns true if all fields are empty
  280. func (s *Secret) IsEmpty() bool {
  281. s.RLock()
  282. defer s.RUnlock()
  283. if s.provider.GetStatus() != "" {
  284. return false
  285. }
  286. if s.provider.GetPayload() != "" {
  287. return false
  288. }
  289. if s.provider.GetKey() != "" {
  290. return false
  291. }
  292. if s.provider.GetAdditionalData() != "" {
  293. return false
  294. }
  295. return true
  296. }
  297. // IsValid returns true if the secret is not empty and valid
  298. func (s *Secret) IsValid() bool {
  299. s.RLock()
  300. defer s.RUnlock()
  301. if !s.IsValidInput() {
  302. return false
  303. }
  304. switch s.provider.GetStatus() {
  305. case sdkkms.SecretStatusAES256GCM, sdkkms.SecretStatusSecretBox:
  306. if len(s.provider.GetKey()) != 64 {
  307. return false
  308. }
  309. case sdkkms.SecretStatusAWS, sdkkms.SecretStatusGCP, sdkkms.SecretStatusVaultTransit:
  310. key := s.provider.GetKey()
  311. if key != "" && len(key) != 64 {
  312. return false
  313. }
  314. }
  315. return true
  316. }
  317. // IsValidInput returns true if the secret is a valid user input
  318. func (s *Secret) IsValidInput() bool {
  319. s.RLock()
  320. defer s.RUnlock()
  321. if !isSecretStatusValid(s.provider.GetStatus()) {
  322. return false
  323. }
  324. if s.provider.GetPayload() == "" {
  325. return false
  326. }
  327. return true
  328. }
  329. // Hide hides info to decrypt data
  330. func (s *Secret) Hide() {
  331. s.Lock()
  332. defer s.Unlock()
  333. s.provider.SetKey("")
  334. s.provider.SetAdditionalData("")
  335. }
  336. // Encrypt encrypts a plain text Secret object
  337. func (s *Secret) Encrypt() error {
  338. s.Lock()
  339. defer s.Unlock()
  340. return s.provider.Encrypt()
  341. }
  342. // Decrypt decrypts a Secret object
  343. func (s *Secret) Decrypt() error {
  344. s.Lock()
  345. defer s.Unlock()
  346. return s.provider.Decrypt()
  347. }
  348. // TryDecrypt decrypts a Secret object if encrypted.
  349. // It returns a nil error if the object is not encrypted
  350. func (s *Secret) TryDecrypt() error {
  351. s.Lock()
  352. defer s.Unlock()
  353. if s.provider.IsEncrypted() {
  354. return s.provider.Decrypt()
  355. }
  356. return nil
  357. }
  358. func isSecretStatusValid(status string) bool {
  359. for idx := range validSecretStatuses {
  360. if validSecretStatuses[idx] == status {
  361. return true
  362. }
  363. }
  364. return false
  365. }