kms.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. // Copyright (C) 2019-2022 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. "os"
  20. "strings"
  21. "sync"
  22. sdkkms "github.com/sftpgo/sdk/kms"
  23. "github.com/drakkan/sftpgo/v2/internal/logger"
  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.MasterKeyString != "" {
  94. c.Secrets.masterKey = c.Secrets.MasterKeyString
  95. }
  96. if c.Secrets.masterKey == "" && c.Secrets.MasterKeyPath != "" {
  97. mKey, err := os.ReadFile(c.Secrets.MasterKeyPath)
  98. if err != nil {
  99. return err
  100. }
  101. c.Secrets.masterKey = strings.TrimSpace(string(mKey))
  102. }
  103. config = *c
  104. if config.Secrets.URL == "" {
  105. config.Secrets.URL = sdkkms.SchemeLocal + "://"
  106. }
  107. for k, v := range secretProviders {
  108. logger.Info(logSender, "", "secret provider registered for scheme: %#v, encrypted status: %#v",
  109. k, v.encryptedStatus)
  110. }
  111. return nil
  112. }
  113. func (c *Configuration) newSecret(status sdkkms.SecretStatus, payload, key, data string) *Secret {
  114. base := BaseSecret{
  115. Status: status,
  116. Key: key,
  117. Payload: payload,
  118. AdditionalData: data,
  119. }
  120. return &Secret{
  121. provider: c.getSecretProvider(base),
  122. }
  123. }
  124. func (c *Configuration) getSecretProvider(base BaseSecret) SecretProvider {
  125. for k, v := range secretProviders {
  126. if strings.HasPrefix(c.Secrets.URL, k) {
  127. return v.newFn(base, c.Secrets.URL, c.Secrets.masterKey)
  128. }
  129. }
  130. logger.Warn(logSender, "", "no secret provider registered for URL %v, fallback to local provider", c.Secrets.URL)
  131. return NewLocalSecret(base, c.Secrets.URL, c.Secrets.masterKey)
  132. }
  133. // Secret defines the struct used to store confidential data
  134. type Secret struct {
  135. sync.RWMutex
  136. provider SecretProvider
  137. }
  138. // MarshalJSON return the JSON encoding of the Secret object
  139. func (s *Secret) MarshalJSON() ([]byte, error) {
  140. s.RLock()
  141. defer s.RUnlock()
  142. return json.Marshal(&BaseSecret{
  143. Status: s.provider.GetStatus(),
  144. Payload: s.provider.GetPayload(),
  145. Key: s.provider.GetKey(),
  146. AdditionalData: s.provider.GetAdditionalData(),
  147. Mode: s.provider.GetMode(),
  148. })
  149. }
  150. // UnmarshalJSON parses the JSON-encoded data and stores the result
  151. // in the Secret object
  152. func (s *Secret) UnmarshalJSON(data []byte) error {
  153. s.Lock()
  154. defer s.Unlock()
  155. baseSecret := BaseSecret{}
  156. err := json.Unmarshal(data, &baseSecret)
  157. if err != nil {
  158. return err
  159. }
  160. if baseSecret.isEmpty() {
  161. s.provider = config.getSecretProvider(baseSecret)
  162. return nil
  163. }
  164. if baseSecret.Status == sdkkms.SecretStatusPlain || baseSecret.Status == sdkkms.SecretStatusRedacted {
  165. s.provider = config.getSecretProvider(baseSecret)
  166. return nil
  167. }
  168. for _, v := range secretProviders {
  169. if v.encryptedStatus == baseSecret.Status {
  170. s.provider = v.newFn(baseSecret, config.Secrets.URL, config.Secrets.masterKey)
  171. return nil
  172. }
  173. }
  174. logger.Error(logSender, "", "no provider registered for status %#v", baseSecret.Status)
  175. return ErrInvalidSecret
  176. }
  177. // IsEqual returns true if all the secrets fields are equal
  178. func (s *Secret) IsEqual(other *Secret) bool {
  179. if s.GetStatus() != other.GetStatus() {
  180. return false
  181. }
  182. if s.GetPayload() != other.GetPayload() {
  183. return false
  184. }
  185. if s.GetKey() != other.GetKey() {
  186. return false
  187. }
  188. if s.GetAdditionalData() != other.GetAdditionalData() {
  189. return false
  190. }
  191. if s.GetMode() != other.GetMode() {
  192. return false
  193. }
  194. return true
  195. }
  196. // Clone returns a copy of the secret object
  197. func (s *Secret) Clone() *Secret {
  198. s.RLock()
  199. defer s.RUnlock()
  200. return &Secret{
  201. provider: s.provider.Clone(),
  202. }
  203. }
  204. // IsEncrypted returns true if the secret is encrypted
  205. // This isn't a pointer receiver because we don't want to pass
  206. // a pointer to html template
  207. func (s *Secret) IsEncrypted() bool {
  208. s.RLock()
  209. defer s.RUnlock()
  210. return s.provider.IsEncrypted()
  211. }
  212. // IsPlain returns true if the secret is in plain text
  213. func (s *Secret) IsPlain() bool {
  214. s.RLock()
  215. defer s.RUnlock()
  216. return s.provider.GetStatus() == sdkkms.SecretStatusPlain
  217. }
  218. // IsNotPlainAndNotEmpty returns true if the secret is not plain and not empty.
  219. // This is an utility method, we update the secret for an existing user
  220. // if it is empty or plain
  221. func (s *Secret) IsNotPlainAndNotEmpty() bool {
  222. s.RLock()
  223. defer s.RUnlock()
  224. return !s.IsPlain() && !s.IsEmpty()
  225. }
  226. // IsRedacted returns true if the secret is redacted
  227. func (s *Secret) IsRedacted() bool {
  228. s.RLock()
  229. defer s.RUnlock()
  230. return s.provider.GetStatus() == sdkkms.SecretStatusRedacted
  231. }
  232. // GetPayload returns the secret payload
  233. func (s *Secret) GetPayload() string {
  234. s.RLock()
  235. defer s.RUnlock()
  236. return s.provider.GetPayload()
  237. }
  238. // GetAdditionalData returns the secret additional data
  239. func (s *Secret) GetAdditionalData() string {
  240. s.RLock()
  241. defer s.RUnlock()
  242. return s.provider.GetAdditionalData()
  243. }
  244. // GetStatus returns the secret status
  245. func (s *Secret) GetStatus() sdkkms.SecretStatus {
  246. s.RLock()
  247. defer s.RUnlock()
  248. return s.provider.GetStatus()
  249. }
  250. // GetKey returns the secret key
  251. func (s *Secret) GetKey() string {
  252. s.RLock()
  253. defer s.RUnlock()
  254. return s.provider.GetKey()
  255. }
  256. // GetMode returns the secret mode
  257. func (s *Secret) GetMode() int {
  258. s.RLock()
  259. defer s.RUnlock()
  260. return s.provider.GetMode()
  261. }
  262. // SetAdditionalData sets the given additional data
  263. func (s *Secret) SetAdditionalData(value string) {
  264. s.Lock()
  265. defer s.Unlock()
  266. s.provider.SetAdditionalData(value)
  267. }
  268. // SetStatus sets the status for this secret
  269. func (s *Secret) SetStatus(value sdkkms.SecretStatus) {
  270. s.Lock()
  271. defer s.Unlock()
  272. s.provider.SetStatus(value)
  273. }
  274. // SetKey sets the key for this secret
  275. func (s *Secret) SetKey(value string) {
  276. s.Lock()
  277. defer s.Unlock()
  278. s.provider.SetKey(value)
  279. }
  280. // IsEmpty returns true if all fields are empty
  281. func (s *Secret) IsEmpty() bool {
  282. s.RLock()
  283. defer s.RUnlock()
  284. if s.provider.GetStatus() != "" {
  285. return false
  286. }
  287. if s.provider.GetPayload() != "" {
  288. return false
  289. }
  290. if s.provider.GetKey() != "" {
  291. return false
  292. }
  293. if s.provider.GetAdditionalData() != "" {
  294. return false
  295. }
  296. return true
  297. }
  298. // IsValid returns true if the secret is not empty and valid
  299. func (s *Secret) IsValid() bool {
  300. s.RLock()
  301. defer s.RUnlock()
  302. if !s.IsValidInput() {
  303. return false
  304. }
  305. switch s.provider.GetStatus() {
  306. case sdkkms.SecretStatusAES256GCM, sdkkms.SecretStatusSecretBox:
  307. if len(s.provider.GetKey()) != 64 {
  308. return false
  309. }
  310. case sdkkms.SecretStatusAWS, sdkkms.SecretStatusGCP, sdkkms.SecretStatusVaultTransit:
  311. key := s.provider.GetKey()
  312. if key != "" && len(key) != 64 {
  313. return false
  314. }
  315. }
  316. return true
  317. }
  318. // IsValidInput returns true if the secret is a valid user input
  319. func (s *Secret) IsValidInput() bool {
  320. s.RLock()
  321. defer s.RUnlock()
  322. if !isSecretStatusValid(s.provider.GetStatus()) {
  323. return false
  324. }
  325. if s.provider.GetPayload() == "" {
  326. return false
  327. }
  328. return true
  329. }
  330. // Hide hides info to decrypt data
  331. func (s *Secret) Hide() {
  332. s.Lock()
  333. defer s.Unlock()
  334. s.provider.SetKey("")
  335. s.provider.SetAdditionalData("")
  336. }
  337. // Encrypt encrypts a plain text Secret object
  338. func (s *Secret) Encrypt() error {
  339. s.Lock()
  340. defer s.Unlock()
  341. return s.provider.Encrypt()
  342. }
  343. // Decrypt decrypts a Secret object
  344. func (s *Secret) Decrypt() error {
  345. s.Lock()
  346. defer s.Unlock()
  347. return s.provider.Decrypt()
  348. }
  349. // TryDecrypt decrypts a Secret object if encrypted.
  350. // It returns a nil error if the object is not encrypted
  351. func (s *Secret) TryDecrypt() error {
  352. s.Lock()
  353. defer s.Unlock()
  354. if s.provider.IsEncrypted() {
  355. return s.provider.Decrypt()
  356. }
  357. return nil
  358. }
  359. func isSecretStatusValid(status string) bool {
  360. for idx := range validSecretStatuses {
  361. if validSecretStatuses[idx] == status {
  362. return true
  363. }
  364. }
  365. return false
  366. }