Don't check parsability of a `ttl` key on write.

On read we already ignore bad values, so we shouldn't be restricting
this on write; doing so alters expected data-in-data-out behavior. In
addition, don't issue a warning if a given `ttl` value can't be parsed,
as this can quickly get annoying if it's on purpose.

The documentation has been updated/clarified to make it clear that this
is optional behavior that doesn't affect the status of the key as POD
and the `lease_duration` returned will otherwise default to the
system/mount defaults.

Fixes #1505
This commit is contained in:
Jeff Mitchell 2016-06-08 20:14:36 -04:00
parent 287de23241
commit 351f536913
2 changed files with 37 additions and 53 deletions

View File

@ -3,6 +3,7 @@ package vault
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"time"
@ -34,11 +35,6 @@ func LeaseSwitchedPassthroughBackend(conf *logical.BackendConfig, leases bool) (
&framework.Path{
Pattern: ".*",
Fields: map[string]*framework.FieldSchema{
//TODO: Deprecated in 0.3; remove in 0.4
"lease": &framework.FieldSchema{
Type: framework.TypeString,
Description: "Lease time for this key when read. Ex: 1h",
},
"ttl": &framework.FieldSchema{
Type: framework.TypeString,
Description: "TTL time for this key when read. Ex: 1h",
@ -142,12 +138,21 @@ func (b *PassthroughBackend) handleRead(
}
ttlDuration := b.System().DefaultLeaseTTL()
if len(ttl) != 0 {
parsedDuration, err := time.ParseDuration(ttl)
if err != nil {
resp.AddWarning(fmt.Sprintf("failed to parse stored ttl '%s' for entry; using default", ttl))
} else {
ttlDuration = parsedDuration
// Parse as a duration string if it has an appropriate suffix
if strings.HasSuffix(ttl, "s") || strings.HasSuffix(ttl, "m") || strings.HasSuffix(ttl, "h") {
dur, err := time.ParseDuration(ttl)
if err == nil {
ttlDuration = dur
}
} else {
// Parse as a straight number of seconds
seconds, err := strconv.ParseInt(ttl, 10, 64)
if err == nil {
ttlDuration = time.Duration(seconds) * time.Second
}
}
if b.generateLeases {
resp.Secret.Renewable = true
}
@ -165,23 +170,6 @@ func (b *PassthroughBackend) handleWrite(
return logical.ErrorResponse("missing data fields"), nil
}
// Check if there is a ttl key; verify parseability if so
var ttl string
ttl = data.Get("ttl").(string)
if len(ttl) == 0 {
ttl = data.Get("lease").(string)
}
if len(ttl) != 0 {
_, err := time.ParseDuration(ttl)
if err != nil {
return logical.ErrorResponse("failed to parse ttl for entry"), nil
}
// Verify that ttl isn't the *only* thing we have
if len(req.Data) == 1 {
return nil, fmt.Errorf("missing data; only ttl found")
}
}
// JSON encode the data
buf, err := json.Marshal(req.Data)
if err != nil {

View File

@ -28,15 +28,19 @@ secret's path.
## Quick Start
The generic backend allows for writing keys with arbitrary values. A `ttl`
value can be provided, which is parsed into seconds and round-tripped as the
`lease_duration` parameter in requests. Specifically, this can be used as a
hint from the writer of a secret to consumers of a secret that the consumer
should wait no more than the `ttl` duration before checking for a new value. If
you expect a secret to change frequently, or if you need clients to react
quickly to a change in the secret's value, specify a low value of `ttl`. Also
note that setting `ttl` does not actually expire the data; it is informational
only.
The generic backend allows for writing keys with arbitrary values. When data is
returned, the `lease_duration` field (in the API JSON) or `refresh_interval`
field (on the CLI) gives a hint as to how often a reader should look for a new
value. This comes from the value of the `default_lease_ttl` set on the mount,
or the system value.
There is one piece of special data handling: if a `ttl` key is provided, it
will be treated as normal data, but on read the backend will attempt to parse
it as a duration (either as a string like `1h` or an integer number of seconds
like `3600`). If successful, the backend will use this value in place of the
normal `lease_duration`. However, the given value will also still be returned
exactly as specified, so you are free to use that key in any way that you like
if it fits your input data.
As an example, we can write a new key "foo" to the generic backend mounted at
"secret/" by default:
@ -54,12 +58,13 @@ We can test this by doing a read:
```
$ vault read secret/foo
Key Value
lease_duration 3600
--- -----
refresh_interval 3600
ttl 1h
zip zap
```
As expected, we get the value previously set back as well as our custom TTL
As expected, we get the values previously set back as well as our custom TTL
both as specified and translated to seconds. The duration has been set to 3600
seconds (one hour) as specified.
@ -169,19 +174,10 @@ seconds (one hour) as specified.
<li>
<span class="param">(key)</span>
<span class="param-flags">optional</span>
A key, paired with an associated value, to be held at the
given location. Multiple key/value pairs can be specified,
and all will be returned on a read operation.
</li>
<li>
<span class="param">ttl</span>
<span class="param-flags">optional</span>
The Time To Live for the entry. This value, converted to
seconds, is round-tripped on read operations as the
`lease_duration` parameter. Vault takes no action when this
value expires; it is only meant as a way for a writer of
a value to indicate to readers how often they should check
for new entries.
A key, paired with an associated value, to be held at the given
location. Multiple key/value pairs can be specified, and all will be
returned on a read operation. A key called `ttl` will trigger some
special behavior; see above for details.
</li>
</ul>
</dd>