mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 18:48:08 +00:00 
			
		
		
		
	 3d7d8f4965
			
		
	
	3d7d8f4965
	
	
	
		
			
			* VAULT-15547 Additional tests, refactoring, for proxy split * VAULT-15547 Additional tests, refactoring, for proxy split * VAULT-15547 Import reorganization * VAULT-15547 Some missed updates for PersistConfig * VAULT-15547 address comments * VAULT-15547 address comments
		
			
				
	
	
		
			238 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright (c) HashiCorp, Inc.
 | |
| // SPDX-License-Identifier: MPL-2.0
 | |
| 
 | |
| package agentproxyshared
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 
 | |
| 	log "github.com/hashicorp/go-hclog"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/alicloud"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/approle"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/aws"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/azure"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/cert"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/cf"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/gcp"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/jwt"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/kerberos"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/kubernetes"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/auth/oci"
 | |
| 	token_file "github.com/hashicorp/vault/command/agentproxyshared/auth/token-file"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/cache"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/cache/cacheboltdb"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/cache/cachememdb"
 | |
| 	"github.com/hashicorp/vault/command/agentproxyshared/cache/keymanager"
 | |
| )
 | |
| 
 | |
| // GetAutoAuthMethodFromConfig Calls the appropriate NewAutoAuthMethod function, initializing
 | |
| // the auto-auth method, based on the auto-auth method type. Returns an error if one happens or
 | |
| // the method type is invalid.
 | |
| func GetAutoAuthMethodFromConfig(autoAuthMethodType string, authConfig *auth.AuthConfig, vaultAddress string) (auth.AuthMethod, error) {
 | |
| 	switch autoAuthMethodType {
 | |
| 	case "alicloud":
 | |
| 		return alicloud.NewAliCloudAuthMethod(authConfig)
 | |
| 	case "aws":
 | |
| 		return aws.NewAWSAuthMethod(authConfig)
 | |
| 	case "azure":
 | |
| 		return azure.NewAzureAuthMethod(authConfig)
 | |
| 	case "cert":
 | |
| 		return cert.NewCertAuthMethod(authConfig)
 | |
| 	case "cf":
 | |
| 		return cf.NewCFAuthMethod(authConfig)
 | |
| 	case "gcp":
 | |
| 		return gcp.NewGCPAuthMethod(authConfig)
 | |
| 	case "jwt":
 | |
| 		return jwt.NewJWTAuthMethod(authConfig)
 | |
| 	case "kerberos":
 | |
| 		return kerberos.NewKerberosAuthMethod(authConfig)
 | |
| 	case "kubernetes":
 | |
| 		return kubernetes.NewKubernetesAuthMethod(authConfig)
 | |
| 	case "approle":
 | |
| 		return approle.NewApproleAuthMethod(authConfig)
 | |
| 	case "oci":
 | |
| 		return oci.NewOCIAuthMethod(authConfig, vaultAddress)
 | |
| 	case "token_file":
 | |
| 		return token_file.NewTokenFileAuthMethod(authConfig)
 | |
| 	case "pcf": // Deprecated.
 | |
| 		return cf.NewCFAuthMethod(authConfig)
 | |
| 	default:
 | |
| 		return nil, errors.New(fmt.Sprintf("unknown auth method %q", autoAuthMethodType))
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // PersistConfig contains configuration needed for persistent caching
 | |
| type PersistConfig struct {
 | |
| 	Type                    string
 | |
| 	Path                    string `hcl:"path"`
 | |
| 	KeepAfterImport         bool   `hcl:"keep_after_import"`
 | |
| 	ExitOnErr               bool   `hcl:"exit_on_err"`
 | |
| 	ServiceAccountTokenFile string `hcl:"service_account_token_file"`
 | |
| }
 | |
| 
 | |
| // AddPersistentStorageToLeaseCache adds persistence to a lease cache, based on a given PersistConfig
 | |
| // Returns a close function to be deferred and the old token, if found, or an error
 | |
| func AddPersistentStorageToLeaseCache(ctx context.Context, leaseCache *cache.LeaseCache, persistConfig *PersistConfig, logger log.Logger) (func() error, string, error) {
 | |
| 	if persistConfig == nil {
 | |
| 		return nil, "", errors.New("persist config was nil")
 | |
| 	}
 | |
| 
 | |
| 	if persistConfig.Path == "" {
 | |
| 		return nil, "", errors.New("must specify persistent cache path")
 | |
| 	}
 | |
| 
 | |
| 	// Set AAD based on key protection type
 | |
| 	var aad string
 | |
| 	var err error
 | |
| 	switch persistConfig.Type {
 | |
| 	case "kubernetes":
 | |
| 		aad, err = getServiceAccountJWT(persistConfig.ServiceAccountTokenFile)
 | |
| 		if err != nil {
 | |
| 			tokenFileName := persistConfig.ServiceAccountTokenFile
 | |
| 			if len(tokenFileName) == 0 {
 | |
| 				tokenFileName = "/var/run/secrets/kubernetes.io/serviceaccount/token"
 | |
| 			}
 | |
| 			return nil, "", fmt.Errorf("failed to read service account token from %s: %w", tokenFileName, err)
 | |
| 		}
 | |
| 	default:
 | |
| 		return nil, "", fmt.Errorf("persistent key protection type %q not supported", persistConfig.Type)
 | |
| 	}
 | |
| 
 | |
| 	// Check if bolt file exists already
 | |
| 	dbFileExists, err := cacheboltdb.DBFileExists(persistConfig.Path)
 | |
| 	if err != nil {
 | |
| 		return nil, "", fmt.Errorf("failed to check if bolt file exists at path %s: %w", persistConfig.Path, err)
 | |
| 	}
 | |
| 	if dbFileExists {
 | |
| 		// Open the bolt file, but wait to setup Encryption
 | |
| 		ps, err := cacheboltdb.NewBoltStorage(&cacheboltdb.BoltStorageConfig{
 | |
| 			Path:   persistConfig.Path,
 | |
| 			Logger: logger.Named("cacheboltdb"),
 | |
| 		})
 | |
| 		if err != nil {
 | |
| 			return nil, "", fmt.Errorf("error opening persistent cache %v", err)
 | |
| 		}
 | |
| 
 | |
| 		// Get the token from bolt for retrieving the encryption key,
 | |
| 		// then setup encryption so that restore is possible
 | |
| 		token, err := ps.GetRetrievalToken()
 | |
| 		if err != nil {
 | |
| 			return nil, "", fmt.Errorf("error getting retrieval token from persistent cache: %w", err)
 | |
| 		}
 | |
| 
 | |
| 		if err := ps.Close(); err != nil {
 | |
| 			return nil, "", fmt.Errorf("failed to close persistent cache file after getting retrieval token: %w", err)
 | |
| 		}
 | |
| 
 | |
| 		km, err := keymanager.NewPassthroughKeyManager(ctx, token)
 | |
| 		if err != nil {
 | |
| 			return nil, "", fmt.Errorf("failed to configure persistence encryption for cache: %w", err)
 | |
| 		}
 | |
| 
 | |
| 		// Open the bolt file with the wrapper provided
 | |
| 		ps, err = cacheboltdb.NewBoltStorage(&cacheboltdb.BoltStorageConfig{
 | |
| 			Path:    persistConfig.Path,
 | |
| 			Logger:  logger.Named("cacheboltdb"),
 | |
| 			Wrapper: km.Wrapper(),
 | |
| 			AAD:     aad,
 | |
| 		})
 | |
| 		if err != nil {
 | |
| 			return nil, "", fmt.Errorf("error opening persistent cache with wrapper: %w", err)
 | |
| 		}
 | |
| 
 | |
| 		// Restore anything in the persistent cache to the memory cache
 | |
| 		if err := leaseCache.Restore(ctx, ps); err != nil {
 | |
| 			logger.Error(fmt.Sprintf("error restoring in-memory cache from persisted file: %v", err))
 | |
| 			if persistConfig.ExitOnErr {
 | |
| 				return nil, "", fmt.Errorf("exiting with error as exit_on_err is set to true")
 | |
| 			}
 | |
| 		}
 | |
| 		logger.Info("loaded memcache from persistent storage")
 | |
| 
 | |
| 		// Check for previous auto-auth token
 | |
| 		oldTokenBytes, err := ps.GetAutoAuthToken(ctx)
 | |
| 		if err != nil {
 | |
| 			logger.Error(fmt.Sprintf("error in fetching previous auto-auth token: %v", err))
 | |
| 			if persistConfig.ExitOnErr {
 | |
| 				return nil, "", fmt.Errorf("exiting with error as exit_on_err is set to true")
 | |
| 			}
 | |
| 		}
 | |
| 		var previousToken string
 | |
| 		if len(oldTokenBytes) > 0 {
 | |
| 			oldToken, err := cachememdb.Deserialize(oldTokenBytes)
 | |
| 			if err != nil {
 | |
| 				logger.Error(fmt.Sprintf("error in deserializing previous auto-auth token cache entryn: %v", err))
 | |
| 				if persistConfig.ExitOnErr {
 | |
| 					return nil, "", fmt.Errorf("exiting with error as exit_on_err is set to true")
 | |
| 				}
 | |
| 			}
 | |
| 			previousToken = oldToken.Token
 | |
| 		}
 | |
| 
 | |
| 		// If keep_after_import true, set persistent storage layer in
 | |
| 		// leaseCache, else remove db file
 | |
| 		if persistConfig.KeepAfterImport {
 | |
| 			leaseCache.SetPersistentStorage(ps)
 | |
| 			return ps.Close, previousToken, nil
 | |
| 		} else {
 | |
| 			if err := ps.Close(); err != nil {
 | |
| 				logger.Warn(fmt.Sprintf("failed to close persistent cache file: %s", err))
 | |
| 			}
 | |
| 			dbFile := filepath.Join(persistConfig.Path, cacheboltdb.DatabaseFileName)
 | |
| 			if err := os.Remove(dbFile); err != nil {
 | |
| 				logger.Error(fmt.Sprintf("failed to remove persistent storage file %s: %v", dbFile, err))
 | |
| 				if persistConfig.ExitOnErr {
 | |
| 					return nil, "", fmt.Errorf("exiting with error as exit_on_err is set to true")
 | |
| 				}
 | |
| 			}
 | |
| 			return nil, previousToken, nil
 | |
| 		}
 | |
| 	} else {
 | |
| 		km, err := keymanager.NewPassthroughKeyManager(ctx, nil)
 | |
| 		if err != nil {
 | |
| 			return nil, "", fmt.Errorf("failed to configure persistence encryption for cache: %w", err)
 | |
| 		}
 | |
| 		ps, err := cacheboltdb.NewBoltStorage(&cacheboltdb.BoltStorageConfig{
 | |
| 			Path:    persistConfig.Path,
 | |
| 			Logger:  logger.Named("cacheboltdb"),
 | |
| 			Wrapper: km.Wrapper(),
 | |
| 			AAD:     aad,
 | |
| 		})
 | |
| 		if err != nil {
 | |
| 			return nil, "", fmt.Errorf("error creating persistent cache: %w", err)
 | |
| 		}
 | |
| 		logger.Info("configured persistent storage", "path", persistConfig.Path)
 | |
| 
 | |
| 		// Stash the key material in bolt
 | |
| 		token, err := km.RetrievalToken(ctx)
 | |
| 		if err != nil {
 | |
| 			return nil, "", fmt.Errorf("error getting persistence key: %w", err)
 | |
| 		}
 | |
| 		if err := ps.StoreRetrievalToken(token); err != nil {
 | |
| 			return nil, "", fmt.Errorf("error setting key in persistent cache: %w", err)
 | |
| 		}
 | |
| 
 | |
| 		leaseCache.SetPersistentStorage(ps)
 | |
| 		return ps.Close, "", nil
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // getServiceAccountJWT attempts to read the service account JWT from the specified token file path.
 | |
| // Defaults to using the Kubernetes default service account file path if token file path is empty.
 | |
| func getServiceAccountJWT(tokenFile string) (string, error) {
 | |
| 	if len(tokenFile) == 0 {
 | |
| 		tokenFile = "/var/run/secrets/kubernetes.io/serviceaccount/token"
 | |
| 	}
 | |
| 	token, err := os.ReadFile(tokenFile)
 | |
| 	if err != nil {
 | |
| 		return "", err
 | |
| 	}
 | |
| 	return strings.TrimSpace(string(token)), nil
 | |
| }
 |