Skip to content

Commit

Permalink
Update to encryption key provider interface (opentofu#1351)
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Mesh <[email protected]>
  • Loading branch information
cam72cam authored Mar 8, 2024
1 parent 8cd4036 commit cef62ea
Show file tree
Hide file tree
Showing 9 changed files with 49 additions and 49 deletions.
10 changes: 5 additions & 5 deletions internal/encryption/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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,
}

Expand Down
58 changes: 27 additions & 31 deletions internal/encryption/keyprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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

}
7 changes: 5 additions & 2 deletions internal/encryption/keyprovider/keyprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
1 change: 0 additions & 1 deletion internal/encryption/keyprovider/output.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 3 additions & 3 deletions internal/encryption/keyprovider/static/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions internal/encryption/keyprovider/static/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions internal/encryption/keyprovider/static/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/encryption/targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ 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
methodValues map[string]map[string]cty.Value
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{
Expand Down
4 changes: 3 additions & 1 deletion internal/varhcl/vardecode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down

0 comments on commit cef62ea

Please sign in to comment.