go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers-sdk/v1/vault/config/vaultconfigstore.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package config 5 6 import ( 7 "context" 8 "encoding/json" 9 "runtime" 10 11 "github.com/aws/aws-sdk-go-v2/config" 12 "github.com/cockroachdb/errors" 13 "github.com/rs/zerolog/log" 14 "go.mondoo.com/cnquery/providers-sdk/v1/vault" 15 "go.mondoo.com/cnquery/providers-sdk/v1/vault/awsparameterstore" 16 "go.mondoo.com/cnquery/providers-sdk/v1/vault/awssecretsmanager" 17 "go.mondoo.com/cnquery/providers-sdk/v1/vault/gcpberglas" 18 "go.mondoo.com/cnquery/providers-sdk/v1/vault/gcpsecretmanager" 19 "go.mondoo.com/cnquery/providers-sdk/v1/vault/hashivault" 20 "go.mondoo.com/cnquery/providers-sdk/v1/vault/inmemory" 21 "go.mondoo.com/cnquery/providers-sdk/v1/vault/keyring" 22 ) 23 24 const ( 25 VaultConfigStoreName = "mondoo-cli-keyring" 26 VaultConfigStoreKey = "user-vaults" 27 ) 28 29 func New(vCfg *vault.VaultConfiguration) (vault.Vault, error) { 30 if vCfg == nil { 31 return nil, errors.New("vault configuration cannot be empty") 32 } 33 log.Debug().Str("vault-name", vCfg.Name).Str("vault-type", vCfg.Type.String()).Msg("initialize new vault") 34 var v vault.Vault 35 switch vCfg.Type { 36 case vault.VaultType_Memory: 37 v = inmemory.New() 38 case vault.VaultType_HashiCorp: 39 serverUrl := vCfg.Options["url"] 40 token := vCfg.Options["token"] 41 v = hashivault.New(serverUrl, token) 42 case vault.VaultType_EncryptedFile: 43 path := vCfg.Options["path"] 44 keyRingName := vCfg.Options["name"] 45 password := vCfg.Options["password"] 46 v = keyring.NewEncryptedFile(path, keyRingName, password) 47 case vault.VaultType_KeyRing: 48 keyRingName := vCfg.Options["name"] 49 v = keyring.New(keyRingName) 50 case vault.VaultType_LinuxKernelKeyring: 51 keyRingName := vCfg.Options["name"] 52 v = keyring.NewLinuxKernelKeyring(keyRingName) 53 case vault.VaultType_GCPSecretsManager: 54 projectID := vCfg.Options["project-id"] 55 v = gcpsecretmanager.New(projectID) 56 case vault.VaultType_AWSSecretsManager: 57 // TODO: do we really want to load it from the env? 58 cfg, err := config.LoadDefaultConfig(context.Background()) 59 if err != nil { 60 return nil, errors.Wrap(err, "cannot not determine aws environment") 61 } 62 v = awssecretsmanager.New(cfg) 63 case vault.VaultType_AWSParameterStore: 64 cfg, err := config.LoadDefaultConfig(context.Background()) 65 if err != nil { 66 return nil, errors.Wrap(err, "cannot not determine aws environment") 67 } 68 v = awsparameterstore.New(cfg) 69 case vault.VaultType_GCPBerglas: 70 projectID := vCfg.Options["project-id"] 71 kmsKeyID := vCfg.Options["kms-key-id"] 72 bucketName := vCfg.Options["bucket-name"] 73 opts := []gcpberglas.Option{} 74 if kmsKeyID != "" { 75 opts = append(opts, gcpberglas.WithKmsKey(kmsKeyID)) 76 } 77 if bucketName != "" { 78 opts = append(opts, gcpberglas.WithBucket(bucketName)) 79 } 80 v = gcpberglas.New(projectID, opts...) 81 82 default: 83 return nil, errors.Errorf("could not connect to vault: %s (%s)", vCfg.Name, vCfg.Type.String()) 84 } 85 return v, nil 86 } 87 88 // GetInternalVault returns the local store that is used in cnquery to store 89 // Vault configurations eg. Hashicorp Vault access data 90 func GetInternalVault() vault.Vault { 91 // on linux we are going to use kernel key management 92 if runtime.GOOS == "linux" { 93 log.Debug().Msg("use linux kernel key management to manage vaults") 94 return keyring.NewLinuxKernelKeyring(VaultConfigStoreName) 95 } 96 97 return keyring.New(VaultConfigStoreName) 98 } 99 100 // GetConfiguredVault returns a vault instance based on the configured user vaults. 101 // It looks up in the internal vault and searches for a configuration for the vaultName 102 func GetConfiguredVault(vaultName string) (vault.Vault, error) { 103 v := GetInternalVault() 104 105 ctx := context.Background() 106 secret, err := v.Get(ctx, &vault.SecretID{ 107 Key: VaultConfigStoreKey, 108 }) 109 if err != nil { 110 return nil, err 111 } 112 113 cfgs, err := NewClientVaultConfig(secret) 114 if err != nil { 115 return nil, err 116 } 117 118 // search for the specified vault 119 vCfg, err := cfgs.Get(vaultName) 120 if err != nil { 121 return nil, err 122 } 123 124 log.Debug().Str("vault-name", vCfg.Name).Str("vault-type", vCfg.Type.String()).Msg("found vault config") 125 return New(&vCfg) 126 } 127 128 // ClientVaultConfig is the structured type where we store the client configuration for 129 // all user configured vaults. We use it to ensure the configuration is stored in structured 130 // format 131 type ClientVaultConfig map[string]vault.VaultConfiguration 132 133 func NewClientVaultConfig(secret *vault.Secret) (ClientVaultConfig, error) { 134 var vCfg ClientVaultConfig 135 err := json.Unmarshal(secret.Data, &vCfg) 136 if err != nil { 137 return nil, errors.Wrap(err, "corrupt vault configuration") 138 } 139 return vCfg, nil 140 } 141 142 func (avc ClientVaultConfig) Delete(key string) { 143 delete(avc, key) 144 } 145 146 func (avc ClientVaultConfig) Set(key string, cfg vault.VaultConfiguration) { 147 avc[key] = cfg 148 } 149 150 func (avc ClientVaultConfig) Get(key string) (vault.VaultConfiguration, error) { 151 vCfg, ok := avc[key] 152 if !ok { 153 return vault.VaultConfiguration{}, errors.New("vault not found") 154 } 155 return vCfg, nil 156 } 157 158 // SecretData returns the marshaled data, it is compatible with New() 159 // In case the data structure cannot be marshalled, the function will panic 160 func (avc ClientVaultConfig) SecretData() []byte { 161 data, err := json.Marshal(avc) 162 if err != nil { 163 panic(err) 164 } 165 return data 166 }