// flushRoleSecrets deletes all the SecretIDs that belong to the given // RoleID. func (b *backend) flushRoleSecrets(s logical.Storage, roleName, hmacKey string) error { roleNameHMAC, err := createHMAC(hmacKey, roleName) if err != nil { return fmt.Errorf("failed to create HMAC of role_name: %s", err) } // Acquire the custom lock to perform listing of SecretIDs customLock := b.secretIDLock("") customLock.RLock() defer customLock.RUnlock() secretIDHMACs, err := s.List(fmt.Sprintf("secret_id/%s/", roleNameHMAC)) if err != nil { return err } for _, secretIDHMAC := range secretIDHMACs { // Acquire the lock belonging to the SecretID lock := b.secretIDLock(secretIDHMAC) lock.Lock() entryIndex := fmt.Sprintf("secret_id/%s/%s", roleNameHMAC, secretIDHMAC) if err := s.Delete(entryIndex); err != nil { lock.Unlock() return fmt.Errorf("error deleting SecretID %s from storage: %s", secretIDHMAC, err) } lock.Unlock() } return nil }
// deleteSecretIDAccessorEntry deletes the storage index mapping the accessor to a SecretID. func (b *backend) deleteSecretIDAccessorEntry(s logical.Storage, secretIDAccessor string) error { accessorEntryIndex := "accessor/" + b.salt.SaltID(secretIDAccessor) accessorLock := b.secretIDAccessorLock(secretIDAccessor) accessorLock.Lock() defer accessorLock.Unlock() // Delete the accessor of the SecretID first if err := s.Delete(accessorEntryIndex); err != nil { return fmt.Errorf("failed to delete accessor storage entry: %s", err) } return nil }
// deletePolicy deletes a policy func (p *policyCache) deletePolicy(storage logical.Storage, name string) error { // Ensure one with this name exists lp, err := p.getPolicy(&logical.Request{ Storage: storage, }, name) if err != nil { return fmt.Errorf("error checking if policy already exists: %s", err) } if lp == nil { return fmt.Errorf("policy %s does not exist", name) } p.Lock() defer p.Unlock() lp = p.cache[name] if lp == nil { return fmt.Errorf("policy %s not found", name) } // We need to ensure all other access has stopped lp.Lock() defer lp.Unlock() // Verify this hasn't changed if !lp.policy.DeletionAllowed { return fmt.Errorf("deletion not allowed for policy %s", name) } err = storage.Delete("policy/" + name) if err != nil { return fmt.Errorf("error deleting policy %s: %s", name, err) } err = storage.Delete("archive/" + name) if err != nil { return fmt.Errorf("error deleting archive %s: %s", name, err) } lp.policy = nil delete(p.cache, name) return nil }
// tidyWhitelistIdentity is used to delete entries in the whitelist that are expired. func (b *backend) tidyWhitelistIdentity(s logical.Storage, safety_buffer int) error { grabbed := atomic.CompareAndSwapUint32(&b.tidyWhitelistCASGuard, 0, 1) if grabbed { defer atomic.StoreUint32(&b.tidyWhitelistCASGuard, 0) } else { return fmt.Errorf("identity whitelist tidy operation already running") } bufferDuration := time.Duration(safety_buffer) * time.Second identities, err := s.List("whitelist/identity/") if err != nil { return err } for _, instanceID := range identities { identityEntry, err := s.Get("whitelist/identity/" + instanceID) if err != nil { return fmt.Errorf("error fetching identity of instanceID %s: %s", instanceID, err) } if identityEntry == nil { return fmt.Errorf("identity entry for instanceID %s is nil", instanceID) } if identityEntry.Value == nil || len(identityEntry.Value) == 0 { return fmt.Errorf("found identity entry for instanceID %s but actual identity is empty", instanceID) } var result whitelistIdentity if err := identityEntry.DecodeJSON(&result); err != nil { return err } if time.Now().UTC().After(result.ExpirationTime.Add(bufferDuration)) { if err := s.Delete("whitelist/identity" + instanceID); err != nil { return fmt.Errorf("error deleting identity of instanceID %s from storage: %s", instanceID, err) } } } return nil }
func (lm *lockManager) DeletePolicy(storage logical.Storage, name string) error { lm.cacheMutex.Lock() lock := lm.policyLock(name, exclusive) defer lock.Unlock() defer lm.cacheMutex.Unlock() var p *policy var err error if lm.CacheActive() { p = lm.cache[name] } if p == nil { p, err = lm.getStoredPolicy(storage, name) if err != nil { return err } if p == nil { return fmt.Errorf("could not delete policy; not found") } } if !p.DeletionAllowed { return fmt.Errorf("deletion is not allowed for this policy") } err = storage.Delete("policy/" + name) if err != nil { return fmt.Errorf("error deleting policy %s: %s", name, err) } err = storage.Delete("archive/" + name) if err != nil { return fmt.Errorf("error deleting archive %s: %s", name, err) } if lm.CacheActive() { delete(lm.cache, name) } return nil }
// tidyBlacklistRoleTag is used to clean-up the entries in the role tag blacklist. func (b *backend) tidyBlacklistRoleTag(s logical.Storage, safety_buffer int) error { grabbed := atomic.CompareAndSwapUint32(&b.tidyBlacklistCASGuard, 0, 1) if grabbed { defer atomic.StoreUint32(&b.tidyBlacklistCASGuard, 0) } else { return fmt.Errorf("roletag blacklist tidy operation already running") } bufferDuration := time.Duration(safety_buffer) * time.Second tags, err := s.List("blacklist/roletag/") if err != nil { return err } for _, tag := range tags { tagEntry, err := s.Get("blacklist/roletag/" + tag) if err != nil { return fmt.Errorf("error fetching tag %s: %s", tag, err) } if tagEntry == nil { return fmt.Errorf("tag entry for tag %s is nil", tag) } if tagEntry.Value == nil || len(tagEntry.Value) == 0 { return fmt.Errorf("found entry for tag %s but actual tag is empty", tag) } var result roleTagBlacklistEntry if err := tagEntry.DecodeJSON(&result); err != nil { return err } if time.Now().After(result.ExpirationTime.Add(bufferDuration)) { if err := s.Delete("blacklist/roletag" + tag); err != nil { return fmt.Errorf("error deleting tag %s from storage: %s", tag, err) } } } return nil }
// validateBindSecretID is used to determine if the given SecretID is a valid one. func (b *backend) validateBindSecretID(s logical.Storage, roleName, secretID, hmacKey string) (bool, map[string]string, error) { secretIDHMAC, err := createHMAC(hmacKey, secretID) if err != nil { return false, nil, fmt.Errorf("failed to create HMAC of secret_id: %s", err) } roleNameHMAC, err := createHMAC(hmacKey, roleName) if err != nil { return false, nil, fmt.Errorf("failed to create HMAC of role_name: %s", err) } entryIndex := fmt.Sprintf("secret_id/%s/%s", roleNameHMAC, secretIDHMAC) // SecretID locks are always index based on secretIDHMACs. This helps // acquiring the locks when the SecretIDs are listed. This allows grabbing // the correct locks even if the SecretIDs are not known in plaintext. lock := b.secretIDLock(secretIDHMAC) lock.RLock() result := secretIDStorageEntry{} if entry, err := s.Get(entryIndex); err != nil { lock.RUnlock() return false, nil, err } else if entry == nil { lock.RUnlock() return false, nil, nil } else if err := entry.DecodeJSON(&result); err != nil { lock.RUnlock() return false, nil, err } // SecretIDNumUses will be zero only if the usage limit was not set at all, // in which case, the SecretID will remain to be valid as long as it is not // expired. if result.SecretIDNumUses == 0 { lock.RUnlock() return true, result.Metadata, nil } // If the SecretIDNumUses is non-zero, it means that its use-count should be updated // in the storage. Switch the lock from a `read` to a `write` and update // the storage entry. lock.RUnlock() lock.Lock() defer lock.Unlock() // Lock switching may change the data. Refresh the contents. result = secretIDStorageEntry{} if entry, err := s.Get(entryIndex); err != nil { return false, nil, err } else if entry == nil { return false, nil, nil } else if err := entry.DecodeJSON(&result); err != nil { return false, nil, err } // If there exists a single use left, delete the SecretID entry from // the storage but do not fail the validation request. Subsequest // requests to use the same SecretID will fail. if result.SecretIDNumUses == 1 { // Delete the secret IDs accessor first if err := b.deleteSecretIDAccessorEntry(s, result.SecretIDAccessor); err != nil { return false, nil, err } if err := s.Delete(entryIndex); err != nil { return false, nil, fmt.Errorf("failed to delete SecretID: %s", err) } } else { // If the use count is greater than one, decrement it and update the last updated time. result.SecretIDNumUses -= 1 result.LastUpdatedTime = time.Now() if entry, err := logical.StorageEntryJSON(entryIndex, &result); err != nil { return false, nil, fmt.Errorf("failed to decrement the use count for SecretID:%s", secretID) } else if err = s.Put(entry); err != nil { return false, nil, fmt.Errorf("failed to decrement the use count for SecretID:%s", secretID) } } return true, result.Metadata, nil }
// Delete removes the structure. func (p *PathStruct) Delete(s logical.Storage) error { return s.Delete(fmt.Sprintf("struct/%s", p.Name)) }
// DeleteWAL commits the WAL entry with the given ID. Once committed, // it is assumed that the operation was a success and doesn't need to // be rolled back. func DeleteWAL(s logical.Storage, id string) error { return s.Delete(WALPrefix + id) }
// tidySecretID is used to delete entries in the whitelist that are expired. func (b *backend) tidySecretID(s logical.Storage) error { grabbed := atomic.CompareAndSwapUint32(&b.tidySecretIDCASGuard, 0, 1) if grabbed { defer atomic.StoreUint32(&b.tidySecretIDCASGuard, 0) } else { return fmt.Errorf("SecretID tidy operation already running") } roleNameHMACs, err := s.List("secret_id/") if err != nil { return err } var result error for _, roleNameHMAC := range roleNameHMACs { // roleNameHMAC will already have a '/' suffix. Don't append another one. secretIDHMACs, err := s.List(fmt.Sprintf("secret_id/%s", roleNameHMAC)) if err != nil { return err } for _, secretIDHMAC := range secretIDHMACs { // In order to avoid lock swroleing in case there is need to delete, // grab the write lock. lock := b.secretIDLock(secretIDHMAC) lock.Lock() // roleNameHMAC will already have a '/' suffix. Don't append another one. entryIndex := fmt.Sprintf("secret_id/%s%s", roleNameHMAC, secretIDHMAC) secretIDEntry, err := s.Get(entryIndex) if err != nil { lock.Unlock() return fmt.Errorf("error fetching SecretID %s: %s", secretIDHMAC, err) } if secretIDEntry == nil { result = multierror.Append(result, fmt.Errorf("entry for SecretID %s is nil", secretIDHMAC)) lock.Unlock() continue } if secretIDEntry.Value == nil || len(secretIDEntry.Value) == 0 { lock.Unlock() return fmt.Errorf("found entry for SecretID %s but actual SecretID is empty", secretIDHMAC) } var result secretIDStorageEntry if err := secretIDEntry.DecodeJSON(&result); err != nil { lock.Unlock() return err } // ExpirationTime not being set indicates non-expiring SecretIDs if !result.ExpirationTime.IsZero() && time.Now().After(result.ExpirationTime) { if err := s.Delete(entryIndex); err != nil { lock.Unlock() return fmt.Errorf("error deleting SecretID %s from storage: %s", secretIDHMAC, err) } } lock.Unlock() } } return result }