Use capabilities to determine upsert-ability in transit.

This commit is contained in:
Jeff Mitchell
2016-02-02 09:58:12 -05:00
parent 216fe1b9da
commit 3ac40a7ae5
4 changed files with 76 additions and 6 deletions

View File

@@ -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) {
dataKeyInfo := make(map[string]interface{})
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(
t *testing.T, name, plaintext, context string, decryptData map[string]interface{}) logicaltest.TestStep {
return logicaltest.TestStep{

View File

@@ -30,14 +30,28 @@ func (b *backend) pathEncrypt() *framework.Path {
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.CreateOperation: b.pathEncryptWrite,
logical.UpdateOperation: b.pathEncryptWrite,
},
ExistenceCheck: b.pathEncryptExistenceCheck,
HelpSynopsis: pathEncryptHelpSyn,
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(
req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
name := d.Get("name").(string)
@@ -65,7 +79,19 @@ func (b *backend) pathEncryptWrite(
// Error if invalid policy
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()

View File

@@ -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
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
key with default values. This was convenient but ultimately allowed a client to
potentially escape an ACL policy restriction, albeit without any dangerous
access. However, this is now disabled by default. If you want to enable this
behavior, you can use the `allow_upsert` parameter to the new `transit/config`
endpoint to turn it back on.
access. Now that Vault supports more granular capabilities in policies,
upsertion behavior is controlled by whether the client has the `create`
capability for the request (upsertion is allowed) or only the `update`
capability (upsertion is denied).
## etcd Physical Backend Uses `sync`

View File

@@ -305,7 +305,13 @@ only encrypt or decrypt using the named keys they need access to.
<dl class="api">
<dt>Description</dt>
<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>
<dt>Method</dt>