// createSecretIDAccessorEntry creates an identifier for the SecretID. A storage index, // mapping the accessor to the SecretID is also created. This method should // be called when the lock for the corresponding SecretID is held. func (b *backend) createSecretIDAccessorEntry(s logical.Storage, entry *secretIDStorageEntry, secretIDHMAC string) error { // Create a random accessor accessorUUID, err := uuid.GenerateUUID() if err != nil { return err } entry.SecretIDAccessor = accessorUUID // Create index entry, mapping the accessor to the token ID entryIndex := "accessor/" + b.salt.SaltID(entry.SecretIDAccessor) accessorLock := b.secretIDAccessorLock(accessorUUID) accessorLock.Lock() defer accessorLock.Unlock() if entry, err := logical.StorageEntryJSON(entryIndex, &secretIDAccessorStorageEntry{ SecretIDHMAC: secretIDHMAC, }); err != nil { return err } else if err = s.Put(entry); err != nil { return fmt.Errorf("failed to persist accessor index entry: %s", err) } return nil }
func (b *backend) setUser(s logical.Storage, username string, userEntry *UserEntry) error { entry, err := logical.StorageEntryJSON("user/"+username, userEntry) if err != nil { return err } return s.Put(entry) }
// NewSalt creates a new salt based on the configuration func NewSalt(view logical.Storage, config *Config) (*Salt, error) { // Setup the configuration if config == nil { config = &Config{} } if config.Location == "" { config.Location = DefaultLocation } if config.HashFunc == nil { config.HashFunc = SHA256Hash } // Create the salt s := &Salt{ config: config, } // Look for the salt raw, err := view.Get(config.Location) if err != nil { return nil, fmt.Errorf("failed to read salt: %v", err) } // Restore the salt if it exists if raw != nil { s.salt = string(raw.Value) } // Generate a new salt if necessary if s.salt == "" { s.salt, err = uuid.GenerateUUID() if err != nil { return nil, fmt.Errorf("failed to generate uuid: %v", err) } s.generated = true if view != nil { raw := &logical.StorageEntry{ Key: config.Location, Value: []byte(s.salt), } if err := view.Put(raw); err != nil { return nil, fmt.Errorf("failed to persist salt: %v", err) } } } if config.HMAC != nil { if len(config.HMACType) == 0 { return nil, fmt.Errorf("HMACType must be defined") } s.hmacType = config.HMACType } return s, nil }
// Stores an instance ID and the information required to validate further login/renewal attempts from // the same instance ID. func setWhitelistIdentityEntry(s logical.Storage, instanceID string, identity *whitelistIdentity) error { entry, err := logical.StorageEntryJSON("whitelist/identity/"+instanceID, identity) if err != nil { return err } if err := s.Put(entry); err != nil { return err } return nil }
// Put writes the structure. func (p *PathStruct) Put(s logical.Storage, v map[string]interface{}) error { bytes, err := json.Marshal(v) if err != nil { return err } return s.Put(&logical.StorageEntry{ Key: fmt.Sprintf("struct/%s", p.Name), Value: bytes, }) }
// Stores the given list of roles at zeroaddress endpoint func (b *backend) putZeroAddressRoles(s logical.Storage, roles []string) error { entry, err := logical.StorageEntryJSON("config/zeroaddress", &zeroAddressRoles{ Roles: roles, }) if err != nil { return err } if err := s.Put(entry); err != nil { return err } return nil }
func (p *policy) storeArchive(archive *archivedKeys, storage logical.Storage) error { // Encode the policy buf, err := json.Marshal(archive) if err != nil { return err } // Write the policy into storage err = storage.Put(&logical.StorageEntry{ Key: "archive/" + p.Name, Value: buf, }) if err != nil { return err } return nil }
func (p *Policy) Persist(storage logical.Storage, name string) error { // Encode the policy buf, err := p.Serialize() if err != nil { return err } // Write the policy into storage err = storage.Put(&logical.StorageEntry{ Key: "policy/" + name, Value: buf, }) if err != nil { return err } return nil }
// nonLockedSetAWSPublicCertificateEntry is used to store the AWS public key in // the storage. This method does not acquire lock before reading the storage. // If locking is desired, use lockedSetAWSPublicCertificateEntry instead. func (b *backend) nonLockedSetAWSPublicCertificateEntry(s logical.Storage, certName string, certEntry *awsPublicCert) error { if certName == "" { return fmt.Errorf("missing certificate name") } if certEntry == nil { return fmt.Errorf("nil AWS public key certificate") } entry, err := logical.StorageEntryJSON("config/certificate/"+certName, certEntry) if err != nil { return err } if entry == nil { return fmt.Errorf("failed to create storage entry for AWS public key certificate") } return s.Put(entry) }
// PutWAL writes some data to the WAL. // // The kind parameter is used by the framework to allow users to store // multiple kinds of WAL data and to easily disambiguate what data they're // expecting. // // Data within the WAL that is uncommitted (CommitWAL hasn't be called) // will be given to the rollback callback when an rollback operation is // received, allowing the backend to clean up some partial states. // // The data must be JSON encodable. // // This returns a unique ID that can be used to reference this WAL data. // WAL data cannot be modified. You can only add to the WAL and commit existing // WAL entries. func PutWAL(s logical.Storage, kind string, data interface{}) (string, error) { value, err := json.Marshal(&WALEntry{ Kind: kind, Data: data, CreatedAt: time.Now().UTC().Unix(), }) if err != nil { return "", err } id, err := logical.UUID() if err != nil { return "", err } return id, s.Put(&logical.StorageEntry{ Key: WALPrefix + id, Value: value, }) }
// nonLockedSetAWSRole creates or updates a role in the storage. This method // does not acquire the write lock before reading the role from the storage. If // locking is desired, use lockedSetAWSRole instead. func (b *backend) nonLockedSetAWSRole(s logical.Storage, roleName string, roleEntry *awsRoleEntry) error { if roleName == "" { return fmt.Errorf("missing role name") } if roleEntry == nil { return fmt.Errorf("nil role entry") } entry, err := logical.StorageEntryJSON("role/"+strings.ToLower(roleName), roleEntry) if err != nil { return err } if err := s.Put(entry); err != nil { return err } return nil }
func (b *backend) getRole(s logical.Storage, n string) (*roleEntry, error) { entry, err := s.Get("role/" + n) if err != nil { return nil, err } if entry == nil { return nil, nil } var result roleEntry if err := entry.DecodeJSON(&result); err != nil { return nil, err } // Migrate existing saved entries and save back if changed modified := false if len(result.TTL) == 0 && len(result.Lease) != 0 { result.TTL = result.Lease result.Lease = "" modified = true } if len(result.MaxTTL) == 0 && len(result.LeaseMax) != 0 { result.MaxTTL = result.LeaseMax result.LeaseMax = "" modified = true } if modified { jsonEntry, err := logical.StorageEntryJSON("role/"+n, &result) if err != nil { return nil, err } if err := s.Put(jsonEntry); err != nil { return nil, err } } return &result, nil }
// nonLockedSetSecretIDStorageEntry creates or updates a secret ID entry at the // physical storage. The entry will be indexed based on the given HMACs of both // role name and the secret ID. This method will not acquire secret ID lock to // create/update the storage entry. Locks need to be acquired before calling // this method. func (b *backend) nonLockedSetSecretIDStorageEntry(s logical.Storage, roleNameHMAC, secretIDHMAC string, secretEntry *secretIDStorageEntry) error { if secretIDHMAC == "" { return fmt.Errorf("missing secret ID HMAC") } if roleNameHMAC == "" { return fmt.Errorf("missing role name HMAC") } if secretEntry == nil { return fmt.Errorf("nil secret entry") } entryIndex := fmt.Sprintf("secret_id/%s/%s", roleNameHMAC, secretIDHMAC) if entry, err := logical.StorageEntryJSON(entryIndex, secretEntry); err != nil { return err } else if err = s.Put(entry); err != nil { return err } return nil }
func (p *policy) Persist(storage logical.Storage) error { err := p.handleArchiving(storage) if err != nil { return err } // Encode the policy buf, err := p.Serialize() if err != nil { return err } // Write the policy into storage err = storage.Put(&logical.StorageEntry{ Key: "policy/" + p.Name, Value: buf, }) if err != nil { return err } return nil }
// generatePolicy is used to create a new named policy with // a randomly generated key func generatePolicy(storage logical.Storage, name string, derived bool) (*Policy, error) { // Create the policy object p := &Policy{ Name: name, CipherMode: "aes-gcm", Derived: derived, } if derived { p.KDFMode = kdfMode } // Generate a 256bit key p.Key = make([]byte, 32) _, err := rand.Read(p.Key) if err != nil { return nil, err } // Encode the policy buf, err := p.Serialize() if err != nil { return nil, err } // Write the policy into storage err = storage.Put(&logical.StorageEntry{ Key: "policy/" + name, Value: buf, }) if err != nil { return nil, err } // Return the policy return p, nil }
// registerSecretIDEntry creates a new storage entry for the given SecretID. func (b *backend) registerSecretIDEntry(s logical.Storage, roleName, secretID, hmacKey string, secretEntry *secretIDStorageEntry) (*secretIDStorageEntry, error) { secretIDHMAC, err := createHMAC(hmacKey, secretID) if err != nil { return nil, fmt.Errorf("failed to create HMAC of secret_id: %s", err) } roleNameHMAC, err := createHMAC(hmacKey, roleName) if err != nil { return nil, fmt.Errorf("failed to create HMAC of role_name: %s", err) } entryIndex := fmt.Sprintf("secret_id/%s/%s", roleNameHMAC, secretIDHMAC) lock := b.secretIDLock(secretIDHMAC) lock.RLock() entry, err := s.Get(entryIndex) if err != nil { lock.RUnlock() return nil, err } if entry != nil { lock.RUnlock() return nil, fmt.Errorf("SecretID is already registered") } // If there isn't an entry for the secretID already, switch the read lock // with a write lock and create an entry. lock.RUnlock() lock.Lock() defer lock.Unlock() // But before saving a new entry, check if the secretID entry was created during the lock switch. entry, err = s.Get(entryIndex) if err != nil { return nil, err } if entry != nil { return nil, fmt.Errorf("SecretID is already registered") } // Create a new entry for the SecretID // Set the creation time for the SecretID currentTime := time.Now() 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) } // Before storing the SecretID, store its accessor. if err := b.createSecretIDAccessorEntry(s, secretEntry, secretIDHMAC); err != nil { return nil, err } if entry, err := logical.StorageEntryJSON(entryIndex, secretEntry); err != nil { return nil, err } else if err = s.Put(entry); err != nil { return nil, err } return secretEntry, 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 }
func (b *backend) getRole(s logical.Storage, n string) (*roleEntry, error) { entry, err := s.Get("role/" + n) if err != nil { return nil, err } if entry == nil { return nil, nil } var result roleEntry if err := entry.DecodeJSON(&result); err != nil { return nil, err } // Migrate existing saved entries and save back if changed modified := false if len(result.TTL) == 0 && len(result.Lease) != 0 { result.TTL = result.Lease result.Lease = "" modified = true } if len(result.MaxTTL) == 0 && len(result.LeaseMax) != 0 { result.MaxTTL = result.LeaseMax result.LeaseMax = "" modified = true } if result.AllowBaseDomain { result.AllowBaseDomain = false result.AllowBareDomains = true modified = true } if result.AllowedBaseDomain != "" { found := false allowedDomains := strings.Split(result.AllowedDomains, ",") if len(allowedDomains) != 0 { for _, v := range allowedDomains { if v == result.AllowedBaseDomain { found = true break } } } if !found { if result.AllowedDomains == "" { result.AllowedDomains = result.AllowedBaseDomain } else { result.AllowedDomains += "," + result.AllowedBaseDomain } } result.AllowedBaseDomain = "" modified = true } if modified { jsonEntry, err := logical.StorageEntryJSON("role/"+n, &result) if err != nil { return nil, err } if err := s.Put(jsonEntry); err != nil { return nil, err } } return &result, nil }