kms.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. // Package kms provides Key Management Services support
  2. package kms
  3. import (
  4. "encoding/json"
  5. "errors"
  6. "os"
  7. "strings"
  8. "sync"
  9. "github.com/drakkan/sftpgo/v2/logger"
  10. "github.com/drakkan/sftpgo/v2/util"
  11. )
  12. // SecretProvider defines the interface for a KMS secrets provider
  13. type SecretProvider interface {
  14. Name() string
  15. Encrypt() error
  16. Decrypt() error
  17. IsEncrypted() bool
  18. GetStatus() SecretStatus
  19. GetPayload() string
  20. GetKey() string
  21. GetAdditionalData() string
  22. GetMode() int
  23. SetKey(string)
  24. SetAdditionalData(string)
  25. SetStatus(SecretStatus)
  26. Clone() SecretProvider
  27. }
  28. const (
  29. logSender = "kms"
  30. )
  31. // SecretStatus defines the statuses of a Secret object
  32. type SecretStatus = string
  33. const (
  34. // SecretStatusPlain means the secret is in plain text and must be encrypted
  35. SecretStatusPlain SecretStatus = "Plain"
  36. // SecretStatusAES256GCM means the secret is encrypted using AES-256-GCM
  37. SecretStatusAES256GCM SecretStatus = "AES-256-GCM"
  38. // SecretStatusSecretBox means the secret is encrypted using a locally provided symmetric key
  39. SecretStatusSecretBox SecretStatus = "Secretbox"
  40. // SecretStatusGCP means we use keys from Google Cloud Platform’s Key Management Service
  41. // (GCP KMS) to keep information secret
  42. SecretStatusGCP SecretStatus = "GCP"
  43. // SecretStatusAWS means we use customer master keys from Amazon Web Service’s
  44. // Key Management Service (AWS KMS) to keep information secret
  45. SecretStatusAWS SecretStatus = "AWS"
  46. // SecretStatusVaultTransit means we use the transit secrets engine in Vault
  47. // to keep information secret
  48. SecretStatusVaultTransit SecretStatus = "VaultTransit"
  49. // SecretStatusAzureKeyVault means we use Azure KeyVault to keep information secret
  50. SecretStatusAzureKeyVault SecretStatus = "AzureKeyVault"
  51. // SecretStatusRedacted means the secret is redacted
  52. SecretStatusRedacted SecretStatus = "Redacted"
  53. )
  54. // Scheme defines the supported URL scheme
  55. type Scheme = string
  56. // supported URL schemes
  57. const (
  58. SchemeLocal Scheme = "local"
  59. SchemeBuiltin Scheme = "builtin"
  60. SchemeAWS Scheme = "awskms"
  61. SchemeGCP Scheme = "gcpkms"
  62. SchemeVaultTransit Scheme = "hashivault"
  63. SchemeAzureKeyVault Scheme = "azurekeyvault"
  64. )
  65. // Configuration defines the KMS configuration
  66. type Configuration struct {
  67. Secrets Secrets `json:"secrets" mapstructure:"secrets"`
  68. }
  69. // Secrets define the KMS configuration for encryption/decryption
  70. type Secrets struct {
  71. URL string `json:"url" mapstructure:"url"`
  72. MasterKeyPath string `json:"master_key_path" mapstructure:"master_key_path"`
  73. masterKey string
  74. }
  75. type registeredSecretProvider struct {
  76. encryptedStatus SecretStatus
  77. newFn func(base BaseSecret, url, masterKey string) SecretProvider
  78. }
  79. var (
  80. // ErrWrongSecretStatus defines the error to return if the secret status is not appropriate
  81. // for the request operation
  82. ErrWrongSecretStatus = errors.New("wrong secret status")
  83. // ErrInvalidSecret defines the error to return if a secret is not valid
  84. ErrInvalidSecret = errors.New("invalid secret")
  85. errMalformedCiphertext = errors.New("malformed ciphertext")
  86. validSecretStatuses = []string{SecretStatusPlain, SecretStatusAES256GCM, SecretStatusSecretBox,
  87. SecretStatusVaultTransit, SecretStatusAWS, SecretStatusGCP, SecretStatusRedacted}
  88. config Configuration
  89. secretProviders = make(map[string]registeredSecretProvider)
  90. )
  91. // RegisterSecretProvider register a new secret provider
  92. func RegisterSecretProvider(scheme string, encryptedStatus SecretStatus, fn func(base BaseSecret, url, masterKey string) SecretProvider) {
  93. secretProviders[scheme] = registeredSecretProvider{
  94. encryptedStatus: encryptedStatus,
  95. newFn: fn,
  96. }
  97. }
  98. // NewSecret builds a new Secret using the provided arguments
  99. func NewSecret(status SecretStatus, payload, key, data string) *Secret {
  100. return config.newSecret(status, payload, key, data)
  101. }
  102. // NewEmptySecret returns an empty secret
  103. func NewEmptySecret() *Secret {
  104. return NewSecret("", "", "", "")
  105. }
  106. // NewPlainSecret stores the give payload in a plain text secret
  107. func NewPlainSecret(payload string) *Secret {
  108. return NewSecret(SecretStatusPlain, payload, "", "")
  109. }
  110. // GetSecretFromCompatString returns a secret from the previous format
  111. func GetSecretFromCompatString(secret string) (*Secret, error) {
  112. plain, err := util.DecryptData(secret)
  113. if err != nil {
  114. return &Secret{}, errMalformedCiphertext
  115. }
  116. return NewSecret(SecretStatusPlain, plain, "", ""), nil
  117. }
  118. // Initialize configures the KMS support
  119. func (c *Configuration) Initialize() error {
  120. if c.Secrets.MasterKeyPath != "" {
  121. mKey, err := os.ReadFile(c.Secrets.MasterKeyPath)
  122. if err != nil {
  123. return err
  124. }
  125. c.Secrets.masterKey = strings.TrimSpace(string(mKey))
  126. }
  127. config = *c
  128. if config.Secrets.URL == "" {
  129. config.Secrets.URL = SchemeLocal + "://"
  130. }
  131. for k, v := range secretProviders {
  132. logger.Debug(logSender, "", "secret provider registered for scheme: %#v, encrypted status: %#v",
  133. k, v.encryptedStatus)
  134. }
  135. return nil
  136. }
  137. func (c *Configuration) newSecret(status SecretStatus, payload, key, data string) *Secret {
  138. base := BaseSecret{
  139. Status: status,
  140. Key: key,
  141. Payload: payload,
  142. AdditionalData: data,
  143. }
  144. return &Secret{
  145. provider: c.getSecretProvider(base),
  146. }
  147. }
  148. func (c *Configuration) getSecretProvider(base BaseSecret) SecretProvider {
  149. for k, v := range secretProviders {
  150. if strings.HasPrefix(c.Secrets.URL, k) {
  151. return v.newFn(base, c.Secrets.URL, c.Secrets.masterKey)
  152. }
  153. }
  154. logger.Warn(logSender, "", "no secret provider registered for URL %v, fallback to local provider", c.Secrets.URL)
  155. return NewLocalSecret(base, c.Secrets.URL, c.Secrets.masterKey)
  156. }
  157. // Secret defines the struct used to store confidential data
  158. type Secret struct {
  159. sync.RWMutex
  160. provider SecretProvider
  161. }
  162. // MarshalJSON return the JSON encoding of the Secret object
  163. func (s *Secret) MarshalJSON() ([]byte, error) {
  164. s.RLock()
  165. defer s.RUnlock()
  166. return json.Marshal(&BaseSecret{
  167. Status: s.provider.GetStatus(),
  168. Payload: s.provider.GetPayload(),
  169. Key: s.provider.GetKey(),
  170. AdditionalData: s.provider.GetAdditionalData(),
  171. Mode: s.provider.GetMode(),
  172. })
  173. }
  174. // UnmarshalJSON parses the JSON-encoded data and stores the result
  175. // in the Secret object
  176. func (s *Secret) UnmarshalJSON(data []byte) error {
  177. s.Lock()
  178. defer s.Unlock()
  179. baseSecret := BaseSecret{}
  180. err := json.Unmarshal(data, &baseSecret)
  181. if err != nil {
  182. return err
  183. }
  184. if baseSecret.isEmpty() {
  185. s.provider = config.getSecretProvider(baseSecret)
  186. return nil
  187. }
  188. if baseSecret.Status == SecretStatusPlain || baseSecret.Status == SecretStatusRedacted {
  189. s.provider = config.getSecretProvider(baseSecret)
  190. return nil
  191. }
  192. for _, v := range secretProviders {
  193. if v.encryptedStatus == baseSecret.Status {
  194. s.provider = v.newFn(baseSecret, config.Secrets.URL, config.Secrets.masterKey)
  195. return nil
  196. }
  197. }
  198. logger.Debug(logSender, "", "no provider registered for status %#v", baseSecret.Status)
  199. return ErrInvalidSecret
  200. }
  201. // IsEqual returns true if all the secrets fields are equal
  202. func (s *Secret) IsEqual(other *Secret) bool {
  203. if s.GetStatus() != other.GetStatus() {
  204. return false
  205. }
  206. if s.GetPayload() != other.GetPayload() {
  207. return false
  208. }
  209. if s.GetKey() != other.GetKey() {
  210. return false
  211. }
  212. if s.GetAdditionalData() != other.GetAdditionalData() {
  213. return false
  214. }
  215. if s.GetMode() != other.GetMode() {
  216. return false
  217. }
  218. return true
  219. }
  220. // Clone returns a copy of the secret object
  221. func (s *Secret) Clone() *Secret {
  222. s.RLock()
  223. defer s.RUnlock()
  224. return &Secret{
  225. provider: s.provider.Clone(),
  226. }
  227. }
  228. // IsEncrypted returns true if the secret is encrypted
  229. // This isn't a pointer receiver because we don't want to pass
  230. // a pointer to html template
  231. func (s *Secret) IsEncrypted() bool {
  232. s.RLock()
  233. defer s.RUnlock()
  234. return s.provider.IsEncrypted()
  235. }
  236. // IsPlain returns true if the secret is in plain text
  237. func (s *Secret) IsPlain() bool {
  238. s.RLock()
  239. defer s.RUnlock()
  240. return s.provider.GetStatus() == SecretStatusPlain
  241. }
  242. // IsNotPlainAndNotEmpty returns true if the secret is not plain and not empty.
  243. // This is an utility method, we update the secret for an existing user
  244. // if it is empty or plain
  245. func (s *Secret) IsNotPlainAndNotEmpty() bool {
  246. s.RLock()
  247. defer s.RUnlock()
  248. return !s.IsPlain() && !s.IsEmpty()
  249. }
  250. // IsRedacted returns true if the secret is redacted
  251. func (s *Secret) IsRedacted() bool {
  252. s.RLock()
  253. defer s.RUnlock()
  254. return s.provider.GetStatus() == SecretStatusRedacted
  255. }
  256. // GetPayload returns the secret payload
  257. func (s *Secret) GetPayload() string {
  258. s.RLock()
  259. defer s.RUnlock()
  260. return s.provider.GetPayload()
  261. }
  262. // GetAdditionalData returns the secret additional data
  263. func (s *Secret) GetAdditionalData() string {
  264. s.RLock()
  265. defer s.RUnlock()
  266. return s.provider.GetAdditionalData()
  267. }
  268. // GetStatus returns the secret status
  269. func (s *Secret) GetStatus() SecretStatus {
  270. s.RLock()
  271. defer s.RUnlock()
  272. return s.provider.GetStatus()
  273. }
  274. // GetKey returns the secret key
  275. func (s *Secret) GetKey() string {
  276. s.RLock()
  277. defer s.RUnlock()
  278. return s.provider.GetKey()
  279. }
  280. // GetMode returns the secret mode
  281. func (s *Secret) GetMode() int {
  282. s.RLock()
  283. defer s.RUnlock()
  284. return s.provider.GetMode()
  285. }
  286. // SetAdditionalData sets the given additional data
  287. func (s *Secret) SetAdditionalData(value string) {
  288. s.Lock()
  289. defer s.Unlock()
  290. s.provider.SetAdditionalData(value)
  291. }
  292. // SetStatus sets the status for this secret
  293. func (s *Secret) SetStatus(value SecretStatus) {
  294. s.Lock()
  295. defer s.Unlock()
  296. s.provider.SetStatus(value)
  297. }
  298. // SetKey sets the key for this secret
  299. func (s *Secret) SetKey(value string) {
  300. s.Lock()
  301. defer s.Unlock()
  302. s.provider.SetKey(value)
  303. }
  304. // IsEmpty returns true if all fields are empty
  305. func (s *Secret) IsEmpty() bool {
  306. s.RLock()
  307. defer s.RUnlock()
  308. if s.provider.GetStatus() != "" {
  309. return false
  310. }
  311. if s.provider.GetPayload() != "" {
  312. return false
  313. }
  314. if s.provider.GetKey() != "" {
  315. return false
  316. }
  317. if s.provider.GetAdditionalData() != "" {
  318. return false
  319. }
  320. return true
  321. }
  322. // IsValid returns true if the secret is not empty and valid
  323. func (s *Secret) IsValid() bool {
  324. s.RLock()
  325. defer s.RUnlock()
  326. if !s.IsValidInput() {
  327. return false
  328. }
  329. switch s.provider.GetStatus() {
  330. case SecretStatusAES256GCM, SecretStatusSecretBox:
  331. if len(s.provider.GetKey()) != 64 {
  332. return false
  333. }
  334. case SecretStatusAWS, SecretStatusGCP, SecretStatusVaultTransit:
  335. key := s.provider.GetKey()
  336. if key != "" && len(key) != 64 {
  337. return false
  338. }
  339. }
  340. return true
  341. }
  342. // IsValidInput returns true if the secret is a valid user input
  343. func (s *Secret) IsValidInput() bool {
  344. s.RLock()
  345. defer s.RUnlock()
  346. if !util.IsStringInSlice(s.provider.GetStatus(), validSecretStatuses) {
  347. return false
  348. }
  349. if s.provider.GetPayload() == "" {
  350. return false
  351. }
  352. return true
  353. }
  354. // Hide hides info to decrypt data
  355. func (s *Secret) Hide() {
  356. s.Lock()
  357. defer s.Unlock()
  358. s.provider.SetKey("")
  359. s.provider.SetAdditionalData("")
  360. }
  361. // Encrypt encrypts a plain text Secret object
  362. func (s *Secret) Encrypt() error {
  363. s.Lock()
  364. defer s.Unlock()
  365. return s.provider.Encrypt()
  366. }
  367. // Decrypt decrypts a Secret object
  368. func (s *Secret) Decrypt() error {
  369. s.Lock()
  370. defer s.Unlock()
  371. return s.provider.Decrypt()
  372. }
  373. // TryDecrypt decrypts a Secret object if encrypted.
  374. // It returns a nil error if the object is not encrypted
  375. func (s *Secret) TryDecrypt() error {
  376. s.Lock()
  377. defer s.Unlock()
  378. if s.provider.IsEncrypted() {
  379. return s.provider.Decrypt()
  380. }
  381. return nil
  382. }