mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
allow static evaluations in encryption configuration (#1728)
Signed-off-by: ollevche <ollevche@gmail.com> Signed-off-by: Christian Mesh <christianmesh1@gmail.com> Signed-off-by: Oleksandr Levchenkov <ollevche@gmail.com> Co-authored-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
parent
8f8e0aa4aa
commit
19b5287b8f
@ -13,6 +13,7 @@ ENHANCEMENTS:
|
|||||||
* Make state persistence interval configurable via `TF_STATE_PERSIST_INTERVAL` environment variable ([#1591](https://github.com/opentofu/opentofu/pull/1591))
|
* Make state persistence interval configurable via `TF_STATE_PERSIST_INTERVAL` environment variable ([#1591](https://github.com/opentofu/opentofu/pull/1591))
|
||||||
* Improved performance of writing state files and reduced their size using compact json encoding. ([#1647](https://github.com/opentofu/opentofu/pull/1647))
|
* Improved performance of writing state files and reduced their size using compact json encoding. ([#1647](https://github.com/opentofu/opentofu/pull/1647))
|
||||||
* Allow to reference variable inside the `variables` block of a test file. ([1488](https://github.com/opentofu/opentofu/pull/1488))
|
* Allow to reference variable inside the `variables` block of a test file. ([1488](https://github.com/opentofu/opentofu/pull/1488))
|
||||||
|
* Allow variables and other static values to be used in encryption configuration. ([1728](https://github.com/opentofu/opentofu/pull/1728))
|
||||||
|
|
||||||
BUG FIXES:
|
BUG FIXES:
|
||||||
* Fixed validation for `enforced` flag in encryption configuration. ([#1711](https://github.com/opentofu/opentofu/pull/1711))
|
* Fixed validation for `enforced` flag in encryption configuration. ([#1711](https://github.com/opentofu/opentofu/pull/1711))
|
||||||
|
@ -1,8 +1,17 @@
|
|||||||
|
variable "passphrase" {
|
||||||
|
type = string
|
||||||
|
default = "aaaaaaaa-83f1-47ec-9b2d-2aebf6417167"
|
||||||
|
}
|
||||||
|
|
||||||
|
locals {
|
||||||
|
key_length = 32
|
||||||
|
}
|
||||||
|
|
||||||
terraform {
|
terraform {
|
||||||
encryption {
|
encryption {
|
||||||
key_provider "pbkdf2" "basic" {
|
key_provider "pbkdf2" "basic" {
|
||||||
passphrase = "aaaaaaaa-83f1-47ec-9b2d-2aebf6417167"
|
passphrase = var.passphrase
|
||||||
key_length = 32
|
key_length = local.key_length
|
||||||
iterations = 200000
|
iterations = 200000
|
||||||
hash_function = "sha512"
|
hash_function = "sha512"
|
||||||
salt_length = 12
|
salt_length = 12
|
||||||
|
@ -52,7 +52,7 @@ func (m *Meta) EncryptionFromModule(module *configs.Module) (encryption.Encrypti
|
|||||||
cfg = cfg.Merge(envCfg)
|
cfg = cfg.Merge(envCfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
enc, encDiags := encryption.New(encryption.DefaultRegistry, cfg)
|
enc, encDiags := encryption.New(encryption.DefaultRegistry, cfg, module.StaticEvaluator)
|
||||||
diags = diags.Append(encDiags)
|
diags = diags.Append(encDiags)
|
||||||
|
|
||||||
return enc, diags
|
return enc, diags
|
||||||
|
@ -64,6 +64,9 @@ type Module struct {
|
|||||||
// IsOverridden indicates if the module is being overridden. It's used in
|
// IsOverridden indicates if the module is being overridden. It's used in
|
||||||
// testing framework to not call the underlying module.
|
// testing framework to not call the underlying module.
|
||||||
IsOverridden bool
|
IsOverridden bool
|
||||||
|
|
||||||
|
// StaticEvaluator is used to evaluate static expressions in the scope of the Module.
|
||||||
|
StaticEvaluator *StaticEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
// File describes the contents of a single configuration file.
|
// File describes the contents of a single configuration file.
|
||||||
@ -186,20 +189,20 @@ func NewModule(primaryFiles, overrideFiles []*File, call StaticModuleCall, sourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Static evaluation to build a StaticContext now that module has all relevant Locals / Variables
|
// Static evaluation to build a StaticContext now that module has all relevant Locals / Variables
|
||||||
eval := NewStaticEvaluator(mod, call)
|
mod.StaticEvaluator = NewStaticEvaluator(mod, call)
|
||||||
|
|
||||||
// If we have a backend, it may have fields that require locals/vars
|
// If we have a backend, it may have fields that require locals/vars
|
||||||
if mod.Backend != nil {
|
if mod.Backend != nil {
|
||||||
// We don't know the backend type / loader at this point so we save the context for later use
|
// We don't know the backend type / loader at this point so we save the context for later use
|
||||||
mod.Backend.Eval = eval
|
mod.Backend.Eval = mod.StaticEvaluator
|
||||||
}
|
}
|
||||||
if mod.CloudConfig != nil {
|
if mod.CloudConfig != nil {
|
||||||
mod.CloudConfig.eval = eval
|
mod.CloudConfig.eval = mod.StaticEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process all module calls now that we have the static context
|
// Process all module calls now that we have the static context
|
||||||
for _, mc := range mod.ModuleCalls {
|
for _, mc := range mod.ModuleCalls {
|
||||||
mDiags := mc.decodeStaticFields(eval)
|
mDiags := mc.decodeStaticFields(mod.StaticEvaluator)
|
||||||
diags = append(diags, mDiags...)
|
diags = append(diags, mDiags...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ func TestParserLoadConfigDirWithTests_TofuFiles(t *testing.T) {
|
|||||||
parser := NewParser(nil)
|
parser := NewParser(nil)
|
||||||
path := tt.path
|
path := tt.path
|
||||||
|
|
||||||
mod, diags := parser.LoadConfigDirWithTests(path, "test")
|
mod, diags := parser.LoadConfigDirWithTests(path, "test", RootModuleCallForTesting())
|
||||||
if len(diags) != 0 {
|
if len(diags) != 0 {
|
||||||
t.Errorf("unexpected diagnostics")
|
t.Errorf("unexpected diagnostics")
|
||||||
for _, diag := range diags {
|
for _, diag := range diags {
|
||||||
|
@ -117,3 +117,12 @@ func (s StaticEvaluator) DecodeBlock(body hcl.Body, spec hcldec.Spec, ident Stat
|
|||||||
diags = append(diags, valDiags...)
|
diags = append(diags, valDiags...)
|
||||||
return val, diags
|
return val, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s StaticEvaluator) EvalContext(ident StaticIdentifier, refs []*addrs.Reference) (*hcl.EvalContext, hcl.Diagnostics) {
|
||||||
|
return s.EvalContextWithParent(nil, ident, refs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s StaticEvaluator) EvalContextWithParent(parent *hcl.EvalContext, ident StaticIdentifier, refs []*addrs.Reference) (*hcl.EvalContext, hcl.Diagnostics) {
|
||||||
|
evalCtx, diags := s.scope(ident).EvalContextWithParent(parent, refs)
|
||||||
|
return evalCtx, diags.ToHCL()
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/keyprovider"
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/method"
|
"github.com/opentofu/opentofu/internal/encryption/method"
|
||||||
@ -28,15 +29,17 @@ type baseEncryption struct {
|
|||||||
name string
|
name string
|
||||||
encMethods []method.Method
|
encMethods []method.Method
|
||||||
encMeta map[keyprovider.Addr][]byte
|
encMeta map[keyprovider.Addr][]byte
|
||||||
|
staticEval *configs.StaticEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
func newBaseEncryption(enc *encryption, target *config.TargetConfig, enforced bool, name string) (*baseEncryption, hcl.Diagnostics) {
|
func newBaseEncryption(enc *encryption, target *config.TargetConfig, enforced bool, name string, staticEval *configs.StaticEvaluator) (*baseEncryption, hcl.Diagnostics) {
|
||||||
base := &baseEncryption{
|
base := &baseEncryption{
|
||||||
enc: enc,
|
enc: enc,
|
||||||
target: target,
|
target: target,
|
||||||
enforced: enforced,
|
enforced: enforced,
|
||||||
name: name,
|
name: name,
|
||||||
encMeta: make(map[keyprovider.Addr][]byte),
|
encMeta: make(map[keyprovider.Addr][]byte),
|
||||||
|
staticEval: staticEval,
|
||||||
}
|
}
|
||||||
// Setup the encryptor
|
// Setup the encryptor
|
||||||
//
|
//
|
||||||
|
@ -31,6 +31,16 @@ func (c *EncryptionConfig) Merge(override *EncryptionConfig) *EncryptionConfig {
|
|||||||
return MergeConfigs(c, override)
|
return MergeConfigs(c, override)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetKeyProvider takes type and name arguments to find a respective KeyProviderConfig in the list.
|
||||||
|
func (c *EncryptionConfig) GetKeyProvider(kpType, kpName string) (KeyProviderConfig, bool) {
|
||||||
|
for _, kp := range c.KeyProviderConfigs {
|
||||||
|
if kp.Type == kpType && kp.Name == kpName {
|
||||||
|
return kp, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return KeyProviderConfig{}, false
|
||||||
|
}
|
||||||
|
|
||||||
// KeyProviderConfig describes the terraform.encryption.key_provider.* block you can use to declare a key provider for
|
// KeyProviderConfig describes the terraform.encryption.key_provider.* block you can use to declare a key provider for
|
||||||
// encryption. The Body field will contain the remaining undeclared fields the key provider can consume.
|
// encryption. The Body field will contain the remaining undeclared fields the key provider can consume.
|
||||||
type KeyProviderConfig struct {
|
type KeyProviderConfig struct {
|
||||||
|
@ -7,6 +7,7 @@ package encryption
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/registry"
|
"github.com/opentofu/opentofu/internal/encryption/registry"
|
||||||
)
|
)
|
||||||
@ -37,7 +38,7 @@ type encryption struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new Encryption provider from the given configuration and registry.
|
// New creates a new Encryption provider from the given configuration and registry.
|
||||||
func New(reg registry.Registry, cfg *config.EncryptionConfig) (Encryption, hcl.Diagnostics) {
|
func New(reg registry.Registry, cfg *config.EncryptionConfig, staticEval *configs.StaticEvaluator) (Encryption, hcl.Diagnostics) {
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
return Disabled(), nil
|
return Disabled(), nil
|
||||||
}
|
}
|
||||||
@ -52,21 +53,21 @@ func New(reg registry.Registry, cfg *config.EncryptionConfig) (Encryption, hcl.D
|
|||||||
var encDiags hcl.Diagnostics
|
var encDiags hcl.Diagnostics
|
||||||
|
|
||||||
if cfg.State != nil {
|
if cfg.State != nil {
|
||||||
enc.state, encDiags = newStateEncryption(enc, cfg.State.AsTargetConfig(), cfg.State.Enforced, "state")
|
enc.state, encDiags = newStateEncryption(enc, cfg.State.AsTargetConfig(), cfg.State.Enforced, "state", staticEval)
|
||||||
diags = append(diags, encDiags...)
|
diags = append(diags, encDiags...)
|
||||||
} else {
|
} else {
|
||||||
enc.state = StateEncryptionDisabled()
|
enc.state = StateEncryptionDisabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Plan != nil {
|
if cfg.Plan != nil {
|
||||||
enc.plan, encDiags = newPlanEncryption(enc, cfg.Plan.AsTargetConfig(), cfg.Plan.Enforced, "plan")
|
enc.plan, encDiags = newPlanEncryption(enc, cfg.Plan.AsTargetConfig(), cfg.Plan.Enforced, "plan", staticEval)
|
||||||
diags = append(diags, encDiags...)
|
diags = append(diags, encDiags...)
|
||||||
} else {
|
} else {
|
||||||
enc.plan = PlanEncryptionDisabled()
|
enc.plan = PlanEncryptionDisabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Remote != nil && cfg.Remote.Default != nil {
|
if cfg.Remote != nil && cfg.Remote.Default != nil {
|
||||||
enc.remoteDefault, encDiags = newStateEncryption(enc, cfg.Remote.Default, false, "remote.default")
|
enc.remoteDefault, encDiags = newStateEncryption(enc, cfg.Remote.Default, false, "remote.default", staticEval)
|
||||||
diags = append(diags, encDiags...)
|
diags = append(diags, encDiags...)
|
||||||
} else {
|
} else {
|
||||||
enc.remoteDefault = StateEncryptionDisabled()
|
enc.remoteDefault = StateEncryptionDisabled()
|
||||||
@ -76,7 +77,7 @@ func New(reg registry.Registry, cfg *config.EncryptionConfig) (Encryption, hcl.D
|
|||||||
for _, remoteTarget := range cfg.Remote.Targets {
|
for _, remoteTarget := range cfg.Remote.Targets {
|
||||||
// TODO the addr here should be generated in one place.
|
// TODO the addr here should be generated in one place.
|
||||||
addr := "remote.remote_state_datasource." + remoteTarget.Name
|
addr := "remote.remote_state_datasource." + remoteTarget.Name
|
||||||
enc.remotes[remoteTarget.Name], encDiags = newStateEncryption(enc, remoteTarget.AsTargetConfig(), false, addr)
|
enc.remotes[remoteTarget.Name], encDiags = newStateEncryption(enc, remoteTarget.AsTargetConfig(), false, addr, staticEval)
|
||||||
diags = append(diags, encDiags...)
|
diags = append(diags, encDiags...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ package enctest
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption"
|
"github.com/opentofu/opentofu/internal/encryption"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
||||||
@ -35,7 +36,9 @@ func EncryptionDirect(configData string) encryption.Encryption {
|
|||||||
|
|
||||||
handleDiags(diags)
|
handleDiags(diags)
|
||||||
|
|
||||||
enc, diags := encryption.New(reg, cfg)
|
staticEval := configs.NewStaticEvaluator(nil, configs.RootModuleCallForTesting())
|
||||||
|
|
||||||
|
enc, diags := encryption.New(reg, cfg, staticEval)
|
||||||
handleDiags(diags)
|
handleDiags(diags)
|
||||||
|
|
||||||
return enc
|
return enc
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption"
|
"github.com/opentofu/opentofu/internal/encryption"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
||||||
@ -57,8 +58,11 @@ func Example() {
|
|||||||
// Merge the configurations
|
// Merge the configurations
|
||||||
cfg := config.MergeConfigs(cfgA, cfgB)
|
cfg := config.MergeConfigs(cfgA, cfgB)
|
||||||
|
|
||||||
|
// Construct static evaluator to pass additional values into encryption configuration.
|
||||||
|
staticEval := configs.NewStaticEvaluator(nil, configs.RootModuleCallForTesting())
|
||||||
|
|
||||||
// Construct the encryption object
|
// Construct the encryption object
|
||||||
enc, diags := encryption.New(reg, cfg)
|
enc, diags := encryption.New(reg, cfg, staticEval)
|
||||||
handleDiags(diags)
|
handleDiags(diags)
|
||||||
|
|
||||||
sfe := enc.State()
|
sfe := enc.State()
|
||||||
|
@ -10,7 +10,10 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/opentofu/opentofu/internal/addrs"
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
|
"github.com/opentofu/opentofu/internal/lang"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/keyprovider"
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider"
|
||||||
@ -88,17 +91,17 @@ func (e *targetBuilder) setupKeyProvider(cfg config.KeyProviderConfig, stack []c
|
|||||||
keyProviderDescriptor, err := e.reg.GetKeyProviderDescriptor(id)
|
keyProviderDescriptor, err := e.reg.GetKeyProviderDescriptor(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ®istry.KeyProviderNotFoundError{}) {
|
if errors.Is(err, ®istry.KeyProviderNotFoundError{}) {
|
||||||
return hcl.Diagnostics{&hcl.Diagnostic{
|
return diags.Append(&hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Unknown key_provider type",
|
Summary: "Unknown key_provider type",
|
||||||
Detail: fmt.Sprintf("Can not find %q", cfg.Type),
|
Detail: fmt.Sprintf("Can not find %q", cfg.Type),
|
||||||
}}
|
})
|
||||||
}
|
}
|
||||||
return hcl.Diagnostics{&hcl.Diagnostic{
|
return diags.Append(&hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: fmt.Sprintf("Error fetching key_provider %q", cfg.Type),
|
Summary: fmt.Sprintf("Error fetching key_provider %q", cfg.Type),
|
||||||
Detail: err.Error(),
|
Detail: err.Error(),
|
||||||
}}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we know we have the correct Descriptor, we can decode the configuration
|
// Now that we know we have the correct Descriptor, we can decode the configuration
|
||||||
@ -106,21 +109,21 @@ func (e *targetBuilder) setupKeyProvider(cfg config.KeyProviderConfig, stack []c
|
|||||||
keyProviderConfig := keyProviderDescriptor.ConfigStruct()
|
keyProviderConfig := keyProviderDescriptor.ConfigStruct()
|
||||||
|
|
||||||
// Locate all the dependencies
|
// Locate all the dependencies
|
||||||
deps, diags := gohcl.VariablesInBody(cfg.Body, keyProviderConfig)
|
deps, varDiags := gohcl.VariablesInBody(cfg.Body, keyProviderConfig)
|
||||||
|
diags = append(diags, varDiags...)
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Required Dependencies
|
// lang.References is going to fail parsing key_provider deps
|
||||||
|
// so we filter them out in nonKeyProviderDeps.
|
||||||
|
var nonKeyProviderDeps []hcl.Traversal
|
||||||
|
|
||||||
|
// Setting up key providers from deps.
|
||||||
for _, dep := range deps {
|
for _, dep := range deps {
|
||||||
// Key Provider references should be in the form key_provider.type.name
|
// Key Provider references should be in the form key_provider.type.name
|
||||||
if len(dep) != 3 {
|
if len(dep) != 3 {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
nonKeyProviderDeps = append(nonKeyProviderDeps, dep)
|
||||||
Severity: hcl.DiagError,
|
|
||||||
Summary: "Invalid key_provider reference",
|
|
||||||
Detail: "Expected reference in form key_provider.type.name",
|
|
||||||
Subject: dep.SourceRange().Ptr(),
|
|
||||||
})
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,23 +133,23 @@ func (e *targetBuilder) setupKeyProvider(cfg config.KeyProviderConfig, stack []c
|
|||||||
depName := (dep[2].(hcl.TraverseAttr)).Name
|
depName := (dep[2].(hcl.TraverseAttr)).Name
|
||||||
|
|
||||||
if depRoot != "key_provider" {
|
if depRoot != "key_provider" {
|
||||||
|
nonKeyProviderDeps = append(nonKeyProviderDeps, dep)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
kpc, ok := e.cfg.GetKeyProvider(depType, depName)
|
||||||
|
if !ok {
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
diags = append(diags, &hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: "Invalid key_provider reference",
|
Summary: "Undefined Key Provider",
|
||||||
Detail: "Expected reference in form key_provider.type.name",
|
Detail: fmt.Sprintf("Key provider %s.%s is missing from the encryption configuration.", depType, depName),
|
||||||
Subject: dep.SourceRange().Ptr(),
|
Subject: dep.SourceRange().Ptr(),
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, kpc := range e.cfg.KeyProviderConfigs {
|
|
||||||
// Find the key provider in the config
|
|
||||||
if kpc.Type == depType && kpc.Name == depName {
|
|
||||||
depDiags := e.setupKeyProvider(kpc, stack)
|
depDiags := e.setupKeyProvider(kpc, stack)
|
||||||
diags = append(diags, depDiags...)
|
diags = append(diags, depDiags...)
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
// We should not continue now if we have any diagnostics that are errors
|
// We should not continue now if we have any diagnostics that are errors
|
||||||
@ -156,8 +159,24 @@ func (e *targetBuilder) setupKeyProvider(cfg config.KeyProviderConfig, stack []c
|
|||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refs, refDiags := lang.References(addrs.ParseRef, nonKeyProviderDeps)
|
||||||
|
diags = append(diags, refDiags.ToHCL()...)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
|
evalCtx, evalDiags := e.staticEval.EvalContextWithParent(e.ctx, configs.StaticIdentifier{
|
||||||
|
Module: addrs.RootModule,
|
||||||
|
Subject: fmt.Sprintf("encryption.key_provider.%s.%s", cfg.Type, cfg.Name),
|
||||||
|
DeclRange: e.cfg.DeclRange,
|
||||||
|
}, refs)
|
||||||
|
diags = append(diags, evalDiags...)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize the Key Provider
|
// Initialize the Key Provider
|
||||||
decodeDiags := gohcl.DecodeBody(cfg.Body, e.ctx, keyProviderConfig)
|
decodeDiags := gohcl.DecodeBody(cfg.Body, evalCtx, keyProviderConfig)
|
||||||
diags = append(diags, decodeDiags...)
|
diags = append(diags, decodeDiags...)
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
return diags
|
return diags
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption"
|
"github.com/opentofu/opentofu/internal/encryption"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
||||||
@ -44,7 +45,9 @@ func Example() {
|
|||||||
panic(diags)
|
panic(diags)
|
||||||
}
|
}
|
||||||
|
|
||||||
enc, diags := encryption.New(registry, cfg)
|
staticEvaluator := configs.NewStaticEvaluator(nil, configs.RootModuleCallForTesting())
|
||||||
|
|
||||||
|
enc, diags := encryption.New(registry, cfg, staticEvaluator)
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
panic(diags)
|
panic(diags)
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,8 +50,8 @@ type planEncryption struct {
|
|||||||
base *baseEncryption
|
base *baseEncryption
|
||||||
}
|
}
|
||||||
|
|
||||||
func newPlanEncryption(enc *encryption, target *config.TargetConfig, enforced bool, name string) (PlanEncryption, hcl.Diagnostics) {
|
func newPlanEncryption(enc *encryption, target *config.TargetConfig, enforced bool, name string, staticEval *configs.StaticEvaluator) (PlanEncryption, hcl.Diagnostics) {
|
||||||
base, diags := newBaseEncryption(enc, target, enforced, name)
|
base, diags := newBaseEncryption(enc, target, enforced, name, staticEval)
|
||||||
return &planEncryption{base}, diags
|
return &planEncryption{base}, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -57,8 +58,8 @@ type stateEncryption struct {
|
|||||||
base *baseEncryption
|
base *baseEncryption
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStateEncryption(enc *encryption, target *config.TargetConfig, enforced bool, name string) (StateEncryption, hcl.Diagnostics) {
|
func newStateEncryption(enc *encryption, target *config.TargetConfig, enforced bool, name string, staticEval *configs.StaticEvaluator) (StateEncryption, hcl.Diagnostics) {
|
||||||
base, diags := newBaseEncryption(enc, target, enforced, name)
|
base, diags := newBaseEncryption(enc, target, enforced, name, staticEval)
|
||||||
return &stateEncryption{base}, diags
|
return &stateEncryption{base}, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
"github.com/hashicorp/hcl/v2/gohcl"
|
"github.com/hashicorp/hcl/v2/gohcl"
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/keyprovider"
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/method"
|
"github.com/opentofu/opentofu/internal/encryption/method"
|
||||||
@ -31,6 +32,7 @@ type targetBuilder struct {
|
|||||||
keyValues map[string]map[string]cty.Value
|
keyValues map[string]map[string]cty.Value
|
||||||
methodValues map[string]map[string]cty.Value
|
methodValues map[string]map[string]cty.Value
|
||||||
methods map[method.Addr]method.Method
|
methods map[method.Addr]method.Method
|
||||||
|
staticEval *configs.StaticEvaluator
|
||||||
}
|
}
|
||||||
|
|
||||||
func (base *baseEncryption) buildTargetMethods(meta map[keyprovider.Addr][]byte) ([]method.Method, hcl.Diagnostics) {
|
func (base *baseEncryption) buildTargetMethods(meta map[keyprovider.Addr][]byte) ([]method.Method, hcl.Diagnostics) {
|
||||||
@ -40,6 +42,7 @@ func (base *baseEncryption) buildTargetMethods(meta map[keyprovider.Addr][]byte)
|
|||||||
cfg: base.enc.cfg,
|
cfg: base.enc.cfg,
|
||||||
reg: base.enc.reg,
|
reg: base.enc.reg,
|
||||||
|
|
||||||
|
staticEval: base.staticEval,
|
||||||
ctx: &hcl.EvalContext{
|
ctx: &hcl.EvalContext{
|
||||||
Variables: map[string]cty.Value{},
|
Variables: map[string]cty.Value{},
|
||||||
},
|
},
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2"
|
"github.com/hashicorp/hcl/v2"
|
||||||
|
"github.com/opentofu/opentofu/internal/addrs"
|
||||||
|
"github.com/opentofu/opentofu/internal/configs"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/config"
|
"github.com/opentofu/opentofu/internal/encryption/config"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/keyprovider"
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
"github.com/opentofu/opentofu/internal/encryption/keyprovider/static"
|
||||||
@ -18,6 +20,7 @@ import (
|
|||||||
"github.com/opentofu/opentofu/internal/encryption/method/unencrypted"
|
"github.com/opentofu/opentofu/internal/encryption/method/unencrypted"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/registry"
|
"github.com/opentofu/opentofu/internal/encryption/registry"
|
||||||
"github.com/opentofu/opentofu/internal/encryption/registry/lockingencryptionregistry"
|
"github.com/opentofu/opentofu/internal/encryption/registry/lockingencryptionregistry"
|
||||||
|
"github.com/zclconf/go-cty/cty"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBaseEncryption_buildTargetMethods(t *testing.T) {
|
func TestBaseEncryption_buildTargetMethods(t *testing.T) {
|
||||||
@ -112,6 +115,36 @@ func TestBaseEncryption_buildTargetMethods(t *testing.T) {
|
|||||||
`,
|
`,
|
||||||
wantErr: "<nil>: Unencrypted method is forbidden; Unable to use `unencrypted` method since the `enforced` flag is used.",
|
wantErr: "<nil>: Unencrypted method is forbidden; Unable to use `unencrypted` method since the `enforced` flag is used.",
|
||||||
},
|
},
|
||||||
|
"key-from-vars": {
|
||||||
|
rawConfig: `
|
||||||
|
key_provider "static" "basic" {
|
||||||
|
key = var.key
|
||||||
|
}
|
||||||
|
method "aes_gcm" "example" {
|
||||||
|
keys = key_provider.static.basic
|
||||||
|
}
|
||||||
|
state {
|
||||||
|
method = method.aes_gcm.example
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
wantMethods: []func(method.Method) bool{
|
||||||
|
aesgcm.Is,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"undefined-key-from-vars": {
|
||||||
|
rawConfig: `
|
||||||
|
key_provider "static" "basic" {
|
||||||
|
key = var.undefinedkey
|
||||||
|
}
|
||||||
|
method "aes_gcm" "example" {
|
||||||
|
keys = key_provider.static.basic
|
||||||
|
}
|
||||||
|
state {
|
||||||
|
method = method.aes_gcm.example
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
wantErr: "Test Config Source:3,12-28: Undefined variable; Undefined variable var.undefinedkey",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
reg := lockingencryptionregistry.New()
|
reg := lockingencryptionregistry.New()
|
||||||
@ -125,8 +158,26 @@ func TestBaseEncryption_buildTargetMethods(t *testing.T) {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod := &configs.Module{
|
||||||
|
Variables: map[string]*configs.Variable{
|
||||||
|
"key": {
|
||||||
|
Name: "key",
|
||||||
|
Default: cty.StringVal("6f6f706830656f67686f6834616872756f3751756165686565796f6f72653169"),
|
||||||
|
Type: cty.String,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
getVars := func(v *configs.Variable) (cty.Value, hcl.Diagnostics) {
|
||||||
|
return v.Default, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
modCall := configs.NewStaticModuleCall(addrs.RootModule, getVars, "<testing>", "")
|
||||||
|
|
||||||
|
staticEval := configs.NewStaticEvaluator(mod, modCall)
|
||||||
|
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
t.Run(name, test.newTestRun(reg))
|
t.Run(name, test.newTestRun(reg, staticEval))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +187,7 @@ type btmTestCase struct {
|
|||||||
wantErr string
|
wantErr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (testCase btmTestCase) newTestRun(reg registry.Registry) func(t *testing.T) {
|
func (testCase btmTestCase) newTestRun(reg registry.Registry, staticEval *configs.StaticEvaluator) func(t *testing.T) {
|
||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@ -154,6 +205,7 @@ func (testCase btmTestCase) newTestRun(reg registry.Registry) func(t *testing.T)
|
|||||||
enforced: cfg.State.Enforced,
|
enforced: cfg.State.Enforced,
|
||||||
name: "test",
|
name: "test",
|
||||||
encMeta: make(map[keyprovider.Addr][]byte),
|
encMeta: make(map[keyprovider.Addr][]byte),
|
||||||
|
staticEval: staticEval,
|
||||||
}
|
}
|
||||||
|
|
||||||
methods, diags := base.buildTargetMethods(base.encMeta)
|
methods, diags := base.buildTargetMethods(base.encMeta)
|
||||||
|
@ -260,7 +260,7 @@ func (s *Scope) EvalReference(ref *addrs.Reference, wantType cty.Type) (cty.Valu
|
|||||||
// We cheat a bit here and just build an EvalContext for our requested
|
// We cheat a bit here and just build an EvalContext for our requested
|
||||||
// reference with the "self" address overridden, and then pull the "self"
|
// reference with the "self" address overridden, and then pull the "self"
|
||||||
// result out of it to return.
|
// result out of it to return.
|
||||||
ctx, ctxDiags := s.evalContext([]*addrs.Reference{ref}, ref.Subject)
|
ctx, ctxDiags := s.evalContext(nil, []*addrs.Reference{ref}, ref.Subject)
|
||||||
diags = diags.Append(ctxDiags)
|
diags = diags.Append(ctxDiags)
|
||||||
val := ctx.Variables["self"]
|
val := ctx.Variables["self"]
|
||||||
if val == cty.NilVal {
|
if val == cty.NilVal {
|
||||||
@ -289,21 +289,34 @@ func (s *Scope) EvalReference(ref *addrs.Reference, wantType cty.Type) (cty.Valu
|
|||||||
// this type offers, but this is here for less common situations where the
|
// this type offers, but this is here for less common situations where the
|
||||||
// caller will handle the evaluation calls itself.
|
// caller will handle the evaluation calls itself.
|
||||||
func (s *Scope) EvalContext(refs []*addrs.Reference) (*hcl.EvalContext, tfdiags.Diagnostics) {
|
func (s *Scope) EvalContext(refs []*addrs.Reference) (*hcl.EvalContext, tfdiags.Diagnostics) {
|
||||||
return s.evalContext(refs, s.SelfAddr)
|
return s.evalContext(nil, refs, s.SelfAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) evalContext(refs []*addrs.Reference, selfAddr addrs.Referenceable) (*hcl.EvalContext, tfdiags.Diagnostics) {
|
// EvalContextWithParent is exactly the same as EvalContext except the resulting hcl.EvalContext
|
||||||
|
// will be derived from the given parental hcl.EvalContext. It will enable different hcl mechanisms
|
||||||
|
// to iteratively lookup target functions and variables in EvalContext's parent.
|
||||||
|
// See Traversal.TraverseAbs (hcl) or FunctionCallExpr.Value (hcl/hclsyntax) for more details.
|
||||||
|
func (s *Scope) EvalContextWithParent(p *hcl.EvalContext, refs []*addrs.Reference) (*hcl.EvalContext, tfdiags.Diagnostics) {
|
||||||
|
return s.evalContext(p, refs, s.SelfAddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:funlen,gocyclo,cyclop // TODO: refactor this function to match linting requirements
|
||||||
|
func (s *Scope) evalContext(parent *hcl.EvalContext, refs []*addrs.Reference, selfAddr addrs.Referenceable) (*hcl.EvalContext, tfdiags.Diagnostics) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
panic("attempt to construct EvalContext for nil Scope")
|
panic("attempt to construct EvalContext for nil Scope")
|
||||||
}
|
}
|
||||||
|
|
||||||
var diags tfdiags.Diagnostics
|
var diags tfdiags.Diagnostics
|
||||||
|
|
||||||
vals := make(map[string]cty.Value)
|
vals := make(map[string]cty.Value)
|
||||||
funcs := make(map[string]function.Function)
|
funcs := make(map[string]function.Function)
|
||||||
ctx := &hcl.EvalContext{
|
|
||||||
Variables: vals,
|
// Calling NewChild() on a nil parent will
|
||||||
Functions: funcs,
|
// produce an EvalContext with no parent.
|
||||||
}
|
ctx := parent.NewChild()
|
||||||
|
ctx.Variables = vals
|
||||||
|
ctx.Functions = funcs
|
||||||
|
|
||||||
for name, fn := range s.Functions() {
|
for name, fn := range s.Functions() {
|
||||||
funcs[name] = fn
|
funcs[name] = fn
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ package lang
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/opentofu/opentofu/internal/addrs"
|
"github.com/opentofu/opentofu/internal/addrs"
|
||||||
@ -19,6 +20,7 @@ import (
|
|||||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||||
|
|
||||||
"github.com/zclconf/go-cty/cty"
|
"github.com/zclconf/go-cty/cty"
|
||||||
|
"github.com/zclconf/go-cty/cty/function"
|
||||||
ctyjson "github.com/zclconf/go-cty/cty/json"
|
ctyjson "github.com/zclconf/go-cty/cty/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -421,6 +423,76 @@ func TestScopeEvalContext(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestScopeEvalContextWithParent tests if the resulting EvalCtx has correct parent.
|
||||||
|
func TestScopeEvalContextWithParent(t *testing.T) {
|
||||||
|
t.Run("with-parent", func(t *testing.T) {
|
||||||
|
barStr, barFunc := cty.StringVal("bar"), function.New(&function.Spec{
|
||||||
|
Impl: func(_ []cty.Value, _ cty.Type) (cty.Value, error) {
|
||||||
|
return cty.NilVal, nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
scope, parent := &Scope{}, &hcl.EvalContext{
|
||||||
|
Variables: map[string]cty.Value{
|
||||||
|
"foo": barStr,
|
||||||
|
},
|
||||||
|
Functions: map[string]function.Function{
|
||||||
|
"foo": barFunc,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
child, diags := scope.EvalContextWithParent(parent, nil)
|
||||||
|
if len(diags) != 0 {
|
||||||
|
t.Errorf("Unexpected diagnostics:")
|
||||||
|
for _, diag := range diags {
|
||||||
|
t.Errorf("- %s", diag)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if child.Parent() == nil {
|
||||||
|
t.Fatalf("Child EvalCtx has no parent")
|
||||||
|
}
|
||||||
|
|
||||||
|
if child.Parent() != parent {
|
||||||
|
t.Fatalf("Child EvalCtx has different parent:\n GOT:%v\nWANT:%v", child.Parent(), parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ln := len(child.Parent().Variables); ln != 1 {
|
||||||
|
t.Fatalf("EvalContextWithParent modified parent's variables: incorrent length: %d", ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := child.Parent().Variables["foo"]; !v.RawEquals(barStr) {
|
||||||
|
t.Fatalf("EvalContextWithParent modified parent's variables:\n GOT:%v\nWANT:%v", v, barStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ln := len(child.Parent().Functions); ln != 1 {
|
||||||
|
t.Fatalf("EvalContextWithParent modified parent's functions: incorrent length: %d", ln)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v := child.Parent().Functions["foo"]; !reflect.DeepEqual(v, barFunc) {
|
||||||
|
t.Fatalf("EvalContextWithParent modified parent's functions:\n GOT:%v\nWANT:%v", v, barFunc)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("zero-parent", func(t *testing.T) {
|
||||||
|
scope := &Scope{}
|
||||||
|
|
||||||
|
root, diags := scope.EvalContextWithParent(nil, nil)
|
||||||
|
if len(diags) != 0 {
|
||||||
|
t.Errorf("Unexpected diagnostics:")
|
||||||
|
for _, diag := range diags {
|
||||||
|
t.Errorf("- %s", diag)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if root.Parent() != nil {
|
||||||
|
t.Fatalf("Resulting EvalCtx has unexpected parent: %v", root.Parent())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestScopeExpandEvalBlock(t *testing.T) {
|
func TestScopeExpandEvalBlock(t *testing.T) {
|
||||||
nestedObjTy := cty.Object(map[string]cty.Type{
|
nestedObjTy := cty.Object(map[string]cty.Type{
|
||||||
"boop": cty.String,
|
"boop": cty.String,
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
variable "passphrase" {
|
||||||
|
# Change passphrase to be at least 16 characters long:
|
||||||
|
default = "changeme!"
|
||||||
|
}
|
||||||
|
|
||||||
terraform {
|
terraform {
|
||||||
encryption {
|
encryption {
|
||||||
## Step 1: Add the unencrypted method:
|
## Step 1: Add the unencrypted method:
|
||||||
@ -5,8 +10,7 @@ terraform {
|
|||||||
|
|
||||||
## Step 2: Add the desired key provider:
|
## Step 2: Add the desired key provider:
|
||||||
key_provider "pbkdf2" "mykey" {
|
key_provider "pbkdf2" "mykey" {
|
||||||
# Change this to be at least 16 characters long:
|
passphrase = var.passphrase
|
||||||
passphrase = "changeme!"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
## Step 3: Add the desired encryption method:
|
## Step 3: Add the desired encryption method:
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
|
variable "passphrase" {
|
||||||
|
# Change passphrase to be at least 16 characters long:
|
||||||
|
default = "changeme!"
|
||||||
|
}
|
||||||
|
|
||||||
terraform {
|
terraform {
|
||||||
encryption {
|
encryption {
|
||||||
## Step 1: Add the desired key provider:
|
## Step 1: Add the desired key provider:
|
||||||
key_provider "pbkdf2" "mykey" {
|
key_provider "pbkdf2" "mykey" {
|
||||||
# Change this to be at least 16 characters long:
|
passphrase = var.passphrase
|
||||||
passphrase = "changeme!"
|
|
||||||
}
|
}
|
||||||
## Step 2: Set up your encryption method:
|
## Step 2: Set up your encryption method:
|
||||||
method "aes_gcm" "new_method" {
|
method "aes_gcm" "new_method" {
|
||||||
|
Loading…
Reference in New Issue
Block a user