kms.go 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. // Package kms provides Key Management Services support
  2. package kms
  3. import (
  4. "encoding/json"
  5. "errors"
  6. "os"
  7. "strings"
  8. "time"
  9. "github.com/drakkan/sftpgo/utils"
  10. )
  11. // SecretProvider defines the interface for a KMS secrets provider
  12. type SecretProvider interface {
  13. Name() string
  14. Encrypt() error
  15. Decrypt() error
  16. IsEncrypted() bool
  17. GetStatus() SecretStatus
  18. GetPayload() string
  19. GetKey() string
  20. GetAdditionalData() string
  21. GetMode() int
  22. SetKey(string)
  23. SetAdditionalData(string)
  24. SetStatus(SecretStatus)
  25. }
  26. // SecretStatus defines the statuses of a Secret object
  27. type SecretStatus = string
  28. const (
  29. // SecretStatusPlain means the secret is in plain text and must be encrypted
  30. SecretStatusPlain SecretStatus = "Plain"
  31. // SecretStatusAES256GCM means the secret is encrypted using AES-256-GCM
  32. SecretStatusAES256GCM SecretStatus = "AES-256-GCM"
  33. // SecretStatusSecretBox means the secret is encrypted using a locally provided symmetric key
  34. SecretStatusSecretBox SecretStatus = "Secretbox"
  35. // SecretStatusGCP means we use keys from Google Cloud Platform’s Key Management Service
  36. // (GCP KMS) to keep information secret
  37. SecretStatusGCP SecretStatus = "GCP"
  38. // SecretStatusAWS means we use customer master keys from Amazon Web Service’s
  39. // Key Management Service (AWS KMS) to keep information secret
  40. SecretStatusAWS SecretStatus = "AWS"
  41. // SecretStatusVaultTransit means we use the transit secrets engine in Vault
  42. // to keep information secret
  43. SecretStatusVaultTransit SecretStatus = "VaultTransit"
  44. // SecretStatusRedacted means the secret is redacted
  45. SecretStatusRedacted SecretStatus = "Redacted"
  46. )
  47. const (
  48. localProviderName = "Local"
  49. builtinProviderName = "Builtin"
  50. awsProviderName = "AWS"
  51. gcpProviderName = "GCP"
  52. vaultProviderName = "VaultTransit"
  53. )
  54. // Configuration defines the KMS configuration
  55. type Configuration struct {
  56. Secrets Secrets `json:"secrets" mapstructure:"secrets"`
  57. }
  58. // Secrets define the KMS configuration for encryption/decryption
  59. type Secrets struct {
  60. URL string `json:"url" mapstructure:"url"`
  61. MasterKeyPath string `json:"master_key_path" mapstructure:"master_key_path"`
  62. masterKey string
  63. }
  64. var (
  65. errWrongSecretStatus = errors.New("wrong secret status")
  66. errMalformedCiphertext = errors.New("malformed ciphertext")
  67. errInvalidSecret = errors.New("invalid secret")
  68. validSecretStatuses = []string{SecretStatusPlain, SecretStatusAES256GCM, SecretStatusSecretBox,
  69. SecretStatusVaultTransit, SecretStatusAWS, SecretStatusGCP, SecretStatusRedacted}
  70. config Configuration
  71. defaultTimeout = 10 * time.Second
  72. )
  73. // NewSecret builds a new Secret using the provided arguments
  74. func NewSecret(status SecretStatus, payload, key, data string) *Secret {
  75. return config.newSecret(status, payload, key, data)
  76. }
  77. // NewEmptySecret returns an empty secret
  78. func NewEmptySecret() *Secret {
  79. return NewSecret("", "", "", "")
  80. }
  81. // NewPlainSecret stores the give payload in a plain text secret
  82. func NewPlainSecret(payload string) *Secret {
  83. return NewSecret(SecretStatusPlain, payload, "", "")
  84. }
  85. // GetSecretFromCompatString returns a secret from the previous format
  86. func GetSecretFromCompatString(secret string) (*Secret, error) {
  87. plain, err := utils.DecryptData(secret)
  88. if err != nil {
  89. return &Secret{}, errMalformedCiphertext
  90. }
  91. return NewSecret(SecretStatusPlain, plain, "", ""), nil
  92. }
  93. // Initialize configures the KMS support
  94. func (c *Configuration) Initialize() error {
  95. if c.Secrets.MasterKeyPath != "" {
  96. mKey, err := os.ReadFile(c.Secrets.MasterKeyPath)
  97. if err != nil {
  98. return err
  99. }
  100. c.Secrets.masterKey = strings.TrimSpace(string(mKey))
  101. }
  102. config = *c
  103. return nil
  104. }
  105. func (c *Configuration) newSecret(status SecretStatus, payload, key, data string) *Secret {
  106. base := baseSecret{
  107. Status: status,
  108. Key: key,
  109. Payload: payload,
  110. AdditionalData: data,
  111. }
  112. return &Secret{
  113. provider: c.getSecretProvider(base),
  114. }
  115. }
  116. func (c *Configuration) getSecretProvider(base baseSecret) SecretProvider {
  117. if strings.HasPrefix(c.Secrets.URL, "hashivault://") {
  118. return newVaultSecret(base, c.Secrets.URL, c.Secrets.masterKey)
  119. }
  120. if strings.HasPrefix(c.Secrets.URL, "awskms://") {
  121. return newAWSSecret(base, c.Secrets.URL, c.Secrets.masterKey)
  122. }
  123. if strings.HasPrefix(c.Secrets.URL, "gcpkms://") {
  124. return newGCPSecret(base, c.Secrets.URL, c.Secrets.masterKey)
  125. }
  126. return newLocalSecret(base, c.Secrets.masterKey)
  127. }
  128. // Secret defines the struct used to store confidential data
  129. type Secret struct {
  130. provider SecretProvider
  131. }
  132. // MarshalJSON return the JSON encoding of the Secret object
  133. func (s *Secret) MarshalJSON() ([]byte, error) {
  134. return json.Marshal(&baseSecret{
  135. Status: s.provider.GetStatus(),
  136. Payload: s.provider.GetPayload(),
  137. Key: s.provider.GetKey(),
  138. AdditionalData: s.provider.GetAdditionalData(),
  139. Mode: s.provider.GetMode(),
  140. })
  141. }
  142. // UnmarshalJSON parses the JSON-encoded data and stores the result
  143. // in the Secret object
  144. func (s *Secret) UnmarshalJSON(data []byte) error {
  145. baseSecret := baseSecret{}
  146. err := json.Unmarshal(data, &baseSecret)
  147. if err != nil {
  148. return err
  149. }
  150. if baseSecret.isEmpty() {
  151. s.provider = config.getSecretProvider(baseSecret)
  152. return nil
  153. }
  154. switch baseSecret.Status {
  155. case SecretStatusAES256GCM:
  156. s.provider = newBuiltinSecret(baseSecret)
  157. case SecretStatusSecretBox:
  158. s.provider = newLocalSecret(baseSecret, config.Secrets.masterKey)
  159. case SecretStatusVaultTransit:
  160. s.provider = newVaultSecret(baseSecret, config.Secrets.URL, config.Secrets.masterKey)
  161. case SecretStatusAWS:
  162. s.provider = newAWSSecret(baseSecret, config.Secrets.URL, config.Secrets.masterKey)
  163. case SecretStatusGCP:
  164. s.provider = newGCPSecret(baseSecret, config.Secrets.URL, config.Secrets.masterKey)
  165. case SecretStatusPlain, SecretStatusRedacted:
  166. s.provider = config.getSecretProvider(baseSecret)
  167. default:
  168. return errInvalidSecret
  169. }
  170. return nil
  171. }
  172. // Clone returns a copy of the secret object
  173. func (s *Secret) Clone() *Secret {
  174. baseSecret := baseSecret{
  175. Status: s.provider.GetStatus(),
  176. Payload: s.provider.GetPayload(),
  177. Key: s.provider.GetKey(),
  178. AdditionalData: s.provider.GetAdditionalData(),
  179. Mode: s.provider.GetMode(),
  180. }
  181. switch s.provider.Name() {
  182. case builtinProviderName:
  183. return &Secret{
  184. provider: newBuiltinSecret(baseSecret),
  185. }
  186. case awsProviderName:
  187. return &Secret{
  188. provider: newAWSSecret(baseSecret, config.Secrets.URL, config.Secrets.masterKey),
  189. }
  190. case gcpProviderName:
  191. return &Secret{
  192. provider: newGCPSecret(baseSecret, config.Secrets.URL, config.Secrets.masterKey),
  193. }
  194. case localProviderName:
  195. return &Secret{
  196. provider: newLocalSecret(baseSecret, config.Secrets.masterKey),
  197. }
  198. case vaultProviderName:
  199. return &Secret{
  200. provider: newVaultSecret(baseSecret, config.Secrets.URL, config.Secrets.masterKey),
  201. }
  202. }
  203. return NewSecret(s.GetStatus(), s.GetPayload(), s.GetKey(), s.GetAdditionalData())
  204. }
  205. // IsEncrypted returns true if the secret is encrypted
  206. // This isn't a pointer receiver because we don't want to pass
  207. // a pointer to html template
  208. func (s *Secret) IsEncrypted() bool {
  209. return s.provider.IsEncrypted()
  210. }
  211. // IsPlain returns true if the secret is in plain text
  212. func (s *Secret) IsPlain() bool {
  213. return s.provider.GetStatus() == SecretStatusPlain
  214. }
  215. // IsNotPlainAndNotEmpty returns true if the secret is not plain and not empty.
  216. // This is an utility method, we update the secret for an existing user
  217. // if it is empty or plain
  218. func (s *Secret) IsNotPlainAndNotEmpty() bool {
  219. return !s.IsPlain() && !s.IsEmpty()
  220. }
  221. // IsRedacted returns true if the secret is redacted
  222. func (s *Secret) IsRedacted() bool {
  223. return s.provider.GetStatus() == SecretStatusRedacted
  224. }
  225. // GetPayload returns the secret payload
  226. func (s *Secret) GetPayload() string {
  227. return s.provider.GetPayload()
  228. }
  229. // GetAdditionalData returns the secret additional data
  230. func (s *Secret) GetAdditionalData() string {
  231. return s.provider.GetAdditionalData()
  232. }
  233. // GetStatus returns the secret status
  234. func (s *Secret) GetStatus() SecretStatus {
  235. return s.provider.GetStatus()
  236. }
  237. // GetKey returns the secret key
  238. func (s *Secret) GetKey() string {
  239. return s.provider.GetKey()
  240. }
  241. // GetMode returns the secret mode
  242. func (s *Secret) GetMode() int {
  243. return s.provider.GetMode()
  244. }
  245. // SetAdditionalData sets the given additional data
  246. func (s *Secret) SetAdditionalData(value string) {
  247. s.provider.SetAdditionalData(value)
  248. }
  249. // SetStatus sets the status for this secret
  250. func (s *Secret) SetStatus(value SecretStatus) {
  251. s.provider.SetStatus(value)
  252. }
  253. // SetKey sets the key for this secret
  254. func (s *Secret) SetKey(value string) {
  255. s.provider.SetKey(value)
  256. }
  257. // IsEmpty returns true if all fields are empty
  258. func (s *Secret) IsEmpty() bool {
  259. if s.provider.GetStatus() != "" {
  260. return false
  261. }
  262. if s.provider.GetPayload() != "" {
  263. return false
  264. }
  265. if s.provider.GetKey() != "" {
  266. return false
  267. }
  268. if s.provider.GetAdditionalData() != "" {
  269. return false
  270. }
  271. return true
  272. }
  273. // IsValid returns true if the secret is not empty and valid
  274. func (s *Secret) IsValid() bool {
  275. if !s.IsValidInput() {
  276. return false
  277. }
  278. switch s.provider.GetStatus() {
  279. case SecretStatusAES256GCM, SecretStatusSecretBox:
  280. if len(s.provider.GetKey()) != 64 {
  281. return false
  282. }
  283. case SecretStatusAWS, SecretStatusGCP, SecretStatusVaultTransit:
  284. key := s.provider.GetKey()
  285. if key != "" && len(key) != 64 {
  286. return false
  287. }
  288. }
  289. return true
  290. }
  291. // IsValidInput returns true if the secret is a valid user input
  292. func (s *Secret) IsValidInput() bool {
  293. if !utils.IsStringInSlice(s.provider.GetStatus(), validSecretStatuses) {
  294. return false
  295. }
  296. if s.provider.GetPayload() == "" {
  297. return false
  298. }
  299. return true
  300. }
  301. // Hide hides info to decrypt data
  302. func (s *Secret) Hide() {
  303. s.provider.SetKey("")
  304. s.provider.SetAdditionalData("")
  305. }
  306. // Encrypt encrypts a plain text Secret object
  307. func (s *Secret) Encrypt() error {
  308. return s.provider.Encrypt()
  309. }
  310. // Decrypt decrypts a Secret object
  311. func (s *Secret) Decrypt() error {
  312. return s.provider.Decrypt()
  313. }