/builtin/logical/transit/path_config.go

https://github.com/hashicorp/vault · Go · 212 lines · 170 code · 34 blank · 8 comment · 40 complexity · 6366f7ba0cb58fbaeee36ec155397d29 MD5 · raw file

  1. package transit
  2. import (
  3. "context"
  4. "fmt"
  5. "github.com/hashicorp/vault/sdk/framework"
  6. "github.com/hashicorp/vault/sdk/helper/keysutil"
  7. "github.com/hashicorp/vault/sdk/logical"
  8. )
  9. func (b *backend) pathConfig() *framework.Path {
  10. return &framework.Path{
  11. Pattern: "keys/" + framework.GenericNameRegex("name") + "/config",
  12. Fields: map[string]*framework.FieldSchema{
  13. "name": &framework.FieldSchema{
  14. Type: framework.TypeString,
  15. Description: "Name of the key",
  16. },
  17. "min_decryption_version": &framework.FieldSchema{
  18. Type: framework.TypeInt,
  19. Description: `If set, the minimum version of the key allowed
  20. to be decrypted. For signing keys, the minimum
  21. version allowed to be used for verification.`,
  22. },
  23. "min_encryption_version": &framework.FieldSchema{
  24. Type: framework.TypeInt,
  25. Description: `If set, the minimum version of the key allowed
  26. to be used for encryption; or for signing keys,
  27. to be used for signing. If set to zero, only
  28. the latest version of the key is allowed.`,
  29. },
  30. "deletion_allowed": &framework.FieldSchema{
  31. Type: framework.TypeBool,
  32. Description: "Whether to allow deletion of the key",
  33. },
  34. "exportable": &framework.FieldSchema{
  35. Type: framework.TypeBool,
  36. Description: `Enables export of the key. Once set, this cannot be disabled.`,
  37. },
  38. "allow_plaintext_backup": &framework.FieldSchema{
  39. Type: framework.TypeBool,
  40. Description: `Enables taking a backup of the named key in plaintext format. Once set, this cannot be disabled.`,
  41. },
  42. },
  43. Callbacks: map[logical.Operation]framework.OperationFunc{
  44. logical.UpdateOperation: b.pathConfigWrite,
  45. },
  46. HelpSynopsis: pathConfigHelpSyn,
  47. HelpDescription: pathConfigHelpDesc,
  48. }
  49. }
  50. func (b *backend) pathConfigWrite(ctx context.Context, req *logical.Request, d *framework.FieldData) (resp *logical.Response, retErr error) {
  51. name := d.Get("name").(string)
  52. // Check if the policy already exists before we lock everything
  53. p, _, err := b.lm.GetPolicy(ctx, keysutil.PolicyRequest{
  54. Storage: req.Storage,
  55. Name: name,
  56. }, b.GetRandomReader())
  57. if err != nil {
  58. return nil, err
  59. }
  60. if p == nil {
  61. return logical.ErrorResponse(
  62. fmt.Sprintf("no existing key named %s could be found", name)),
  63. logical.ErrInvalidRequest
  64. }
  65. if !b.System().CachingDisabled() {
  66. p.Lock(true)
  67. }
  68. defer p.Unlock()
  69. originalMinDecryptionVersion := p.MinDecryptionVersion
  70. originalMinEncryptionVersion := p.MinEncryptionVersion
  71. originalDeletionAllowed := p.DeletionAllowed
  72. originalExportable := p.Exportable
  73. originalAllowPlaintextBackup := p.AllowPlaintextBackup
  74. defer func() {
  75. if retErr != nil || (resp != nil && resp.IsError()) {
  76. p.MinDecryptionVersion = originalMinDecryptionVersion
  77. p.MinEncryptionVersion = originalMinEncryptionVersion
  78. p.DeletionAllowed = originalDeletionAllowed
  79. p.Exportable = originalExportable
  80. p.AllowPlaintextBackup = originalAllowPlaintextBackup
  81. }
  82. }()
  83. resp = &logical.Response{}
  84. persistNeeded := false
  85. minDecryptionVersionRaw, ok := d.GetOk("min_decryption_version")
  86. if ok {
  87. minDecryptionVersion := minDecryptionVersionRaw.(int)
  88. if minDecryptionVersion < 0 {
  89. return logical.ErrorResponse("min decryption version cannot be negative"), nil
  90. }
  91. if minDecryptionVersion == 0 {
  92. minDecryptionVersion = 1
  93. resp.AddWarning("since Vault 0.3, transit key numbering starts at 1; forcing minimum to 1")
  94. }
  95. if minDecryptionVersion != p.MinDecryptionVersion {
  96. if minDecryptionVersion > p.LatestVersion {
  97. return logical.ErrorResponse(
  98. fmt.Sprintf("cannot set min decryption version of %d, latest key version is %d", minDecryptionVersion, p.LatestVersion)), nil
  99. }
  100. p.MinDecryptionVersion = minDecryptionVersion
  101. persistNeeded = true
  102. }
  103. }
  104. minEncryptionVersionRaw, ok := d.GetOk("min_encryption_version")
  105. if ok {
  106. minEncryptionVersion := minEncryptionVersionRaw.(int)
  107. if minEncryptionVersion < 0 {
  108. return logical.ErrorResponse("min encryption version cannot be negative"), nil
  109. }
  110. if minEncryptionVersion != p.MinEncryptionVersion {
  111. if minEncryptionVersion > p.LatestVersion {
  112. return logical.ErrorResponse(
  113. fmt.Sprintf("cannot set min encryption version of %d, latest key version is %d", minEncryptionVersion, p.LatestVersion)), nil
  114. }
  115. p.MinEncryptionVersion = minEncryptionVersion
  116. persistNeeded = true
  117. }
  118. }
  119. // Check here to get the final picture after the logic on each
  120. // individually. MinDecryptionVersion will always be 1 or above.
  121. if p.MinEncryptionVersion > 0 &&
  122. p.MinEncryptionVersion < p.MinDecryptionVersion {
  123. return logical.ErrorResponse(
  124. fmt.Sprintf("cannot set min encryption/decryption values; min encryption version of %d must be greater than or equal to min decryption version of %d", p.MinEncryptionVersion, p.MinDecryptionVersion)), nil
  125. }
  126. allowDeletionInt, ok := d.GetOk("deletion_allowed")
  127. if ok {
  128. allowDeletion := allowDeletionInt.(bool)
  129. if allowDeletion != p.DeletionAllowed {
  130. p.DeletionAllowed = allowDeletion
  131. persistNeeded = true
  132. }
  133. }
  134. // Add this as a guard here before persisting since we now require the min
  135. // decryption version to start at 1; even if it's not explicitly set here,
  136. // force the upgrade
  137. if p.MinDecryptionVersion == 0 {
  138. p.MinDecryptionVersion = 1
  139. persistNeeded = true
  140. }
  141. exportableRaw, ok := d.GetOk("exportable")
  142. if ok {
  143. exportable := exportableRaw.(bool)
  144. // Don't unset the already set value
  145. if exportable && !p.Exportable {
  146. p.Exportable = exportable
  147. persistNeeded = true
  148. }
  149. }
  150. allowPlaintextBackupRaw, ok := d.GetOk("allow_plaintext_backup")
  151. if ok {
  152. allowPlaintextBackup := allowPlaintextBackupRaw.(bool)
  153. // Don't unset the already set value
  154. if allowPlaintextBackup && !p.AllowPlaintextBackup {
  155. p.AllowPlaintextBackup = allowPlaintextBackup
  156. persistNeeded = true
  157. }
  158. }
  159. if !persistNeeded {
  160. return nil, nil
  161. }
  162. switch {
  163. case p.MinAvailableVersion > p.MinEncryptionVersion:
  164. return logical.ErrorResponse("min encryption version should not be less than min available version"), nil
  165. case p.MinAvailableVersion > p.MinDecryptionVersion:
  166. return logical.ErrorResponse("min decryption version should not be less then min available version"), nil
  167. }
  168. if len(resp.Warnings) == 0 {
  169. return nil, p.Persist(ctx, req.Storage)
  170. }
  171. return resp, p.Persist(ctx, req.Storage)
  172. }
  173. const pathConfigHelpSyn = `Configure a named encryption key`
  174. const pathConfigHelpDesc = `
  175. This path is used to configure the named key. Currently, this
  176. supports adjusting the minimum version of the key allowed to
  177. be used for decryption via the min_decryption_version parameter.
  178. `