config_loader.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. package kms
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "github.com/seaweedfs/seaweedfs/weed/glog"
  7. )
  8. // ViperConfig interface extends Configuration with additional methods needed for KMS configuration
  9. type ViperConfig interface {
  10. GetString(key string) string
  11. GetBool(key string) bool
  12. GetInt(key string) int
  13. GetStringSlice(key string) []string
  14. SetDefault(key string, value interface{})
  15. GetStringMap(key string) map[string]interface{}
  16. IsSet(key string) bool
  17. }
  18. // ConfigLoader handles loading KMS configurations from filer.toml
  19. type ConfigLoader struct {
  20. viper ViperConfig
  21. manager *KMSManager
  22. }
  23. // NewConfigLoader creates a new KMS configuration loader
  24. func NewConfigLoader(v ViperConfig) *ConfigLoader {
  25. return &ConfigLoader{
  26. viper: v,
  27. manager: GetKMSManager(),
  28. }
  29. }
  30. // LoadConfigurations loads all KMS provider configurations from filer.toml
  31. func (loader *ConfigLoader) LoadConfigurations() error {
  32. // Check if KMS section exists
  33. if !loader.viper.IsSet("kms") {
  34. glog.V(1).Infof("No KMS configuration found in filer.toml")
  35. return nil
  36. }
  37. // Get the KMS configuration section
  38. kmsConfig := loader.viper.GetStringMap("kms")
  39. // Load global KMS settings
  40. if err := loader.loadGlobalKMSSettings(kmsConfig); err != nil {
  41. return fmt.Errorf("failed to load global KMS settings: %w", err)
  42. }
  43. // Load KMS providers
  44. if providersConfig, exists := kmsConfig["providers"]; exists {
  45. if providers, ok := providersConfig.(map[string]interface{}); ok {
  46. if err := loader.loadKMSProviders(providers); err != nil {
  47. return fmt.Errorf("failed to load KMS providers: %w", err)
  48. }
  49. }
  50. }
  51. // Set default provider after all providers are loaded
  52. if err := loader.setDefaultProvider(); err != nil {
  53. return fmt.Errorf("failed to set default KMS provider: %w", err)
  54. }
  55. // Initialize global KMS provider for backwards compatibility
  56. if err := loader.initializeGlobalKMSProvider(); err != nil {
  57. glog.Warningf("Failed to initialize global KMS provider: %v", err)
  58. }
  59. // Load bucket-specific KMS configurations
  60. if bucketsConfig, exists := kmsConfig["buckets"]; exists {
  61. if buckets, ok := bucketsConfig.(map[string]interface{}); ok {
  62. if err := loader.loadBucketKMSConfigurations(buckets); err != nil {
  63. return fmt.Errorf("failed to load bucket KMS configurations: %w", err)
  64. }
  65. }
  66. }
  67. glog.V(1).Infof("KMS configuration loaded successfully")
  68. return nil
  69. }
  70. // loadGlobalKMSSettings loads global KMS settings
  71. func (loader *ConfigLoader) loadGlobalKMSSettings(kmsConfig map[string]interface{}) error {
  72. // Set default KMS provider if specified
  73. if defaultProvider, exists := kmsConfig["default_provider"]; exists {
  74. if providerName, ok := defaultProvider.(string); ok {
  75. // We'll set this after providers are loaded
  76. glog.V(2).Infof("Default KMS provider will be set to: %s", providerName)
  77. }
  78. }
  79. return nil
  80. }
  81. // loadKMSProviders loads individual KMS provider configurations
  82. func (loader *ConfigLoader) loadKMSProviders(providers map[string]interface{}) error {
  83. for providerName, providerConfigInterface := range providers {
  84. providerConfig, ok := providerConfigInterface.(map[string]interface{})
  85. if !ok {
  86. glog.Warningf("Invalid configuration for KMS provider %s", providerName)
  87. continue
  88. }
  89. if err := loader.loadSingleKMSProvider(providerName, providerConfig); err != nil {
  90. glog.Errorf("Failed to load KMS provider %s: %v", providerName, err)
  91. continue
  92. }
  93. glog.V(1).Infof("Loaded KMS provider: %s", providerName)
  94. }
  95. return nil
  96. }
  97. // loadSingleKMSProvider loads a single KMS provider configuration
  98. func (loader *ConfigLoader) loadSingleKMSProvider(providerName string, config map[string]interface{}) error {
  99. // Get provider type
  100. providerType, exists := config["type"]
  101. if !exists {
  102. return fmt.Errorf("provider type not specified for %s", providerName)
  103. }
  104. providerTypeStr, ok := providerType.(string)
  105. if !ok {
  106. return fmt.Errorf("invalid provider type for %s", providerName)
  107. }
  108. // Get provider-specific configuration
  109. providerConfig := make(map[string]interface{})
  110. for key, value := range config {
  111. if key != "type" {
  112. providerConfig[key] = value
  113. }
  114. }
  115. // Set default cache settings if not specified
  116. if _, exists := providerConfig["cache_enabled"]; !exists {
  117. providerConfig["cache_enabled"] = true
  118. }
  119. if _, exists := providerConfig["cache_ttl"]; !exists {
  120. providerConfig["cache_ttl"] = "1h"
  121. }
  122. if _, exists := providerConfig["max_cache_size"]; !exists {
  123. providerConfig["max_cache_size"] = 1000
  124. }
  125. // Parse cache TTL
  126. cacheTTL := time.Hour // default
  127. if ttlStr, exists := providerConfig["cache_ttl"]; exists {
  128. if ttlStrValue, ok := ttlStr.(string); ok {
  129. if parsed, err := time.ParseDuration(ttlStrValue); err == nil {
  130. cacheTTL = parsed
  131. }
  132. }
  133. }
  134. // Create KMS configuration
  135. kmsConfig := &KMSConfig{
  136. Provider: providerTypeStr,
  137. Config: providerConfig,
  138. CacheEnabled: getBoolFromConfig(providerConfig, "cache_enabled", true),
  139. CacheTTL: cacheTTL,
  140. MaxCacheSize: getIntFromConfig(providerConfig, "max_cache_size", 1000),
  141. }
  142. // Add the provider to the KMS manager
  143. if err := loader.manager.AddKMSProvider(providerName, kmsConfig); err != nil {
  144. return err
  145. }
  146. // Test the provider with a health check
  147. ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  148. defer cancel()
  149. health := loader.manager.GetKMSHealth(ctx)
  150. if providerHealth, exists := health[providerName]; exists && providerHealth != nil {
  151. glog.Warningf("KMS provider %s health check failed: %v", providerName, providerHealth)
  152. }
  153. return nil
  154. }
  155. // loadBucketKMSConfigurations loads bucket-specific KMS configurations
  156. func (loader *ConfigLoader) loadBucketKMSConfigurations(buckets map[string]interface{}) error {
  157. for bucketName, bucketConfigInterface := range buckets {
  158. bucketConfig, ok := bucketConfigInterface.(map[string]interface{})
  159. if !ok {
  160. glog.Warningf("Invalid KMS configuration for bucket %s", bucketName)
  161. continue
  162. }
  163. // Get provider for this bucket
  164. if provider, exists := bucketConfig["provider"]; exists {
  165. if providerName, ok := provider.(string); ok {
  166. if err := loader.manager.SetBucketKMSProvider(bucketName, providerName); err != nil {
  167. glog.Errorf("Failed to set KMS provider for bucket %s: %v", bucketName, err)
  168. continue
  169. }
  170. glog.V(2).Infof("Set KMS provider for bucket %s to %s", bucketName, providerName)
  171. }
  172. }
  173. }
  174. return nil
  175. }
  176. // setDefaultProvider sets the default KMS provider after all providers are loaded
  177. func (loader *ConfigLoader) setDefaultProvider() error {
  178. kmsConfig := loader.viper.GetStringMap("kms")
  179. if defaultProvider, exists := kmsConfig["default_provider"]; exists {
  180. if providerName, ok := defaultProvider.(string); ok {
  181. if err := loader.manager.SetDefaultKMSProvider(providerName); err != nil {
  182. return fmt.Errorf("failed to set default KMS provider: %w", err)
  183. }
  184. glog.V(1).Infof("Set default KMS provider to: %s", providerName)
  185. }
  186. }
  187. return nil
  188. }
  189. // initializeGlobalKMSProvider initializes the global KMS provider for backwards compatibility
  190. func (loader *ConfigLoader) initializeGlobalKMSProvider() error {
  191. // Get the default provider from the manager
  192. defaultProviderName := ""
  193. kmsConfig := loader.viper.GetStringMap("kms")
  194. if defaultProvider, exists := kmsConfig["default_provider"]; exists {
  195. if providerName, ok := defaultProvider.(string); ok {
  196. defaultProviderName = providerName
  197. }
  198. }
  199. if defaultProviderName == "" {
  200. // If no default provider, try to use the first available provider
  201. providers := loader.manager.ListKMSProviders()
  202. if len(providers) > 0 {
  203. defaultProviderName = providers[0]
  204. }
  205. }
  206. if defaultProviderName == "" {
  207. glog.V(2).Infof("No KMS providers configured, skipping global KMS initialization")
  208. return nil
  209. }
  210. // Get the provider from the manager
  211. provider, err := loader.manager.GetKMSProviderByName(defaultProviderName)
  212. if err != nil {
  213. return fmt.Errorf("failed to get KMS provider %s: %w", defaultProviderName, err)
  214. }
  215. // Set as global KMS provider
  216. SetGlobalKMSProvider(provider)
  217. glog.V(1).Infof("Initialized global KMS provider: %s", defaultProviderName)
  218. return nil
  219. }
  220. // ValidateConfiguration validates the KMS configuration
  221. func (loader *ConfigLoader) ValidateConfiguration() error {
  222. providers := loader.manager.ListKMSProviders()
  223. if len(providers) == 0 {
  224. glog.V(1).Infof("No KMS providers configured")
  225. return nil
  226. }
  227. // Test connectivity to all providers
  228. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  229. defer cancel()
  230. health := loader.manager.GetKMSHealth(ctx)
  231. hasHealthyProvider := false
  232. for providerName, err := range health {
  233. if err != nil {
  234. glog.Warningf("KMS provider %s is unhealthy: %v", providerName, err)
  235. } else {
  236. hasHealthyProvider = true
  237. glog.V(2).Infof("KMS provider %s is healthy", providerName)
  238. }
  239. }
  240. if !hasHealthyProvider {
  241. glog.Warningf("No healthy KMS providers found")
  242. }
  243. return nil
  244. }
  245. // LoadKMSFromFilerToml is a convenience function to load KMS configuration from filer.toml
  246. func LoadKMSFromFilerToml(v ViperConfig) error {
  247. loader := NewConfigLoader(v)
  248. if err := loader.LoadConfigurations(); err != nil {
  249. return err
  250. }
  251. return loader.ValidateConfiguration()
  252. }
  253. // LoadKMSFromConfig loads KMS configuration directly from parsed JSON data
  254. func LoadKMSFromConfig(kmsConfig interface{}) error {
  255. kmsMap, ok := kmsConfig.(map[string]interface{})
  256. if !ok {
  257. return fmt.Errorf("invalid KMS configuration format")
  258. }
  259. // Create a direct config adapter that doesn't use Viper
  260. // Wrap the KMS config under a "kms" key as expected by LoadConfigurations
  261. wrappedConfig := map[string]interface{}{
  262. "kms": kmsMap,
  263. }
  264. adapter := &directConfigAdapter{config: wrappedConfig}
  265. loader := NewConfigLoader(adapter)
  266. if err := loader.LoadConfigurations(); err != nil {
  267. return err
  268. }
  269. return loader.ValidateConfiguration()
  270. }
  271. // directConfigAdapter implements ViperConfig interface for direct map access
  272. type directConfigAdapter struct {
  273. config map[string]interface{}
  274. }
  275. func (d *directConfigAdapter) GetStringMap(key string) map[string]interface{} {
  276. if val, exists := d.config[key]; exists {
  277. if mapVal, ok := val.(map[string]interface{}); ok {
  278. return mapVal
  279. }
  280. }
  281. return make(map[string]interface{})
  282. }
  283. func (d *directConfigAdapter) GetString(key string) string {
  284. if val, exists := d.config[key]; exists {
  285. if strVal, ok := val.(string); ok {
  286. return strVal
  287. }
  288. }
  289. return ""
  290. }
  291. func (d *directConfigAdapter) GetBool(key string) bool {
  292. if val, exists := d.config[key]; exists {
  293. if boolVal, ok := val.(bool); ok {
  294. return boolVal
  295. }
  296. }
  297. return false
  298. }
  299. func (d *directConfigAdapter) GetInt(key string) int {
  300. if val, exists := d.config[key]; exists {
  301. switch v := val.(type) {
  302. case int:
  303. return v
  304. case float64:
  305. return int(v)
  306. }
  307. }
  308. return 0
  309. }
  310. func (d *directConfigAdapter) GetStringSlice(key string) []string {
  311. if val, exists := d.config[key]; exists {
  312. if sliceVal, ok := val.([]interface{}); ok {
  313. result := make([]string, len(sliceVal))
  314. for i, item := range sliceVal {
  315. if strItem, ok := item.(string); ok {
  316. result[i] = strItem
  317. }
  318. }
  319. return result
  320. }
  321. if strSlice, ok := val.([]string); ok {
  322. return strSlice
  323. }
  324. }
  325. return []string{}
  326. }
  327. func (d *directConfigAdapter) SetDefault(key string, value interface{}) {
  328. // For direct config adapter, we don't need to set defaults
  329. // as the configuration is already parsed
  330. }
  331. func (d *directConfigAdapter) IsSet(key string) bool {
  332. _, exists := d.config[key]
  333. return exists
  334. }
  335. // Helper functions
  336. func getBoolFromConfig(config map[string]interface{}, key string, defaultValue bool) bool {
  337. if value, exists := config[key]; exists {
  338. if boolValue, ok := value.(bool); ok {
  339. return boolValue
  340. }
  341. }
  342. return defaultValue
  343. }
  344. func getIntFromConfig(config map[string]interface{}, key string, defaultValue int) int {
  345. if value, exists := config[key]; exists {
  346. if intValue, ok := value.(int); ok {
  347. return intValue
  348. }
  349. if floatValue, ok := value.(float64); ok {
  350. return int(floatValue)
  351. }
  352. }
  353. return defaultValue
  354. }
  355. func getStringFromConfig(config map[string]interface{}, key string, defaultValue string) string {
  356. if value, exists := config[key]; exists {
  357. if stringValue, ok := value.(string); ok {
  358. return stringValue
  359. }
  360. }
  361. return defaultValue
  362. }