diff --git a/secret.go b/secret.go index fac5ca8..00a039c 100644 --- a/secret.go +++ b/secret.go @@ -2,6 +2,7 @@ package skipper import ( "fmt" + "os" "path/filepath" "regexp" "strings" @@ -36,10 +37,11 @@ func NewSecret(secretFile *SecretFile, driver string, alternative *Call, path [] type SecretFileData struct { Data string `yaml:"data"` Type string `yaml:"type"` + Key string `yaml:"key"` } // NewSecretData constructs a [Data] map as it is required for secrets. -func NewSecretData(data string, driver string) (*SecretFileData, error) { +func NewSecretData(data string, driver string, key string) (*SecretFileData, error) { if data == "" { return nil, fmt.Errorf("secret data cannot be empty") } @@ -50,6 +52,7 @@ func NewSecretData(data string, driver string) (*SecretFileData, error) { return &SecretFileData{ Data: data, Type: driver, + Key: key, }, nil } @@ -141,7 +144,7 @@ func (secret *Secret) attemptCreate(fs afero.Fs, secretPath string) error { } // create new Data map which can then be written into the secret file - secretFileData, err := NewSecretData(encryptedData, secret.Driver.Type()) + secretFileData, err := NewSecretData(encryptedData, secret.Driver.Type(), secret.Driver.GetKey()) if err != nil { return fmt.Errorf("could not create NewSecretData: %w", err) } @@ -229,7 +232,10 @@ func secretYamlFileLoader(secretFileList *[]*SecretFile) YamlFileLoaderFunc { // Value returns the actual secret value. func (s *Secret) Value() (string, error) { - return s.Driver.Decrypt(s.Data.Data) + if s.Driver.GetKey() != s.Data.Key { + fmt.Fprintf(os.Stderr, "key in secret file '%s' differs from the key in the inventory\n", s.Path()) + } + return s.Driver.Decrypt(s.Data.Data, s.Data.Key) } // FullName returns the full secret name as it would be expected to ocurr in a class/target. diff --git a/secret/driver.go b/secret/driver.go index 55c2287..0d5e2c8 100644 --- a/secret/driver.go +++ b/secret/driver.go @@ -9,8 +9,10 @@ import ( type Driver interface { Type() string + GetKey() string Encrypt(data string) (string, error) - Decrypt(encrypted string) (string, error) + // if key is set, use that one for decryption, otherwise use the key set in the driver (if available) + Decrypt(encrypted string, key string) (string, error) } type ConfigurableDriver interface { diff --git a/secret/driver/aes.go b/secret/driver/aes.go index 92b0346..1fd2401 100644 --- a/secret/driver/aes.go +++ b/secret/driver/aes.go @@ -36,7 +36,9 @@ func (driver *Aes) Configure(config map[string]interface{}) error { return nil } -func (driver *Aes) Decrypt(encrypted string) (string, error) { +func (driver *Aes) Decrypt(encrypted string, key string) (string, error) { + // key is dismissed, as we always use the key in the driver config here + decrypted, err := driver.decrypt([]byte(driver.config.Key), encrypted) if err != nil { return "", err @@ -107,3 +109,7 @@ func (driver *Aes) decrypt(key []byte, secure string) (decoded string, err error func (driver *Aes) Type() string { return "aes" } + +func (driver *Aes) GetKey() string { + return "aesIsSymmetricThereIsNoKey" +} diff --git a/secret/driver/azure.go b/secret/driver/azure.go index eab05d9..4cb1260 100644 --- a/secret/driver/azure.go +++ b/secret/driver/azure.go @@ -28,6 +28,7 @@ type azureConfig struct { // IgnoreVersion will ignore any key version, even if given, and always use the latest version. IgnoreVersion bool `mapstructure:"ignore_version"` // The Azure Vault KeyId to use for encryption and decryption + // KeyId is the full key string, example: https://secretkeyvault.vault.azure.net/keys/secrets-key/1111231232312111 KeyId string `mapstructure:"key_id"` VaultName string @@ -90,7 +91,20 @@ func (driver *Azure) Encrypt(input string) (string, error) { return base64.RawStdEncoding.EncodeToString(res.Result), nil } -func (driver *Azure) Decrypt(input string) (string, error) { +// Decrypt decrypts an input either using the key configured in the driver or if the key parameter isn't empty it will use that one. +func (driver *Azure) Decrypt(input string, key string) (string, error) { + var err error + keyName := driver.config.KeyName + keyVersion := driver.config.KeyVersion + + // if we hand over a key to this func, make sure to use this key for the decryption, otherwise use the key configured in the driver + if len(key) > 0 { + _, keyName, keyVersion, err = parseAzureKeyVaultKeyId(key) + if err != nil { + return "", fmt.Errorf("the key we handed over to Decrypt() could not be parsed") + } + } + decoded, err := base64.RawStdEncoding.DecodeString(input) if err != nil { return "", err @@ -101,11 +115,10 @@ func (driver *Azure) Decrypt(input string) (string, error) { Value: []byte(decoded), } - version := driver.config.KeyVersion if driver.config.IgnoreVersion { - version = "" + keyVersion = "" } - res, err := driver.client.Decrypt(context.TODO(), driver.config.KeyName, version, encryptParams, nil) + res, err := driver.client.Decrypt(context.TODO(), keyName, keyVersion, encryptParams, nil) if err != nil { return "", err } @@ -157,3 +170,7 @@ func parseAzureKeyVaultKeyId(key string) (vaultName string, keyName string, keyV func (driver *Azure) Type() string { return "azurekv" } + +func (driver Azure) GetKey() string { + return driver.config.KeyId +} diff --git a/secret/driver/base64.go b/secret/driver/base64.go index 25acf52..0a634aa 100644 --- a/secret/driver/base64.go +++ b/secret/driver/base64.go @@ -17,7 +17,9 @@ func NewBase64() (*Base64, error) { return &driver, nil } -func (p *Base64) Decrypt(encrypted string) (string, error) { +func (p *Base64) Decrypt(encrypted string, key string) (string, error) { + // key is dismissed, as base64 isn't decrypting stuff + out, err := base64.StdEncoding.DecodeString(encrypted) if err != nil { return "", err @@ -32,3 +34,7 @@ func (p *Base64) Encrypt(input string) (string, error) { func (p *Base64) Type() string { return "base64" } + +func (p *Base64) GetKey() string { + return "base64DoesNotHaveAKey" +} diff --git a/secret/driver/plain.go b/secret/driver/plain.go index d18119a..ff013dd 100644 --- a/secret/driver/plain.go +++ b/secret/driver/plain.go @@ -14,7 +14,8 @@ func NewPlain() (*Plain, error) { } // the plain driver does not do anything -func (p *Plain) Decrypt(encrypted string) (string, error) { +func (p *Plain) Decrypt(encrypted string, key string) (string, error) { + // key is dismissed, as plain does not do anything return encrypted, nil } @@ -23,6 +24,10 @@ func (p *Plain) Encrypt(input string) (string, error) { return input, nil } -func (p *Plain) Type() string { +func (p Plain) Type() string { return "plain" } + +func (p Plain) GetKey() string { + return "plainDoesntHaveAKey" +}