kms.go 11 KB

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