From cef62ea73871996cfe896cae939bf338d31dbdec Mon Sep 17 00:00:00 2001 From: Christian Mesh Date: Fri, 8 Mar 2024 07:55:08 -0500 Subject: [PATCH] Update to encryption key provider interface (#1351) Signed-off-by: Christian Mesh --- internal/encryption/base.go | 10 ++-- internal/encryption/keyprovider.go | 58 +++++++++---------- .../encryption/keyprovider/keyprovider.go | 7 ++- internal/encryption/keyprovider/output.go | 1 - .../encryption/keyprovider/static/config.go | 6 +- .../encryption/keyprovider/static/provider.go | 4 +- .../keyprovider/static/provider_test.go | 4 +- internal/encryption/targets.go | 4 +- internal/varhcl/vardecode.go | 4 +- 9 files changed, 49 insertions(+), 49 deletions(-) diff --git a/internal/encryption/base.go b/internal/encryption/base.go index bb859ddb2ca..45c453a2549 100644 --- a/internal/encryption/base.go +++ b/internal/encryption/base.go @@ -36,14 +36,14 @@ func newBaseEncryption(enc *encryption, target *config.TargetConfig, enforced bo } // This performs a e2e validation run of the config -> methods flow. It serves as a validation step and allows us to // return detailed diagnostics here and simple errors below - _, diags := base.buildTargetMethods(make(map[keyprovider.Addr]any)) + _, diags := base.buildTargetMethods(make(map[keyprovider.Addr][]byte)) return base, diags } type basedata struct { - Meta map[keyprovider.Addr]any `json:"meta"` - Data []byte `json:"encrypted_data"` - Version string `json:"encryption_version"` // This is both a sigil for a valid encrypted payload and a future compatability field + Meta map[keyprovider.Addr][]byte `json:"meta"` + Data []byte `json:"encrypted_data"` + Version string `json:"encryption_version"` // This is both a sigil for a valid encrypted payload and a future compatability field } func IsEncryptionPayload(data []byte) (bool, error) { @@ -64,7 +64,7 @@ func (s *baseEncryption) encrypt(data []byte) ([]byte, error) { } es := basedata{ - Meta: make(map[keyprovider.Addr]any), + Meta: make(map[keyprovider.Addr][]byte), Version: encryptionVersion, } diff --git a/internal/encryption/keyprovider.go b/internal/encryption/keyprovider.go index d94d4dbb200..34fe36a5741 100644 --- a/internal/encryption/keyprovider.go +++ b/internal/encryption/keyprovider.go @@ -6,11 +6,10 @@ package encryption import ( + "encoding/json" "errors" "fmt" - "github.com/go-viper/mapstructure/v2" - "github.com/opentofu/opentofu/internal/encryption/config" "github.com/hashicorp/hcl/v2" @@ -164,55 +163,52 @@ func (e *targetBuilder) setupKeyProvider(cfg config.KeyProviderConfig, stack []c if diags.HasErrors() { return diags } + + // Build the Key Provider from the configuration + keyProvider, keyMetaIn, err := keyProviderConfig.Build() + if err != nil { + return append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Unable to build encryption key data", + Detail: fmt.Sprintf("%s failed with error: %s", metakey, err.Error()), + }) + } + // Add the metadata if meta, ok := e.keyProviderMetadata[metakey]; ok { - decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ - // We want all metadata fields to be consumed: - ErrorUnused: true, - // Fill the results in this struct: - Result: &keyProviderConfig, - // Use the "meta" tag: - TagName: "meta", - // Ignore fields not tagged with "meta": - IgnoreUntaggedFields: true, - }) + err := json.Unmarshal(meta, keyMetaIn) if err != nil { return append(diags, &hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Unable to decode encrypted metadata (did you change your encryption config?)", - Detail: fmt.Sprintf("initializing metadata decoder for %s failed with error: %s", metakey, err.Error()), - }) - } - if err := decoder.Decode(meta); err != nil { - return append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unable to decode encrypted metadata (did you change your encryption config?)", - Detail: fmt.Sprintf("decoding %s failed with error: %s", metakey, err.Error()), + Detail: fmt.Sprintf("metadata decoder for %s failed with error: %s", metakey, err.Error()), }) } } - // Build the Key Provider from the configuration - keyProvider, err := keyProviderConfig.Build() + output, keyMetaOut, err := keyProvider.Provide(keyMetaIn) if err != nil { return append(diags, &hcl.Diagnostic{ Severity: hcl.DiagError, - Summary: "Unable to build encryption key data", + Summary: "Unable to fetch encryption key data", Detail: fmt.Sprintf("%s failed with error: %s", metakey, err.Error()), }) } - output, err := keyProvider.Provide() - if err != nil { - return append(diags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Unable to fetch encryption key data", - Detail: fmt.Sprintf("%s failed with error: %s", metakey, err.Error()), - }) + if keyMetaOut != nil { + e.keyProviderMetadata[metakey], err = json.Marshal(keyMetaOut) + + if err != nil { + return append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Unable to encode encrypted metadata", + Detail: fmt.Sprintf("metadata encoder for %s failed with error: %s", metakey, err.Error()), + }) + } } - e.keyProviderMetadata[metakey] = output.Metadata e.keyValues[cfg.Type][cfg.Name] = output.Cty() return nil + } diff --git a/internal/encryption/keyprovider/keyprovider.go b/internal/encryption/keyprovider/keyprovider.go index 207cf84006b..8a319468149 100644 --- a/internal/encryption/keyprovider/keyprovider.go +++ b/internal/encryption/keyprovider/keyprovider.go @@ -5,8 +5,11 @@ package keyprovider +// Reference to struct with json tags +type KeyMeta any + type Config interface { - Build() (KeyProvider, error) + Build() (KeyProvider, KeyMeta, error) } type Descriptor interface { @@ -24,5 +27,5 @@ type Descriptor interface { type KeyProvider interface { // Provide provides an encryption and decryption keys. If the process fails, it returns an error. - Provide() (Output, error) + Provide(KeyMeta) (Output, KeyMeta, error) } diff --git a/internal/encryption/keyprovider/output.go b/internal/encryption/keyprovider/output.go index 3b4c0a7d549..9765214e9ff 100644 --- a/internal/encryption/keyprovider/output.go +++ b/internal/encryption/keyprovider/output.go @@ -11,7 +11,6 @@ import "github.com/zclconf/go-cty/cty" type Output struct { EncryptionKey []byte `hcl:"encryption_key" cty:"encryption_key" json:"encryption_key" yaml:"encryption_key"` DecryptionKey []byte `hcl:"decryption_key" cty:"decryption_key" json:"decryption_key" yaml:"decryption_key"` - Metadata any } func (o *Output) Cty() cty.Value { diff --git a/internal/encryption/keyprovider/static/config.go b/internal/encryption/keyprovider/static/config.go index 5fb35c0e64e..12b8063d201 100644 --- a/internal/encryption/keyprovider/static/config.go +++ b/internal/encryption/keyprovider/static/config.go @@ -16,10 +16,10 @@ type Config struct { Key string `hcl:"key"` } -func (c Config) Build() (keyprovider.KeyProvider, error) { +func (c Config) Build() (keyprovider.KeyProvider, keyprovider.KeyMeta, error) { decodedData, err := hex.DecodeString(c.Key) if err != nil { - return nil, fmt.Errorf("failed to hex-decode the provided key (%w)", err) + return nil, nil, fmt.Errorf("failed to hex-decode the provided key (%w)", err) } - return &staticKeyProvider{decodedData}, nil + return &staticKeyProvider{decodedData}, nil, nil } diff --git a/internal/encryption/keyprovider/static/provider.go b/internal/encryption/keyprovider/static/provider.go index 1f4ad353a93..ec97dd9d3d4 100644 --- a/internal/encryption/keyprovider/static/provider.go +++ b/internal/encryption/keyprovider/static/provider.go @@ -12,9 +12,9 @@ type staticKeyProvider struct { key []byte } -func (p staticKeyProvider) Provide() (keyprovider.Output, error) { +func (p staticKeyProvider) Provide(meta keyprovider.KeyMeta) (keyprovider.Output, keyprovider.KeyMeta, error) { return keyprovider.Output{ EncryptionKey: p.key, DecryptionKey: p.key, - }, nil + }, nil, nil } diff --git a/internal/encryption/keyprovider/static/provider_test.go b/internal/encryption/keyprovider/static/provider_test.go index 23027a4c8a9..1129282a299 100644 --- a/internal/encryption/keyprovider/static/provider_test.go +++ b/internal/encryption/keyprovider/static/provider_test.go @@ -52,13 +52,13 @@ func TestKeyProvider(t *testing.T) { c.Key = tc.key } - keyProvider, buildErr := c.Build() + keyProvider, keyMeta, buildErr := c.Build() if tc.expectSuccess { if buildErr != nil { t.Fatalf("unexpected error: %v", buildErr) } - output, err := keyProvider.Provide() + output, _, err := keyProvider.Provide(keyMeta) if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/internal/encryption/targets.go b/internal/encryption/targets.go index 182ec4f85f5..3365c91b8ff 100644 --- a/internal/encryption/targets.go +++ b/internal/encryption/targets.go @@ -24,7 +24,7 @@ type targetBuilder struct { // Used to evaluate hcl expressions ctx *hcl.EvalContext - keyProviderMetadata map[keyprovider.Addr]any + keyProviderMetadata map[keyprovider.Addr][]byte // Used to build EvalContext (and related mappings) keyValues map[string]map[string]cty.Value @@ -32,7 +32,7 @@ type targetBuilder struct { methods map[method.Addr]method.Method } -func (base *baseEncryption) buildTargetMethods(meta map[keyprovider.Addr]any) ([]method.Method, hcl.Diagnostics) { +func (base *baseEncryption) buildTargetMethods(meta map[keyprovider.Addr][]byte) ([]method.Method, hcl.Diagnostics) { var diags hcl.Diagnostics builder := &targetBuilder{ diff --git a/internal/varhcl/vardecode.go b/internal/varhcl/vardecode.go index 9093d3121a3..646a998d3f4 100644 --- a/internal/varhcl/vardecode.go +++ b/internal/varhcl/vardecode.go @@ -54,7 +54,9 @@ func findVariablesInBodyStruct(body hcl.Body, val reflect.Value) ([]hcl.Traversa for name := range tags.Attributes { attr := content.Attributes[name] - variables = append(variables, attr.Expr.Variables()...) + if attr != nil { + variables = append(variables, attr.Expr.Variables()...) + } } blocksByType := content.Blocks.ByType()