kms.go 9.4 KB

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