mirror of
https://github.com/hashicorp/vault.git
synced 2025-11-27 05:31:40 +01:00
Use capabilities to determine upsert-ability in transit.
This commit is contained in:
parent
216fe1b9da
commit
3ac40a7ae5
@ -39,6 +39,19 @@ func TestBackend_basic(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBackend_upsert(t *testing.T) {
|
||||||
|
decryptData := make(map[string]interface{})
|
||||||
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
|
Factory: Factory,
|
||||||
|
Steps: []logicaltest.TestStep{
|
||||||
|
testAccStepReadPolicy(t, "test", true, false),
|
||||||
|
testAccStepEncryptUpsert(t, "test", testPlaintext, decryptData),
|
||||||
|
testAccStepReadPolicy(t, "test", false, false),
|
||||||
|
testAccStepDecrypt(t, "test", testPlaintext, decryptData),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestBackend_datakey(t *testing.T) {
|
func TestBackend_datakey(t *testing.T) {
|
||||||
dataKeyInfo := make(map[string]interface{})
|
dataKeyInfo := make(map[string]interface{})
|
||||||
logicaltest.Test(t, logicaltest.TestCase{
|
logicaltest.Test(t, logicaltest.TestCase{
|
||||||
@ -268,6 +281,30 @@ func testAccStepEncrypt(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testAccStepEncryptUpsert(
|
||||||
|
t *testing.T, name, plaintext string, decryptData map[string]interface{}) logicaltest.TestStep {
|
||||||
|
return logicaltest.TestStep{
|
||||||
|
Operation: logical.CreateOperation,
|
||||||
|
Path: "encrypt/" + name,
|
||||||
|
Data: map[string]interface{}{
|
||||||
|
"plaintext": base64.StdEncoding.EncodeToString([]byte(plaintext)),
|
||||||
|
},
|
||||||
|
Check: func(resp *logical.Response) error {
|
||||||
|
var d struct {
|
||||||
|
Ciphertext string `mapstructure:"ciphertext"`
|
||||||
|
}
|
||||||
|
if err := mapstructure.Decode(resp.Data, &d); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if d.Ciphertext == "" {
|
||||||
|
return fmt.Errorf("missing ciphertext")
|
||||||
|
}
|
||||||
|
decryptData["ciphertext"] = d.Ciphertext
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testAccStepEncryptContext(
|
func testAccStepEncryptContext(
|
||||||
t *testing.T, name, plaintext, context string, decryptData map[string]interface{}) logicaltest.TestStep {
|
t *testing.T, name, plaintext, context string, decryptData map[string]interface{}) logicaltest.TestStep {
|
||||||
return logicaltest.TestStep{
|
return logicaltest.TestStep{
|
||||||
|
|||||||
@ -30,14 +30,28 @@ func (b *backend) pathEncrypt() *framework.Path {
|
|||||||
},
|
},
|
||||||
|
|
||||||
Callbacks: map[logical.Operation]framework.OperationFunc{
|
Callbacks: map[logical.Operation]framework.OperationFunc{
|
||||||
|
logical.CreateOperation: b.pathEncryptWrite,
|
||||||
logical.UpdateOperation: b.pathEncryptWrite,
|
logical.UpdateOperation: b.pathEncryptWrite,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
ExistenceCheck: b.pathEncryptExistenceCheck,
|
||||||
|
|
||||||
HelpSynopsis: pathEncryptHelpSyn,
|
HelpSynopsis: pathEncryptHelpSyn,
|
||||||
HelpDescription: pathEncryptHelpDesc,
|
HelpDescription: pathEncryptHelpDesc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *backend) pathEncryptExistenceCheck(
|
||||||
|
req *logical.Request, d *framework.FieldData) (bool, error) {
|
||||||
|
name := d.Get("name").(string)
|
||||||
|
lp, err := b.policies.getPolicy(req, name)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return lp != nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *backend) pathEncryptWrite(
|
func (b *backend) pathEncryptWrite(
|
||||||
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
|
||||||
name := d.Get("name").(string)
|
name := d.Get("name").(string)
|
||||||
@ -65,7 +79,19 @@ func (b *backend) pathEncryptWrite(
|
|||||||
|
|
||||||
// Error if invalid policy
|
// Error if invalid policy
|
||||||
if lp == nil {
|
if lp == nil {
|
||||||
return logical.ErrorResponse("policy not found"), logical.ErrInvalidRequest
|
if req.Operation != logical.CreateOperation {
|
||||||
|
return logical.ErrorResponse("policy not found"), logical.ErrInvalidRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
isDerived := len(context) != 0
|
||||||
|
|
||||||
|
lp, err = b.policies.generatePolicy(req.Storage, name, isDerived)
|
||||||
|
// If the error is that the policy has been created in the interim we
|
||||||
|
// will get the policy back, so only consider it an error if err is not
|
||||||
|
// nil and we do not get a policy back
|
||||||
|
if err != nil && lp != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lp.RLock()
|
lp.RLock()
|
||||||
|
|||||||
@ -48,14 +48,15 @@ endpoint. Since the `default` policy contains `auth/token/renew-self` this
|
|||||||
makes it much more likely that the request will succeed rather than somewhat
|
makes it much more likely that the request will succeed rather than somewhat
|
||||||
confusingly failing due to a lack of permissions on `auth/token/renew`.
|
confusingly failing due to a lack of permissions on `auth/token/renew`.
|
||||||
|
|
||||||
## Transit No Longer Upserts Keys By Default
|
## Transit Upsertion Behavior Uses Capabilities
|
||||||
|
|
||||||
Previously, attempting to encrypt with a key that did not exist would create a
|
Previously, attempting to encrypt with a key that did not exist would create a
|
||||||
key with default values. This was convenient but ultimately allowed a client to
|
key with default values. This was convenient but ultimately allowed a client to
|
||||||
potentially escape an ACL policy restriction, albeit without any dangerous
|
potentially escape an ACL policy restriction, albeit without any dangerous
|
||||||
access. However, this is now disabled by default. If you want to enable this
|
access. Now that Vault supports more granular capabilities in policies,
|
||||||
behavior, you can use the `allow_upsert` parameter to the new `transit/config`
|
upsertion behavior is controlled by whether the client has the `create`
|
||||||
endpoint to turn it back on.
|
capability for the request (upsertion is allowed) or only the `update`
|
||||||
|
capability (upsertion is denied).
|
||||||
|
|
||||||
## etcd Physical Backend Uses `sync`
|
## etcd Physical Backend Uses `sync`
|
||||||
|
|
||||||
|
|||||||
@ -305,7 +305,13 @@ only encrypt or decrypt using the named keys they need access to.
|
|||||||
<dl class="api">
|
<dl class="api">
|
||||||
<dt>Description</dt>
|
<dt>Description</dt>
|
||||||
<dd>
|
<dd>
|
||||||
Encrypts the provided plaintext using the named key.
|
Encrypts the provided plaintext using the named key. This path supports the
|
||||||
|
`create` and `update` policy capabilities as follows: if the user has the
|
||||||
|
`create` capability for this endpoint in their policies, and the key does
|
||||||
|
not exist, it will be upserted with default values (whether the key
|
||||||
|
requires derivation depends on whether the context parameter is empty or
|
||||||
|
not). If the user only has `update` capability and the key does not exist,
|
||||||
|
an error will be returned.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt>Method</dt>
|
<dt>Method</dt>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user