| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426 |
- package kms
- import (
- "context"
- "fmt"
- "time"
- "github.com/seaweedfs/seaweedfs/weed/glog"
- )
- // ViperConfig interface extends Configuration with additional methods needed for KMS configuration
- type ViperConfig interface {
- GetString(key string) string
- GetBool(key string) bool
- GetInt(key string) int
- GetStringSlice(key string) []string
- SetDefault(key string, value interface{})
- GetStringMap(key string) map[string]interface{}
- IsSet(key string) bool
- }
- // ConfigLoader handles loading KMS configurations from filer.toml
- type ConfigLoader struct {
- viper ViperConfig
- manager *KMSManager
- }
- // NewConfigLoader creates a new KMS configuration loader
- func NewConfigLoader(v ViperConfig) *ConfigLoader {
- return &ConfigLoader{
- viper: v,
- manager: GetKMSManager(),
- }
- }
- // LoadConfigurations loads all KMS provider configurations from filer.toml
- func (loader *ConfigLoader) LoadConfigurations() error {
- // Check if KMS section exists
- if !loader.viper.IsSet("kms") {
- glog.V(1).Infof("No KMS configuration found in filer.toml")
- return nil
- }
- // Get the KMS configuration section
- kmsConfig := loader.viper.GetStringMap("kms")
- // Load global KMS settings
- if err := loader.loadGlobalKMSSettings(kmsConfig); err != nil {
- return fmt.Errorf("failed to load global KMS settings: %w", err)
- }
- // Load KMS providers
- if providersConfig, exists := kmsConfig["providers"]; exists {
- if providers, ok := providersConfig.(map[string]interface{}); ok {
- if err := loader.loadKMSProviders(providers); err != nil {
- return fmt.Errorf("failed to load KMS providers: %w", err)
- }
- }
- }
- // Set default provider after all providers are loaded
- if err := loader.setDefaultProvider(); err != nil {
- return fmt.Errorf("failed to set default KMS provider: %w", err)
- }
- // Initialize global KMS provider for backwards compatibility
- if err := loader.initializeGlobalKMSProvider(); err != nil {
- glog.Warningf("Failed to initialize global KMS provider: %v", err)
- }
- // Load bucket-specific KMS configurations
- if bucketsConfig, exists := kmsConfig["buckets"]; exists {
- if buckets, ok := bucketsConfig.(map[string]interface{}); ok {
- if err := loader.loadBucketKMSConfigurations(buckets); err != nil {
- return fmt.Errorf("failed to load bucket KMS configurations: %w", err)
- }
- }
- }
- glog.V(1).Infof("KMS configuration loaded successfully")
- return nil
- }
- // loadGlobalKMSSettings loads global KMS settings
- func (loader *ConfigLoader) loadGlobalKMSSettings(kmsConfig map[string]interface{}) error {
- // Set default KMS provider if specified
- if defaultProvider, exists := kmsConfig["default_provider"]; exists {
- if providerName, ok := defaultProvider.(string); ok {
- // We'll set this after providers are loaded
- glog.V(2).Infof("Default KMS provider will be set to: %s", providerName)
- }
- }
- return nil
- }
- // loadKMSProviders loads individual KMS provider configurations
- func (loader *ConfigLoader) loadKMSProviders(providers map[string]interface{}) error {
- for providerName, providerConfigInterface := range providers {
- providerConfig, ok := providerConfigInterface.(map[string]interface{})
- if !ok {
- glog.Warningf("Invalid configuration for KMS provider %s", providerName)
- continue
- }
- if err := loader.loadSingleKMSProvider(providerName, providerConfig); err != nil {
- glog.Errorf("Failed to load KMS provider %s: %v", providerName, err)
- continue
- }
- glog.V(1).Infof("Loaded KMS provider: %s", providerName)
- }
- return nil
- }
- // loadSingleKMSProvider loads a single KMS provider configuration
- func (loader *ConfigLoader) loadSingleKMSProvider(providerName string, config map[string]interface{}) error {
- // Get provider type
- providerType, exists := config["type"]
- if !exists {
- return fmt.Errorf("provider type not specified for %s", providerName)
- }
- providerTypeStr, ok := providerType.(string)
- if !ok {
- return fmt.Errorf("invalid provider type for %s", providerName)
- }
- // Get provider-specific configuration
- providerConfig := make(map[string]interface{})
- for key, value := range config {
- if key != "type" {
- providerConfig[key] = value
- }
- }
- // Set default cache settings if not specified
- if _, exists := providerConfig["cache_enabled"]; !exists {
- providerConfig["cache_enabled"] = true
- }
- if _, exists := providerConfig["cache_ttl"]; !exists {
- providerConfig["cache_ttl"] = "1h"
- }
- if _, exists := providerConfig["max_cache_size"]; !exists {
- providerConfig["max_cache_size"] = 1000
- }
- // Parse cache TTL
- cacheTTL := time.Hour // default
- if ttlStr, exists := providerConfig["cache_ttl"]; exists {
- if ttlStrValue, ok := ttlStr.(string); ok {
- if parsed, err := time.ParseDuration(ttlStrValue); err == nil {
- cacheTTL = parsed
- }
- }
- }
- // Create KMS configuration
- kmsConfig := &KMSConfig{
- Provider: providerTypeStr,
- Config: providerConfig,
- CacheEnabled: getBoolFromConfig(providerConfig, "cache_enabled", true),
- CacheTTL: cacheTTL,
- MaxCacheSize: getIntFromConfig(providerConfig, "max_cache_size", 1000),
- }
- // Add the provider to the KMS manager
- if err := loader.manager.AddKMSProvider(providerName, kmsConfig); err != nil {
- return err
- }
- // Test the provider with a health check
- ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
- defer cancel()
- health := loader.manager.GetKMSHealth(ctx)
- if providerHealth, exists := health[providerName]; exists && providerHealth != nil {
- glog.Warningf("KMS provider %s health check failed: %v", providerName, providerHealth)
- }
- return nil
- }
- // loadBucketKMSConfigurations loads bucket-specific KMS configurations
- func (loader *ConfigLoader) loadBucketKMSConfigurations(buckets map[string]interface{}) error {
- for bucketName, bucketConfigInterface := range buckets {
- bucketConfig, ok := bucketConfigInterface.(map[string]interface{})
- if !ok {
- glog.Warningf("Invalid KMS configuration for bucket %s", bucketName)
- continue
- }
- // Get provider for this bucket
- if provider, exists := bucketConfig["provider"]; exists {
- if providerName, ok := provider.(string); ok {
- if err := loader.manager.SetBucketKMSProvider(bucketName, providerName); err != nil {
- glog.Errorf("Failed to set KMS provider for bucket %s: %v", bucketName, err)
- continue
- }
- glog.V(2).Infof("Set KMS provider for bucket %s to %s", bucketName, providerName)
- }
- }
- }
- return nil
- }
- // setDefaultProvider sets the default KMS provider after all providers are loaded
- func (loader *ConfigLoader) setDefaultProvider() error {
- kmsConfig := loader.viper.GetStringMap("kms")
- if defaultProvider, exists := kmsConfig["default_provider"]; exists {
- if providerName, ok := defaultProvider.(string); ok {
- if err := loader.manager.SetDefaultKMSProvider(providerName); err != nil {
- return fmt.Errorf("failed to set default KMS provider: %w", err)
- }
- glog.V(1).Infof("Set default KMS provider to: %s", providerName)
- }
- }
- return nil
- }
- // initializeGlobalKMSProvider initializes the global KMS provider for backwards compatibility
- func (loader *ConfigLoader) initializeGlobalKMSProvider() error {
- // Get the default provider from the manager
- defaultProviderName := ""
- kmsConfig := loader.viper.GetStringMap("kms")
- if defaultProvider, exists := kmsConfig["default_provider"]; exists {
- if providerName, ok := defaultProvider.(string); ok {
- defaultProviderName = providerName
- }
- }
- if defaultProviderName == "" {
- // If no default provider, try to use the first available provider
- providers := loader.manager.ListKMSProviders()
- if len(providers) > 0 {
- defaultProviderName = providers[0]
- }
- }
- if defaultProviderName == "" {
- glog.V(2).Infof("No KMS providers configured, skipping global KMS initialization")
- return nil
- }
- // Get the provider from the manager
- provider, err := loader.manager.GetKMSProviderByName(defaultProviderName)
- if err != nil {
- return fmt.Errorf("failed to get KMS provider %s: %w", defaultProviderName, err)
- }
- // Set as global KMS provider
- SetGlobalKMSProvider(provider)
- glog.V(1).Infof("Initialized global KMS provider: %s", defaultProviderName)
- return nil
- }
- // ValidateConfiguration validates the KMS configuration
- func (loader *ConfigLoader) ValidateConfiguration() error {
- providers := loader.manager.ListKMSProviders()
- if len(providers) == 0 {
- glog.V(1).Infof("No KMS providers configured")
- return nil
- }
- // Test connectivity to all providers
- ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
- defer cancel()
- health := loader.manager.GetKMSHealth(ctx)
- hasHealthyProvider := false
- for providerName, err := range health {
- if err != nil {
- glog.Warningf("KMS provider %s is unhealthy: %v", providerName, err)
- } else {
- hasHealthyProvider = true
- glog.V(2).Infof("KMS provider %s is healthy", providerName)
- }
- }
- if !hasHealthyProvider {
- glog.Warningf("No healthy KMS providers found")
- }
- return nil
- }
- // LoadKMSFromFilerToml is a convenience function to load KMS configuration from filer.toml
- func LoadKMSFromFilerToml(v ViperConfig) error {
- loader := NewConfigLoader(v)
- if err := loader.LoadConfigurations(); err != nil {
- return err
- }
- return loader.ValidateConfiguration()
- }
- // LoadKMSFromConfig loads KMS configuration directly from parsed JSON data
- func LoadKMSFromConfig(kmsConfig interface{}) error {
- kmsMap, ok := kmsConfig.(map[string]interface{})
- if !ok {
- return fmt.Errorf("invalid KMS configuration format")
- }
- // Create a direct config adapter that doesn't use Viper
- // Wrap the KMS config under a "kms" key as expected by LoadConfigurations
- wrappedConfig := map[string]interface{}{
- "kms": kmsMap,
- }
- adapter := &directConfigAdapter{config: wrappedConfig}
- loader := NewConfigLoader(adapter)
- if err := loader.LoadConfigurations(); err != nil {
- return err
- }
- return loader.ValidateConfiguration()
- }
- // directConfigAdapter implements ViperConfig interface for direct map access
- type directConfigAdapter struct {
- config map[string]interface{}
- }
- func (d *directConfigAdapter) GetStringMap(key string) map[string]interface{} {
- if val, exists := d.config[key]; exists {
- if mapVal, ok := val.(map[string]interface{}); ok {
- return mapVal
- }
- }
- return make(map[string]interface{})
- }
- func (d *directConfigAdapter) GetString(key string) string {
- if val, exists := d.config[key]; exists {
- if strVal, ok := val.(string); ok {
- return strVal
- }
- }
- return ""
- }
- func (d *directConfigAdapter) GetBool(key string) bool {
- if val, exists := d.config[key]; exists {
- if boolVal, ok := val.(bool); ok {
- return boolVal
- }
- }
- return false
- }
- func (d *directConfigAdapter) GetInt(key string) int {
- if val, exists := d.config[key]; exists {
- switch v := val.(type) {
- case int:
- return v
- case float64:
- return int(v)
- }
- }
- return 0
- }
- func (d *directConfigAdapter) GetStringSlice(key string) []string {
- if val, exists := d.config[key]; exists {
- if sliceVal, ok := val.([]interface{}); ok {
- result := make([]string, len(sliceVal))
- for i, item := range sliceVal {
- if strItem, ok := item.(string); ok {
- result[i] = strItem
- }
- }
- return result
- }
- if strSlice, ok := val.([]string); ok {
- return strSlice
- }
- }
- return []string{}
- }
- func (d *directConfigAdapter) SetDefault(key string, value interface{}) {
- // For direct config adapter, we don't need to set defaults
- // as the configuration is already parsed
- }
- func (d *directConfigAdapter) IsSet(key string) bool {
- _, exists := d.config[key]
- return exists
- }
- // Helper functions
- func getBoolFromConfig(config map[string]interface{}, key string, defaultValue bool) bool {
- if value, exists := config[key]; exists {
- if boolValue, ok := value.(bool); ok {
- return boolValue
- }
- }
- return defaultValue
- }
- func getIntFromConfig(config map[string]interface{}, key string, defaultValue int) int {
- if value, exists := config[key]; exists {
- if intValue, ok := value.(int); ok {
- return intValue
- }
- if floatValue, ok := value.(float64); ok {
- return int(floatValue)
- }
- }
- return defaultValue
- }
- func getStringFromConfig(config map[string]interface{}, key string, defaultValue string) string {
- if value, exists := config[key]; exists {
- if stringValue, ok := value.(string); ok {
- return stringValue
- }
- }
- return defaultValue
- }
|