open-vault/builtin/credential/aws/path_tidy_identity_whitelist.go
Jeff Mitchell 98bf463a65 Make single-lease revocation behave like expiration (#4883)
This change makes it so that if a lease is revoked through user action,
we set the expiration time to now and update pending, just as we do with
tokens. This allows the normal retry logic to apply in these cases as
well, instead of just erroring out immediately. The idea being that once
you tell Vault to revoke something it should keep doing its darndest to
actually make that happen.
2018-07-11 15:45:35 -04:00

120 lines
3.8 KiB
Go

package awsauth
import (
"context"
"fmt"
"net/http"
"sync/atomic"
"time"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/logical/framework"
)
func pathTidyIdentityWhitelist(b *backend) *framework.Path {
return &framework.Path{
Pattern: "tidy/identity-whitelist$",
Fields: map[string]*framework.FieldSchema{
"safety_buffer": &framework.FieldSchema{
Type: framework.TypeDurationSecond,
Default: 259200,
Description: `The amount of extra time that must have passed beyond the identity's
expiration, before it is removed from the backend storage.`,
},
},
Callbacks: map[logical.Operation]framework.OperationFunc{
logical.UpdateOperation: b.pathTidyIdentityWhitelistUpdate,
},
HelpSynopsis: pathTidyIdentityWhitelistSyn,
HelpDescription: pathTidyIdentityWhitelistDesc,
}
}
// tidyWhitelistIdentity is used to delete entries in the whitelist that are expired.
func (b *backend) tidyWhitelistIdentity(ctx context.Context, req *logical.Request, safetyBuffer int) (*logical.Response, error) {
if !atomic.CompareAndSwapUint32(b.tidyWhitelistCASGuard, 0, 1) {
resp := &logical.Response{}
resp.AddWarning("Tidy operation already in progress.")
return resp, nil
}
s := req.Storage
go func() {
defer atomic.StoreUint32(b.tidyWhitelistCASGuard, 0)
// Don't cancel when the original client request goes away
ctx = context.Background()
logger := b.Logger().Named("wltidy")
bufferDuration := time.Duration(safetyBuffer) * time.Second
doTidy := func() error {
identities, err := s.List(ctx, "whitelist/identity/")
if err != nil {
return err
}
for _, instanceID := range identities {
identityEntry, err := s.Get(ctx, "whitelist/identity/"+instanceID)
if err != nil {
return errwrap.Wrapf(fmt.Sprintf("error fetching identity of instanceID %q: {{err}}", instanceID), err)
}
if identityEntry == nil {
return fmt.Errorf("identity entry for instanceID %q is nil", instanceID)
}
if identityEntry.Value == nil || len(identityEntry.Value) == 0 {
return fmt.Errorf("found identity entry for instanceID %q but actual identity is empty", instanceID)
}
var result whitelistIdentity
if err := identityEntry.DecodeJSON(&result); err != nil {
return err
}
if time.Now().After(result.ExpirationTime.Add(bufferDuration)) {
if err := s.Delete(ctx, "whitelist/identity/"+instanceID); err != nil {
return errwrap.Wrapf(fmt.Sprintf("error deleting identity of instanceID %q from storage: {{err}}", instanceID), err)
}
}
}
return nil
}
if err := doTidy(); err != nil {
logger.Error("error running whitelist tidy", "error", err)
return
}
}()
resp := &logical.Response{}
resp.AddWarning("Tidy operation successfully started. Any information from the operation will be printed to Vault's server logs.")
return logical.RespondWithStatusCode(resp, req, http.StatusAccepted)
}
// pathTidyIdentityWhitelistUpdate is used to delete entries in the whitelist that are expired.
func (b *backend) pathTidyIdentityWhitelistUpdate(ctx context.Context, req *logical.Request, data *framework.FieldData) (*logical.Response, error) {
return b.tidyWhitelistIdentity(ctx, req, data.Get("safety_buffer").(int))
}
const pathTidyIdentityWhitelistSyn = `
Clean-up the whitelist instance identity entries.
`
const pathTidyIdentityWhitelistDesc = `
When an instance identity is whitelisted, the expiration time of the whitelist
entry is set based on the maximum 'max_ttl' value set on: the role, the role tag
and the backend's mount.
When this endpoint is invoked, all the entries that are expired will be deleted.
A 'safety_buffer' (duration in seconds) can be provided, to ensure deletion of
only those entries that are expired before 'safety_buffer' seconds.
`