mirror of
https://github.com/hashicorp/vault.git
synced 2026-02-18 18:38:08 -05:00
approle: add ttl to the secret ID generation response (#10826)
* approle: add ttl to the secret ID generation response * approle: move TTL derivation into helper func * changelog: add changelog entry * docs: update approle docs and api-docs pages
This commit is contained in:
parent
8351a10154
commit
298b9cde2f
6 changed files with 118 additions and 13 deletions
|
|
@ -2358,12 +2358,15 @@ func (b *backend) handleRoleSecretIDCommon(ctx context.Context, req *logical.Req
|
|||
return nil, errwrap.Wrapf("failed to store secret_id: {{err}}", err)
|
||||
}
|
||||
|
||||
return &logical.Response{
|
||||
resp := &logical.Response{
|
||||
Data: map[string]interface{}{
|
||||
"secret_id": secretID,
|
||||
"secret_id_accessor": secretIDStorage.SecretIDAccessor,
|
||||
"secret_id_ttl": int64(b.deriveSecretIDTTL(secretIDStorage.SecretIDTTL).Seconds()),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (b *backend) roleIDLock(roleID string) *locksutil.LockEntry {
|
||||
|
|
|
|||
|
|
@ -1931,3 +1931,92 @@ func TestAppRole_TokenutilUpgrade(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAppRole_SecretID_WithTTL(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
roleName string
|
||||
ttl int64
|
||||
sysTTLCap bool
|
||||
}{
|
||||
{
|
||||
"zero ttl",
|
||||
"role-zero-ttl",
|
||||
0,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"custom ttl",
|
||||
"role-custom-ttl",
|
||||
60,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"system ttl capped",
|
||||
"role-sys-ttl-cap",
|
||||
700000000,
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
b, storage := createBackendWithStorage(t)
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Create role
|
||||
roleData := map[string]interface{}{
|
||||
"policies": "default",
|
||||
"secret_id_ttl": tt.ttl,
|
||||
}
|
||||
|
||||
roleReq := &logical.Request{
|
||||
Operation: logical.CreateOperation,
|
||||
Path: "role/" + tt.roleName,
|
||||
Storage: storage,
|
||||
Data: roleData,
|
||||
}
|
||||
resp, err := b.HandleRequest(context.Background(), roleReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
// Generate secret ID
|
||||
secretIDReq := &logical.Request{
|
||||
Operation: logical.UpdateOperation,
|
||||
Path: "role/" + tt.roleName + "/secret-id",
|
||||
Storage: storage,
|
||||
}
|
||||
resp, err = b.HandleRequest(context.Background(), secretIDReq)
|
||||
if err != nil || (resp != nil && resp.IsError()) {
|
||||
t.Fatalf("err:%v resp:%#v", err, resp)
|
||||
}
|
||||
|
||||
// Extract the "ttl" value from the response data if it exists
|
||||
ttlRaw, okTTL := resp.Data["secret_id_ttl"]
|
||||
if !okTTL {
|
||||
t.Fatalf("expected TTL value in response")
|
||||
}
|
||||
|
||||
var (
|
||||
respTTL int64
|
||||
ok bool
|
||||
)
|
||||
respTTL, ok = ttlRaw.(int64)
|
||||
if !ok {
|
||||
t.Fatalf("expected ttl to be an integer, got: %s", err)
|
||||
}
|
||||
|
||||
// Verify secret ID response for different cases
|
||||
switch {
|
||||
case tt.sysTTLCap:
|
||||
if respTTL != int64(b.System().MaxLeaseTTL().Seconds()) {
|
||||
t.Fatalf("expected TTL value to be system's max lease TTL, got: %d", respTTL)
|
||||
}
|
||||
default:
|
||||
if respTTL != tt.ttl {
|
||||
t.Fatalf("expected TTL value to be %d, got: %d", tt.ttl, respTTL)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -238,15 +238,8 @@ func (b *backend) registerSecretIDEntry(ctx context.Context, s logical.Storage,
|
|||
secretEntry.CreationTime = currentTime
|
||||
secretEntry.LastUpdatedTime = currentTime
|
||||
|
||||
// If SecretIDTTL is not specified or if it crosses the backend mount's limit,
|
||||
// cap the expiration to backend's max. Otherwise, use it to determine the
|
||||
// expiration time.
|
||||
if secretEntry.SecretIDTTL < time.Duration(0) || secretEntry.SecretIDTTL > b.System().MaxLeaseTTL() {
|
||||
secretEntry.ExpirationTime = currentTime.Add(b.System().MaxLeaseTTL())
|
||||
} else if secretEntry.SecretIDTTL != time.Duration(0) {
|
||||
// Set the ExpirationTime only if SecretIDTTL was set. SecretIDs should not
|
||||
// expire by default.
|
||||
secretEntry.ExpirationTime = currentTime.Add(secretEntry.SecretIDTTL)
|
||||
if ttl := b.deriveSecretIDTTL(secretEntry.SecretIDTTL); ttl != time.Duration(0) {
|
||||
secretEntry.ExpirationTime = currentTime.Add(ttl)
|
||||
}
|
||||
|
||||
// Before storing the SecretID, store its accessor.
|
||||
|
|
@ -261,6 +254,20 @@ func (b *backend) registerSecretIDEntry(ctx context.Context, s logical.Storage,
|
|||
return secretEntry, nil
|
||||
}
|
||||
|
||||
// deriveSecretIDTTL determines the secret ID TTL to use based on the system's
|
||||
// max lease TTL.
|
||||
//
|
||||
// If SecretIDTTL is negative or if it crosses the backend mount's limit,
|
||||
// return to backend's max lease TTL. Otherwise, return the provided secretIDTTL
|
||||
// value.
|
||||
func (b *backend) deriveSecretIDTTL(secretIDTTL time.Duration) time.Duration {
|
||||
if secretIDTTL < time.Duration(0) || secretIDTTL > b.System().MaxLeaseTTL() {
|
||||
return b.System().MaxLeaseTTL()
|
||||
}
|
||||
|
||||
return secretIDTTL
|
||||
}
|
||||
|
||||
// secretIDAccessorEntry is used to read the storage entry that maps an
|
||||
// accessor to a secret_id.
|
||||
func (b *backend) secretIDAccessorEntry(ctx context.Context, s logical.Storage, secretIDAccessor, roleSecretIDPrefix string) (*secretIDAccessorStorageEntry, error) {
|
||||
|
|
|
|||
3
changelog/10826.txt
Normal file
3
changelog/10826.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
```changelog:changes
|
||||
auth/approle: Secrets ID generation endpoint now returns `secret_id_ttl` as part of its response.
|
||||
```
|
||||
|
|
@ -301,7 +301,8 @@ $ curl \
|
|||
"wrap_info": null,
|
||||
"data": {
|
||||
"secret_id_accessor": "84896a0c-1347-aa90-a4f6-aca8b7558780",
|
||||
"secret_id": "841771dc-11c9-bbc7-bcac-6a3945a69cd9"
|
||||
"secret_id": "841771dc-11c9-bbc7-bcac-6a3945a69cd9",
|
||||
"secret_id_ttl": 600
|
||||
},
|
||||
"lease_duration": 0,
|
||||
"renewable": false,
|
||||
|
|
|
|||
|
|
@ -113,6 +113,7 @@ documentation.
|
|||
$ vault write -f auth/approle/role/my-role/secret-id
|
||||
secret_id 6a174c20-f6de-a53c-74d2-6018fcceff64
|
||||
secret_id_accessor c454f7e5-996e-7230-6074-6ef26b7bcf86
|
||||
secret_id_ttl 10m
|
||||
```
|
||||
|
||||
### Via the API
|
||||
|
|
@ -170,7 +171,8 @@ documentation.
|
|||
{
|
||||
"data": {
|
||||
"secret_id_accessor": "45946873-1d96-a9d4-678c-9229f74386a5",
|
||||
"secret_id": "37b74931-c4cd-d49a-9246-ccc62d682a25"
|
||||
"secret_id": "37b74931-c4cd-d49a-9246-ccc62d682a25",
|
||||
"secret_id_ttl": 600
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
Loading…
Reference in a new issue